unc_primitives/
views.rs

1//! This module defines "stable" internal API to view internal data using view_client.
2//!
3//! These types should only change when we cannot avoid this. Thus, when the counterpart internal
4//! type gets changed, the view should preserve the old shape and only re-map the necessary bits
5//! from the source structure in the relevant `From<SourceStruct>` impl.
6use crate::account::{AccessKey, AccessKeyPermission, Account, FunctionCallPermission};
7use crate::action::delegate::{DelegateAction, SignedDelegateAction};
8use crate::block::{Block, BlockHeader, Tip};
9use crate::block_header::{
10    BlockHeaderInnerLite, BlockHeaderInnerRest, BlockHeaderInnerRestV2, BlockHeaderInnerRestV3,
11    BlockHeaderV1, BlockHeaderV2, BlockHeaderV3,
12};
13use crate::block_header::{BlockHeaderInnerRestV4, BlockHeaderV4};
14use crate::challenge::{Challenge, ChallengesResult};
15use crate::checked_feature;
16use crate::errors::TxExecutionError;
17use crate::hash::{hash, CryptoHash};
18use crate::merkle::{combine_hash, MerklePath};
19use crate::network::PeerId;
20use crate::receipt::{ActionReceipt, DataReceipt, DataReceiver, Receipt, ReceiptEnum};
21use crate::serialize::dec_format;
22use crate::sharding::{
23    ChunkHash, ShardChunk, ShardChunkHeader, ShardChunkHeaderInner, ShardChunkHeaderInnerV2,
24    ShardChunkHeaderV3,
25};
26use crate::transaction::{
27    Action, AddKeyAction, CreateAccountAction, DeleteAccountAction, DeleteKeyAction,
28    DeployContractAction, ExecutionMetadata, ExecutionOutcome, ExecutionOutcomeWithIdAndProof,
29    ExecutionStatus, FunctionCallAction, PartialExecutionOutcome, PartialExecutionStatus,
30    PledgeAction, SignedTransaction, TransferAction,
31};
32use crate::types::{
33    AccountId, AccountWithPublicKey, Balance, BlockHeight, EpochHeight, EpochId, FunctionArgs, Gas,
34    Nonce, NumBlocks, Power, ShardId, StateChangeCause, StateChangeKind, StateChangeValue,
35    StateChangeWithCause, StateChangesRequest, StateRoot, StorageUsage, StoreKey, StoreValue,
36    ValidatorKickoutReason,
37};
38
39use crate::action::{CreateRsa2048ChallengeAction, RegisterRsa2048KeysAction};
40use crate::types::validator_power_and_pledge::{
41    ValidatorPowerAndPledge, ValidatorPowerAndPledgeIter,
42};
43use crate::version::{ProtocolVersion, Version};
44use crate::views::validator_pledge_view::ValidatorPledgeView;
45use crate::views::validator_power_and_pledge_view::ValidatorPowerAndPledgeView;
46use borsh::{BorshDeserialize, BorshSerialize};
47use chrono::DateTime;
48use serde_with::base64::Base64;
49use serde_with::serde_as;
50use std::collections::HashMap;
51use std::fmt;
52use std::ops::Range;
53use std::sync::Arc;
54use strum::IntoEnumIterator;
55use unc_crypto::{PublicKey, Signature};
56use unc_fmt::{AbbrBytes, Slice};
57use unc_parameters::{ActionCosts, ExtCosts};
58use unc_vm_runner::logic::CompiledContractCache;
59use unc_vm_runner::ContractCode;
60use validator_power_view::ValidatorPowerView;
61
62/// A view of the account
63#[derive(serde::Serialize, serde::Deserialize, Debug, Eq, PartialEq, Clone)]
64pub struct AccountView {
65    #[serde(with = "dec_format")]
66    pub amount: Balance,
67    #[serde(with = "dec_format")]
68    pub pledging: Balance,
69    #[serde(with = "dec_format")]
70    pub power: Power,
71    pub code_hash: CryptoHash,
72    pub storage_usage: StorageUsage,
73    /// TODO(2271): deprecated.
74    #[serde(default)]
75    pub storage_paid_at: BlockHeight,
76}
77
78/// A view of the contract code.
79#[serde_as]
80#[derive(serde::Serialize, serde::Deserialize, PartialEq, Eq, Debug, Clone)]
81pub struct ContractCodeView {
82    #[serde(rename = "code_base64")]
83    #[serde_as(as = "Base64")]
84    pub code: Vec<u8>,
85    pub hash: CryptoHash,
86}
87
88/// State for the view call.
89#[derive(Debug)]
90pub struct ViewApplyState {
91    /// Currently building block height.
92    pub block_height: BlockHeight,
93    /// Prev block hash
94    pub prev_block_hash: CryptoHash,
95    /// Currently building block hash
96    pub block_hash: CryptoHash,
97    /// Current epoch id
98    pub epoch_id: EpochId,
99    /// Current epoch height
100    pub epoch_height: EpochHeight,
101    /// The current block timestamp (number of non-leap-nanoseconds since January 1, 1970 0:00:00 UTC).
102    pub block_timestamp: u64,
103    /// Current Protocol version when we apply the state transition
104    pub current_protocol_version: ProtocolVersion,
105    /// Cache for compiled contracts.
106    pub cache: Option<Box<dyn CompiledContractCache>>,
107}
108
109impl From<&Account> for AccountView {
110    fn from(account: &Account) -> Self {
111        AccountView {
112            amount: account.amount(),
113            pledging: account.pledging(),
114            power: account.power(),
115            code_hash: account.code_hash(),
116            storage_usage: account.storage_usage(),
117            storage_paid_at: 0,
118        }
119    }
120}
121
122impl From<Account> for AccountView {
123    fn from(account: Account) -> Self {
124        (&account).into()
125    }
126}
127
128impl From<&AccountView> for Account {
129    fn from(view: &AccountView) -> Self {
130        Account::new(view.amount, view.pledging, view.power, view.code_hash, view.storage_usage)
131    }
132}
133
134impl From<AccountView> for Account {
135    fn from(view: AccountView) -> Self {
136        (&view).into()
137    }
138}
139
140impl From<ContractCode> for ContractCodeView {
141    fn from(contract_code: ContractCode) -> Self {
142        let hash = *contract_code.hash();
143        let code = contract_code.into_code();
144        ContractCodeView { code, hash }
145    }
146}
147
148impl From<ContractCodeView> for ContractCode {
149    fn from(contract_code: ContractCodeView) -> Self {
150        ContractCode::new(contract_code.code, Some(contract_code.hash))
151    }
152}
153
154#[derive(
155    BorshSerialize,
156    BorshDeserialize,
157    Debug,
158    Eq,
159    PartialEq,
160    Clone,
161    serde::Serialize,
162    serde::Deserialize,
163)]
164pub enum AccessKeyPermissionView {
165    FunctionCall {
166        #[serde(with = "dec_format")]
167        allowance: Option<Balance>,
168        receiver_id: String,
169        method_names: Vec<String>,
170    },
171    FullAccess,
172}
173
174impl From<AccessKeyPermission> for AccessKeyPermissionView {
175    fn from(permission: AccessKeyPermission) -> Self {
176        match permission {
177            AccessKeyPermission::FunctionCall(func_call) => AccessKeyPermissionView::FunctionCall {
178                allowance: func_call.allowance,
179                receiver_id: func_call.receiver_id,
180                method_names: func_call.method_names,
181            },
182            AccessKeyPermission::FullAccess => AccessKeyPermissionView::FullAccess,
183        }
184    }
185}
186
187impl From<AccessKeyPermissionView> for AccessKeyPermission {
188    fn from(view: AccessKeyPermissionView) -> Self {
189        match view {
190            AccessKeyPermissionView::FunctionCall { allowance, receiver_id, method_names } => {
191                AccessKeyPermission::FunctionCall(FunctionCallPermission {
192                    allowance,
193                    receiver_id,
194                    method_names,
195                })
196            }
197            AccessKeyPermissionView::FullAccess => AccessKeyPermission::FullAccess,
198        }
199    }
200}
201
202#[derive(
203    BorshSerialize,
204    BorshDeserialize,
205    Debug,
206    Eq,
207    PartialEq,
208    Clone,
209    serde::Serialize,
210    serde::Deserialize,
211)]
212pub struct AccessKeyView {
213    pub nonce: Nonce,
214    pub permission: AccessKeyPermissionView,
215}
216
217impl From<AccessKey> for AccessKeyView {
218    fn from(access_key: AccessKey) -> Self {
219        Self { nonce: access_key.nonce, permission: access_key.permission.into() }
220    }
221}
222
223impl From<AccessKeyView> for AccessKey {
224    fn from(view: AccessKeyView) -> Self {
225        Self { nonce: view.nonce, permission: view.permission.into() }
226    }
227}
228
229/// Item of the state, key and value are serialized in base64 and proof for inclusion of given state item.
230#[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Eq, Clone)]
231pub struct StateItem {
232    pub key: StoreKey,
233    pub value: StoreValue,
234}
235
236#[serde_as]
237#[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Eq, Clone)]
238pub struct ViewStateResult {
239    pub values: Vec<StateItem>,
240    #[serde_as(as = "Vec<Base64>")]
241    #[serde(default, skip_serializing_if = "Vec::is_empty")]
242    pub proof: Vec<Arc<[u8]>>,
243}
244
245#[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Eq, Clone, Default)]
246pub struct CallResult {
247    pub result: Vec<u8>,
248    pub logs: Vec<String>,
249}
250
251#[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Eq, Clone)]
252pub struct QueryError {
253    pub error: String,
254    pub logs: Vec<String>,
255}
256
257#[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Eq, Clone)]
258pub struct AccessKeyInfoView {
259    pub public_key: PublicKey,
260    pub access_key: AccessKeyView,
261}
262
263#[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Eq, Clone)]
264pub struct AccessKeyList {
265    pub keys: Vec<AccessKeyInfoView>,
266}
267
268impl FromIterator<AccessKeyInfoView> for AccessKeyList {
269    fn from_iter<I: IntoIterator<Item = AccessKeyInfoView>>(iter: I) -> Self {
270        Self { keys: iter.into_iter().collect() }
271    }
272}
273
274#[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Eq, Clone)]
275pub struct ChipsList {
276    pub total_power: Power,
277    pub chips: Vec<ChipView>,
278}
279
280impl FromIterator<ChipView> for ChipsList {
281    fn from_iter<I: IntoIterator<Item = ChipView>>(iter: I) -> Self {
282        let chips: Vec<ChipView> = iter.into_iter().collect();
283
284        // Calculate total power by summing up the power of each chip
285        let total_power: u64 = chips.iter().map(|chip| chip.power).sum();
286
287        ChipsList { total_power: total_power.into(), chips }
288    }
289}
290
291#[cfg_attr(feature = "deepsize_feature", derive(deepsize::DeepSizeOf))]
292#[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Eq, Clone)]
293pub struct KnownPeerStateView {
294    pub peer_id: PeerId,
295    pub status: String,
296    pub addr: String,
297    pub first_seen: i64,
298    pub last_seen: i64,
299    pub last_attempt: Option<(i64, String)>,
300}
301
302#[cfg_attr(feature = "deepsize_feature", derive(deepsize::DeepSizeOf))]
303#[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Eq, Clone)]
304pub struct ConnectionInfoView {
305    pub peer_id: PeerId,
306    pub addr: String,
307    pub time_established: i64,
308    pub time_connected_until: i64,
309}
310
311#[cfg_attr(feature = "deepsize_feature", derive(deepsize::DeepSizeOf))]
312#[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Eq, Clone)]
313pub struct SnapshotHostInfoView {
314    pub peer_id: PeerId,
315    pub sync_hash: CryptoHash,
316    pub epoch_height: u64,
317    pub shards: Vec<u64>,
318}
319
320#[cfg_attr(feature = "deepsize_feature", derive(deepsize::DeepSizeOf))]
321#[derive(Debug, PartialEq, Eq, Clone)]
322pub enum QueryResponseKind {
323    ViewAccount(AccountView),
324    ViewCode(ContractCodeView),
325    ViewState(ViewStateResult),
326    CallResult(CallResult),
327    AccessKey(AccessKeyView),
328    AccessKeyList(AccessKeyList),
329    ChipList(ChipsList),
330}
331
332#[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Eq, Clone)]
333#[serde(tag = "request_type", rename_all = "snake_case")]
334pub enum QueryRequest {
335    ViewAccount {
336        account_id: AccountId,
337    },
338    ViewCode {
339        account_id: AccountId,
340    },
341    ViewState {
342        account_id: AccountId,
343        #[serde(rename = "prefix_base64")]
344        prefix: StoreKey,
345        #[serde(default, skip_serializing_if = "is_false")]
346        include_proof: bool,
347    },
348    ViewAccessKey {
349        account_id: AccountId,
350        public_key: PublicKey,
351    },
352    ViewAccessKeyList {
353        account_id: AccountId,
354    },
355    ViewChipList {
356        account_id: AccountId,
357    },
358    CallFunction {
359        account_id: AccountId,
360        method_name: String,
361        #[serde(rename = "args_base64")]
362        args: FunctionArgs,
363    },
364}
365
366fn is_false(v: &bool) -> bool {
367    !*v
368}
369
370#[derive(Debug, PartialEq, Eq, Clone)]
371pub struct QueryResponse {
372    pub kind: QueryResponseKind,
373    pub block_height: BlockHeight,
374    pub block_hash: CryptoHash,
375}
376
377#[derive(serde::Serialize, serde::Deserialize, Debug)]
378pub struct StatusSyncInfo {
379    pub latest_block_hash: CryptoHash,
380    pub latest_block_height: BlockHeight,
381    pub latest_state_root: CryptoHash,
382    pub latest_block_time: DateTime<chrono::Utc>,
383    pub syncing: bool,
384    pub earliest_block_hash: Option<CryptoHash>,
385    pub earliest_block_height: Option<BlockHeight>,
386    pub earliest_block_time: Option<DateTime<chrono::Utc>>,
387    pub epoch_id: Option<EpochId>,
388    pub epoch_start_height: Option<BlockHeight>,
389}
390
391// TODO: add more information to ValidatorInfo
392#[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Eq, Clone)]
393pub struct ValidatorInfo {
394    pub account_id: AccountId,
395    pub is_slashed: bool,
396}
397
398#[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Eq)]
399pub struct PeerInfoView {
400    pub addr: String,
401    pub account_id: Option<AccountId>,
402    pub height: Option<BlockHeight>,
403    pub block_hash: Option<CryptoHash>,
404    pub is_highest_block_invalid: bool,
405    pub tracked_shards: Vec<ShardId>,
406    pub archival: bool,
407    pub peer_id: PublicKey,
408    pub received_bytes_per_sec: u64,
409    pub sent_bytes_per_sec: u64,
410    pub last_time_peer_requested_millis: u64,
411    pub last_time_received_message_millis: u64,
412    pub connection_established_time_millis: u64,
413    pub is_outbound_peer: bool,
414    /// Connection nonce.
415    pub nonce: u64,
416}
417
418/// Information about a Producer: its account name, peer_id and a list of connected peers that
419/// the node can use to send message for this producer.
420#[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Eq)]
421pub struct KnownProducerView {
422    pub account_id: AccountId,
423    pub peer_id: PublicKey,
424    pub next_hops: Option<Vec<PublicKey>>,
425}
426
427#[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Eq)]
428pub struct Tier1ProxyView {
429    pub addr: std::net::SocketAddr,
430    pub peer_id: PublicKey,
431}
432
433#[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Eq)]
434pub struct AccountDataView {
435    pub peer_id: PublicKey,
436    pub proxies: Vec<Tier1ProxyView>,
437    pub account_key: PublicKey,
438    pub timestamp: DateTime<chrono::Utc>,
439}
440
441#[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Eq)]
442pub struct NetworkInfoView {
443    pub peer_max_count: u32,
444    pub num_connected_peers: usize,
445    pub connected_peers: Vec<PeerInfoView>,
446    pub known_producers: Vec<KnownProducerView>,
447    pub tier1_accounts_keys: Vec<PublicKey>,
448    pub tier1_accounts_data: Vec<AccountDataView>,
449    pub tier1_connections: Vec<PeerInfoView>,
450}
451
452#[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Eq)]
453pub enum SyncStatusView {
454    /// Initial state. Not enough peers to do anything yet.
455    AwaitingPeers,
456    /// Not syncing / Done syncing.
457    NoSync,
458    /// Syncing using light-client headers to a recent epoch
459    // TODO #3488
460    // Bowen: why do we use epoch ordinal instead of epoch id?
461    EpochSync { epoch_ord: u64 },
462    /// Downloading block headers for fast sync.
463    HeaderSync {
464        start_height: BlockHeight,
465        current_height: BlockHeight,
466        highest_height: BlockHeight,
467    },
468    /// State sync, with different states of state sync for different shards.
469    StateSync(CryptoHash, HashMap<ShardId, ShardSyncDownloadView>),
470    /// Sync state across all shards is done.
471    StateSyncDone,
472    /// Download and process blocks until the head reaches the head of the network.
473    BlockSync {
474        start_height: BlockHeight,
475        current_height: BlockHeight,
476        highest_height: BlockHeight,
477    },
478}
479
480#[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Eq)]
481pub struct PeerStoreView {
482    pub peer_states: Vec<KnownPeerStateView>,
483}
484
485#[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Eq)]
486pub struct RecentOutboundConnectionsView {
487    pub recent_outbound_connections: Vec<ConnectionInfoView>,
488}
489
490#[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Eq)]
491pub struct SnapshotHostsView {
492    pub hosts: Vec<SnapshotHostInfoView>,
493}
494
495#[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Eq)]
496pub struct EdgeView {
497    pub peer0: PeerId,
498    pub peer1: PeerId,
499    pub nonce: u64,
500}
501
502#[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Eq)]
503pub struct NetworkGraphView {
504    pub edges: Vec<EdgeView>,
505    pub next_hops: HashMap<PeerId, Vec<PeerId>>,
506}
507
508#[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Eq)]
509pub struct LabeledEdgeView {
510    pub peer0: u32,
511    pub peer1: u32,
512    pub nonce: u64,
513}
514
515#[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Eq)]
516pub struct EdgeCacheView {
517    pub peer_labels: HashMap<PeerId, u32>,
518    pub spanning_trees: HashMap<u32, Vec<LabeledEdgeView>>,
519}
520
521#[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Eq)]
522pub struct PeerDistancesView {
523    pub distance: Vec<Option<u32>>,
524    pub min_nonce: u64,
525}
526
527#[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Eq)]
528pub struct NetworkRoutesView {
529    pub edge_cache: EdgeCacheView,
530    pub local_edges: HashMap<PeerId, EdgeView>,
531    pub peer_distances: HashMap<PeerId, PeerDistancesView>,
532    pub my_distances: HashMap<PeerId, u32>,
533}
534
535#[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Eq)]
536pub struct ShardSyncDownloadView {
537    pub downloads: Vec<DownloadStatusView>,
538    pub status: String,
539}
540
541#[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Eq)]
542pub struct DownloadStatusView {
543    pub error: bool,
544    pub done: bool,
545}
546
547#[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Eq)]
548pub struct CatchupStatusView {
549    // This is the first block of the epoch that we are catching up
550    pub sync_block_hash: CryptoHash,
551    pub sync_block_height: BlockHeight,
552    // Status of all shards that need to sync
553    pub shard_sync_status: HashMap<ShardId, String>,
554    // Blocks that we need to catchup, if it is empty, it means catching up is done
555    pub blocks_to_catchup: Vec<BlockStatusView>,
556}
557
558#[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Eq)]
559pub struct RequestedStatePartsView {
560    // This is the first block of the epoch that was requested
561    pub block_hash: CryptoHash,
562    // All the part ids of the shards that were requested
563    pub shard_requested_parts: HashMap<ShardId, Vec<PartElapsedTimeView>>,
564}
565
566#[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Eq)]
567pub struct BlockStatusView {
568    pub height: BlockHeight,
569    pub hash: CryptoHash,
570}
571
572impl BlockStatusView {
573    pub fn new(height: &BlockHeight, hash: &CryptoHash) -> BlockStatusView {
574        Self { height: *height, hash: *hash }
575    }
576}
577
578impl From<Tip> for BlockStatusView {
579    fn from(tip: Tip) -> Self {
580        Self { height: tip.height, hash: tip.last_block_hash }
581    }
582}
583
584#[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Eq, Clone)]
585pub struct PartElapsedTimeView {
586    pub part_id: u64,
587    pub elapsed_ms: u128,
588}
589
590impl PartElapsedTimeView {
591    pub fn new(part_id: &u64, elapsed_ms: u128) -> PartElapsedTimeView {
592        Self { part_id: *part_id, elapsed_ms }
593    }
594}
595
596#[derive(serde::Serialize, serde::Deserialize, Debug)]
597pub struct BlockByChunksView {
598    pub height: BlockHeight,
599    pub hash: CryptoHash,
600    pub block_status: String,
601    pub chunk_status: String,
602}
603
604#[derive(serde::Serialize, serde::Deserialize, Debug)]
605pub struct ChainProcessingInfo {
606    pub num_blocks_in_processing: usize,
607    pub num_orphans: usize,
608    pub num_blocks_missing_chunks: usize,
609    /// contains processing info of recent blocks, ordered by height high to low
610    pub blocks_info: Vec<BlockProcessingInfo>,
611    /// contains processing info of chunks that we don't know which block it belongs to yet
612    pub floating_chunks_info: Vec<ChunkProcessingInfo>,
613}
614
615#[derive(serde::Serialize, serde::Deserialize, Debug)]
616pub struct BlockProcessingInfo {
617    pub height: BlockHeight,
618    pub hash: CryptoHash,
619    pub received_timestamp: DateTime<chrono::Utc>,
620    /// Timestamp when block was received.
621    //pub received_timestamp: DateTime<chrono::Utc>,
622    /// Time (in ms) between when the block was first received and when it was processed
623    pub in_progress_ms: u128,
624    /// Time (in ms) that the block spent in the orphan pool. If the block was never put in the
625    /// orphan pool, it is None. If the block is still in the orphan pool, it is since the time
626    /// it was put into the pool until the current time.
627    pub orphaned_ms: Option<u128>,
628    /// Time (in ms) that the block spent in the missing chunks pool. If the block was never put in the
629    /// missing chunks pool, it is None. If the block is still in the missing chunks pool, it is
630    /// since the time it was put into the pool until the current time.
631    pub missing_chunks_ms: Option<u128>,
632    pub block_status: BlockProcessingStatus,
633    /// Only contains new chunks that belong to this block, if the block doesn't produce a new chunk
634    /// for a shard, the corresponding item will be None.
635    pub chunks_info: Vec<Option<ChunkProcessingInfo>>,
636}
637
638#[derive(
639    BorshSerialize,
640    BorshDeserialize,
641    Clone,
642    Debug,
643    PartialEq,
644    Eq,
645    serde::Serialize,
646    serde::Deserialize,
647)]
648pub enum BlockProcessingStatus {
649    Orphan,
650    WaitingForChunks,
651    InProcessing,
652    Accepted,
653    Error(String),
654    Dropped(DroppedReason),
655    Unknown,
656}
657
658#[derive(
659    BorshSerialize,
660    BorshDeserialize,
661    Clone,
662    Debug,
663    PartialEq,
664    Eq,
665    serde::Serialize,
666    serde::Deserialize,
667)]
668pub enum DroppedReason {
669    // If the node has already processed a block at this height
670    HeightProcessed,
671    // If the block processing pool is full
672    TooManyProcessingBlocks,
673}
674
675#[derive(serde::Serialize, serde::Deserialize, Debug)]
676pub struct ChunkProcessingInfo {
677    pub height_created: BlockHeight,
678    pub shard_id: ShardId,
679    pub chunk_hash: ChunkHash,
680    pub prev_block_hash: CryptoHash,
681    /// Account id of the validator who created this chunk
682    /// Theoretically this field should never be None unless there is some database corruption.
683    pub created_by: Option<AccountId>,
684    pub status: ChunkProcessingStatus,
685    /// Timestamp of first time when we request for this chunk.
686    pub requested_timestamp: Option<DateTime<chrono::Utc>>,
687    /// Timestamp of when the chunk is complete
688    pub completed_timestamp: Option<DateTime<chrono::Utc>>,
689    /// Time (in millis) that it takes between when the chunk is requested and when it is completed.
690    pub request_duration: Option<u64>,
691    pub chunk_parts_collection: Vec<PartCollectionInfo>,
692}
693
694#[derive(serde::Serialize, serde::Deserialize, Debug)]
695pub struct PartCollectionInfo {
696    pub part_owner: AccountId,
697    // Time when the part is received through any message
698    pub received_time: Option<DateTime<chrono::Utc>>,
699    // Time when we receive a PartialEncodedChunkForward containing this part
700    pub forwarded_received_time: Option<DateTime<chrono::Utc>>,
701    // Time when we receive the PartialEncodedChunk message containing this part
702    pub chunk_received_time: Option<DateTime<chrono::Utc>>,
703}
704
705#[derive(serde::Serialize, serde::Deserialize, Debug)]
706pub enum ChunkProcessingStatus {
707    NeedToRequest,
708    Requested,
709    Completed,
710}
711
712#[derive(serde::Serialize, serde::Deserialize, Debug)]
713pub struct DetailedDebugStatus {
714    pub network_info: NetworkInfoView,
715    pub sync_status: String,
716    pub catchup_status: Vec<CatchupStatusView>,
717    pub current_head_status: BlockStatusView,
718    pub current_header_head_status: BlockStatusView,
719    pub block_production_delay_millis: u64,
720}
721
722// TODO: add more information to status.
723#[derive(serde::Serialize, serde::Deserialize, Debug)]
724pub struct StatusResponse {
725    /// Binary version.
726    pub version: Version,
727    /// Unique chain id.
728    pub chain_id: String,
729    /// Currently active protocol version.
730    pub protocol_version: u32,
731    /// Latest protocol version that this client supports.
732    pub latest_protocol_version: u32,
733    /// Address for RPC server.  None if node doesn’t have RPC endpoint enabled.
734    #[serde(skip_serializing_if = "Option::is_none")]
735    pub rpc_addr: Option<String>,
736    /// Current epoch validators.
737    pub validators: Vec<ValidatorInfo>,
738    /// Sync status of the node.
739    pub sync_info: StatusSyncInfo,
740    /// Validator id of the node
741    pub validator_account_id: Option<AccountId>,
742    /// Public key of the validator.
743    pub validator_public_key: Option<PublicKey>,
744    /// Public key of the node.
745    pub node_public_key: PublicKey,
746    /// Deprecated; same as `validator_public_key` which you should use instead.
747    pub node_key: Option<PublicKey>,
748    /// Uptime of the node.
749    pub uptime_sec: i64,
750    /// Information about last blocks, network, epoch and chain & chunk info.
751    #[serde(skip_serializing_if = "Option::is_none")]
752    pub detailed_debug_status: Option<DetailedDebugStatus>,
753}
754
755#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)]
756pub struct ChallengeView {
757    // TODO: decide how to represent challenges in json.
758}
759
760impl From<Challenge> for ChallengeView {
761    fn from(_challenge: Challenge) -> Self {
762        Self {}
763    }
764}
765
766#[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Eq, Clone)]
767pub struct ChipView {
768    pub miner_id: String,
769    pub public_key: String,
770    pub power: u64,
771    pub sn: String,
772    pub bus_id: String,
773    pub p2key: String,
774}
775#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)]
776pub struct BlockHeaderView {
777    pub height: BlockHeight,
778    pub prev_height: Option<BlockHeight>,
779    pub epoch_id: CryptoHash,
780    pub next_epoch_id: CryptoHash,
781    pub hash: CryptoHash,
782    pub prev_hash: CryptoHash,
783    pub prev_state_root: CryptoHash,
784    pub block_body_hash: Option<CryptoHash>,
785    pub chunk_receipts_root: CryptoHash,
786    pub chunk_headers_root: CryptoHash,
787    pub chunk_tx_root: CryptoHash,
788    pub outcome_root: CryptoHash,
789    pub chunks_included: u64,
790    pub challenges_root: CryptoHash,
791    /// Legacy json number. Should not be used.
792    pub timestamp: u64,
793    #[serde(with = "dec_format")]
794    pub timestamp_nanosec: u64,
795    pub random_value: CryptoHash,
796    pub validator_power_proposals: Vec<ValidatorPowerView>,
797    pub validator_pledge_proposals: Vec<ValidatorPledgeView>,
798    pub chunk_mask: Vec<bool>,
799    #[serde(with = "dec_format")]
800    pub gas_price: Balance,
801    pub block_ordinal: Option<NumBlocks>,
802    /// TODO(2271): deprecated.
803    #[serde(with = "dec_format")]
804    pub rent_paid: Balance,
805    /// TODO(2271): deprecated.
806    #[serde(with = "dec_format")]
807    pub validator_reward: Balance,
808    #[serde(with = "dec_format")]
809    pub total_supply: Balance,
810    pub challenges_result: ChallengesResult,
811    pub last_final_block: CryptoHash,
812    pub last_ds_final_block: CryptoHash,
813    pub next_bp_hash: CryptoHash,
814    pub block_merkle_root: CryptoHash,
815    pub epoch_sync_data_hash: Option<CryptoHash>,
816    pub approvals: Vec<Option<Box<Signature>>>,
817    pub signature: Signature,
818    pub latest_protocol_version: ProtocolVersion,
819}
820
821impl From<BlockHeader> for BlockHeaderView {
822    fn from(header: BlockHeader) -> Self {
823        Self {
824            height: header.height(),
825            prev_height: header.prev_height(),
826            epoch_id: header.epoch_id().0,
827            next_epoch_id: header.next_epoch_id().0,
828            hash: *header.hash(),
829            prev_hash: *header.prev_hash(),
830            prev_state_root: *header.prev_state_root(),
831            block_body_hash: header.block_body_hash(),
832            chunk_receipts_root: *header.prev_chunk_outgoing_receipts_root(),
833            chunk_headers_root: *header.chunk_headers_root(),
834            chunk_tx_root: *header.chunk_tx_root(),
835            chunks_included: header.chunks_included(),
836            challenges_root: *header.challenges_root(),
837            outcome_root: *header.outcome_root(),
838            timestamp: header.raw_timestamp(),
839            timestamp_nanosec: header.raw_timestamp(),
840            random_value: *header.random_value(),
841            validator_power_proposals: header
842                .prev_validator_power_proposals()
843                .map(Into::into)
844                .collect(),
845            validator_pledge_proposals: header
846                .prev_validator_pledge_proposals()
847                .map(Into::into)
848                .collect(),
849            chunk_mask: header.chunk_mask().to_vec(),
850            block_ordinal: if header.block_ordinal() != 0 {
851                Some(header.block_ordinal())
852            } else {
853                None
854            },
855            gas_price: header.next_gas_price(),
856            rent_paid: 0,
857            validator_reward: 0,
858            total_supply: header.total_supply(),
859            challenges_result: header.challenges_result().clone(),
860            last_final_block: *header.last_final_block(),
861            last_ds_final_block: *header.last_ds_final_block(),
862            next_bp_hash: *header.next_bp_hash(),
863            block_merkle_root: *header.block_merkle_root(),
864            epoch_sync_data_hash: header.epoch_sync_data_hash(),
865            approvals: header.approvals().to_vec(),
866            signature: header.signature().clone(),
867            latest_protocol_version: header.latest_protocol_version(),
868        }
869    }
870}
871
872impl From<BlockHeaderView> for BlockHeader {
873    fn from(view: BlockHeaderView) -> Self {
874        let inner_lite = BlockHeaderInnerLite {
875            height: view.height,
876            epoch_id: EpochId(view.epoch_id),
877            next_epoch_id: EpochId(view.next_epoch_id),
878            prev_state_root: view.prev_state_root,
879            prev_outcome_root: view.outcome_root,
880            timestamp: view.timestamp,
881            next_bp_hash: view.next_bp_hash,
882            block_merkle_root: view.block_merkle_root,
883        };
884        const LAST_HEADER_V2_VERSION: ProtocolVersion =
885            crate::version::ProtocolFeature::BlockHeaderV3.protocol_version() - 1;
886        if view.latest_protocol_version <= 29 {
887            let validator_power_proposals = view
888                .validator_power_proposals
889                .into_iter()
890                .map(|v| v.into_validator_power().into_v1())
891                .collect();
892            let validator_pledge_proposals = view
893                .validator_pledge_proposals
894                .into_iter()
895                .map(|v| v.into_validator_pledge().into_v1())
896                .collect();
897            let mut header = BlockHeaderV1 {
898                prev_hash: view.prev_hash,
899                inner_lite,
900                inner_rest: BlockHeaderInnerRest {
901                    prev_chunk_outgoing_receipts_root: view.chunk_receipts_root,
902                    chunk_headers_root: view.chunk_headers_root,
903                    chunk_tx_root: view.chunk_tx_root,
904                    chunks_included: view.chunks_included,
905                    challenges_root: view.challenges_root,
906                    random_value: view.random_value,
907                    prev_validator_power_proposals: validator_power_proposals,
908                    prev_validator_pledge_proposals: validator_pledge_proposals,
909                    chunk_mask: view.chunk_mask,
910                    next_gas_price: view.gas_price,
911                    total_supply: view.total_supply,
912                    challenges_result: view.challenges_result,
913                    last_final_block: view.last_final_block,
914                    last_ds_final_block: view.last_ds_final_block,
915                    approvals: view.approvals.clone(),
916                    latest_protocol_version: view.latest_protocol_version,
917                },
918                signature: view.signature,
919                hash: CryptoHash::default(),
920            };
921            header.init();
922            BlockHeader::BlockHeaderV1(Arc::new(header))
923        } else if view.latest_protocol_version <= LAST_HEADER_V2_VERSION {
924            let validator_power_proposals = view
925                .validator_power_proposals
926                .into_iter()
927                .map(|v| v.into_validator_power().into_v1())
928                .collect();
929            let validator_pledge_proposals = view
930                .validator_pledge_proposals
931                .into_iter()
932                .map(|v| v.into_validator_pledge().into_v1())
933                .collect();
934            let mut header = BlockHeaderV2 {
935                prev_hash: view.prev_hash,
936                inner_lite,
937                inner_rest: BlockHeaderInnerRestV2 {
938                    prev_chunk_outgoing_receipts_root: view.chunk_receipts_root,
939                    chunk_headers_root: view.chunk_headers_root,
940                    chunk_tx_root: view.chunk_tx_root,
941                    challenges_root: view.challenges_root,
942                    random_value: view.random_value,
943                    prev_validator_power_proposals: validator_power_proposals,
944                    prev_validator_pledge_proposals: validator_pledge_proposals,
945                    chunk_mask: view.chunk_mask,
946                    next_gas_price: view.gas_price,
947                    total_supply: view.total_supply,
948                    challenges_result: view.challenges_result,
949                    last_final_block: view.last_final_block,
950                    last_ds_final_block: view.last_ds_final_block,
951                    approvals: view.approvals.clone(),
952                    latest_protocol_version: view.latest_protocol_version,
953                },
954                signature: view.signature,
955                hash: CryptoHash::default(),
956            };
957            header.init();
958            BlockHeader::BlockHeaderV2(Arc::new(header))
959        } else if !checked_feature!("stable", BlockHeaderV4, view.latest_protocol_version) {
960            let mut header = BlockHeaderV3 {
961                prev_hash: view.prev_hash,
962                inner_lite,
963                inner_rest: BlockHeaderInnerRestV3 {
964                    prev_chunk_outgoing_receipts_root: view.chunk_receipts_root,
965                    chunk_headers_root: view.chunk_headers_root,
966                    chunk_tx_root: view.chunk_tx_root,
967                    challenges_root: view.challenges_root,
968                    random_value: view.random_value,
969                    prev_validator_power_proposals: view
970                        .validator_power_proposals
971                        .into_iter()
972                        .map(Into::into)
973                        .collect(),
974                    prev_validator_pledge_proposals: view
975                        .validator_pledge_proposals
976                        .into_iter()
977                        .map(Into::into)
978                        .collect(),
979                    chunk_mask: view.chunk_mask,
980                    next_gas_price: view.gas_price,
981                    block_ordinal: view.block_ordinal.unwrap_or(0),
982                    total_supply: view.total_supply,
983                    challenges_result: view.challenges_result,
984                    last_final_block: view.last_final_block,
985                    last_ds_final_block: view.last_ds_final_block,
986                    prev_height: view.prev_height.unwrap_or_default(),
987                    epoch_sync_data_hash: view.epoch_sync_data_hash,
988                    approvals: view.approvals.clone(),
989                    latest_protocol_version: view.latest_protocol_version,
990                },
991                signature: view.signature,
992                hash: CryptoHash::default(),
993            };
994            header.init();
995            BlockHeader::BlockHeaderV3(Arc::new(header))
996        } else {
997            let mut header = BlockHeaderV4 {
998                prev_hash: view.prev_hash,
999                inner_lite,
1000                inner_rest: BlockHeaderInnerRestV4 {
1001                    block_body_hash: view.block_body_hash.unwrap_or_default(),
1002                    prev_chunk_outgoing_receipts_root: view.chunk_receipts_root,
1003                    chunk_headers_root: view.chunk_headers_root,
1004                    chunk_tx_root: view.chunk_tx_root,
1005                    challenges_root: view.challenges_root,
1006                    random_value: view.random_value,
1007                    prev_validator_power_proposals: view
1008                        .validator_power_proposals
1009                        .into_iter()
1010                        .map(Into::into)
1011                        .collect(),
1012                    prev_validator_pledge_proposals: view
1013                        .validator_pledge_proposals
1014                        .into_iter()
1015                        .map(Into::into)
1016                        .collect(),
1017                    chunk_mask: view.chunk_mask,
1018                    next_gas_price: view.gas_price,
1019                    block_ordinal: view.block_ordinal.unwrap_or(0),
1020                    total_supply: view.total_supply,
1021                    challenges_result: view.challenges_result,
1022                    last_final_block: view.last_final_block,
1023                    last_ds_final_block: view.last_ds_final_block,
1024                    prev_height: view.prev_height.unwrap_or_default(),
1025                    epoch_sync_data_hash: view.epoch_sync_data_hash,
1026                    approvals: view.approvals.clone(),
1027                    latest_protocol_version: view.latest_protocol_version,
1028                },
1029                signature: view.signature,
1030                hash: CryptoHash::default(),
1031            };
1032            header.init();
1033            BlockHeader::BlockHeaderV4(Arc::new(header))
1034        }
1035    }
1036}
1037
1038#[derive(
1039    PartialEq,
1040    Eq,
1041    Debug,
1042    Clone,
1043    BorshDeserialize,
1044    BorshSerialize,
1045    serde::Serialize,
1046    serde::Deserialize,
1047)]
1048pub struct BlockHeaderInnerLiteView {
1049    pub height: BlockHeight,
1050    pub epoch_id: CryptoHash,
1051    pub next_epoch_id: CryptoHash,
1052    pub prev_state_root: CryptoHash,
1053    pub outcome_root: CryptoHash,
1054    /// Legacy json number. Should not be used.
1055    pub timestamp: u64,
1056    #[serde(with = "dec_format")]
1057    pub timestamp_nanosec: u64,
1058    pub next_bp_hash: CryptoHash,
1059    pub block_merkle_root: CryptoHash,
1060}
1061
1062impl From<BlockHeader> for BlockHeaderInnerLiteView {
1063    fn from(header: BlockHeader) -> Self {
1064        let inner_lite = match &header {
1065            BlockHeader::BlockHeaderV1(header) => &header.inner_lite,
1066            BlockHeader::BlockHeaderV2(header) => &header.inner_lite,
1067            BlockHeader::BlockHeaderV3(header) => &header.inner_lite,
1068            BlockHeader::BlockHeaderV4(header) => &header.inner_lite,
1069        };
1070        BlockHeaderInnerLiteView {
1071            height: inner_lite.height,
1072            epoch_id: inner_lite.epoch_id.0,
1073            next_epoch_id: inner_lite.next_epoch_id.0,
1074            prev_state_root: inner_lite.prev_state_root,
1075            outcome_root: inner_lite.prev_outcome_root,
1076            timestamp: inner_lite.timestamp,
1077            timestamp_nanosec: inner_lite.timestamp,
1078            next_bp_hash: inner_lite.next_bp_hash,
1079            block_merkle_root: inner_lite.block_merkle_root,
1080        }
1081    }
1082}
1083
1084impl From<BlockHeaderInnerLiteView> for BlockHeaderInnerLite {
1085    fn from(view: BlockHeaderInnerLiteView) -> Self {
1086        BlockHeaderInnerLite {
1087            height: view.height,
1088            epoch_id: EpochId(view.epoch_id),
1089            next_epoch_id: EpochId(view.next_epoch_id),
1090            prev_state_root: view.prev_state_root,
1091            prev_outcome_root: view.outcome_root,
1092            timestamp: view.timestamp_nanosec,
1093            next_bp_hash: view.next_bp_hash,
1094            block_merkle_root: view.block_merkle_root,
1095        }
1096    }
1097}
1098
1099#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)]
1100pub struct ChunkHeaderView {
1101    pub chunk_hash: CryptoHash,
1102    pub prev_block_hash: CryptoHash,
1103    pub outcome_root: CryptoHash,
1104    pub prev_state_root: StateRoot,
1105    pub encoded_merkle_root: CryptoHash,
1106    pub encoded_length: u64,
1107    pub height_created: BlockHeight,
1108    pub height_included: BlockHeight,
1109    pub shard_id: ShardId,
1110    pub gas_used: Gas,
1111    pub gas_limit: Gas,
1112    /// TODO(2271): deprecated.
1113    #[serde(with = "dec_format")]
1114    pub rent_paid: Balance,
1115    /// TODO(2271): deprecated.
1116    #[serde(with = "dec_format")]
1117    pub validator_reward: Balance,
1118    #[serde(with = "dec_format")]
1119    pub balance_burnt: Balance,
1120    pub outgoing_receipts_root: CryptoHash,
1121    pub tx_root: CryptoHash,
1122    pub validator_power_proposals: Vec<ValidatorPowerView>,
1123    pub validator_pledge_proposals: Vec<ValidatorPledgeView>,
1124    pub signature: Signature,
1125}
1126
1127impl From<ShardChunkHeader> for ChunkHeaderView {
1128    fn from(chunk: ShardChunkHeader) -> Self {
1129        let hash = chunk.chunk_hash();
1130        let signature = chunk.signature().clone();
1131        let height_included = chunk.height_included();
1132        let inner = chunk.take_inner();
1133        ChunkHeaderView {
1134            chunk_hash: hash.0,
1135            prev_block_hash: *inner.prev_block_hash(),
1136            outcome_root: *inner.prev_outcome_root(),
1137            prev_state_root: *inner.prev_state_root(),
1138            encoded_merkle_root: *inner.encoded_merkle_root(),
1139            encoded_length: inner.encoded_length(),
1140            height_created: inner.height_created(),
1141            height_included,
1142            shard_id: inner.shard_id(),
1143            gas_used: inner.prev_gas_used(),
1144            gas_limit: inner.gas_limit(),
1145            rent_paid: 0,
1146            validator_reward: 0,
1147            balance_burnt: inner.prev_balance_burnt(),
1148            outgoing_receipts_root: *inner.prev_outgoing_receipts_root(),
1149            tx_root: *inner.tx_root(),
1150            validator_power_proposals: inner
1151                .prev_validator_power_proposals()
1152                .map(Into::into)
1153                .collect(),
1154            validator_pledge_proposals: inner
1155                .prev_validator_pledge_proposals()
1156                .map(Into::into)
1157                .collect(),
1158            signature,
1159        }
1160    }
1161}
1162
1163impl From<ChunkHeaderView> for ShardChunkHeader {
1164    fn from(view: ChunkHeaderView) -> Self {
1165        let mut header = ShardChunkHeaderV3 {
1166            inner: ShardChunkHeaderInner::V2(ShardChunkHeaderInnerV2 {
1167                prev_block_hash: view.prev_block_hash,
1168                prev_state_root: view.prev_state_root,
1169                prev_outcome_root: view.outcome_root,
1170                encoded_merkle_root: view.encoded_merkle_root,
1171                encoded_length: view.encoded_length,
1172                height_created: view.height_created,
1173                shard_id: view.shard_id,
1174                prev_gas_used: view.gas_used,
1175                gas_limit: view.gas_limit,
1176                prev_balance_burnt: view.balance_burnt,
1177                prev_outgoing_receipts_root: view.outgoing_receipts_root,
1178                tx_root: view.tx_root,
1179                prev_validator_power_proposals: view
1180                    .validator_power_proposals
1181                    .into_iter()
1182                    .map(Into::into)
1183                    .collect(),
1184                prev_validator_pledge_proposals: view
1185                    .validator_pledge_proposals
1186                    .into_iter()
1187                    .map(Into::into)
1188                    .collect(),
1189            }),
1190            height_included: view.height_included,
1191            signature: view.signature,
1192            hash: ChunkHash::default(),
1193        };
1194        header.init();
1195        ShardChunkHeader::V3(header)
1196    }
1197}
1198
1199#[derive(serde::Serialize, serde::Deserialize, Debug)]
1200pub struct AllMinersView {
1201    pub total_power: Power,
1202    pub miners: Vec<ValidatorPowerView>,
1203}
1204
1205impl From<ValidatorPowerAndPledgeIter<'_>> for AllMinersView {
1206    fn from(iter: ValidatorPowerAndPledgeIter) -> Self {
1207        let mut total_power = 0; // Initialize total power
1208        let mut miners = Vec::new(); // Initialize the vector to store ValidatorPowerView instances
1209
1210        // Iterate over each ValidatorPowerAndPledge
1211        for validator in iter {
1212            match validator {
1213                // Assuming we only deal with V1 here, similar logic could apply for other versions
1214                ValidatorPowerAndPledge::V1(v) => {
1215                    total_power += v.power; // Accumulate the total power
1216                                            // Convert ValidatorPowerAndPledge to ValidatorPowerView
1217                    let miner = ValidatorPowerView::V1(ValidatorPowerViewV1 {
1218                        account_id: v.account_id,
1219                        public_key: v.public_key,
1220                        power: v.power,
1221                    });
1222                    miners.push(miner); // Add the converted ValidatorPowerView to the miners vector
1223                } // Handle other variants as needed
1224            }
1225        }
1226
1227        // Create an instance of AllMinersView with the aggregated data
1228        AllMinersView { total_power, miners }
1229    }
1230}
1231
1232#[derive(serde::Serialize, serde::Deserialize, Debug)]
1233pub struct BlockView {
1234    pub author: AccountId,
1235    pub header: BlockHeaderView,
1236    pub chunks: Vec<ChunkHeaderView>,
1237}
1238
1239impl BlockView {
1240    pub fn from_author_block(author: AccountId, block: Block) -> Self {
1241        BlockView {
1242            author,
1243            header: block.header().clone().into(),
1244            chunks: block.chunks().iter().cloned().map(Into::into).collect(),
1245        }
1246    }
1247}
1248
1249#[derive(serde::Serialize, serde::Deserialize, Debug)]
1250pub struct ChunkView {
1251    pub author: AccountId,
1252    pub header: ChunkHeaderView,
1253    pub transactions: Vec<SignedTransactionView>,
1254    pub receipts: Vec<ReceiptView>,
1255}
1256
1257impl ChunkView {
1258    pub fn from_author_chunk(author: AccountId, chunk: ShardChunk) -> Self {
1259        match chunk {
1260            ShardChunk::V1(chunk) => Self {
1261                author,
1262                header: ShardChunkHeader::V1(chunk.header).into(),
1263                transactions: chunk.transactions.into_iter().map(Into::into).collect(),
1264                receipts: chunk.prev_outgoing_receipts.into_iter().map(Into::into).collect(),
1265            },
1266            ShardChunk::V2(chunk) => Self {
1267                author,
1268                header: chunk.header.into(),
1269                transactions: chunk.transactions.into_iter().map(Into::into).collect(),
1270                receipts: chunk.prev_outgoing_receipts.into_iter().map(Into::into).collect(),
1271            },
1272        }
1273    }
1274}
1275
1276#[serde_as]
1277#[derive(
1278    BorshSerialize,
1279    BorshDeserialize,
1280    Clone,
1281    Debug,
1282    PartialEq,
1283    Eq,
1284    serde::Serialize,
1285    serde::Deserialize,
1286)]
1287pub enum ActionView {
1288    CreateAccount,
1289    DeployContract {
1290        #[serde_as(as = "Base64")]
1291        code: Vec<u8>,
1292    },
1293    FunctionCall {
1294        method_name: String,
1295        args: FunctionArgs,
1296        gas: Gas,
1297        #[serde(with = "dec_format")]
1298        deposit: Balance,
1299    },
1300    Transfer {
1301        #[serde(with = "dec_format")]
1302        deposit: Balance,
1303    },
1304    Pledge {
1305        #[serde(with = "dec_format")]
1306        pledge: Balance,
1307        public_key: PublicKey,
1308    },
1309    AddKey {
1310        public_key: PublicKey,
1311        access_key: AccessKeyView,
1312    },
1313    DeleteKey {
1314        public_key: PublicKey,
1315    },
1316    DeleteAccount {
1317        beneficiary_id: AccountId,
1318    },
1319    Delegate {
1320        delegate_action: DelegateAction,
1321        signature: Signature,
1322    },
1323    RegisterRsa2048Keys {
1324        public_key: PublicKey,
1325        operation_type: u8,
1326        #[serde_as(as = "Base64")]
1327        args: Vec<u8>,
1328    },
1329    CreateRsa2048Challenge {
1330        public_key: PublicKey,
1331        challenge_key: PublicKey,
1332        #[serde_as(as = "Base64")]
1333        args: Vec<u8>,
1334    },
1335}
1336
1337impl From<Action> for ActionView {
1338    fn from(action: Action) -> Self {
1339        match action {
1340            Action::CreateAccount(_) => ActionView::CreateAccount,
1341            Action::DeployContract(action) => {
1342                let code = hash(&action.code).as_ref().to_vec();
1343                ActionView::DeployContract { code }
1344            }
1345            Action::FunctionCall(action) => ActionView::FunctionCall {
1346                method_name: action.method_name,
1347                args: action.args.into(),
1348                gas: action.gas,
1349                deposit: action.deposit,
1350            },
1351            Action::Transfer(action) => ActionView::Transfer { deposit: action.deposit },
1352            Action::Pledge(action) => {
1353                ActionView::Pledge { pledge: action.pledge, public_key: action.public_key }
1354            }
1355            Action::AddKey(action) => ActionView::AddKey {
1356                public_key: action.public_key,
1357                access_key: action.access_key.into(),
1358            },
1359            Action::DeleteKey(action) => ActionView::DeleteKey { public_key: action.public_key },
1360            Action::DeleteAccount(action) => {
1361                ActionView::DeleteAccount { beneficiary_id: action.beneficiary_id }
1362            }
1363            Action::Delegate(action) => ActionView::Delegate {
1364                delegate_action: action.delegate_action,
1365                signature: action.signature,
1366            },
1367            Action::RegisterRsa2048Keys(action) => ActionView::RegisterRsa2048Keys {
1368                public_key: action.public_key,
1369                operation_type: action.operation_type,
1370                args: action.args.into(),
1371            },
1372            Action::CreateRsa2048Challenge(action) => ActionView::CreateRsa2048Challenge {
1373                public_key: action.public_key,
1374                challenge_key: action.challenge_key,
1375                args: action.args.into(),
1376            },
1377        }
1378    }
1379}
1380
1381impl TryFrom<ActionView> for Action {
1382    type Error = Box<dyn std::error::Error + Send + Sync>;
1383
1384    fn try_from(action_view: ActionView) -> Result<Self, Self::Error> {
1385        Ok(match action_view {
1386            ActionView::CreateAccount => Action::CreateAccount(CreateAccountAction {}),
1387            ActionView::DeployContract { code } => {
1388                Action::DeployContract(DeployContractAction { code })
1389            }
1390            ActionView::FunctionCall { method_name, args, gas, deposit } => {
1391                Action::FunctionCall(Box::new(FunctionCallAction {
1392                    method_name,
1393                    args: args.into(),
1394                    gas,
1395                    deposit,
1396                }))
1397            }
1398            ActionView::Transfer { deposit } => Action::Transfer(TransferAction { deposit }),
1399            ActionView::Pledge { pledge, public_key } => {
1400                Action::Pledge(Box::new(PledgeAction { pledge, public_key }))
1401            }
1402            ActionView::AddKey { public_key, access_key } => {
1403                Action::AddKey(Box::new(AddKeyAction { public_key, access_key: access_key.into() }))
1404            }
1405            ActionView::DeleteKey { public_key } => {
1406                Action::DeleteKey(Box::new(DeleteKeyAction { public_key }))
1407            }
1408            ActionView::DeleteAccount { beneficiary_id } => {
1409                Action::DeleteAccount(DeleteAccountAction { beneficiary_id })
1410            }
1411            ActionView::Delegate { delegate_action, signature } => {
1412                Action::Delegate(Box::new(SignedDelegateAction { delegate_action, signature }))
1413            }
1414            ActionView::RegisterRsa2048Keys { public_key, operation_type, args } => {
1415                Action::RegisterRsa2048Keys(Box::new(RegisterRsa2048KeysAction {
1416                    public_key,
1417                    operation_type,
1418                    args: args.into(),
1419                }))
1420            }
1421            ActionView::CreateRsa2048Challenge { public_key, challenge_key, args } => {
1422                Action::CreateRsa2048Challenge(Box::new(CreateRsa2048ChallengeAction {
1423                    public_key,
1424                    challenge_key,
1425                    args: args.into(),
1426                }))
1427            }
1428        })
1429    }
1430}
1431
1432#[derive(
1433    BorshSerialize,
1434    BorshDeserialize,
1435    Debug,
1436    PartialEq,
1437    Eq,
1438    Clone,
1439    serde::Serialize,
1440    serde::Deserialize,
1441)]
1442pub struct SignedTransactionView {
1443    pub signer_id: AccountId,
1444    pub public_key: PublicKey,
1445    pub nonce: Nonce,
1446    pub receiver_id: AccountId,
1447    pub actions: Vec<ActionView>,
1448    pub signature: Signature,
1449    pub hash: CryptoHash,
1450}
1451
1452impl From<SignedTransaction> for SignedTransactionView {
1453    fn from(signed_tx: SignedTransaction) -> Self {
1454        let hash = signed_tx.get_hash();
1455        SignedTransactionView {
1456            signer_id: signed_tx.transaction.signer_id,
1457            public_key: signed_tx.transaction.public_key,
1458            nonce: signed_tx.transaction.nonce,
1459            receiver_id: signed_tx.transaction.receiver_id,
1460            actions: signed_tx
1461                .transaction
1462                .actions
1463                .into_iter()
1464                .map(|action| action.into())
1465                .collect(),
1466            signature: signed_tx.signature,
1467            hash,
1468        }
1469    }
1470}
1471
1472#[serde_as]
1473#[derive(
1474    BorshSerialize,
1475    BorshDeserialize,
1476    serde::Serialize,
1477    serde::Deserialize,
1478    PartialEq,
1479    Eq,
1480    Clone,
1481    Default,
1482)]
1483pub enum FinalExecutionStatus {
1484    /// The execution has not yet started.
1485    #[default]
1486    NotStarted,
1487    /// The execution has started and still going.
1488    Started,
1489    /// The execution has failed with the given error.
1490    Failure(TxExecutionError),
1491    /// The execution has succeeded and returned some value or an empty vec encoded in base64.
1492    SuccessValue(#[serde_as(as = "Base64")] Vec<u8>),
1493}
1494
1495impl fmt::Debug for FinalExecutionStatus {
1496    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1497        match self {
1498            FinalExecutionStatus::NotStarted => f.write_str("NotStarted"),
1499            FinalExecutionStatus::Started => f.write_str("Started"),
1500            FinalExecutionStatus::Failure(e) => f.write_fmt(format_args!("Failure({:?})", e)),
1501            FinalExecutionStatus::SuccessValue(v) => {
1502                f.write_fmt(format_args!("SuccessValue({})", AbbrBytes(v)))
1503            }
1504        }
1505    }
1506}
1507
1508#[derive(
1509    BorshSerialize,
1510    BorshDeserialize,
1511    Debug,
1512    PartialEq,
1513    Eq,
1514    Clone,
1515    serde::Serialize,
1516    serde::Deserialize,
1517)]
1518pub enum ServerError {
1519    TxExecutionError(TxExecutionError),
1520    Timeout,
1521    Closed,
1522}
1523
1524#[serde_as]
1525#[derive(
1526    BorshSerialize, BorshDeserialize, serde::Serialize, serde::Deserialize, PartialEq, Eq, Clone,
1527)]
1528pub enum ExecutionStatusView {
1529    /// The execution is pending or unknown.
1530    Unknown,
1531    /// The execution has failed.
1532    Failure(TxExecutionError),
1533    /// The final action succeeded and returned some value or an empty vec encoded in base64.
1534    SuccessValue(#[serde_as(as = "Base64")] Vec<u8>),
1535    /// The final action of the receipt returned a promise or the signed transaction was converted
1536    /// to a receipt. Contains the receipt_id of the generated receipt.
1537    SuccessReceiptId(CryptoHash),
1538}
1539
1540impl fmt::Debug for ExecutionStatusView {
1541    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1542        match self {
1543            ExecutionStatusView::Unknown => f.write_str("Unknown"),
1544            ExecutionStatusView::Failure(e) => f.write_fmt(format_args!("Failure({:?})", e)),
1545            ExecutionStatusView::SuccessValue(v) => {
1546                f.write_fmt(format_args!("SuccessValue({})", AbbrBytes(v)))
1547            }
1548            ExecutionStatusView::SuccessReceiptId(receipt_id) => {
1549                f.write_fmt(format_args!("SuccessReceiptId({})", receipt_id))
1550            }
1551        }
1552    }
1553}
1554
1555impl From<ExecutionStatus> for ExecutionStatusView {
1556    fn from(outcome: ExecutionStatus) -> Self {
1557        match outcome {
1558            ExecutionStatus::Unknown => ExecutionStatusView::Unknown,
1559            ExecutionStatus::Failure(e) => ExecutionStatusView::Failure(e),
1560            ExecutionStatus::SuccessValue(v) => ExecutionStatusView::SuccessValue(v),
1561            ExecutionStatus::SuccessReceiptId(receipt_id) => {
1562                ExecutionStatusView::SuccessReceiptId(receipt_id)
1563            }
1564        }
1565    }
1566}
1567
1568#[derive(
1569    BorshSerialize,
1570    BorshDeserialize,
1571    PartialEq,
1572    Clone,
1573    Eq,
1574    Debug,
1575    serde::Serialize,
1576    serde::Deserialize,
1577)]
1578pub struct CostGasUsed {
1579    pub cost_category: String,
1580    pub cost: String,
1581    #[serde(with = "dec_format")]
1582    pub gas_used: Gas,
1583}
1584
1585#[derive(
1586    BorshSerialize,
1587    BorshDeserialize,
1588    PartialEq,
1589    Clone,
1590    Eq,
1591    Debug,
1592    serde::Serialize,
1593    serde::Deserialize,
1594)]
1595pub struct ExecutionMetadataView {
1596    pub version: u32,
1597    pub gas_profile: Option<Vec<CostGasUsed>>,
1598}
1599
1600impl Default for ExecutionMetadataView {
1601    fn default() -> Self {
1602        ExecutionMetadata::V1.into()
1603    }
1604}
1605
1606impl From<ExecutionMetadata> for ExecutionMetadataView {
1607    fn from(metadata: ExecutionMetadata) -> Self {
1608        let version = match metadata {
1609            ExecutionMetadata::V1 => 1,
1610            ExecutionMetadata::V2(_) => 2,
1611            ExecutionMetadata::V3(_) => 3,
1612        };
1613        let mut gas_profile = match metadata {
1614            ExecutionMetadata::V1 => None,
1615            ExecutionMetadata::V2(profile_data) => {
1616                // Add actions, wasm op, and ext costs in groups.
1617
1618                // actions should use the old format, since `ActionCosts`
1619                // includes more detailed entries than were present in the old
1620                // profile
1621                let mut costs: Vec<CostGasUsed> = profile_data
1622                    .legacy_action_costs()
1623                    .into_iter()
1624                    .filter(|&(_, gas)| gas > 0)
1625                    .map(|(name, gas)| CostGasUsed::action(name.to_string(), gas))
1626                    .collect();
1627
1628                // wasm op is a single cost, for historical reasons it is inaccurately displayed as "wasm host"
1629                costs.push(CostGasUsed::wasm_host(
1630                    "WASM_INSTRUCTION".to_string(),
1631                    profile_data.get_wasm_cost(),
1632                ));
1633
1634                // ext costs are 1-to-1, except for those added later which we will display as 0
1635                for ext_cost in ExtCosts::iter() {
1636                    costs.push(CostGasUsed::wasm_host(
1637                        format!("{:?}", ext_cost).to_ascii_uppercase(),
1638                        profile_data.get_ext_cost(ext_cost),
1639                    ));
1640                }
1641
1642                Some(costs)
1643            }
1644            ExecutionMetadata::V3(profile) => {
1645                // Add actions, wasm op, and ext costs in groups.
1646                // actions costs are 1-to-1
1647                let mut costs: Vec<CostGasUsed> = ActionCosts::iter()
1648                    .flat_map(|cost| {
1649                        let gas_used = profile.get_action_cost(cost);
1650                        (gas_used > 0).then(|| {
1651                            CostGasUsed::action(
1652                                format!("{:?}", cost).to_ascii_uppercase(),
1653                                gas_used,
1654                            )
1655                        })
1656                    })
1657                    .collect();
1658
1659                // wasm op is a single cost, for historical reasons it is inaccurately displayed as "wasm host"
1660                let wasm_gas_used = profile.get_wasm_cost();
1661                if wasm_gas_used > 0 {
1662                    costs.push(CostGasUsed::wasm_host(
1663                        "WASM_INSTRUCTION".to_string(),
1664                        wasm_gas_used,
1665                    ));
1666                }
1667
1668                // ext costs are 1-to-1
1669                for ext_cost in ExtCosts::iter() {
1670                    let gas_used = profile.get_ext_cost(ext_cost);
1671                    if gas_used > 0 {
1672                        costs.push(CostGasUsed::wasm_host(
1673                            format!("{:?}", ext_cost).to_ascii_uppercase(),
1674                            gas_used,
1675                        ));
1676                    }
1677                }
1678
1679                Some(costs)
1680            }
1681        };
1682        if let Some(ref mut costs) = gas_profile {
1683            // The order doesn't really matter, but the default one is just
1684            // historical, which is especially unintuitive, so let's sort
1685            // lexicographically.
1686            //
1687            // Can't `sort_by_key` here because lifetime inference in
1688            // closures is limited.
1689            costs.sort_by(|lhs, rhs| {
1690                lhs.cost_category.cmp(&rhs.cost_category).then_with(|| lhs.cost.cmp(&rhs.cost))
1691            });
1692        }
1693        ExecutionMetadataView { version, gas_profile }
1694    }
1695}
1696
1697impl CostGasUsed {
1698    pub fn action(cost: String, gas_used: Gas) -> Self {
1699        Self { cost_category: "ACTION_COST".to_string(), cost, gas_used }
1700    }
1701
1702    pub fn wasm_host(cost: String, gas_used: Gas) -> Self {
1703        Self { cost_category: "WASM_HOST_COST".to_string(), cost, gas_used }
1704    }
1705}
1706
1707#[derive(
1708    BorshSerialize,
1709    BorshDeserialize,
1710    Debug,
1711    Clone,
1712    PartialEq,
1713    Eq,
1714    serde::Serialize,
1715    serde::Deserialize,
1716)]
1717pub struct ExecutionOutcomeView {
1718    /// Logs from this transaction or receipt.
1719    pub logs: Vec<String>,
1720    /// Receipt IDs generated by this transaction or receipt.
1721    pub receipt_ids: Vec<CryptoHash>,
1722    /// The amount of the gas burnt by the given transaction or receipt.
1723    pub gas_burnt: Gas,
1724    /// The amount of tokens burnt corresponding to the burnt gas amount.
1725    /// This value doesn't always equal to the `gas_burnt` multiplied by the gas price, because
1726    /// the prepaid gas price might be lower than the actual gas price and it creates a deficit.
1727    #[serde(with = "dec_format")]
1728    pub tokens_burnt: Balance,
1729    /// The id of the account on which the execution happens. For transaction this is signer_id,
1730    /// for receipt this is receiver_id.
1731    pub executor_id: AccountId,
1732    /// Execution status. Contains the result in case of successful execution.
1733    pub status: ExecutionStatusView,
1734    /// Execution metadata, versioned
1735    #[serde(default)]
1736    pub metadata: ExecutionMetadataView,
1737}
1738
1739impl From<ExecutionOutcome> for ExecutionOutcomeView {
1740    fn from(outcome: ExecutionOutcome) -> Self {
1741        Self {
1742            logs: outcome.logs,
1743            receipt_ids: outcome.receipt_ids,
1744            gas_burnt: outcome.gas_burnt,
1745            tokens_burnt: outcome.tokens_burnt,
1746            executor_id: outcome.executor_id,
1747            status: outcome.status.into(),
1748            metadata: outcome.metadata.into(),
1749        }
1750    }
1751}
1752
1753impl From<&ExecutionOutcomeView> for PartialExecutionOutcome {
1754    fn from(outcome: &ExecutionOutcomeView) -> Self {
1755        Self {
1756            receipt_ids: outcome.receipt_ids.clone(),
1757            gas_burnt: outcome.gas_burnt,
1758            tokens_burnt: outcome.tokens_burnt,
1759            executor_id: outcome.executor_id.clone(),
1760            status: outcome.status.clone().into(),
1761        }
1762    }
1763}
1764impl From<ExecutionStatusView> for PartialExecutionStatus {
1765    fn from(status: ExecutionStatusView) -> PartialExecutionStatus {
1766        match status {
1767            ExecutionStatusView::Unknown => PartialExecutionStatus::Unknown,
1768            ExecutionStatusView::Failure(_) => PartialExecutionStatus::Failure,
1769            ExecutionStatusView::SuccessValue(value) => PartialExecutionStatus::SuccessValue(value),
1770            ExecutionStatusView::SuccessReceiptId(id) => {
1771                PartialExecutionStatus::SuccessReceiptId(id)
1772            }
1773        }
1774    }
1775}
1776
1777impl ExecutionOutcomeView {
1778    // Same behavior as ExecutionOutcomeWithId's to_hashes.
1779    pub fn to_hashes(&self, id: CryptoHash) -> Vec<CryptoHash> {
1780        let mut result = Vec::with_capacity(self.logs.len().saturating_add(2));
1781        result.push(id);
1782        result.push(CryptoHash::hash_borsh(&PartialExecutionOutcome::from(self)));
1783        result.extend(self.logs.iter().map(|log| hash(log.as_bytes())));
1784        result
1785    }
1786}
1787
1788#[cfg_attr(feature = "deepsize_feature", derive(deepsize::DeepSizeOf))]
1789#[derive(
1790    BorshSerialize,
1791    BorshDeserialize,
1792    Debug,
1793    PartialEq,
1794    Eq,
1795    Clone,
1796    serde::Serialize,
1797    serde::Deserialize,
1798)]
1799pub struct ExecutionOutcomeWithIdView {
1800    pub proof: MerklePath,
1801    pub block_hash: CryptoHash,
1802    pub id: CryptoHash,
1803    pub outcome: ExecutionOutcomeView,
1804}
1805
1806impl From<ExecutionOutcomeWithIdAndProof> for ExecutionOutcomeWithIdView {
1807    fn from(outcome_with_id_and_proof: ExecutionOutcomeWithIdAndProof) -> Self {
1808        Self {
1809            proof: outcome_with_id_and_proof.proof,
1810            block_hash: outcome_with_id_and_proof.block_hash,
1811            id: outcome_with_id_and_proof.outcome_with_id.id,
1812            outcome: outcome_with_id_and_proof.outcome_with_id.outcome.into(),
1813        }
1814    }
1815}
1816
1817impl ExecutionOutcomeWithIdView {
1818    pub fn to_hashes(&self) -> Vec<CryptoHash> {
1819        self.outcome.to_hashes(self.id)
1820    }
1821}
1822#[derive(Clone, Debug)]
1823pub struct TxStatusView {
1824    pub execution_outcome: Option<FinalExecutionOutcomeViewEnum>,
1825    pub status: TxExecutionStatus,
1826}
1827
1828#[derive(
1829    BorshSerialize,
1830    BorshDeserialize,
1831    serde::Serialize,
1832    serde::Deserialize,
1833    Clone,
1834    Debug,
1835    Default,
1836    Eq,
1837    PartialEq,
1838)]
1839#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
1840pub enum TxExecutionStatus {
1841    /// Transaction is waiting to be included into the block
1842    None,
1843    /// Transaction is included into the block. The block may be not finalised yet
1844    Included,
1845    /// Transaction is included into the block +
1846    /// All non-refund transaction receipts finished their execution.
1847    /// The corresponding blocks for tx and each receipt may be not finalised yet
1848    #[default]
1849    ExecutedOptimistic,
1850    /// Transaction is included into finalised block
1851    IncludedFinal,
1852    /// Transaction is included into finalised block +
1853    /// All the transaction receipts finished their execution.
1854    /// The corresponding blocks for each receipt may be not finalised yet
1855    Executed,
1856    /// Transaction is included into finalised block +
1857    /// Execution of transaction receipts is finalised
1858    Final,
1859}
1860
1861#[derive(BorshSerialize, BorshDeserialize, serde::Serialize, serde::Deserialize, Debug, Clone)]
1862#[serde(untagged)]
1863pub enum FinalExecutionOutcomeViewEnum {
1864    FinalExecutionOutcome(FinalExecutionOutcomeView),
1865    FinalExecutionOutcomeWithReceipt(FinalExecutionOutcomeWithReceiptView),
1866}
1867
1868impl FinalExecutionOutcomeViewEnum {
1869    pub fn into_outcome(self) -> FinalExecutionOutcomeView {
1870        match self {
1871            Self::FinalExecutionOutcome(outcome) => outcome,
1872            Self::FinalExecutionOutcomeWithReceipt(outcome) => outcome.final_outcome,
1873        }
1874    }
1875}
1876
1877impl TxStatusView {
1878    pub fn into_outcome(self) -> Option<FinalExecutionOutcomeView> {
1879        self.execution_outcome.map(|outcome| match outcome {
1880            FinalExecutionOutcomeViewEnum::FinalExecutionOutcome(outcome) => outcome,
1881            FinalExecutionOutcomeViewEnum::FinalExecutionOutcomeWithReceipt(outcome) => {
1882                outcome.final_outcome
1883            }
1884        })
1885    }
1886}
1887
1888/// Execution outcome of the transaction and all of subsequent the receipts.
1889/// Could be not finalised yet
1890#[derive(
1891    BorshSerialize, BorshDeserialize, serde::Serialize, serde::Deserialize, PartialEq, Eq, Clone,
1892)]
1893pub struct FinalExecutionOutcomeView {
1894    /// Execution status defined by chain.rs:get_final_transaction_result
1895    /// FinalExecutionStatus::NotStarted - the tx is not converted to the receipt yet
1896    /// FinalExecutionStatus::Started - we have at least 1 receipt, but the first leaf receipt_id (using dfs) hasn't finished the execution
1897    /// FinalExecutionStatus::Failure - the result of the first leaf receipt_id
1898    /// FinalExecutionStatus::SuccessValue - the result of the first leaf receipt_id
1899    pub status: FinalExecutionStatus,
1900    /// Signed Transaction
1901    pub transaction: SignedTransactionView,
1902    /// The execution outcome of the signed transaction.
1903    pub transaction_outcome: ExecutionOutcomeWithIdView,
1904    /// The execution outcome of receipts.
1905    pub receipts_outcome: Vec<ExecutionOutcomeWithIdView>,
1906}
1907
1908impl fmt::Debug for FinalExecutionOutcomeView {
1909    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1910        f.debug_struct("FinalExecutionOutcome")
1911            .field("status", &self.status)
1912            .field("transaction", &self.transaction)
1913            .field("transaction_outcome", &self.transaction_outcome)
1914            .field("receipts_outcome", &Slice(&self.receipts_outcome))
1915            .finish()
1916    }
1917}
1918
1919/// Final execution outcome of the transaction and all of subsequent the receipts. Also includes
1920/// the generated receipt.
1921#[derive(
1922    BorshSerialize,
1923    BorshDeserialize,
1924    PartialEq,
1925    Eq,
1926    Clone,
1927    Debug,
1928    serde::Serialize,
1929    serde::Deserialize,
1930)]
1931pub struct FinalExecutionOutcomeWithReceiptView {
1932    /// Final outcome view without receipts
1933    #[serde(flatten)]
1934    pub final_outcome: FinalExecutionOutcomeView,
1935    /// Receipts generated from the transaction
1936    pub receipts: Vec<ReceiptView>,
1937}
1938
1939pub mod validator_pledge_view {
1940    pub use super::ValidatorPowerViewV1;
1941    use crate::types::validator_stake::ValidatorPledge;
1942    use borsh::{BorshDeserialize, BorshSerialize};
1943    use serde::Deserialize;
1944    use unc_primitives_core::types::AccountId;
1945
1946    #[derive(
1947        BorshSerialize, BorshDeserialize, serde::Serialize, Deserialize, Debug, Clone, Eq, PartialEq,
1948    )]
1949    #[serde(tag = "validator_pledge_struct_version")]
1950    pub enum ValidatorPledgeView {
1951        V1(crate::views::ValidatorPledgeViewV1),
1952    }
1953
1954    impl crate::views::validator_pledge_view::ValidatorPledgeView {
1955        pub fn into_validator_pledge(self) -> ValidatorPledge {
1956            self.into()
1957        }
1958
1959        #[inline]
1960        pub fn take_account_id(self) -> AccountId {
1961            match self {
1962                Self::V1(v1) => v1.account_id,
1963            }
1964        }
1965
1966        #[inline]
1967        pub fn account_id(&self) -> &AccountId {
1968            match self {
1969                Self::V1(v1) => &v1.account_id,
1970            }
1971        }
1972    }
1973
1974    impl From<ValidatorPledge> for crate::views::validator_pledge_view::ValidatorPledgeView {
1975        fn from(pledge: ValidatorPledge) -> Self {
1976            match pledge {
1977                ValidatorPledge::V1(v1) => Self::V1(crate::views::ValidatorPledgeViewV1 {
1978                    account_id: v1.account_id,
1979                    public_key: v1.public_key,
1980                    pledge: v1.pledge,
1981                }),
1982            }
1983        }
1984    }
1985
1986    impl From<crate::views::validator_pledge_view::ValidatorPledgeView> for ValidatorPledge {
1987        fn from(view: crate::views::validator_pledge_view::ValidatorPledgeView) -> Self {
1988            match view {
1989                crate::views::validator_pledge_view::ValidatorPledgeView::V1(v1) => {
1990                    Self::new_v1(v1.account_id, v1.public_key, v1.pledge)
1991                }
1992            }
1993        }
1994    }
1995}
1996
1997#[derive(
1998    BorshSerialize,
1999    BorshDeserialize,
2000    Debug,
2001    Clone,
2002    Eq,
2003    PartialEq,
2004    serde::Serialize,
2005    serde::Deserialize,
2006)]
2007pub struct ValidatorPledgeViewV1 {
2008    pub account_id: AccountId,
2009    pub public_key: PublicKey,
2010    #[serde(with = "dec_format")]
2011    pub pledge: Balance,
2012}
2013pub mod validator_power_view {
2014    pub use super::ValidatorPowerViewV1;
2015    use crate::types::validator_power::ValidatorPower;
2016    use borsh::{BorshDeserialize, BorshSerialize};
2017    use serde::Deserialize;
2018    use unc_primitives_core::types::AccountId;
2019
2020    #[derive(
2021        BorshSerialize, BorshDeserialize, serde::Serialize, Deserialize, Debug, Clone, Eq, PartialEq,
2022    )]
2023    #[serde(tag = "validator_power_struct_version")]
2024    pub enum ValidatorPowerView {
2025        V1(ValidatorPowerViewV1),
2026    }
2027
2028    impl ValidatorPowerView {
2029        pub fn into_validator_power(self) -> ValidatorPower {
2030            self.into()
2031        }
2032
2033        #[inline]
2034        pub fn take_account_id(self) -> AccountId {
2035            match self {
2036                Self::V1(v1) => v1.account_id,
2037            }
2038        }
2039
2040        #[inline]
2041        pub fn account_id(&self) -> &AccountId {
2042            match self {
2043                Self::V1(v1) => &v1.account_id,
2044            }
2045        }
2046    }
2047
2048    impl From<ValidatorPower> for ValidatorPowerView {
2049        fn from(power: ValidatorPower) -> Self {
2050            match power {
2051                ValidatorPower::V1(v1) => Self::V1(ValidatorPowerViewV1 {
2052                    account_id: v1.account_id,
2053                    public_key: v1.public_key,
2054                    power: v1.power,
2055                }),
2056            }
2057        }
2058    }
2059
2060    impl From<ValidatorPowerView> for ValidatorPower {
2061        fn from(view: ValidatorPowerView) -> Self {
2062            match view {
2063                ValidatorPowerView::V1(v1) => Self::new_v1(v1.account_id, v1.public_key, v1.power),
2064            }
2065        }
2066    }
2067}
2068
2069#[derive(
2070    BorshSerialize,
2071    BorshDeserialize,
2072    Debug,
2073    Clone,
2074    Eq,
2075    PartialEq,
2076    serde::Serialize,
2077    serde::Deserialize,
2078)]
2079pub struct ValidatorPowerViewV1 {
2080    pub account_id: AccountId,
2081    pub public_key: PublicKey,
2082    #[serde(with = "dec_format")]
2083    pub power: Power,
2084}
2085
2086pub mod validator_power_and_pledge_view {
2087    pub use super::ValidatorPowerViewV1;
2088    use crate::types::validator_power_and_pledge::ValidatorPowerAndPledge;
2089    use borsh::{BorshDeserialize, BorshSerialize};
2090    use serde::Deserialize;
2091    use unc_primitives_core::types::AccountId;
2092
2093    #[derive(
2094        BorshSerialize, BorshDeserialize, serde::Serialize, Deserialize, Debug, Clone, Eq, PartialEq,
2095    )]
2096    #[serde(tag = "validator_power_and_pledge_struct_version")]
2097    pub enum ValidatorPowerAndPledgeView {
2098        V1(crate::views::ValidatorPowerAndPledgeViewV1),
2099    }
2100
2101    impl crate::views::validator_power_and_pledge_view::ValidatorPowerAndPledgeView {
2102        pub fn into_validator_power_and_pledge(self) -> ValidatorPowerAndPledge {
2103            self.into()
2104        }
2105
2106        #[inline]
2107        pub fn take_account_id(self) -> AccountId {
2108            match self {
2109                Self::V1(v1) => v1.account_id,
2110            }
2111        }
2112
2113        #[inline]
2114        pub fn account_id(&self) -> &AccountId {
2115            match self {
2116                Self::V1(v1) => &v1.account_id,
2117            }
2118        }
2119    }
2120
2121    impl From<ValidatorPowerAndPledge>
2122        for crate::views::validator_power_and_pledge_view::ValidatorPowerAndPledgeView
2123    {
2124        fn from(power_pledge: ValidatorPowerAndPledge) -> Self {
2125            match power_pledge {
2126                ValidatorPowerAndPledge::V1(v1) => {
2127                    Self::V1(crate::views::ValidatorPowerAndPledgeViewV1 {
2128                        account_id: v1.account_id,
2129                        public_key: v1.public_key,
2130                        power: v1.power,
2131                        pledge: v1.pledge,
2132                    })
2133                }
2134            }
2135        }
2136    }
2137
2138    impl From<crate::views::validator_power_and_pledge_view::ValidatorPowerAndPledgeView>
2139        for ValidatorPowerAndPledge
2140    {
2141        fn from(
2142            view: crate::views::validator_power_and_pledge_view::ValidatorPowerAndPledgeView,
2143        ) -> Self {
2144            match view {
2145                crate::views::validator_power_and_pledge_view::ValidatorPowerAndPledgeView::V1(
2146                    v1,
2147                ) => Self::new_v1(v1.account_id, v1.public_key, v1.power, v1.pledge),
2148            }
2149        }
2150    }
2151}
2152
2153#[derive(
2154    BorshSerialize,
2155    BorshDeserialize,
2156    Debug,
2157    Clone,
2158    Eq,
2159    PartialEq,
2160    serde::Serialize,
2161    serde::Deserialize,
2162)]
2163pub struct ValidatorPowerAndPledgeViewV1 {
2164    pub account_id: AccountId,
2165    pub public_key: PublicKey,
2166    #[serde(with = "dec_format")]
2167    pub power: Power,
2168    pub pledge: Balance,
2169}
2170
2171#[derive(
2172    BorshSerialize,
2173    BorshDeserialize,
2174    Clone,
2175    Debug,
2176    PartialEq,
2177    Eq,
2178    serde::Serialize,
2179    serde::Deserialize,
2180)]
2181pub struct ReceiptView {
2182    pub predecessor_id: AccountId,
2183    pub receiver_id: AccountId,
2184    pub receipt_id: CryptoHash,
2185
2186    pub receipt: ReceiptEnumView,
2187}
2188
2189#[derive(
2190    BorshSerialize,
2191    BorshDeserialize,
2192    Clone,
2193    Debug,
2194    PartialEq,
2195    Eq,
2196    serde::Serialize,
2197    serde::Deserialize,
2198)]
2199pub struct DataReceiverView {
2200    pub data_id: CryptoHash,
2201    pub receiver_id: AccountId,
2202}
2203
2204#[serde_as]
2205#[derive(
2206    BorshSerialize,
2207    BorshDeserialize,
2208    Clone,
2209    Debug,
2210    PartialEq,
2211    Eq,
2212    serde::Serialize,
2213    serde::Deserialize,
2214)]
2215pub enum ReceiptEnumView {
2216    Action {
2217        signer_id: AccountId,
2218        signer_public_key: PublicKey,
2219        #[serde(with = "dec_format")]
2220        gas_price: Balance,
2221        output_data_receivers: Vec<DataReceiverView>,
2222        input_data_ids: Vec<CryptoHash>,
2223        actions: Vec<ActionView>,
2224    },
2225    Data {
2226        data_id: CryptoHash,
2227        #[serde_as(as = "Option<Base64>")]
2228        data: Option<Vec<u8>>,
2229    },
2230}
2231
2232impl From<Receipt> for ReceiptView {
2233    fn from(receipt: Receipt) -> Self {
2234        ReceiptView {
2235            predecessor_id: receipt.predecessor_id,
2236            receiver_id: receipt.receiver_id,
2237            receipt_id: receipt.receipt_id,
2238            receipt: match receipt.receipt {
2239                ReceiptEnum::Action(action_receipt) => ReceiptEnumView::Action {
2240                    signer_id: action_receipt.signer_id,
2241                    signer_public_key: action_receipt.signer_public_key,
2242                    gas_price: action_receipt.gas_price,
2243                    output_data_receivers: action_receipt
2244                        .output_data_receivers
2245                        .into_iter()
2246                        .map(|data_receiver| DataReceiverView {
2247                            data_id: data_receiver.data_id,
2248                            receiver_id: data_receiver.receiver_id,
2249                        })
2250                        .collect(),
2251                    input_data_ids: action_receipt
2252                        .input_data_ids
2253                        .into_iter()
2254                        .map(Into::into)
2255                        .collect(),
2256                    actions: action_receipt.actions.into_iter().map(Into::into).collect(),
2257                },
2258                ReceiptEnum::Data(data_receipt) => {
2259                    ReceiptEnumView::Data { data_id: data_receipt.data_id, data: data_receipt.data }
2260                }
2261            },
2262        }
2263    }
2264}
2265
2266impl TryFrom<ReceiptView> for Receipt {
2267    type Error = Box<dyn std::error::Error + Send + Sync>;
2268
2269    fn try_from(receipt_view: ReceiptView) -> Result<Self, Self::Error> {
2270        Ok(Receipt {
2271            predecessor_id: receipt_view.predecessor_id,
2272            receiver_id: receipt_view.receiver_id,
2273            receipt_id: receipt_view.receipt_id,
2274            receipt: match receipt_view.receipt {
2275                ReceiptEnumView::Action {
2276                    signer_id,
2277                    signer_public_key,
2278                    gas_price,
2279                    output_data_receivers,
2280                    input_data_ids,
2281                    actions,
2282                } => ReceiptEnum::Action(ActionReceipt {
2283                    signer_id,
2284                    signer_public_key,
2285                    gas_price,
2286                    output_data_receivers: output_data_receivers
2287                        .into_iter()
2288                        .map(|data_receiver_view| DataReceiver {
2289                            data_id: data_receiver_view.data_id,
2290                            receiver_id: data_receiver_view.receiver_id,
2291                        })
2292                        .collect(),
2293                    input_data_ids: input_data_ids.into_iter().map(Into::into).collect(),
2294                    actions: actions
2295                        .into_iter()
2296                        .map(TryInto::try_into)
2297                        .collect::<Result<Vec<_>, _>>()?,
2298                }),
2299                ReceiptEnumView::Data { data_id, data } => {
2300                    ReceiptEnum::Data(DataReceipt { data_id, data })
2301                }
2302            },
2303        })
2304    }
2305}
2306
2307/// Information about this epoch validators and next epoch validators
2308#[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Eq, Clone)]
2309pub struct EpochValidatorInfo {
2310    /// Validators for the current epoch
2311    pub current_validators: Vec<CurrentEpochValidatorInfo>,
2312    /// Validators for the next epoch
2313    pub next_validators: Vec<NextEpochValidatorInfo>,
2314    /// Fishermen for the current epoch
2315    pub current_fishermen: Vec<ValidatorPledgeView>,
2316    /// Fishermen for the next epoch
2317    pub next_fishermen: Vec<ValidatorPledgeView>,
2318    /// Power proposals in the current epoch
2319    pub current_power_proposals: Vec<ValidatorPowerView>,
2320    /// Pledge proposals in the current epoch
2321    pub current_pledge_proposals: Vec<ValidatorPledgeView>,
2322    /// Kickout in the previous epoch
2323    pub prev_epoch_kickout: Vec<ValidatorKickoutView>,
2324    /// Epoch start block height
2325    pub epoch_start_height: BlockHeight,
2326    /// Epoch height
2327    pub epoch_height: EpochHeight,
2328}
2329
2330#[derive(
2331    BorshSerialize,
2332    BorshDeserialize,
2333    Debug,
2334    PartialEq,
2335    Eq,
2336    Clone,
2337    serde::Serialize,
2338    serde::Deserialize,
2339)]
2340pub struct ValidatorKickoutView {
2341    pub account_id: AccountId,
2342    pub reason: ValidatorKickoutReason,
2343}
2344
2345#[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Eq, Clone)]
2346pub struct CurrentEpochValidatorInfo {
2347    pub account_id: AccountId,
2348    pub public_key: PublicKey,
2349    pub is_slashed: bool,
2350    #[serde(with = "dec_format")]
2351    pub power: Power,
2352    #[serde(with = "dec_format")]
2353    pub pledge: Balance,
2354    pub shards: Vec<ShardId>,
2355    pub num_produced_blocks: NumBlocks,
2356    pub num_expected_blocks: NumBlocks,
2357    #[serde(default)]
2358    pub num_produced_chunks: NumBlocks,
2359    #[serde(default)]
2360    pub num_expected_chunks: NumBlocks,
2361    // The following two fields correspond to the shards in the shard array.
2362    #[serde(default)]
2363    pub num_produced_chunks_per_shard: Vec<NumBlocks>,
2364    #[serde(default)]
2365    pub num_expected_chunks_per_shard: Vec<NumBlocks>,
2366}
2367
2368#[derive(
2369    BorshSerialize,
2370    BorshDeserialize,
2371    Debug,
2372    PartialEq,
2373    Eq,
2374    Clone,
2375    serde::Serialize,
2376    serde::Deserialize,
2377)]
2378pub struct NextEpochValidatorInfo {
2379    pub account_id: AccountId,
2380    pub public_key: PublicKey,
2381    #[serde(with = "dec_format")]
2382    pub power: Power,
2383    #[serde(with = "dec_format")]
2384    pub pledge: Balance,
2385    pub shards: Vec<ShardId>,
2386}
2387
2388#[derive(
2389    PartialEq,
2390    Eq,
2391    Debug,
2392    Clone,
2393    BorshDeserialize,
2394    BorshSerialize,
2395    serde::Serialize,
2396    serde::Deserialize,
2397)]
2398pub struct LightClientBlockView {
2399    pub prev_block_hash: CryptoHash,
2400    pub next_block_inner_hash: CryptoHash,
2401    pub inner_lite: BlockHeaderInnerLiteView,
2402    pub inner_rest_hash: CryptoHash,
2403    pub next_bps: Option<Vec<ValidatorPowerAndPledgeView>>,
2404    pub approvals_after_next: Vec<Option<Box<Signature>>>,
2405}
2406
2407#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, BorshDeserialize, BorshSerialize)]
2408pub struct LightClientBlockLiteView {
2409    pub prev_block_hash: CryptoHash,
2410    pub inner_rest_hash: CryptoHash,
2411    pub inner_lite: BlockHeaderInnerLiteView,
2412}
2413
2414impl From<BlockHeader> for LightClientBlockLiteView {
2415    fn from(header: BlockHeader) -> Self {
2416        Self {
2417            prev_block_hash: *header.prev_hash(),
2418            inner_rest_hash: hash(&header.inner_rest_bytes()),
2419            inner_lite: header.into(),
2420        }
2421    }
2422}
2423impl LightClientBlockLiteView {
2424    pub fn hash(&self) -> CryptoHash {
2425        let block_header_inner_lite: BlockHeaderInnerLite = self.inner_lite.clone().into();
2426        combine_hash(
2427            &combine_hash(
2428                &hash(&borsh::to_vec(&block_header_inner_lite).unwrap()),
2429                &self.inner_rest_hash,
2430            ),
2431            &self.prev_block_hash,
2432        )
2433    }
2434}
2435
2436#[derive(serde::Serialize, serde::Deserialize, Debug)]
2437pub struct GasPriceView {
2438    #[serde(with = "dec_format")]
2439    pub gas_price: Balance,
2440}
2441
2442/// It is a [serializable view] of [`StateChangesRequest`].
2443///
2444/// [serializable view]: ./index.html
2445/// [`StateChangesRequest`]: ../types/struct.StateChangesRequest.html
2446#[derive(Debug, serde::Serialize, serde::Deserialize)]
2447#[serde(tag = "changes_type", rename_all = "snake_case")]
2448pub enum StateChangesRequestView {
2449    AccountChanges {
2450        account_ids: Vec<AccountId>,
2451    },
2452    SingleAccessKeyChanges {
2453        keys: Vec<AccountWithPublicKey>,
2454    },
2455    AllAccessKeyChanges {
2456        account_ids: Vec<AccountId>,
2457    },
2458    ContractCodeChanges {
2459        account_ids: Vec<AccountId>,
2460    },
2461    DataChanges {
2462        account_ids: Vec<AccountId>,
2463        #[serde(rename = "key_prefix_base64")]
2464        key_prefix: StoreKey,
2465    },
2466}
2467
2468impl From<StateChangesRequestView> for StateChangesRequest {
2469    fn from(request: StateChangesRequestView) -> Self {
2470        match request {
2471            StateChangesRequestView::AccountChanges { account_ids } => {
2472                Self::AccountChanges { account_ids }
2473            }
2474            StateChangesRequestView::SingleAccessKeyChanges { keys } => {
2475                Self::SingleAccessKeyChanges { keys }
2476            }
2477            StateChangesRequestView::AllAccessKeyChanges { account_ids } => {
2478                Self::AllAccessKeyChanges { account_ids }
2479            }
2480            StateChangesRequestView::ContractCodeChanges { account_ids } => {
2481                Self::ContractCodeChanges { account_ids }
2482            }
2483            StateChangesRequestView::DataChanges { account_ids, key_prefix } => {
2484                Self::DataChanges { account_ids, key_prefix }
2485            }
2486        }
2487    }
2488}
2489
2490/// It is a [serializable view] of [`StateChangeKind`].
2491///
2492/// [serializable view]: ./index.html
2493/// [`StateChangeKind`]: ../types/struct.StateChangeKind.html
2494#[derive(Debug, serde::Serialize, serde::Deserialize)]
2495#[serde(rename_all = "snake_case", tag = "type")]
2496pub enum StateChangeKindView {
2497    AccountTouched { account_id: AccountId },
2498    AccessKeyTouched { account_id: AccountId },
2499    DataTouched { account_id: AccountId },
2500    ContractCodeTouched { account_id: AccountId },
2501    RsaKeyTouched { account_id: AccountId },
2502}
2503
2504impl From<StateChangeKind> for StateChangeKindView {
2505    fn from(state_change_kind: StateChangeKind) -> Self {
2506        match state_change_kind {
2507            StateChangeKind::AccountTouched { account_id } => Self::AccountTouched { account_id },
2508            StateChangeKind::AccessKeyTouched { account_id } => {
2509                Self::AccessKeyTouched { account_id }
2510            }
2511            StateChangeKind::RsaKeyTouched { account_id } => Self::RsaKeyTouched { account_id },
2512            StateChangeKind::DataTouched { account_id } => Self::DataTouched { account_id },
2513            StateChangeKind::ContractCodeTouched { account_id } => {
2514                Self::ContractCodeTouched { account_id }
2515            }
2516        }
2517    }
2518}
2519
2520pub type StateChangesKindsView = Vec<StateChangeKindView>;
2521
2522/// See crate::types::StateChangeCause for details.
2523#[derive(Debug, serde::Serialize, serde::Deserialize)]
2524#[serde(rename_all = "snake_case", tag = "type")]
2525pub enum StateChangeCauseView {
2526    NotWritableToDisk,
2527    InitialState,
2528    TransactionProcessing { tx_hash: CryptoHash },
2529    ActionReceiptProcessingStarted { receipt_hash: CryptoHash },
2530    ActionReceiptGasReward { receipt_hash: CryptoHash },
2531    ReceiptProcessing { receipt_hash: CryptoHash },
2532    PostponedReceipt { receipt_hash: CryptoHash },
2533    UpdatedDelayedReceipts,
2534    ValidatorAccountsUpdate,
2535    Migration,
2536    Resharding,
2537}
2538
2539impl From<StateChangeCause> for StateChangeCauseView {
2540    fn from(state_change_cause: StateChangeCause) -> Self {
2541        match state_change_cause {
2542            StateChangeCause::NotWritableToDisk => Self::NotWritableToDisk,
2543            StateChangeCause::InitialState => Self::InitialState,
2544            StateChangeCause::TransactionProcessing { tx_hash } => {
2545                Self::TransactionProcessing { tx_hash }
2546            }
2547            StateChangeCause::ActionReceiptProcessingStarted { receipt_hash } => {
2548                Self::ActionReceiptProcessingStarted { receipt_hash }
2549            }
2550            StateChangeCause::ActionReceiptGasReward { receipt_hash } => {
2551                Self::ActionReceiptGasReward { receipt_hash }
2552            }
2553            StateChangeCause::ReceiptProcessing { receipt_hash } => {
2554                Self::ReceiptProcessing { receipt_hash }
2555            }
2556            StateChangeCause::PostponedReceipt { receipt_hash } => {
2557                Self::PostponedReceipt { receipt_hash }
2558            }
2559            StateChangeCause::UpdatedDelayedReceipts => Self::UpdatedDelayedReceipts,
2560            StateChangeCause::ValidatorAccountsUpdate => Self::ValidatorAccountsUpdate,
2561            StateChangeCause::Migration => Self::Migration,
2562            StateChangeCause::Resharding => Self::Resharding,
2563        }
2564    }
2565}
2566
2567#[serde_as]
2568#[derive(Debug, serde::Serialize, serde::Deserialize)]
2569#[serde(rename_all = "snake_case", tag = "type", content = "change")]
2570pub enum StateChangeValueView {
2571    AccountUpdate {
2572        account_id: AccountId,
2573        #[serde(flatten)]
2574        account: AccountView,
2575    },
2576    AccountDeletion {
2577        account_id: AccountId,
2578    },
2579    AccessKeyUpdate {
2580        account_id: AccountId,
2581        public_key: PublicKey,
2582        access_key: AccessKeyView,
2583    },
2584    AccessKeyDeletion {
2585        account_id: AccountId,
2586        public_key: PublicKey,
2587    },
2588    DataUpdate {
2589        account_id: AccountId,
2590        #[serde(rename = "key_base64")]
2591        key: StoreKey,
2592        #[serde(rename = "value_base64")]
2593        value: StoreValue,
2594    },
2595    DataDeletion {
2596        account_id: AccountId,
2597        #[serde(rename = "key_base64")]
2598        key: StoreKey,
2599    },
2600    ContractCodeUpdate {
2601        account_id: AccountId,
2602        #[serde(rename = "code_base64")]
2603        #[serde_as(as = "Base64")]
2604        code: Vec<u8>,
2605    },
2606    ContractCodeDeletion {
2607        account_id: AccountId,
2608    },
2609    RsaKeyUpdate {
2610        account_id: AccountId,
2611        public_key: PublicKey,
2612        rsa_key: RegisterRsa2048KeysAction,
2613    },
2614    RsaKeyDeletion {
2615        account_id: AccountId,
2616        public_key: PublicKey,
2617    },
2618}
2619
2620impl From<StateChangeValue> for StateChangeValueView {
2621    fn from(state_change: StateChangeValue) -> Self {
2622        match state_change {
2623            StateChangeValue::AccountUpdate { account_id, account } => {
2624                Self::AccountUpdate { account_id, account: account.into() }
2625            }
2626            StateChangeValue::AccountDeletion { account_id } => {
2627                Self::AccountDeletion { account_id }
2628            }
2629            StateChangeValue::AccessKeyUpdate { account_id, public_key, access_key } => {
2630                Self::AccessKeyUpdate { account_id, public_key, access_key: access_key.into() }
2631            }
2632            StateChangeValue::AccessKeyDeletion { account_id, public_key } => {
2633                Self::AccessKeyDeletion { account_id, public_key }
2634            }
2635            StateChangeValue::DataUpdate { account_id, key, value } => {
2636                Self::DataUpdate { account_id, key, value }
2637            }
2638            StateChangeValue::DataDeletion { account_id, key } => {
2639                Self::DataDeletion { account_id, key }
2640            }
2641            StateChangeValue::ContractCodeUpdate { account_id, code } => {
2642                Self::ContractCodeUpdate { account_id, code }
2643            }
2644            StateChangeValue::ContractCodeDeletion { account_id } => {
2645                Self::ContractCodeDeletion { account_id }
2646            }
2647            StateChangeValue::RsaKeyUpdate { account_id, public_key, rsa_key } => {
2648                Self::RsaKeyUpdate { account_id, public_key, rsa_key: rsa_key.into() }
2649            }
2650            StateChangeValue::RsaKeyDeletion { account_id, public_key } => {
2651                Self::RsaKeyDeletion { account_id, public_key }
2652            }
2653        }
2654    }
2655}
2656
2657#[derive(Debug, serde::Serialize, serde::Deserialize)]
2658pub struct StateChangeWithCauseView {
2659    pub cause: StateChangeCauseView,
2660    #[serde(flatten)]
2661    pub value: StateChangeValueView,
2662}
2663
2664impl From<StateChangeWithCause> for StateChangeWithCauseView {
2665    fn from(state_change_with_cause: StateChangeWithCause) -> Self {
2666        let StateChangeWithCause { cause, value } = state_change_with_cause;
2667        Self { cause: cause.into(), value: value.into() }
2668    }
2669}
2670
2671pub type StateChangesView = Vec<StateChangeWithCauseView>;
2672
2673/// Maintenance windows view are a vector of maintenance window.
2674pub type MaintenanceWindowsView = Vec<Range<BlockHeight>>;
2675
2676/// Contains the split storage information.
2677#[derive(serde::Serialize, serde::Deserialize, Debug)]
2678pub struct SplitStorageInfoView {
2679    pub head_height: Option<BlockHeight>,
2680    pub final_head_height: Option<BlockHeight>,
2681    pub cold_head_height: Option<BlockHeight>,
2682
2683    pub hot_db_kind: Option<String>,
2684}
2685
2686#[cfg(test)]
2687mod tests {
2688    use super::ExecutionMetadataView;
2689    use crate::transaction::ExecutionMetadata;
2690    use unc_vm_runner::{ProfileDataV2, ProfileDataV3};
2691
2692    /// The JSON representation used in RPC responses must not remove or rename
2693    /// fields, only adding fields is allowed or we risk breaking clients.
2694    #[test]
2695    #[cfg_attr(feature = "nightly", ignore)]
2696    fn test_runtime_config_view() {
2697        use unc_parameters::{RuntimeConfig, RuntimeConfigStore, RuntimeConfigView};
2698        use unc_primitives_core::version::PROTOCOL_VERSION;
2699
2700        let config_store = RuntimeConfigStore::new(None);
2701        let config = config_store.get_config(PROTOCOL_VERSION);
2702        let view = RuntimeConfigView::from(RuntimeConfig::clone(config));
2703        insta::assert_json_snapshot!(&view, { ".wasm_config.vm_kind" => "<REDACTED>"});
2704    }
2705
2706    /// `ExecutionMetadataView` with profile V1 displayed on the RPC should not change.
2707    #[test]
2708    #[cfg_attr(feature = "nightly", ignore)]
2709    fn test_exec_metadata_v1_view() {
2710        let metadata = ExecutionMetadata::V1;
2711        let view = ExecutionMetadataView::from(metadata);
2712        insta::assert_json_snapshot!(view);
2713    }
2714
2715    /// `ExecutionMetadataView` with profile V2 displayed on the RPC should not change.
2716    #[test]
2717    #[cfg_attr(feature = "nightly", ignore)]
2718    fn test_exec_metadata_v2_view() {
2719        let metadata = ExecutionMetadata::V2(ProfileDataV2::test());
2720        let view = ExecutionMetadataView::from(metadata);
2721        insta::assert_json_snapshot!(view);
2722    }
2723
2724    /// `ExecutionMetadataView` with profile V3 displayed on the RPC should not change.
2725    #[test]
2726    #[cfg_attr(feature = "nightly", ignore)]
2727    fn test_exec_metadata_v3_view() {
2728        let metadata = ExecutionMetadata::V3(ProfileDataV3::test().into());
2729        let view = ExecutionMetadataView::from(metadata);
2730        insta::assert_json_snapshot!(view);
2731    }
2732}