1use crate::account::{AccessKey, AccessKeyPermission, Account, FunctionCallPermission};
7use crate::action::delegate::{
8 DelegateAction, SignedDelegateAction, VersionedDelegateActionPayload,
9 VersionedSignedDelegateAction,
10};
11use crate::action::{
12 DeployGlobalContractAction, DeterministicStateInitAction, GlobalContractDeployMode,
13 GlobalContractIdentifier, TransferToGasKeyAction, UseGlobalContractAction,
14 WithdrawFromGasKeyAction,
15};
16use crate::bandwidth_scheduler::BandwidthRequests;
17use crate::block::{Block, BlockHeader, Tip};
18use crate::block_header::BlockHeaderInnerLite;
19use crate::challenge::SlashedValidator;
20use crate::congestion_info::{CongestionInfo, CongestionInfoV1};
21use crate::errors::TxExecutionError;
22use crate::hash::{CryptoHash, hash};
23use crate::merkle::{MerklePath, combine_hash};
24use crate::network::PeerId;
25use crate::profile_data_v3::ProfileDataV3;
26use crate::receipt::{
27 ActionReceipt, ActionReceiptV2, DataReceipt, DataReceiver, GlobalContractDistributionReceipt,
28 Receipt, ReceiptEnum, ReceiptV0, VersionedActionReceipt, VersionedReceiptEnum,
29};
30use crate::serialize::dec_format;
31use crate::sharding::shard_chunk_header_inner::{ShardChunkHeaderInnerV4, ShardChunkHeaderInnerV5};
32use crate::sharding::{
33 ChunkHash, ShardChunk, ShardChunkHeader, ShardChunkHeaderInner, ShardChunkHeaderInnerV2,
34 ShardChunkHeaderInnerV3, ShardChunkHeaderV3,
35};
36use crate::stateless_validation::chunk_endorsements_bitmap::ChunkEndorsementsBitmap;
37use crate::transaction::{
38 Action, AddKeyAction, CreateAccountAction, DeleteAccountAction, DeleteKeyAction,
39 DeployContractAction, ExecutionMetadata, ExecutionOutcome, ExecutionOutcomeWithIdAndProof,
40 ExecutionStatus, FunctionCallAction, NonceMode, PartialExecutionOutcome,
41 PartialExecutionStatus, SignedTransaction, StakeAction, TransferAction,
42};
43use crate::trie_split::TrieSplit;
44use crate::types::{
45 AccountId, AccountWithPublicKey, Balance, BlockHeight, EpochHeight, EpochId, FunctionArgs, Gas,
46 Nonce, NumBlocks, ShardId, SpiceChunkEndorsementStats, StateChangeCause, StateChangeKind,
47 StateChangeValue, StateChangeWithCause, StateChangesRequest, StateRoot, StorageUsage, StoreKey,
48 StoreValue, ValidatorKickoutReason,
49};
50use crate::version::{ProtocolVersion, Version};
51use borsh::{BorshDeserialize, BorshSerialize};
52use near_crypto::{PublicKey, PublicKeyHandle, Signature};
53use near_fmt::{AbbrBytes, Slice};
54use near_parameters::config::CongestionControlConfig;
55use near_parameters::view::CongestionControlConfigView;
56use near_parameters::{ActionCosts, ExtCosts};
57use near_primitives_core::account::{AccountContract, GasKeyInfo};
58use near_primitives_core::deterministic_account_id::{
59 DeterministicAccountStateInit, DeterministicAccountStateInitV1,
60};
61use near_primitives_core::types::NonceIndex;
62use near_time::Utc;
63use serde_with::base64::Base64;
64use serde_with::serde_as;
65use std::collections::{BTreeMap, HashMap};
66use std::fmt;
67use std::num::NonZeroU32;
68use std::ops::Range;
69use std::sync::Arc;
70use strum::IntoEnumIterator;
71use validator_stake_view::ValidatorStakeView;
72
73#[derive(serde::Serialize, serde::Deserialize, Debug, Eq, PartialEq, Clone)]
75#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
76pub struct AccountView {
77 pub amount: Balance,
78 pub locked: Balance,
79 pub code_hash: CryptoHash,
80 pub storage_usage: StorageUsage,
81 #[serde(default)]
83 pub storage_paid_at: BlockHeight,
84 #[serde(default, skip_serializing_if = "Option::is_none")]
85 pub global_contract_hash: Option<CryptoHash>,
86 #[serde(default, skip_serializing_if = "Option::is_none")]
87 pub global_contract_account_id: Option<AccountId>,
88}
89
90#[serde_as]
92#[derive(serde::Serialize, serde::Deserialize, PartialEq, Eq, Debug, Clone)]
93#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
94pub struct ContractCodeView {
95 #[serde(rename = "code_base64")]
96 #[serde_as(as = "Base64")]
97 #[cfg_attr(feature = "schemars", schemars(with = "String"))]
98 pub code: Vec<u8>,
99 pub hash: CryptoHash,
100}
101
102impl From<&Account> for AccountView {
103 fn from(account: &Account) -> Self {
104 let (global_contract_hash, global_contract_account_id) =
105 match account.contract().into_owned() {
106 AccountContract::Global(contract) => (Some(contract), None),
107 AccountContract::GlobalByAccount(account_id) => (None, Some(account_id)),
108 AccountContract::Local(_) | AccountContract::None => (None, None),
109 };
110 AccountView {
111 amount: account.amount(),
112 locked: account.locked(),
113 code_hash: account.local_contract_hash().unwrap_or_default(),
114 storage_usage: account.storage_usage(),
115 storage_paid_at: 0,
116 global_contract_hash,
117 global_contract_account_id,
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 let contract = match &view.global_contract_account_id {
131 Some(account_id) => AccountContract::GlobalByAccount(account_id.clone()),
132 None => match view.global_contract_hash {
133 Some(hash) => AccountContract::Global(hash),
134 None => AccountContract::from_local_code_hash(view.code_hash),
135 },
136 };
137 Account::new(view.amount, view.locked, contract, view.storage_usage)
138 }
139}
140
141impl From<AccountView> for Account {
142 fn from(view: AccountView) -> Self {
143 (&view).into()
144 }
145}
146
147#[derive(
149 BorshSerialize,
150 BorshDeserialize,
151 Debug,
152 Eq,
153 PartialEq,
154 Clone,
155 serde::Serialize,
156 serde::Deserialize,
157)]
158#[borsh(use_discriminant = true)]
159#[repr(u8)]
160#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
161pub enum AccessKeyPermissionView {
162 FunctionCall {
163 allowance: Option<Balance>,
164 receiver_id: String,
165 method_names: Vec<String>,
166 } = 0,
167 FullAccess = 1,
168 GasKeyFunctionCall {
169 balance: Balance,
170 num_nonces: NonceIndex,
171 allowance: Option<Balance>,
172 receiver_id: String,
173 method_names: Vec<String>,
174 } = 2,
175 GasKeyFullAccess {
176 balance: Balance,
177 num_nonces: NonceIndex,
178 } = 3,
179}
180
181impl From<AccessKeyPermission> for AccessKeyPermissionView {
182 fn from(permission: AccessKeyPermission) -> Self {
183 match permission {
184 AccessKeyPermission::FunctionCall(func_call) => AccessKeyPermissionView::FunctionCall {
185 allowance: func_call.allowance,
186 receiver_id: func_call.receiver_id,
187 method_names: func_call.method_names,
188 },
189 AccessKeyPermission::FullAccess => AccessKeyPermissionView::FullAccess,
190 AccessKeyPermission::GasKeyFunctionCall(gas_key_info, func_call) => {
191 AccessKeyPermissionView::GasKeyFunctionCall {
192 balance: gas_key_info.balance,
193 num_nonces: gas_key_info.num_nonces,
194 allowance: func_call.allowance,
195 receiver_id: func_call.receiver_id,
196 method_names: func_call.method_names,
197 }
198 }
199 AccessKeyPermission::GasKeyFullAccess(gas_key_info) => {
200 AccessKeyPermissionView::GasKeyFullAccess {
201 balance: gas_key_info.balance,
202 num_nonces: gas_key_info.num_nonces,
203 }
204 }
205 }
206 }
207}
208
209impl From<AccessKeyPermissionView> for AccessKeyPermission {
210 fn from(view: AccessKeyPermissionView) -> Self {
211 match view {
212 AccessKeyPermissionView::FunctionCall { allowance, receiver_id, method_names } => {
213 AccessKeyPermission::FunctionCall(FunctionCallPermission {
214 allowance,
215 receiver_id,
216 method_names,
217 })
218 }
219 AccessKeyPermissionView::FullAccess => AccessKeyPermission::FullAccess,
220 AccessKeyPermissionView::GasKeyFunctionCall {
221 balance,
222 num_nonces,
223 allowance,
224 receiver_id,
225 method_names,
226 } => AccessKeyPermission::GasKeyFunctionCall(
227 GasKeyInfo { balance, num_nonces },
228 FunctionCallPermission { allowance, receiver_id, method_names },
229 ),
230 AccessKeyPermissionView::GasKeyFullAccess { balance, num_nonces } => {
231 AccessKeyPermission::GasKeyFullAccess(GasKeyInfo { balance, num_nonces })
232 }
233 }
234 }
235}
236
237#[derive(
239 BorshSerialize,
240 BorshDeserialize,
241 Debug,
242 Eq,
243 PartialEq,
244 Clone,
245 serde::Serialize,
246 serde::Deserialize,
247)]
248#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
249pub struct AccessKeyView {
250 pub nonce: Nonce,
251 pub permission: AccessKeyPermissionView,
252}
253
254impl From<AccessKey> for AccessKeyView {
255 fn from(access_key: AccessKey) -> Self {
256 Self { nonce: access_key.nonce, permission: access_key.permission.into() }
257 }
258}
259
260impl From<AccessKeyView> for AccessKey {
261 fn from(view: AccessKeyView) -> Self {
262 Self { nonce: view.nonce, permission: view.permission.into() }
263 }
264}
265
266#[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Eq, Clone)]
268#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
269pub struct StateItem {
270 pub key: StoreKey,
271 pub value: StoreValue,
272}
273
274#[serde_as]
276#[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Eq, Clone)]
277#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
278pub struct ViewStateResult {
279 pub values: Vec<StateItem>,
280 #[serde_as(as = "Vec<Base64>")]
281 #[serde(default, skip_serializing_if = "Vec::is_empty")]
282 #[cfg_attr(feature = "schemars", schemars(with = "Vec<String>"))]
283 pub proof: Vec<Arc<[u8]>>,
284 #[serde(default, skip_serializing_if = "Option::is_none")]
285 pub last_key: Option<StoreKey>,
286}
287
288#[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Eq, Clone, Default)]
290#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
291pub struct CallResult {
292 pub result: Vec<u8>,
293 pub logs: Vec<String>,
294}
295
296#[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Eq, Clone)]
297pub struct QueryError {
298 pub error: String,
299 pub logs: Vec<String>,
300}
301
302#[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Eq, Clone)]
308#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
309pub struct AccessKeyInfoView {
310 pub public_key: PublicKeyHandle,
311 pub access_key: AccessKeyView,
312}
313
314impl AccessKeyInfoView {
315 pub fn new(public_key: impl Into<PublicKeyHandle>, access_key: AccessKeyView) -> Self {
320 Self { public_key: public_key.into(), access_key }
321 }
322}
323
324#[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Eq, Clone)]
326#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
327pub struct AccessKeyList {
328 pub keys: Vec<AccessKeyInfoView>,
329}
330
331impl FromIterator<AccessKeyInfoView> for AccessKeyList {
332 fn from_iter<I: IntoIterator<Item = AccessKeyInfoView>>(iter: I) -> Self {
333 Self { keys: iter.into_iter().collect() }
334 }
335}
336
337#[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Eq, Clone)]
339#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
340pub struct GasKeyNoncesView {
341 pub nonces: Vec<Nonce>,
342}
343
344#[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Eq, Clone)]
345#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
346pub struct KnownPeerStateView {
347 pub peer_id: PeerId,
348 pub status: String,
349 pub addr: String,
350 pub first_seen: i64,
351 pub last_seen: i64,
352 pub last_attempt: Option<(i64, String)>,
353}
354
355#[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Eq, Clone)]
356#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
357pub struct ConnectionInfoView {
358 pub peer_id: PeerId,
359 pub addr: String,
360 pub time_established: i64,
361 pub time_connected_until: i64,
362}
363
364#[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Eq, Clone)]
365#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
366pub struct SnapshotHostInfoView {
367 pub peer_id: PeerId,
368 pub sync_hash: CryptoHash,
369 pub epoch_height: u64,
370 pub shards: Vec<u64>,
371}
372
373#[derive(Debug, PartialEq, Eq, Clone)]
374pub enum QueryResponseKind {
375 ViewAccount(AccountView),
376 ViewCode(ContractCodeView),
377 ViewState(ViewStateResult),
378 CallResult(CallResult),
379 AccessKey(AccessKeyView),
380 AccessKeyList(AccessKeyList),
381 GasKeyNonces(GasKeyNoncesView),
382}
383
384#[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Eq, Clone)]
385#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
386#[serde(tag = "request_type", rename_all = "snake_case")]
387pub enum QueryRequest {
388 ViewAccount {
389 account_id: AccountId,
390 },
391 ViewCode {
392 account_id: AccountId,
393 },
394 ViewState {
395 account_id: AccountId,
396 #[serde(rename = "prefix_base64")]
397 prefix: StoreKey,
398 #[serde(default, rename = "after_key_base64", skip_serializing_if = "Option::is_none")]
399 after_key: Option<StoreKey>,
400 #[serde(default, skip_serializing_if = "Option::is_none")]
401 limit: Option<NonZeroU32>,
402 #[serde(default, skip_serializing_if = "is_false")]
403 include_proof: bool,
404 },
405 ViewAccessKey {
406 account_id: AccountId,
407 public_key: PublicKey,
408 },
409 ViewAccessKeyList {
410 account_id: AccountId,
411 },
412 ViewGasKeyNonces {
413 account_id: AccountId,
414 public_key: PublicKey,
415 },
416 CallFunction {
417 account_id: AccountId,
418 method_name: String,
419 #[serde(rename = "args_base64")]
420 args: FunctionArgs,
421 },
422 ViewGlobalContractCode {
423 code_hash: CryptoHash,
424 },
425 ViewGlobalContractCodeByAccountId {
426 account_id: AccountId,
427 },
428}
429
430fn is_false(v: &bool) -> bool {
431 !*v
432}
433
434#[derive(Debug, PartialEq, Eq, Clone)]
435pub struct QueryResponse {
436 pub kind: QueryResponseKind,
437 pub block_height: BlockHeight,
438 pub block_hash: CryptoHash,
439}
440
441#[derive(serde::Serialize, serde::Deserialize, Debug)]
442#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
443pub struct StatusSyncInfo {
444 pub latest_block_hash: CryptoHash,
445 pub latest_block_height: BlockHeight,
446 pub latest_state_root: CryptoHash,
447 #[serde(with = "near_time::serde_utc_as_iso")]
448 #[cfg_attr(feature = "schemars", schemars(with = "String"))]
449 pub latest_block_time: Utc,
450 pub syncing: bool,
451 pub earliest_block_hash: Option<CryptoHash>,
452 pub earliest_block_height: Option<BlockHeight>,
453 #[serde(with = "near_time::serde_opt_utc_as_iso")]
454 #[cfg_attr(feature = "schemars", schemars(with = "Option<String>"))]
455 pub earliest_block_time: Option<Utc>,
456 pub epoch_id: Option<EpochId>,
457 pub epoch_start_height: Option<BlockHeight>,
458}
459
460#[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Eq, Clone)]
462#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
463pub struct ValidatorInfo {
464 pub account_id: AccountId,
465}
466
467#[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Eq)]
468#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
469pub struct PeerInfoView {
470 pub addr: String,
471 pub account_id: Option<AccountId>,
472 pub height: Option<BlockHeight>,
473 pub block_hash: Option<CryptoHash>,
474 pub is_highest_block_invalid: bool,
475 pub tracked_shards: Vec<ShardId>,
476 pub archival: bool,
477 pub peer_id: PublicKey,
478 pub received_bytes_per_sec: u64,
479 pub sent_bytes_per_sec: u64,
480 pub last_time_peer_requested_millis: u64,
481 pub last_time_received_message_millis: u64,
482 pub connection_established_time_millis: u64,
483 pub is_outbound_peer: bool,
484 pub nonce: u64,
486}
487
488#[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Eq)]
491#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
492pub struct KnownProducerView {
493 pub account_id: AccountId,
494 pub peer_id: PublicKey,
495 pub next_hops: Option<Vec<PublicKey>>,
496}
497
498#[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Eq)]
499#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
500pub struct Tier1ProxyView {
501 pub addr: std::net::SocketAddr,
502 pub peer_id: PublicKey,
503}
504
505#[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Eq)]
517#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
518pub struct AccountDataView {
519 pub peer_id: PublicKey,
521 pub proxies: Vec<Tier1ProxyView>,
526 pub account_key: PublicKey,
528 #[serde(with = "near_time::serde_utc_as_iso")]
530 #[cfg_attr(feature = "schemars", schemars(with = "String"))]
531 pub timestamp: Utc,
532}
533
534#[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Eq)]
535#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
536pub struct NetworkInfoView {
537 pub peer_max_count: u32,
538 pub num_connected_peers: usize,
539 pub connected_peers: Vec<PeerInfoView>,
540 pub known_producers: Vec<KnownProducerView>,
541 pub tier1_accounts_keys: Vec<PublicKey>,
542 pub tier1_accounts_data: Vec<AccountDataView>,
543 pub tier1_connections: Vec<PeerInfoView>,
544}
545
546#[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Eq)]
547#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
548pub enum EpochSyncStatusView {
549 NotStarted,
550 InProgress { source_peer_height: BlockHeight, source_peer_id: String, attempt_time: String },
551 Done,
552}
553
554#[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Eq)]
555#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
556pub enum SyncStatusView {
557 AwaitingPeers,
559 NoSync,
561 EpochSync(EpochSyncStatusView),
563 HeaderSync {
565 start_height: BlockHeight,
566 current_height: BlockHeight,
567 highest_height: BlockHeight,
568 },
569 StateSync(StateSyncStatusView),
571 BlockSync {
573 start_height: BlockHeight,
574 current_height: BlockHeight,
575 highest_height: BlockHeight,
576 },
577}
578
579#[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Eq)]
580#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
581pub struct StateSyncStatusView {
582 pub sync_hash: CryptoHash,
583 pub shard_sync_status: HashMap<ShardId, String>,
584 pub download_tasks: Vec<String>,
585 pub computation_tasks: Vec<String>,
586}
587
588#[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Eq)]
589#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
590pub struct PeerStoreView {
591 pub peer_states: Vec<KnownPeerStateView>,
592}
593
594#[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Eq)]
595#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
596pub struct RecentOutboundConnectionsView {
597 pub recent_outbound_connections: Vec<ConnectionInfoView>,
598}
599
600#[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Eq)]
601#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
602pub struct SnapshotHostsView {
603 pub hosts: Vec<SnapshotHostInfoView>,
604}
605
606#[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Eq)]
607#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
608pub struct EdgeView {
609 pub peer0: PeerId,
610 pub peer1: PeerId,
611 pub nonce: u64,
612}
613
614#[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Eq)]
615#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
616pub struct NetworkGraphView {
617 pub edges: Vec<EdgeView>,
618 pub next_hops: HashMap<PeerId, Vec<PeerId>>,
619}
620
621#[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Eq)]
622#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
623pub struct ShardSyncDownloadView {
624 pub downloads: Vec<DownloadStatusView>,
625 pub status: String,
626}
627
628#[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Eq)]
629#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
630pub struct DownloadStatusView {
631 pub error: bool,
632 pub done: bool,
633}
634
635#[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Eq)]
637#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
638pub struct CatchupStatusView {
639 pub sync_block_hash: CryptoHash,
641 pub sync_block_height: BlockHeight,
642 pub shard_sync_status: HashMap<ShardId, String>,
644 pub blocks_to_catchup: Vec<BlockStatusView>,
646}
647
648#[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Eq)]
649#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
650pub struct RequestedStatePartsView {
651 pub block_hash: CryptoHash,
653 pub shard_requested_parts: HashMap<ShardId, Vec<PartElapsedTimeView>>,
655}
656
657#[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Eq)]
659#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
660pub struct BlockStatusView {
661 pub height: BlockHeight,
662 pub hash: CryptoHash,
663}
664
665impl BlockStatusView {
666 pub fn new(height: &BlockHeight, hash: &CryptoHash) -> BlockStatusView {
667 Self { height: *height, hash: *hash }
668 }
669}
670
671impl From<Tip> for BlockStatusView {
672 fn from(tip: Tip) -> Self {
673 Self { height: tip.height, hash: tip.last_block_hash }
674 }
675}
676
677impl From<&Tip> for BlockStatusView {
678 fn from(tip: &Tip) -> Self {
679 Self { height: tip.height, hash: tip.last_block_hash }
680 }
681}
682
683#[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Eq, Clone)]
684#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
685pub struct PartElapsedTimeView {
686 pub part_id: u64,
687 pub elapsed_ms: u128,
688}
689
690impl PartElapsedTimeView {
691 pub fn new(part_id: &u64, elapsed_ms: u128) -> PartElapsedTimeView {
692 Self { part_id: *part_id, elapsed_ms }
693 }
694}
695
696#[derive(serde::Serialize, serde::Deserialize, Debug)]
697#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
698pub struct BlockByChunksView {
699 pub height: BlockHeight,
700 pub hash: CryptoHash,
701 pub block_status: String,
702 pub chunk_status: String,
703}
704
705#[derive(serde::Serialize, serde::Deserialize, Debug)]
706#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
707pub struct ChainProcessingInfo {
708 pub num_blocks_in_processing: usize,
709 pub num_orphans: usize,
710 pub num_blocks_missing_chunks: usize,
711 pub blocks_info: Vec<BlockProcessingInfo>,
713 pub floating_chunks_info: Vec<ChunkProcessingInfo>,
715}
716
717#[derive(serde::Serialize, serde::Deserialize, Debug)]
718#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
719pub struct BlockProcessingInfo {
720 pub height: BlockHeight,
721 pub hash: CryptoHash,
722 #[serde(with = "near_time::serde_utc_as_iso")]
723 #[cfg_attr(feature = "schemars", schemars(with = "String"))]
724 pub received_timestamp: Utc,
725 pub in_progress_ms: u128,
727 pub orphaned_ms: Option<u128>,
731 pub missing_chunks_ms: Option<u128>,
735 pub block_status: BlockProcessingStatus,
736 pub chunks_info: Vec<Option<ChunkProcessingInfo>>,
739}
740
741#[derive(
742 BorshSerialize,
743 BorshDeserialize,
744 Clone,
745 Debug,
746 PartialEq,
747 Eq,
748 serde::Serialize,
749 serde::Deserialize,
750)]
751#[borsh(use_discriminant = true)]
752#[repr(u8)]
753#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
754pub enum BlockProcessingStatus {
755 Orphan = 0,
756 WaitingForChunks = 1,
757 InProcessing = 2,
758 Accepted = 3,
759 Error(String) = 4,
760 Dropped(DroppedReason) = 5,
761 Unknown = 6,
762}
763
764#[derive(
765 BorshSerialize,
766 BorshDeserialize,
767 Clone,
768 Debug,
769 PartialEq,
770 Eq,
771 serde::Serialize,
772 serde::Deserialize,
773)]
774#[borsh(use_discriminant = true)]
775#[repr(u8)]
776#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
777pub enum DroppedReason {
778 HeightProcessed = 0,
780 TooManyProcessingBlocks = 1,
782}
783
784#[derive(serde::Serialize, serde::Deserialize, Debug)]
785#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
786pub struct ChunkProcessingInfo {
787 pub height_created: BlockHeight,
788 pub shard_id: ShardId,
789 pub chunk_hash: ChunkHash,
790 pub prev_block_hash: CryptoHash,
791 pub created_by: Option<AccountId>,
794 pub status: ChunkProcessingStatus,
795 #[serde(with = "near_time::serde_opt_utc_as_iso")]
797 #[cfg_attr(feature = "schemars", schemars(with = "Option<String>"))]
798 pub requested_timestamp: Option<Utc>,
799 #[serde(with = "near_time::serde_opt_utc_as_iso")]
801 #[cfg_attr(feature = "schemars", schemars(with = "Option<String>"))]
802 pub completed_timestamp: Option<Utc>,
803 pub request_duration: Option<u64>,
805 pub chunk_parts_collection: Vec<PartCollectionInfo>,
806}
807
808#[derive(serde::Serialize, serde::Deserialize, Debug)]
809#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
810pub struct PartCollectionInfo {
811 pub part_owner: AccountId,
812 #[serde(with = "near_time::serde_opt_utc_as_iso")]
814 #[cfg_attr(feature = "schemars", schemars(with = "Option<String>"))]
815 pub received_time: Option<Utc>,
816 #[serde(with = "near_time::serde_opt_utc_as_iso")]
818 #[cfg_attr(feature = "schemars", schemars(with = "Option<String>"))]
819 pub forwarded_received_time: Option<Utc>,
820 #[serde(with = "near_time::serde_opt_utc_as_iso")]
822 #[cfg_attr(feature = "schemars", schemars(with = "Option<String>"))]
823 pub chunk_received_time: Option<Utc>,
824}
825
826#[derive(serde::Serialize, serde::Deserialize, Debug)]
827#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
828pub enum ChunkProcessingStatus {
829 NeedToRequest,
830 Requested,
831 Completed,
832}
833
834#[derive(serde::Serialize, serde::Deserialize, Debug)]
835#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
836pub struct DetailedDebugStatus {
837 pub network_info: NetworkInfoView,
838 pub sync_status: String,
839 pub catchup_status: Vec<CatchupStatusView>,
840 pub current_head_status: BlockStatusView,
841 pub current_header_head_status: BlockStatusView,
842 pub block_production_delay_millis: u64,
843}
844
845#[derive(serde::Serialize, serde::Deserialize, Debug)]
847#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
848pub struct StatusResponse {
849 pub version: Version,
851 pub chain_id: String,
853 pub protocol_version: u32,
855 pub latest_protocol_version: u32,
857 #[serde(skip_serializing_if = "Option::is_none")]
859 pub rpc_addr: Option<String>,
860 pub validators: Vec<ValidatorInfo>,
862 pub sync_info: StatusSyncInfo,
864 pub validator_account_id: Option<AccountId>,
866 pub validator_public_key: Option<PublicKey>,
868 pub node_public_key: PublicKey,
870 pub node_key: Option<PublicKey>,
872 pub uptime_sec: i64,
874 pub genesis_hash: CryptoHash,
876 #[serde(skip_serializing_if = "Option::is_none")]
878 pub detailed_debug_status: Option<DetailedDebugStatus>,
879}
880
881#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, Default)]
883#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
884pub struct BlockHeaderView {
885 pub height: BlockHeight,
886 pub prev_height: Option<BlockHeight>,
887 pub epoch_id: CryptoHash,
888 pub next_epoch_id: CryptoHash,
889 pub hash: CryptoHash,
890 pub prev_hash: CryptoHash,
892 pub prev_state_root: CryptoHash,
893 pub block_body_hash: Option<CryptoHash>,
894 pub chunk_receipts_root: CryptoHash,
895 pub chunk_headers_root: CryptoHash,
896 pub chunk_tx_root: CryptoHash,
897 pub outcome_root: CryptoHash,
898 pub chunks_included: u64,
899 pub challenges_root: CryptoHash,
900 pub timestamp: u64,
902 #[serde(with = "dec_format")]
903 #[cfg_attr(feature = "schemars", schemars(with = "String"))]
904 pub timestamp_nanosec: u64,
905 pub random_value: CryptoHash,
906 pub validator_proposals: Vec<ValidatorStakeView>,
907 pub chunk_mask: Vec<bool>,
908 pub gas_price: Balance,
909 pub block_ordinal: Option<NumBlocks>,
910 #[serde(default)]
912 pub rent_paid: Balance,
913 #[serde(default)]
915 pub validator_reward: Balance,
916 pub total_supply: Balance,
917 pub challenges_result: Vec<SlashedValidator>,
919 pub last_final_block: CryptoHash,
920 pub last_ds_final_block: CryptoHash,
921 pub next_bp_hash: CryptoHash,
922 pub block_merkle_root: CryptoHash,
923 pub epoch_sync_data_hash: Option<CryptoHash>,
924 pub approvals: Vec<Option<Box<Signature>>>,
925 pub signature: Signature,
927 pub latest_protocol_version: ProtocolVersion,
928 pub chunk_endorsements: Option<Vec<Vec<u8>>>,
929 pub shard_split: Option<(ShardId, AccountId)>,
930 #[serde(default, skip_serializing_if = "Option::is_none")]
931 pub prev_last_certified_block_epoch_id: Option<EpochId>,
932 #[serde(default, skip_serializing_if = "Option::is_none")]
933 pub spice_chunk_endorsement_stats: Option<Vec<SpiceChunkEndorsementStats>>,
934}
935
936impl From<&BlockHeader> for BlockHeaderView {
937 fn from(header: &BlockHeader) -> Self {
938 Self {
939 height: header.height(),
940 prev_height: header.prev_height(),
941 epoch_id: header.epoch_id().0,
942 next_epoch_id: header.next_epoch_id().0,
943 hash: *header.hash(),
944 prev_hash: *header.prev_hash(),
945 prev_state_root: *header.prev_state_root(),
946 block_body_hash: header.block_body_hash(),
947 chunk_receipts_root: *header.prev_chunk_outgoing_receipts_root(),
948 chunk_headers_root: *header.chunk_headers_root(),
949 chunk_tx_root: *header.chunk_tx_root(),
950 chunks_included: header.chunks_included(),
951 challenges_root: CryptoHash::default(),
952 outcome_root: *header.outcome_root(),
953 timestamp: header.raw_timestamp(),
954 timestamp_nanosec: header.raw_timestamp(),
955 random_value: *header.random_value(),
956 validator_proposals: header.prev_validator_proposals().map(Into::into).collect(),
957 chunk_mask: header.chunk_mask().to_vec(),
958 block_ordinal: if header.block_ordinal() != 0 {
959 Some(header.block_ordinal())
960 } else {
961 None
962 },
963 gas_price: header.next_gas_price(),
964 rent_paid: Balance::ZERO,
965 validator_reward: Balance::ZERO,
966 total_supply: header.total_supply(),
967 challenges_result: vec![],
968 last_final_block: *header.last_final_block(),
969 last_ds_final_block: *header.last_ds_final_block(),
970 next_bp_hash: *header.next_bp_hash(),
971 block_merkle_root: *header.block_merkle_root(),
972 epoch_sync_data_hash: header.epoch_sync_data_hash(),
973 approvals: header.approvals().to_vec(),
974 signature: header.signature().clone(),
975 latest_protocol_version: header.latest_protocol_version(),
976 chunk_endorsements: header.chunk_endorsements().map(|bitmap| bitmap.bytes()),
977 shard_split: header.shard_split().cloned(),
978 prev_last_certified_block_epoch_id: header
979 .prev_last_certified_block_epoch_id()
980 .cloned(),
981 spice_chunk_endorsement_stats: header
982 .spice_chunk_endorsement_stats()
983 .map(<[SpiceChunkEndorsementStats]>::to_vec),
984 }
985 }
986}
987
988impl From<BlockHeaderView> for BlockHeader {
989 fn from(view: BlockHeaderView) -> Self {
990 BlockHeader::from_view(
991 &view.hash,
992 view.latest_protocol_version,
993 view.height,
994 view.prev_hash,
995 view.block_body_hash.unwrap_or_default(),
996 view.prev_state_root,
997 view.chunk_receipts_root,
998 view.chunk_headers_root,
999 view.chunk_tx_root,
1000 view.outcome_root,
1001 view.timestamp,
1002 view.random_value,
1003 view.validator_proposals.into_iter().map(|v| v.into_validator_stake()).collect(),
1004 view.chunk_mask,
1005 view.block_ordinal.unwrap_or(0),
1006 EpochId(view.epoch_id),
1007 EpochId(view.next_epoch_id),
1008 view.gas_price,
1009 view.total_supply,
1010 view.signature,
1011 view.last_final_block,
1012 view.last_ds_final_block,
1013 view.epoch_sync_data_hash,
1014 view.approvals,
1015 view.next_bp_hash,
1016 view.block_merkle_root,
1017 view.prev_height.unwrap_or_default(),
1018 view.chunk_endorsements.map(|bytes| ChunkEndorsementsBitmap::from_bytes(bytes)),
1019 view.shard_split,
1020 view.prev_last_certified_block_epoch_id,
1021 view.spice_chunk_endorsement_stats,
1022 )
1023 }
1024}
1025
1026#[derive(
1028 PartialEq,
1029 Eq,
1030 Debug,
1031 Clone,
1032 BorshDeserialize,
1033 BorshSerialize,
1034 serde::Serialize,
1035 serde::Deserialize,
1036)]
1037#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1038pub struct BlockHeaderInnerLiteView {
1039 pub height: BlockHeight,
1040 pub epoch_id: CryptoHash,
1042 pub next_epoch_id: CryptoHash,
1044 pub prev_state_root: CryptoHash,
1045 pub outcome_root: CryptoHash,
1046 pub timestamp: u64,
1048 #[serde(with = "dec_format")]
1049 #[cfg_attr(feature = "schemars", schemars(with = "String"))]
1050 pub timestamp_nanosec: u64,
1051 pub next_bp_hash: CryptoHash,
1053 pub block_merkle_root: CryptoHash,
1055}
1056
1057impl From<BlockHeader> for BlockHeaderInnerLiteView {
1058 fn from(header: BlockHeader) -> Self {
1059 let inner_lite = header.inner_lite();
1060 BlockHeaderInnerLiteView {
1061 height: inner_lite.height,
1062 epoch_id: inner_lite.epoch_id.0,
1063 next_epoch_id: inner_lite.next_epoch_id.0,
1064 prev_state_root: inner_lite.prev_state_root,
1065 outcome_root: inner_lite.prev_outcome_root,
1066 timestamp: inner_lite.timestamp,
1067 timestamp_nanosec: inner_lite.timestamp,
1068 next_bp_hash: inner_lite.next_bp_hash,
1069 block_merkle_root: inner_lite.block_merkle_root,
1070 }
1071 }
1072}
1073
1074impl From<BlockHeaderInnerLiteView> for BlockHeaderInnerLite {
1075 fn from(view: BlockHeaderInnerLiteView) -> Self {
1076 BlockHeaderInnerLite {
1077 height: view.height,
1078 epoch_id: EpochId(view.epoch_id),
1079 next_epoch_id: EpochId(view.next_epoch_id),
1080 prev_state_root: view.prev_state_root,
1081 prev_outcome_root: view.outcome_root,
1082 timestamp: view.timestamp_nanosec,
1083 next_bp_hash: view.next_bp_hash,
1084 block_merkle_root: view.block_merkle_root,
1085 }
1086 }
1087}
1088
1089#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)]
1091#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1092pub struct ChunkHeaderView {
1094 pub chunk_hash: CryptoHash,
1095 pub prev_block_hash: CryptoHash,
1096 pub outcome_root: CryptoHash,
1097 pub prev_state_root: StateRoot,
1098 pub encoded_merkle_root: CryptoHash,
1099 pub encoded_length: u64,
1100 pub height_created: BlockHeight,
1101 pub height_included: BlockHeight,
1102 pub shard_id: ShardId,
1103 pub gas_used: Gas,
1104 pub gas_limit: Gas,
1105 #[serde(default)]
1107 pub rent_paid: Balance,
1108 #[serde(default)]
1110 pub validator_reward: Balance,
1111 pub balance_burnt: Balance,
1112 pub outgoing_receipts_root: CryptoHash,
1113 pub tx_root: CryptoHash,
1114 pub validator_proposals: Vec<ValidatorStakeView>,
1115 pub congestion_info: Option<CongestionInfoView>,
1116 pub bandwidth_requests: Option<BandwidthRequests>,
1117 #[serde(default, skip_serializing_if = "Option::is_none")]
1122 pub proposed_split: Option<Option<TrieSplit>>,
1123 pub signature: Signature,
1124}
1125
1126impl ChunkHeaderView {
1127 pub fn is_new_chunk(&self, block_height: BlockHeight) -> bool {
1128 self.height_included == block_height
1129 }
1130}
1131
1132impl From<ShardChunkHeader> for ChunkHeaderView {
1133 fn from(chunk: ShardChunkHeader) -> Self {
1134 let hash = chunk.chunk_hash().0;
1135 let signature = chunk.signature().clone();
1136 let height_included = chunk.height_included();
1137 let inner = chunk.take_inner();
1138 ChunkHeaderView {
1139 chunk_hash: hash,
1140 prev_block_hash: *inner.prev_block_hash(),
1141 outcome_root: *inner.prev_outcome_root(),
1142 prev_state_root: if inner.is_spice_chunk() {
1143 CryptoHash::default()
1144 } else {
1145 *inner.prev_state_root()
1146 },
1147 encoded_merkle_root: *inner.encoded_merkle_root(),
1148 encoded_length: inner.encoded_length(),
1149 height_created: inner.height_created(),
1150 height_included,
1151 shard_id: inner.shard_id(),
1152 gas_used: inner.prev_gas_used(),
1153 gas_limit: if inner.is_spice_chunk() { Gas::default() } else { inner.gas_limit() },
1154 rent_paid: Balance::ZERO,
1155 validator_reward: Balance::ZERO,
1156 balance_burnt: inner.prev_balance_burnt(),
1157 outgoing_receipts_root: *inner.prev_outgoing_receipts_root(),
1158 tx_root: *inner.tx_root(),
1159 validator_proposals: inner.prev_validator_proposals().map(Into::into).collect(),
1160 congestion_info: Some(inner.congestion_info().into()),
1161 bandwidth_requests: inner.bandwidth_requests().cloned(),
1162 proposed_split: inner
1163 .has_proposed_split_field()
1164 .then(|| inner.proposed_split().cloned()),
1165 signature,
1166 }
1167 }
1168}
1169
1170impl From<ChunkHeaderView> for ShardChunkHeader {
1171 fn from(view: ChunkHeaderView) -> Self {
1172 let prev_validator_proposals =
1173 view.validator_proposals.into_iter().map(Into::into).collect();
1174 let inner = match (view.proposed_split, view.bandwidth_requests, view.congestion_info) {
1177 (Some(proposed_split), Some(bandwidth_requests), Some(congestion_info)) => {
1178 ShardChunkHeaderInner::V5(ShardChunkHeaderInnerV5 {
1179 prev_block_hash: view.prev_block_hash,
1180 prev_state_root: view.prev_state_root,
1181 prev_outcome_root: view.outcome_root,
1182 encoded_merkle_root: view.encoded_merkle_root,
1183 encoded_length: view.encoded_length,
1184 height_created: view.height_created,
1185 shard_id: view.shard_id,
1186 prev_gas_used: view.gas_used,
1187 gas_limit: view.gas_limit,
1188 prev_balance_burnt: view.balance_burnt,
1189 prev_outgoing_receipts_root: view.outgoing_receipts_root,
1190 tx_root: view.tx_root,
1191 prev_validator_proposals,
1192 congestion_info: congestion_info.into(),
1193 bandwidth_requests,
1194 proposed_split,
1195 })
1196 }
1197 (None, Some(bandwidth_requests), Some(congestion_info)) => {
1198 ShardChunkHeaderInner::V4(ShardChunkHeaderInnerV4 {
1199 prev_block_hash: view.prev_block_hash,
1200 prev_state_root: view.prev_state_root,
1201 prev_outcome_root: view.outcome_root,
1202 encoded_merkle_root: view.encoded_merkle_root,
1203 encoded_length: view.encoded_length,
1204 height_created: view.height_created,
1205 shard_id: view.shard_id,
1206 prev_gas_used: view.gas_used,
1207 gas_limit: view.gas_limit,
1208 prev_balance_burnt: view.balance_burnt,
1209 prev_outgoing_receipts_root: view.outgoing_receipts_root,
1210 tx_root: view.tx_root,
1211 prev_validator_proposals,
1212 congestion_info: congestion_info.into(),
1213 bandwidth_requests,
1214 })
1215 }
1216 (None, None, Some(congestion_info)) => {
1217 ShardChunkHeaderInner::V3(ShardChunkHeaderInnerV3 {
1218 prev_block_hash: view.prev_block_hash,
1219 prev_state_root: view.prev_state_root,
1220 prev_outcome_root: view.outcome_root,
1221 encoded_merkle_root: view.encoded_merkle_root,
1222 encoded_length: view.encoded_length,
1223 height_created: view.height_created,
1224 shard_id: view.shard_id,
1225 prev_gas_used: view.gas_used,
1226 gas_limit: view.gas_limit,
1227 prev_balance_burnt: view.balance_burnt,
1228 prev_outgoing_receipts_root: view.outgoing_receipts_root,
1229 tx_root: view.tx_root,
1230 prev_validator_proposals,
1231 congestion_info: congestion_info.into(),
1232 })
1233 }
1234 (None, None, None) => ShardChunkHeaderInner::V2(ShardChunkHeaderInnerV2 {
1235 prev_block_hash: view.prev_block_hash,
1236 prev_state_root: view.prev_state_root,
1237 prev_outcome_root: view.outcome_root,
1238 encoded_merkle_root: view.encoded_merkle_root,
1239 encoded_length: view.encoded_length,
1240 height_created: view.height_created,
1241 shard_id: view.shard_id,
1242 prev_gas_used: view.gas_used,
1243 gas_limit: view.gas_limit,
1244 prev_balance_burnt: view.balance_burnt,
1245 prev_outgoing_receipts_root: view.outgoing_receipts_root,
1246 tx_root: view.tx_root,
1247 prev_validator_proposals,
1248 }),
1249 (proposed_split, bandwidth_requests, congestion_info) => unreachable!(
1250 "unexpected combination of chunk header view fields: \
1251 proposed_split={}, bandwidth_requests={}, congestion_info={}",
1252 proposed_split.is_some(),
1253 bandwidth_requests.is_some(),
1254 congestion_info.is_some(),
1255 ),
1256 };
1257 let mut header = ShardChunkHeaderV3 {
1258 inner,
1259 height_included: view.height_included,
1260 signature: view.signature,
1261 hash: ChunkHash::default(),
1262 };
1263 header.init();
1264 ShardChunkHeader::V3(header)
1265 }
1266}
1267
1268#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)]
1269#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1270pub struct BlockView {
1271 pub author: AccountId,
1273 pub header: BlockHeaderView,
1274 pub chunks: Vec<ChunkHeaderView>,
1275}
1276
1277impl BlockView {
1278 pub fn from_author_block(author: AccountId, block: &Block) -> Self {
1279 BlockView {
1280 author,
1281 header: block.header().into(),
1282 chunks: block.chunks().iter_raw().cloned().map(Into::into).collect(),
1283 }
1284 }
1285}
1286
1287#[derive(serde::Serialize, serde::Deserialize, Debug)]
1288#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1289pub struct ChunkView {
1290 pub author: AccountId,
1291 pub header: ChunkHeaderView,
1292 pub transactions: Vec<SignedTransactionView>,
1293 pub receipts: Vec<ReceiptView>,
1294}
1295
1296impl ChunkView {
1297 pub fn from_author_chunk(author: AccountId, chunk: ShardChunk) -> Self {
1298 match chunk {
1299 ShardChunk::V1(chunk) => Self {
1300 author,
1301 header: ShardChunkHeader::V1(chunk.header).into(),
1302 transactions: chunk.transactions.into_iter().map(Into::into).collect(),
1303 receipts: chunk.prev_outgoing_receipts.into_iter().map(Into::into).collect(),
1304 },
1305 ShardChunk::V2(chunk) => Self {
1306 author,
1307 header: chunk.header.into(),
1308 transactions: chunk.transactions.into_iter().map(Into::into).collect(),
1309 receipts: chunk.prev_outgoing_receipts.into_iter().map(Into::into).collect(),
1310 },
1311 }
1312 }
1313}
1314
1315#[derive(serde::Deserialize)]
1316#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1317#[serde(untagged)]
1318enum BackwardCompatibleGlobalContractIdentifierView {
1323 CodeHash { hash: CryptoHash },
1324 AccountId { account_id: AccountId },
1325 DeprecatedCodeHash(CryptoHash),
1326 DeprecatedAccountId(AccountId),
1327}
1328
1329#[derive(
1330 BorshSerialize,
1331 BorshDeserialize,
1332 Clone,
1333 Debug,
1334 PartialEq,
1335 Eq,
1336 serde::Serialize,
1337 serde::Deserialize,
1338)]
1339#[serde(rename_all = "snake_case", from = "BackwardCompatibleGlobalContractIdentifierView")]
1340#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema), schemars(!from))]
1341#[borsh(use_discriminant = true)]
1342#[repr(u8)]
1343pub enum GlobalContractIdentifierView {
1344 #[serde(rename = "hash")]
1345 CodeHash(CryptoHash) = 0,
1346 AccountId(AccountId) = 1,
1347}
1348
1349impl From<BackwardCompatibleGlobalContractIdentifierView> for GlobalContractIdentifierView {
1350 fn from(value: BackwardCompatibleGlobalContractIdentifierView) -> Self {
1351 match value {
1352 BackwardCompatibleGlobalContractIdentifierView::DeprecatedCodeHash(hash)
1353 | BackwardCompatibleGlobalContractIdentifierView::CodeHash { hash } => {
1354 GlobalContractIdentifierView::CodeHash(hash)
1355 }
1356 BackwardCompatibleGlobalContractIdentifierView::DeprecatedAccountId(account_id)
1357 | BackwardCompatibleGlobalContractIdentifierView::AccountId { account_id } => {
1358 GlobalContractIdentifierView::AccountId(account_id)
1359 }
1360 }
1361 }
1362}
1363
1364impl From<GlobalContractIdentifier> for GlobalContractIdentifierView {
1365 fn from(code: GlobalContractIdentifier) -> Self {
1366 match code {
1367 GlobalContractIdentifier::CodeHash(code_hash) => {
1368 GlobalContractIdentifierView::CodeHash(code_hash)
1369 }
1370 GlobalContractIdentifier::AccountId(account_id) => {
1371 GlobalContractIdentifierView::AccountId(account_id)
1372 }
1373 }
1374 }
1375}
1376
1377#[derive(
1390 BorshSerialize,
1391 BorshDeserialize,
1392 Clone,
1393 Debug,
1394 PartialEq,
1395 Eq,
1396 serde::Serialize,
1397 serde::Deserialize,
1398)]
1399#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1400#[serde(rename_all = "snake_case")]
1401#[borsh(use_discriminant = true)]
1402#[repr(u8)]
1403pub enum AccountContractView {
1404 Local(CryptoHash) = 0,
1405 GlobalHash(CryptoHash) = 1,
1406 GlobalAccountId(AccountId) = 2,
1407}
1408
1409impl AccountContractView {
1410 pub fn from_account_contract(contract: AccountContract) -> Option<Self> {
1414 match contract {
1415 AccountContract::None => None,
1416 AccountContract::Local(hash) => Some(AccountContractView::Local(hash)),
1417 AccountContract::Global(hash) => Some(AccountContractView::GlobalHash(hash)),
1418 AccountContract::GlobalByAccount(account_id) => {
1419 Some(AccountContractView::GlobalAccountId(account_id))
1420 }
1421 }
1422 }
1423}
1424
1425impl From<GlobalContractIdentifierView> for GlobalContractIdentifier {
1426 fn from(code: GlobalContractIdentifierView) -> Self {
1427 match code {
1428 GlobalContractIdentifierView::CodeHash(code_hash) => {
1429 GlobalContractIdentifier::CodeHash(code_hash)
1430 }
1431 GlobalContractIdentifierView::AccountId(account_id) => {
1432 GlobalContractIdentifier::AccountId(account_id)
1433 }
1434 }
1435 }
1436}
1437
1438#[serde_as]
1439#[derive(
1440 BorshSerialize,
1441 BorshDeserialize,
1442 Clone,
1443 Debug,
1444 PartialEq,
1445 Eq,
1446 serde::Serialize,
1447 serde::Deserialize,
1448)]
1449#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1450#[borsh(use_discriminant = true)]
1451#[repr(u8)]
1452pub enum ActionView {
1453 CreateAccount = 0,
1454 DeployContract {
1455 #[serde_as(as = "Base64")]
1456 #[cfg_attr(
1457 feature = "schemars",
1458 schemars(schema_with = "crate::serialize::base64_schema")
1459 )]
1460 code: Vec<u8>,
1461 } = 1,
1462 FunctionCall {
1463 method_name: String,
1464 args: FunctionArgs,
1465 gas: Gas,
1466 deposit: Balance,
1467 } = 2,
1468 Transfer {
1469 deposit: Balance,
1470 } = 3,
1471 Stake {
1472 stake: Balance,
1473 public_key: PublicKey,
1474 } = 4,
1475 AddKey {
1476 public_key: PublicKey,
1477 access_key: AccessKeyView,
1478 } = 5,
1479 DeleteKey {
1480 public_key: PublicKey,
1481 } = 6,
1482 DeleteAccount {
1483 beneficiary_id: AccountId,
1484 } = 7,
1485 Delegate {
1486 delegate_action: DelegateAction,
1487 signature: Signature,
1488 } = 8,
1489 DelegateV2 {
1490 delegate_action: VersionedDelegateActionPayload,
1491 signature: Signature,
1492 } = 16,
1493 DeployGlobalContract {
1494 #[serde_as(as = "Base64")]
1495 #[cfg_attr(
1496 feature = "schemars",
1497 schemars(schema_with = "crate::serialize::base64_schema")
1498 )]
1499 code: Vec<u8>,
1500 } = 9,
1501 DeployGlobalContractByAccountId {
1502 #[serde_as(as = "Base64")]
1503 #[cfg_attr(
1504 feature = "schemars",
1505 schemars(schema_with = "crate::serialize::base64_schema")
1506 )]
1507 code: Vec<u8>,
1508 } = 10,
1509 UseGlobalContract {
1510 code_hash: CryptoHash,
1511 } = 11,
1512 UseGlobalContractByAccountId {
1513 account_id: AccountId,
1514 } = 12,
1515 DeterministicStateInit {
1516 code: GlobalContractIdentifierView,
1517 #[serde_as(as = "BTreeMap<Base64, Base64>")]
1518 #[cfg_attr(feature = "schemars", schemars(with = "BTreeMap<String, String>"))]
1519 data: BTreeMap<Vec<u8>, Vec<u8>>,
1520 deposit: Balance,
1521 } = 13,
1522 TransferToGasKey {
1523 public_key: PublicKey,
1524 deposit: Balance,
1525 } = 14,
1526 WithdrawFromGasKey {
1527 public_key: PublicKey,
1528 amount: Balance,
1529 } = 15,
1530}
1531
1532impl From<Action> for ActionView {
1533 fn from(action: Action) -> Self {
1534 match action {
1535 Action::CreateAccount(_) => ActionView::CreateAccount,
1536 Action::DeployContract(action) => {
1537 let code = hash(&action.code).as_ref().to_vec();
1538 ActionView::DeployContract { code }
1539 }
1540 Action::FunctionCall(action) => ActionView::FunctionCall {
1541 method_name: action.method_name,
1542 args: action.args.into(),
1543 gas: action.gas,
1544 deposit: action.deposit,
1545 },
1546 Action::Transfer(action) => ActionView::Transfer { deposit: action.deposit },
1547 Action::Stake(action) => {
1548 ActionView::Stake { stake: action.stake, public_key: action.public_key }
1549 }
1550 Action::AddKey(action) => ActionView::AddKey {
1551 public_key: action.public_key,
1552 access_key: action.access_key.into(),
1553 },
1554 Action::DeleteKey(action) => ActionView::DeleteKey { public_key: action.public_key },
1555 Action::DeleteAccount(action) => {
1556 ActionView::DeleteAccount { beneficiary_id: action.beneficiary_id }
1557 }
1558 Action::Delegate(action) => ActionView::Delegate {
1559 delegate_action: action.delegate_action,
1560 signature: action.signature,
1561 },
1562 Action::DelegateV2(action) => ActionView::DelegateV2 {
1563 delegate_action: action.delegate_action,
1564 signature: action.signature,
1565 },
1566 Action::DeployGlobalContract(action) => {
1567 let code = hash(&action.code).as_ref().to_vec();
1568 match action.deploy_mode {
1569 GlobalContractDeployMode::CodeHash => ActionView::DeployGlobalContract { code },
1570 GlobalContractDeployMode::AccountId => {
1571 ActionView::DeployGlobalContractByAccountId { code }
1572 }
1573 }
1574 }
1575 Action::UseGlobalContract(action) => match action.contract_identifier {
1576 GlobalContractIdentifier::CodeHash(code_hash) => {
1577 ActionView::UseGlobalContract { code_hash }
1578 }
1579 GlobalContractIdentifier::AccountId(account_id) => {
1580 ActionView::UseGlobalContractByAccountId { account_id }
1581 }
1582 },
1583 Action::DeterministicStateInit(action) => {
1584 let (code, data) = action.state_init.take();
1585 let identifier = GlobalContractIdentifierView::from(code);
1586 ActionView::DeterministicStateInit {
1587 code: identifier,
1588 data,
1589 deposit: action.deposit,
1590 }
1591 }
1592 Action::TransferToGasKey(action) => ActionView::TransferToGasKey {
1593 public_key: action.public_key,
1594 deposit: action.deposit,
1595 },
1596 Action::WithdrawFromGasKey(action) => ActionView::WithdrawFromGasKey {
1597 public_key: action.public_key,
1598 amount: action.amount,
1599 },
1600 }
1601 }
1602}
1603
1604impl TryFrom<ActionView> for Action {
1605 type Error = Box<dyn std::error::Error + Send + Sync>;
1606
1607 fn try_from(action_view: ActionView) -> Result<Self, Self::Error> {
1608 Ok(match action_view {
1609 ActionView::CreateAccount => Action::CreateAccount(CreateAccountAction {}),
1610 ActionView::DeployContract { code } => {
1611 Action::DeployContract(DeployContractAction { code })
1612 }
1613 ActionView::FunctionCall { method_name, args, gas, deposit } => {
1614 Action::FunctionCall(Box::new(FunctionCallAction {
1615 method_name,
1616 args: args.into(),
1617 gas,
1618 deposit,
1619 }))
1620 }
1621 ActionView::Transfer { deposit } => Action::Transfer(TransferAction { deposit }),
1622 ActionView::Stake { stake, public_key } => {
1623 Action::Stake(Box::new(StakeAction { stake, public_key }))
1624 }
1625 ActionView::AddKey { public_key, access_key } => {
1626 Action::AddKey(Box::new(AddKeyAction { public_key, access_key: access_key.into() }))
1627 }
1628 ActionView::DeleteKey { public_key } => {
1629 Action::DeleteKey(Box::new(DeleteKeyAction { public_key }))
1630 }
1631 ActionView::DeleteAccount { beneficiary_id } => {
1632 Action::DeleteAccount(DeleteAccountAction { beneficiary_id })
1633 }
1634 ActionView::Delegate { delegate_action, signature } => {
1635 Action::Delegate(Box::new(SignedDelegateAction { delegate_action, signature }))
1636 }
1637 ActionView::DelegateV2 { delegate_action, signature } => {
1638 Action::DelegateV2(Box::new(VersionedSignedDelegateAction {
1639 delegate_action,
1640 signature,
1641 }))
1642 }
1643 ActionView::DeployGlobalContract { code } => {
1644 Action::DeployGlobalContract(DeployGlobalContractAction {
1645 code: code.into(),
1646 deploy_mode: GlobalContractDeployMode::CodeHash,
1647 })
1648 }
1649 ActionView::DeployGlobalContractByAccountId { code } => {
1650 Action::DeployGlobalContract(DeployGlobalContractAction {
1651 code: code.into(),
1652 deploy_mode: GlobalContractDeployMode::AccountId,
1653 })
1654 }
1655 ActionView::UseGlobalContract { code_hash } => {
1656 Action::UseGlobalContract(Box::new(UseGlobalContractAction {
1657 contract_identifier: GlobalContractIdentifier::CodeHash(code_hash),
1658 }))
1659 }
1660 ActionView::UseGlobalContractByAccountId { account_id } => {
1661 Action::UseGlobalContract(Box::new(UseGlobalContractAction {
1662 contract_identifier: GlobalContractIdentifier::AccountId(account_id),
1663 }))
1664 }
1665 ActionView::DeterministicStateInit { code, data, deposit } => {
1666 let code = GlobalContractIdentifier::from(code);
1667 Action::DeterministicStateInit(Box::new(DeterministicStateInitAction {
1668 state_init: DeterministicAccountStateInit::V1(
1669 DeterministicAccountStateInitV1 { code, data },
1670 ),
1671 deposit,
1672 }))
1673 }
1674 ActionView::TransferToGasKey { public_key, deposit } => {
1675 Action::TransferToGasKey(Box::new(TransferToGasKeyAction { public_key, deposit }))
1676 }
1677 ActionView::WithdrawFromGasKey { public_key, amount } => {
1678 Action::WithdrawFromGasKey(Box::new(WithdrawFromGasKeyAction {
1679 public_key,
1680 amount,
1681 }))
1682 }
1683 })
1684 }
1685}
1686
1687#[derive(
1688 BorshSerialize,
1689 BorshDeserialize,
1690 Debug,
1691 PartialEq,
1692 Eq,
1693 Clone,
1694 serde::Serialize,
1695 serde::Deserialize,
1696)]
1697#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1698pub struct SignedTransactionView {
1699 pub signer_id: AccountId,
1700 pub public_key: PublicKey,
1701 pub nonce: Nonce,
1702 pub receiver_id: AccountId,
1703 pub actions: Vec<ActionView>,
1704 #[serde(default, rename = "priority_fee")]
1706 pub _priority_fee: u64,
1707 pub signature: Signature,
1708 pub hash: CryptoHash,
1709 #[serde(skip_serializing_if = "Option::is_none", default)]
1710 pub nonce_index: Option<NonceIndex>,
1711 #[serde(skip_serializing_if = "Option::is_none", default)]
1712 pub nonce_mode: Option<NonceMode>,
1713}
1714
1715impl From<SignedTransaction> for SignedTransactionView {
1716 fn from(signed_tx: SignedTransaction) -> Self {
1717 let hash = signed_tx.get_hash();
1718 let transaction = signed_tx.transaction;
1719 let nonce_mode = match transaction.nonce_mode() {
1720 NonceMode::Monotonic => None,
1721 mode => Some(mode),
1722 };
1723 SignedTransactionView {
1724 signer_id: transaction.signer_id().clone(),
1725 public_key: transaction.public_key().clone(),
1726 nonce: transaction.nonce().nonce(),
1727 nonce_index: transaction.nonce().nonce_index(),
1728 receiver_id: transaction.receiver_id().clone(),
1729 actions: transaction.take_actions().into_iter().map(|action| action.into()).collect(),
1730 signature: signed_tx.signature,
1731 hash,
1732 _priority_fee: 0,
1733 nonce_mode,
1734 }
1735 }
1736}
1737
1738#[serde_as]
1739#[derive(
1740 BorshSerialize,
1741 BorshDeserialize,
1742 serde::Serialize,
1743 serde::Deserialize,
1744 PartialEq,
1745 Eq,
1746 Clone,
1747 Default,
1748)]
1749#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1750#[borsh(use_discriminant = true)]
1751#[repr(u8)]
1752pub enum FinalExecutionStatus {
1753 #[default]
1755 NotStarted = 0,
1756 Started = 1,
1758 Failure(TxExecutionError) = 2,
1760 SuccessValue(
1762 #[serde_as(as = "Base64")]
1763 #[cfg_attr(feature = "schemars", schemars(with = "String"))]
1764 Vec<u8>,
1765 ) = 3,
1766}
1767
1768impl fmt::Debug for FinalExecutionStatus {
1769 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1770 match self {
1771 FinalExecutionStatus::NotStarted => f.write_str("NotStarted"),
1772 FinalExecutionStatus::Started => f.write_str("Started"),
1773 FinalExecutionStatus::Failure(e) => f.write_fmt(format_args!("Failure({:?})", e)),
1774 FinalExecutionStatus::SuccessValue(v) => {
1775 f.write_fmt(format_args!("SuccessValue({})", AbbrBytes(v)))
1776 }
1777 }
1778 }
1779}
1780
1781#[derive(
1782 BorshSerialize,
1783 BorshDeserialize,
1784 Debug,
1785 PartialEq,
1786 Eq,
1787 Clone,
1788 serde::Serialize,
1789 serde::Deserialize,
1790)]
1791#[borsh(use_discriminant = true)]
1792#[repr(u8)]
1793pub enum ServerError {
1794 TxExecutionError(TxExecutionError) = 0,
1795 Timeout = 1,
1796 Closed = 2,
1797}
1798
1799#[serde_as]
1800#[derive(
1801 BorshSerialize, BorshDeserialize, serde::Serialize, serde::Deserialize, PartialEq, Eq, Clone,
1802)]
1803#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1804#[borsh(use_discriminant = true)]
1805#[repr(u8)]
1806pub enum ExecutionStatusView {
1807 Unknown = 0,
1809 Failure(TxExecutionError) = 1,
1811 SuccessValue(
1813 #[serde_as(as = "Base64")]
1814 #[cfg_attr(feature = "schemars", schemars(with = "String"))]
1815 Vec<u8>,
1816 ) = 2,
1817 SuccessReceiptId(CryptoHash) = 3,
1820}
1821
1822impl fmt::Debug for ExecutionStatusView {
1823 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1824 match self {
1825 ExecutionStatusView::Unknown => f.write_str("Unknown"),
1826 ExecutionStatusView::Failure(e) => f.write_fmt(format_args!("Failure({:?})", e)),
1827 ExecutionStatusView::SuccessValue(v) => {
1828 f.write_fmt(format_args!("SuccessValue({})", AbbrBytes(v)))
1829 }
1830 ExecutionStatusView::SuccessReceiptId(receipt_id) => {
1831 f.write_fmt(format_args!("SuccessReceiptId({})", receipt_id))
1832 }
1833 }
1834 }
1835}
1836
1837impl From<ExecutionStatus> for ExecutionStatusView {
1838 fn from(outcome: ExecutionStatus) -> Self {
1839 match outcome {
1840 ExecutionStatus::Unknown => ExecutionStatusView::Unknown,
1841 ExecutionStatus::Failure(e) => ExecutionStatusView::Failure(e),
1842 ExecutionStatus::SuccessValue(v) => ExecutionStatusView::SuccessValue(v),
1843 ExecutionStatus::SuccessReceiptId(receipt_id) => {
1844 ExecutionStatusView::SuccessReceiptId(receipt_id)
1845 }
1846 }
1847 }
1848}
1849
1850#[derive(
1852 BorshSerialize,
1853 BorshDeserialize,
1854 PartialEq,
1855 Clone,
1856 Eq,
1857 Debug,
1858 serde::Serialize,
1859 serde::Deserialize,
1860)]
1861#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1862pub struct CostGasUsed {
1863 pub cost_category: String,
1865 pub cost: String,
1866 #[serde(with = "dec_format")]
1867 #[cfg_attr(feature = "schemars", schemars(with = "String"))]
1868 pub gas_used: Gas,
1869}
1870
1871#[derive(
1872 BorshSerialize,
1873 BorshDeserialize,
1874 PartialEq,
1875 Clone,
1876 Eq,
1877 Debug,
1878 serde::Serialize,
1879 serde::Deserialize,
1880)]
1881#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1882pub struct ExecutionMetadataView {
1883 pub version: u32,
1884 pub gas_profile: Option<Vec<CostGasUsed>>,
1885 #[serde(default, skip_serializing_if = "Option::is_none")]
1892 pub contracts: Option<Vec<Option<AccountContractView>>>,
1893}
1894
1895impl Default for ExecutionMetadataView {
1896 fn default() -> Self {
1897 ExecutionMetadata::V1.into()
1898 }
1899}
1900
1901impl From<ExecutionMetadata> for ExecutionMetadataView {
1902 fn from(metadata: ExecutionMetadata) -> Self {
1903 let version = match metadata {
1904 ExecutionMetadata::V1 => 1,
1905 ExecutionMetadata::V2(_) => 2,
1906 ExecutionMetadata::V3(_) => 3,
1907 ExecutionMetadata::V4(_) => 4,
1908 };
1909 let contracts = match &metadata {
1910 ExecutionMetadata::V1 | ExecutionMetadata::V2(_) | ExecutionMetadata::V3(_) => None,
1911 ExecutionMetadata::V4(v4) => Some(
1912 v4.contracts
1913 .iter()
1914 .cloned()
1915 .map(AccountContractView::from_account_contract)
1916 .collect(),
1917 ),
1918 };
1919 let mut gas_profile = match metadata {
1920 ExecutionMetadata::V1 => None,
1921 ExecutionMetadata::V2(profile_data) => {
1922 let mut costs: Vec<CostGasUsed> = profile_data
1928 .legacy_action_costs()
1929 .into_iter()
1930 .filter(|&(_, gas)| gas > Gas::ZERO)
1931 .map(|(name, gas)| CostGasUsed::action(name.to_string(), gas))
1932 .collect();
1933
1934 costs.push(CostGasUsed::wasm_host(
1936 "WASM_INSTRUCTION".to_string(),
1937 profile_data.get_wasm_cost(),
1938 ));
1939
1940 for ext_cost in ExtCosts::iter() {
1942 costs.push(CostGasUsed::wasm_host(
1943 format!("{:?}", ext_cost).to_ascii_uppercase(),
1944 profile_data.get_ext_cost(ext_cost),
1945 ));
1946 }
1947
1948 Some(costs)
1949 }
1950 ExecutionMetadata::V3(profile) => Some(profile_v3_to_costs(&profile)),
1951 ExecutionMetadata::V4(v4) => Some(profile_v3_to_costs(&v4.profile)),
1952 };
1953 if let Some(ref mut costs) = gas_profile {
1954 costs.sort_by(|lhs, rhs| {
1961 lhs.cost_category.cmp(&rhs.cost_category).then_with(|| lhs.cost.cmp(&rhs.cost))
1962 });
1963 }
1964 ExecutionMetadataView { version, gas_profile, contracts }
1965 }
1966}
1967
1968fn profile_v3_to_costs(profile: &ProfileDataV3) -> Vec<CostGasUsed> {
1969 let mut costs: Vec<CostGasUsed> = ActionCosts::iter()
1972 .filter_map(|cost| {
1973 let gas_used = profile.get_action_cost(cost);
1974 (gas_used > Gas::ZERO)
1975 .then(|| CostGasUsed::action(format!("{:?}", cost).to_ascii_uppercase(), gas_used))
1976 })
1977 .collect();
1978
1979 let wasm_gas_used = profile.get_wasm_cost();
1981 if wasm_gas_used > Gas::ZERO {
1982 costs.push(CostGasUsed::wasm_host("WASM_INSTRUCTION".to_string(), wasm_gas_used));
1983 }
1984
1985 for ext_cost in ExtCosts::iter() {
1987 let gas_used = profile.get_ext_cost(ext_cost);
1988 if gas_used > Gas::ZERO {
1989 costs.push(CostGasUsed::wasm_host(
1990 format!("{:?}", ext_cost).to_ascii_uppercase(),
1991 gas_used,
1992 ));
1993 }
1994 }
1995 costs
1996}
1997
1998impl CostGasUsed {
1999 pub fn action(cost: String, gas_used: Gas) -> Self {
2000 Self { cost_category: "ACTION_COST".to_string(), cost, gas_used }
2001 }
2002
2003 pub fn wasm_host(cost: String, gas_used: Gas) -> Self {
2004 Self { cost_category: "WASM_HOST_COST".to_string(), cost, gas_used }
2005 }
2006}
2007
2008#[derive(
2009 BorshSerialize,
2010 BorshDeserialize,
2011 Debug,
2012 Clone,
2013 PartialEq,
2014 Eq,
2015 serde::Serialize,
2016 serde::Deserialize,
2017)]
2018#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
2019pub struct ExecutionOutcomeView {
2020 pub logs: Vec<String>,
2022 pub receipt_ids: Vec<CryptoHash>,
2024 pub gas_burnt: Gas,
2026 pub tokens_burnt: Balance,
2032 pub executor_id: AccountId,
2035 pub status: ExecutionStatusView,
2037 #[serde(default)]
2039 pub metadata: ExecutionMetadataView,
2040}
2041
2042impl From<ExecutionOutcome> for ExecutionOutcomeView {
2043 fn from(outcome: ExecutionOutcome) -> Self {
2044 Self {
2045 logs: outcome.logs,
2046 receipt_ids: outcome.receipt_ids,
2047 gas_burnt: outcome.gas_burnt,
2048 tokens_burnt: outcome.tokens_burnt,
2049 executor_id: outcome.executor_id,
2050 status: outcome.status.into(),
2051 metadata: outcome.metadata.into(),
2052 }
2053 }
2054}
2055
2056impl From<&ExecutionOutcomeView> for PartialExecutionOutcome {
2057 fn from(outcome: &ExecutionOutcomeView) -> Self {
2058 Self {
2059 receipt_ids: outcome.receipt_ids.clone(),
2060 gas_burnt: outcome.gas_burnt,
2061 tokens_burnt: outcome.tokens_burnt,
2062 executor_id: outcome.executor_id.clone(),
2063 status: outcome.status.clone().into(),
2064 }
2065 }
2066}
2067impl From<ExecutionStatusView> for PartialExecutionStatus {
2068 fn from(status: ExecutionStatusView) -> PartialExecutionStatus {
2069 match status {
2070 ExecutionStatusView::Unknown => PartialExecutionStatus::Unknown,
2071 ExecutionStatusView::Failure(_) => PartialExecutionStatus::Failure,
2072 ExecutionStatusView::SuccessValue(value) => PartialExecutionStatus::SuccessValue(value),
2073 ExecutionStatusView::SuccessReceiptId(id) => {
2074 PartialExecutionStatus::SuccessReceiptId(id)
2075 }
2076 }
2077 }
2078}
2079
2080impl ExecutionOutcomeView {
2081 pub fn to_hashes(&self, id: CryptoHash) -> Vec<CryptoHash> {
2083 let mut result = Vec::with_capacity(self.logs.len().saturating_add(2));
2084 result.push(id);
2085 result.push(CryptoHash::hash_borsh(&PartialExecutionOutcome::from(self)));
2086 result.extend(self.logs.iter().map(|log| hash(log.as_bytes())));
2087 result
2088 }
2089}
2090
2091#[derive(
2092 BorshSerialize,
2093 BorshDeserialize,
2094 Debug,
2095 PartialEq,
2096 Eq,
2097 Clone,
2098 serde::Serialize,
2099 serde::Deserialize,
2100)]
2101#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
2102pub struct ExecutionOutcomeWithIdView {
2103 pub proof: MerklePath,
2104 pub block_hash: CryptoHash,
2105 pub id: CryptoHash,
2106 pub outcome: ExecutionOutcomeView,
2107}
2108
2109impl From<ExecutionOutcomeWithIdAndProof> for ExecutionOutcomeWithIdView {
2110 fn from(outcome_with_id_and_proof: ExecutionOutcomeWithIdAndProof) -> Self {
2111 Self {
2112 proof: outcome_with_id_and_proof.proof,
2113 block_hash: outcome_with_id_and_proof.block_hash,
2114 id: outcome_with_id_and_proof.outcome_with_id.id,
2115 outcome: outcome_with_id_and_proof.outcome_with_id.outcome.into(),
2116 }
2117 }
2118}
2119
2120impl ExecutionOutcomeWithIdView {
2121 pub fn to_hashes(&self) -> Vec<CryptoHash> {
2122 self.outcome.to_hashes(self.id)
2123 }
2124}
2125#[derive(Clone, Debug)]
2126pub struct TxStatusView {
2127 pub execution_outcome: Option<FinalExecutionOutcomeViewEnum>,
2128 pub status: TxExecutionStatus,
2129}
2130
2131#[derive(
2132 BorshSerialize,
2133 BorshDeserialize,
2134 serde::Serialize,
2135 serde::Deserialize,
2136 Clone,
2137 Debug,
2138 Default,
2139 Eq,
2140 PartialEq,
2141)]
2142#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
2143#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
2144#[borsh(use_discriminant = true)]
2145#[repr(u8)]
2146pub enum TxExecutionStatus {
2147 None = 0,
2149 Included = 1,
2151 #[default]
2155 ExecutedOptimistic = 2,
2156 IncludedFinal = 3,
2158 Executed = 4,
2162 Final = 5,
2165}
2166
2167#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)]
2168#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
2169#[serde(untagged)]
2170pub enum FinalExecutionOutcomeViewEnum {
2173 FinalExecutionOutcomeWithReceipt(FinalExecutionOutcomeWithReceiptView),
2174 FinalExecutionOutcome(FinalExecutionOutcomeView),
2175}
2176
2177impl FinalExecutionOutcomeViewEnum {
2178 pub fn into_outcome(self) -> FinalExecutionOutcomeView {
2179 match self {
2180 Self::FinalExecutionOutcome(outcome) => outcome,
2181 Self::FinalExecutionOutcomeWithReceipt(outcome) => outcome.final_outcome,
2182 }
2183 }
2184}
2185
2186impl TxStatusView {
2187 pub fn into_outcome(self) -> Option<FinalExecutionOutcomeView> {
2188 self.execution_outcome.map(|outcome| match outcome {
2189 FinalExecutionOutcomeViewEnum::FinalExecutionOutcome(outcome) => outcome,
2190 FinalExecutionOutcomeViewEnum::FinalExecutionOutcomeWithReceipt(outcome) => {
2191 outcome.final_outcome
2192 }
2193 })
2194 }
2195}
2196
2197#[derive(
2200 BorshSerialize, BorshDeserialize, serde::Serialize, serde::Deserialize, PartialEq, Eq, Clone,
2201)]
2202#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
2203pub struct FinalExecutionOutcomeView {
2204 pub status: FinalExecutionStatus,
2210 pub transaction: SignedTransactionView,
2212 pub transaction_outcome: ExecutionOutcomeWithIdView,
2214 pub receipts_outcome: Vec<ExecutionOutcomeWithIdView>,
2216}
2217
2218impl fmt::Debug for FinalExecutionOutcomeView {
2219 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2220 f.debug_struct("FinalExecutionOutcome")
2221 .field("status", &self.status)
2222 .field("transaction", &self.transaction)
2223 .field("transaction_outcome", &self.transaction_outcome)
2224 .field("receipts_outcome", &Slice(&self.receipts_outcome))
2225 .finish()
2226 }
2227}
2228
2229#[derive(
2232 BorshSerialize,
2233 BorshDeserialize,
2234 PartialEq,
2235 Eq,
2236 Clone,
2237 Debug,
2238 serde::Serialize,
2239 serde::Deserialize,
2240)]
2241#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
2242pub struct FinalExecutionOutcomeWithReceiptView {
2243 #[serde(flatten)]
2245 pub final_outcome: FinalExecutionOutcomeView,
2246 pub receipts: Vec<ReceiptView>,
2248}
2249
2250pub mod validator_stake_view {
2251 pub use super::ValidatorStakeViewV1;
2252 use crate::types::validator_stake::ValidatorStake;
2253 use borsh::{BorshDeserialize, BorshSerialize};
2254 use near_primitives_core::types::AccountId;
2255 use serde::Deserialize;
2256
2257 #[derive(
2258 BorshSerialize, BorshDeserialize, serde::Serialize, Deserialize, Debug, Clone, Eq, PartialEq,
2259 )]
2260 #[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
2261 #[serde(tag = "validator_stake_struct_version")]
2262 pub enum ValidatorStakeView {
2263 V1(ValidatorStakeViewV1),
2264 }
2265
2266 impl ValidatorStakeView {
2267 pub fn into_validator_stake(self) -> ValidatorStake {
2268 self.into()
2269 }
2270
2271 #[inline]
2272 pub fn take_account_id(self) -> AccountId {
2273 match self {
2274 Self::V1(v1) => v1.account_id,
2275 }
2276 }
2277
2278 #[inline]
2279 pub fn account_id(&self) -> &AccountId {
2280 match self {
2281 Self::V1(v1) => &v1.account_id,
2282 }
2283 }
2284 }
2285
2286 impl From<ValidatorStake> for ValidatorStakeView {
2287 fn from(stake: ValidatorStake) -> Self {
2288 match stake {
2289 ValidatorStake::V1(v1) => Self::V1(ValidatorStakeViewV1 {
2290 account_id: v1.account_id,
2291 public_key: v1.public_key,
2292 stake: v1.stake,
2293 }),
2294 }
2295 }
2296 }
2297
2298 impl From<ValidatorStakeView> for ValidatorStake {
2299 fn from(view: ValidatorStakeView) -> Self {
2300 match view {
2301 ValidatorStakeView::V1(v1) => Self::new_v1(v1.account_id, v1.public_key, v1.stake),
2302 }
2303 }
2304 }
2305}
2306
2307#[derive(
2308 BorshSerialize,
2309 BorshDeserialize,
2310 Debug,
2311 Clone,
2312 Eq,
2313 PartialEq,
2314 serde::Serialize,
2315 serde::Deserialize,
2316)]
2317#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
2318pub struct ValidatorStakeViewV1 {
2319 pub account_id: AccountId,
2320 pub public_key: PublicKey,
2321 pub stake: Balance,
2322}
2323
2324#[derive(
2325 BorshSerialize,
2326 BorshDeserialize,
2327 Clone,
2328 Debug,
2329 PartialEq,
2330 Eq,
2331 serde::Serialize,
2332 serde::Deserialize,
2333)]
2334#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
2335pub struct ReceiptView {
2336 pub predecessor_id: AccountId,
2337 pub receiver_id: AccountId,
2338 pub receipt_id: CryptoHash,
2339
2340 pub receipt: ReceiptEnumView,
2341 #[serde(default, rename = "priority")]
2343 pub _priority: u64,
2344}
2345
2346#[derive(
2347 BorshSerialize,
2348 BorshDeserialize,
2349 Clone,
2350 Debug,
2351 PartialEq,
2352 Eq,
2353 serde::Serialize,
2354 serde::Deserialize,
2355)]
2356#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
2357pub struct DataReceiverView {
2358 pub data_id: CryptoHash,
2359 pub receiver_id: AccountId,
2360}
2361
2362#[serde_as]
2363#[derive(
2364 BorshSerialize,
2365 BorshDeserialize,
2366 Clone,
2367 Debug,
2368 PartialEq,
2369 Eq,
2370 serde::Serialize,
2371 serde::Deserialize,
2372)]
2373#[borsh(use_discriminant = true)]
2374#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
2375#[repr(u8)]
2376pub enum ReceiptEnumView {
2377 Action {
2378 signer_id: AccountId,
2379 signer_public_key: PublicKey,
2380 gas_price: Balance,
2381 output_data_receivers: Vec<DataReceiverView>,
2382 input_data_ids: Vec<CryptoHash>,
2383 actions: Vec<ActionView>,
2384 #[serde(default = "default_is_promise")]
2385 is_promise_yield: bool,
2386 #[serde(default, skip_serializing_if = "Option::is_none")]
2387 refund_to: Option<AccountId>,
2388 } = 0,
2389 Data {
2390 data_id: CryptoHash,
2391 #[serde_as(as = "Option<Base64>")]
2392 #[cfg_attr(feature = "schemars", schemars(with = "Option<String>"))]
2393 data: Option<Vec<u8>>,
2394 #[serde(default = "default_is_promise")]
2395 is_promise_resume: bool,
2396 } = 1,
2397 GlobalContractDistribution {
2398 id: GlobalContractIdentifier,
2399 target_shard: ShardId,
2400 already_delivered_shards: Vec<ShardId>,
2401 #[serde_as(as = "Base64")]
2402 #[cfg_attr(feature = "schemars", schemars(with = "String"))]
2403 code: Vec<u8>,
2404 #[serde(default, skip_serializing_if = "Option::is_none")]
2405 nonce: Option<u64>,
2406 } = 2,
2407}
2408
2409fn default_is_promise() -> bool {
2413 false
2414}
2415
2416impl From<Receipt> for ReceiptView {
2417 fn from(receipt: Receipt) -> Self {
2418 let is_promise_yield =
2419 matches!(receipt.versioned_receipt(), VersionedReceiptEnum::PromiseYield(_));
2420 let is_promise_resume = matches!(receipt.receipt(), ReceiptEnum::PromiseResume(_));
2421 ReceiptView {
2422 predecessor_id: receipt.predecessor_id().clone(),
2423 receiver_id: receipt.receiver_id().clone(),
2424 receipt_id: *receipt.receipt_id(),
2425 receipt: match receipt.take_versioned_receipt() {
2426 VersionedReceiptEnum::Action(action_receipt)
2427 | VersionedReceiptEnum::PromiseYield(action_receipt) => {
2428 ReceiptEnumView::from_action_receipt(action_receipt, is_promise_yield)
2429 }
2430 VersionedReceiptEnum::Data(data_receipt)
2431 | VersionedReceiptEnum::PromiseResume(data_receipt) => {
2432 let data_receipt = data_receipt.into_owned();
2434 ReceiptEnumView::Data {
2435 data_id: data_receipt.data_id,
2436 data: data_receipt.data,
2437 is_promise_resume,
2438 }
2439 }
2440 VersionedReceiptEnum::GlobalContractDistribution(receipt) => {
2441 ReceiptEnumView::GlobalContractDistribution {
2442 id: receipt.id().clone(),
2443 target_shard: receipt.target_shard(),
2444 already_delivered_shards: receipt.already_delivered_shards().to_vec(),
2445 code: hash(receipt.code()).as_bytes().to_vec(),
2446 nonce: receipt.maybe_nonce(),
2447 }
2448 }
2449 },
2450 _priority: 0,
2451 }
2452 }
2453}
2454
2455impl ReceiptEnumView {
2456 fn from_action_receipt(
2457 action_receipt: VersionedActionReceipt,
2458 is_promise_yield: bool,
2459 ) -> ReceiptEnumView {
2460 ReceiptEnumView::Action {
2461 signer_id: action_receipt.signer_id().clone(),
2462 signer_public_key: action_receipt.signer_public_key().clone(),
2463 gas_price: action_receipt.gas_price(),
2464 output_data_receivers: action_receipt
2465 .output_data_receivers()
2466 .iter()
2467 .cloned()
2468 .map(|data_receiver| DataReceiverView {
2469 data_id: data_receiver.data_id,
2470 receiver_id: data_receiver.receiver_id,
2471 })
2472 .collect(),
2473 input_data_ids: action_receipt
2474 .input_data_ids()
2475 .iter()
2476 .cloned()
2477 .map(Into::into)
2478 .collect(),
2479 actions: action_receipt.actions().iter().cloned().map(Into::into).collect(),
2480 is_promise_yield,
2481 refund_to: action_receipt.refund_to().clone(),
2482 }
2483 }
2484}
2485
2486impl TryFrom<ReceiptView> for Receipt {
2487 type Error = Box<dyn std::error::Error + Send + Sync>;
2488
2489 fn try_from(receipt_view: ReceiptView) -> Result<Self, Self::Error> {
2490 Ok(Receipt::V0(ReceiptV0 {
2491 predecessor_id: receipt_view.predecessor_id,
2492 receiver_id: receipt_view.receiver_id,
2493 receipt_id: receipt_view.receipt_id,
2494 receipt: match receipt_view.receipt {
2495 ReceiptEnumView::Action {
2496 signer_id,
2497 signer_public_key,
2498 gas_price,
2499 output_data_receivers,
2500 input_data_ids,
2501 actions,
2502 is_promise_yield,
2503 refund_to,
2504 } => {
2505 let output_data_receivers: Vec<_> = output_data_receivers
2506 .into_iter()
2507 .map(|data_receiver_view| DataReceiver {
2508 data_id: data_receiver_view.data_id,
2509 receiver_id: data_receiver_view.receiver_id,
2510 })
2511 .collect();
2512 let input_data_ids: Vec<CryptoHash> =
2513 input_data_ids.into_iter().map(Into::into).collect();
2514 let actions = actions
2515 .into_iter()
2516 .map(TryInto::try_into)
2517 .collect::<Result<Vec<_>, _>>()?;
2518 if refund_to.is_some() {
2523 let action_receipt = ActionReceiptV2 {
2524 signer_id,
2525 signer_public_key,
2526 gas_price,
2527 output_data_receivers,
2528 input_data_ids,
2529 actions,
2530 refund_to,
2531 };
2532 if is_promise_yield {
2533 ReceiptEnum::PromiseYieldV2(action_receipt)
2534 } else {
2535 ReceiptEnum::ActionV2(action_receipt)
2536 }
2537 } else {
2538 let action_receipt = ActionReceipt {
2539 signer_id,
2540 signer_public_key,
2541 gas_price,
2542 output_data_receivers,
2543 input_data_ids,
2544 actions,
2545 };
2546 if is_promise_yield {
2547 ReceiptEnum::PromiseYield(action_receipt)
2548 } else {
2549 ReceiptEnum::Action(action_receipt)
2550 }
2551 }
2552 }
2553 ReceiptEnumView::Data { data_id, data, is_promise_resume } => {
2554 let data_receipt = DataReceipt { data_id, data };
2555
2556 if is_promise_resume {
2557 ReceiptEnum::PromiseResume(data_receipt)
2558 } else {
2559 ReceiptEnum::Data(data_receipt)
2560 }
2561 }
2562 ReceiptEnumView::GlobalContractDistribution {
2563 id,
2564 target_shard,
2565 already_delivered_shards,
2566 code,
2567 nonce,
2568 } => {
2569 let receipt = match nonce {
2570 Some(nonce) => GlobalContractDistributionReceipt::new_v2(
2571 id,
2572 target_shard,
2573 already_delivered_shards,
2574 code.into(),
2575 nonce,
2576 ),
2577 None => GlobalContractDistributionReceipt::new_v1(
2578 id,
2579 target_shard,
2580 already_delivered_shards,
2581 code.into(),
2582 ),
2583 };
2584 ReceiptEnum::GlobalContractDistribution(receipt)
2585 }
2586 },
2587 }))
2588 }
2589}
2590
2591#[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Eq, Clone)]
2593#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
2594pub struct EpochValidatorInfo {
2595 pub current_validators: Vec<CurrentEpochValidatorInfo>,
2597 pub next_validators: Vec<NextEpochValidatorInfo>,
2599 pub current_fishermen: Vec<ValidatorStakeView>,
2601 pub next_fishermen: Vec<ValidatorStakeView>,
2603 pub current_proposals: Vec<ValidatorStakeView>,
2605 pub prev_epoch_kickout: Vec<ValidatorKickoutView>,
2607 pub epoch_start_height: BlockHeight,
2609 pub epoch_height: EpochHeight,
2611 #[serde(default)]
2616 pub validator_reward_paid_prev_epoch: HashMap<AccountId, Balance>,
2617}
2618
2619#[derive(Debug, PartialEq, Eq, Clone, serde::Serialize, serde::Deserialize)]
2620#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
2621pub struct ValidatorKickoutView {
2622 pub account_id: AccountId,
2623 pub reason: ValidatorKickoutReason,
2624}
2625
2626#[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Eq, Clone)]
2628#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
2629pub struct CurrentEpochValidatorInfo {
2630 pub account_id: AccountId,
2631 pub public_key: PublicKey,
2632 pub is_slashed: bool,
2633 pub stake: Balance,
2634 #[serde(rename = "shards")]
2636 pub shards_produced: Vec<ShardId>,
2637 pub num_produced_blocks: NumBlocks,
2638 pub num_expected_blocks: NumBlocks,
2639 #[serde(default)]
2640 pub num_produced_chunks: NumBlocks,
2641 #[serde(default)]
2642 pub num_expected_chunks: NumBlocks,
2643 #[serde(default)]
2645 pub num_produced_chunks_per_shard: Vec<NumBlocks>,
2646 #[serde(default)]
2649 pub num_expected_chunks_per_shard: Vec<NumBlocks>,
2650 #[serde(default)]
2651 pub num_produced_endorsements: NumBlocks,
2652 #[serde(default)]
2653 pub num_expected_endorsements: NumBlocks,
2654 #[serde(default)]
2655 pub num_produced_endorsements_per_shard: Vec<NumBlocks>,
2656 #[serde(default)]
2659 pub num_expected_endorsements_per_shard: Vec<NumBlocks>,
2660 #[serde(default)]
2662 pub shards_endorsed: Vec<ShardId>,
2663}
2664
2665#[derive(Debug, PartialEq, Eq, Clone, serde::Serialize, serde::Deserialize)]
2666#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
2667pub struct NextEpochValidatorInfo {
2668 pub account_id: AccountId,
2669 pub public_key: PublicKey,
2670 pub stake: Balance,
2671 pub shards: Vec<ShardId>,
2672}
2673
2674#[derive(
2676 PartialEq,
2677 Eq,
2678 Debug,
2679 Clone,
2680 BorshDeserialize,
2681 BorshSerialize,
2682 serde::Serialize,
2683 serde::Deserialize,
2684)]
2685#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
2686pub struct LightClientBlockView {
2687 pub prev_block_hash: CryptoHash,
2688 pub next_block_inner_hash: CryptoHash,
2689 pub inner_lite: BlockHeaderInnerLiteView,
2692 pub inner_rest_hash: CryptoHash,
2693 pub next_bps: Option<Vec<ValidatorStakeView>>,
2694 pub approvals_after_next: Vec<Option<Box<Signature>>>,
2695}
2696
2697#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, BorshDeserialize, BorshSerialize)]
2698#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
2699pub struct LightClientBlockLiteView {
2700 pub prev_block_hash: CryptoHash,
2701 pub inner_rest_hash: CryptoHash,
2702 pub inner_lite: BlockHeaderInnerLiteView,
2703}
2704
2705impl From<BlockHeader> for LightClientBlockLiteView {
2706 fn from(header: BlockHeader) -> Self {
2707 Self {
2708 prev_block_hash: *header.prev_hash(),
2709 inner_rest_hash: hash(&header.inner_rest_bytes()),
2710 inner_lite: header.into(),
2711 }
2712 }
2713}
2714impl LightClientBlockLiteView {
2715 pub fn hash(&self) -> CryptoHash {
2716 let block_header_inner_lite: BlockHeaderInnerLite = self.inner_lite.clone().into();
2717 combine_hash(
2718 &combine_hash(
2719 &hash(&borsh::to_vec(&block_header_inner_lite).unwrap()),
2720 &self.inner_rest_hash,
2721 ),
2722 &self.prev_block_hash,
2723 )
2724 }
2725}
2726
2727#[derive(serde::Serialize, serde::Deserialize, Debug)]
2728#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
2729pub struct GasPriceView {
2730 pub gas_price: Balance,
2731}
2732
2733#[derive(Debug, serde::Serialize, serde::Deserialize)]
2738#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
2739#[serde(tag = "changes_type", rename_all = "snake_case")]
2740pub enum StateChangesRequestView {
2741 AccountChanges {
2742 account_ids: Vec<AccountId>,
2743 },
2744 SingleAccessKeyChanges {
2745 keys: Vec<AccountWithPublicKey>,
2746 },
2747 AllAccessKeyChanges {
2748 account_ids: Vec<AccountId>,
2749 },
2750 ContractCodeChanges {
2751 account_ids: Vec<AccountId>,
2752 },
2753 DataChanges {
2754 account_ids: Vec<AccountId>,
2755 #[serde(rename = "key_prefix_base64")]
2756 key_prefix: StoreKey,
2757 },
2758}
2759
2760impl From<StateChangesRequestView> for StateChangesRequest {
2761 fn from(request: StateChangesRequestView) -> Self {
2762 match request {
2763 StateChangesRequestView::AccountChanges { account_ids } => {
2764 Self::AccountChanges { account_ids }
2765 }
2766 StateChangesRequestView::SingleAccessKeyChanges { keys } => {
2767 Self::SingleAccessKeyChanges { keys }
2768 }
2769 StateChangesRequestView::AllAccessKeyChanges { account_ids } => {
2770 Self::AllAccessKeyChanges { account_ids }
2771 }
2772 StateChangesRequestView::ContractCodeChanges { account_ids } => {
2773 Self::ContractCodeChanges { account_ids }
2774 }
2775 StateChangesRequestView::DataChanges { account_ids, key_prefix } => {
2776 Self::DataChanges { account_ids, key_prefix }
2777 }
2778 }
2779 }
2780}
2781
2782#[derive(Debug, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
2787#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
2788#[serde(rename_all = "snake_case", tag = "type")]
2789pub enum StateChangeKindView {
2790 AccountTouched { account_id: AccountId },
2791 AccessKeyTouched { account_id: AccountId },
2792 DataTouched { account_id: AccountId },
2793 ContractCodeTouched { account_id: AccountId },
2794}
2795
2796impl StateChangeKindView {
2797 pub fn account_id(&self) -> &AccountId {
2798 match self {
2799 Self::AccountTouched { account_id }
2800 | Self::AccessKeyTouched { account_id }
2801 | Self::DataTouched { account_id }
2802 | Self::ContractCodeTouched { account_id } => account_id,
2803 }
2804 }
2805}
2806
2807impl From<StateChangeKind> for StateChangeKindView {
2808 fn from(state_change_kind: StateChangeKind) -> Self {
2809 match state_change_kind {
2810 StateChangeKind::AccountTouched { account_id } => Self::AccountTouched { account_id },
2811 StateChangeKind::AccessKeyTouched { account_id } => {
2812 Self::AccessKeyTouched { account_id }
2813 }
2814 StateChangeKind::DataTouched { account_id } => Self::DataTouched { account_id },
2815 StateChangeKind::ContractCodeTouched { account_id } => {
2816 Self::ContractCodeTouched { account_id }
2817 }
2818 }
2819 }
2820}
2821
2822pub type StateChangesKindsView = Vec<StateChangeKindView>;
2823
2824#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
2826#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
2827#[serde(rename_all = "snake_case", tag = "type")]
2828pub enum StateChangeCauseView {
2829 NotWritableToDisk,
2830 InitialState,
2831 TransactionProcessing { tx_hash: CryptoHash },
2832 ActionReceiptProcessingStarted { receipt_hash: CryptoHash },
2833 ActionReceiptGasReward { receipt_hash: CryptoHash },
2834 ReceiptProcessing { receipt_hash: CryptoHash },
2835 PostponedReceipt { receipt_hash: CryptoHash },
2836 UpdatedDelayedReceipts,
2837 ValidatorAccountsUpdate,
2838 Migration,
2839 BandwidthSchedulerStateUpdate,
2840}
2841
2842impl From<StateChangeCause> for StateChangeCauseView {
2843 fn from(state_change_cause: StateChangeCause) -> Self {
2844 match state_change_cause {
2845 StateChangeCause::NotWritableToDisk => Self::NotWritableToDisk,
2846 StateChangeCause::InitialState => Self::InitialState,
2847 StateChangeCause::TransactionProcessing { tx_hash } => {
2848 Self::TransactionProcessing { tx_hash }
2849 }
2850 StateChangeCause::ActionReceiptProcessingStarted { receipt_hash } => {
2851 Self::ActionReceiptProcessingStarted { receipt_hash }
2852 }
2853 StateChangeCause::ActionReceiptGasReward { receipt_hash } => {
2854 Self::ActionReceiptGasReward { receipt_hash }
2855 }
2856 StateChangeCause::ReceiptProcessing { receipt_hash } => {
2857 Self::ReceiptProcessing { receipt_hash }
2858 }
2859 StateChangeCause::PostponedReceipt { receipt_hash } => {
2860 Self::PostponedReceipt { receipt_hash }
2861 }
2862 StateChangeCause::UpdatedDelayedReceipts => Self::UpdatedDelayedReceipts,
2863 StateChangeCause::ValidatorAccountsUpdate => Self::ValidatorAccountsUpdate,
2864 StateChangeCause::Migration => Self::Migration,
2865 StateChangeCause::_UnusedReshardingV2 => Self::BandwidthSchedulerStateUpdate,
2872 StateChangeCause::BandwidthSchedulerStateUpdate => Self::BandwidthSchedulerStateUpdate,
2873 }
2874 }
2875}
2876
2877#[serde_as]
2878#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
2879#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
2880#[serde(rename_all = "snake_case", tag = "type", content = "change")]
2881pub enum StateChangeValueView {
2882 AccountUpdate {
2883 account_id: AccountId,
2884 #[serde(flatten)]
2885 account: AccountView,
2886 },
2887 AccountDeletion {
2888 account_id: AccountId,
2889 },
2890 AccessKeyUpdate {
2891 account_id: AccountId,
2892 public_key: PublicKeyHandle,
2893 access_key: AccessKeyView,
2894 },
2895 AccessKeyDeletion {
2896 account_id: AccountId,
2897 public_key: PublicKeyHandle,
2898 },
2899 GasKeyNonceUpdate {
2900 account_id: AccountId,
2901 public_key: PublicKeyHandle,
2902 index: NonceIndex,
2903 nonce: Nonce,
2904 },
2905 DataUpdate {
2906 account_id: AccountId,
2907 #[serde(rename = "key_base64")]
2908 key: StoreKey,
2909 #[serde(rename = "value_base64")]
2910 value: StoreValue,
2911 },
2912 DataDeletion {
2913 account_id: AccountId,
2914 #[serde(rename = "key_base64")]
2915 key: StoreKey,
2916 },
2917 ContractCodeUpdate {
2918 account_id: AccountId,
2919 #[serde(rename = "code_base64")]
2920 #[serde_as(as = "Base64")]
2921 #[cfg_attr(feature = "schemars", schemars(with = "String"))]
2922 code: Vec<u8>,
2923 },
2924 ContractCodeDeletion {
2925 account_id: AccountId,
2926 },
2927}
2928
2929impl StateChangeValueView {
2930 pub fn account_id(&self) -> &AccountId {
2931 match self {
2932 Self::AccountUpdate { account_id, .. }
2933 | Self::AccountDeletion { account_id }
2934 | Self::AccessKeyUpdate { account_id, .. }
2935 | Self::AccessKeyDeletion { account_id, .. }
2936 | Self::GasKeyNonceUpdate { account_id, .. }
2937 | Self::DataUpdate { account_id, .. }
2938 | Self::DataDeletion { account_id, .. }
2939 | Self::ContractCodeUpdate { account_id, .. }
2940 | Self::ContractCodeDeletion { account_id } => account_id,
2941 }
2942 }
2943}
2944
2945impl From<StateChangeValue> for StateChangeValueView {
2946 fn from(state_change: StateChangeValue) -> Self {
2947 match state_change {
2948 StateChangeValue::AccountUpdate { account_id, account } => {
2949 Self::AccountUpdate { account_id, account: account.into() }
2950 }
2951 StateChangeValue::AccountDeletion { account_id } => {
2952 Self::AccountDeletion { account_id }
2953 }
2954 StateChangeValue::AccessKeyUpdate { account_id, public_key, access_key } => {
2955 Self::AccessKeyUpdate { account_id, public_key, access_key: access_key.into() }
2956 }
2957 StateChangeValue::AccessKeyDeletion { account_id, public_key } => {
2958 Self::AccessKeyDeletion { account_id, public_key }
2959 }
2960 StateChangeValue::GasKeyNonceUpdate { account_id, public_key, index, nonce } => {
2961 Self::GasKeyNonceUpdate { account_id, public_key, index, nonce }
2962 }
2963 StateChangeValue::DataUpdate { account_id, key, value } => {
2964 Self::DataUpdate { account_id, key, value }
2965 }
2966 StateChangeValue::DataDeletion { account_id, key } => {
2967 Self::DataDeletion { account_id, key }
2968 }
2969 StateChangeValue::ContractCodeUpdate { account_id, code } => {
2970 Self::ContractCodeUpdate { account_id, code }
2971 }
2972 StateChangeValue::ContractCodeDeletion { account_id } => {
2973 Self::ContractCodeDeletion { account_id }
2974 }
2975 }
2976 }
2977}
2978
2979#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
2980#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
2981pub struct StateChangeWithCauseView {
2982 pub cause: StateChangeCauseView,
2983 #[serde(flatten)]
2984 pub value: StateChangeValueView,
2985}
2986
2987impl From<StateChangeWithCause> for StateChangeWithCauseView {
2988 fn from(state_change_with_cause: StateChangeWithCause) -> Self {
2989 let StateChangeWithCause { cause, value } = state_change_with_cause;
2990 Self { cause: cause.into(), value: value.into() }
2991 }
2992}
2993
2994pub type StateChangesView = Vec<StateChangeWithCauseView>;
2995
2996pub type MaintenanceWindowsView = Vec<Range<BlockHeight>>;
2998
2999#[derive(serde::Serialize, serde::Deserialize, Debug)]
3001#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
3002pub struct SplitStorageInfoView {
3003 pub head_height: Option<BlockHeight>,
3004 pub final_head_height: Option<BlockHeight>,
3005 pub cold_head_height: Option<BlockHeight>,
3006
3007 pub hot_db_kind: Option<String>,
3008}
3009
3010#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
3012#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
3013pub struct CongestionInfoView {
3014 #[serde(with = "dec_format")]
3015 #[cfg_attr(feature = "schemars", schemars(with = "String"))]
3016 pub delayed_receipts_gas: u128,
3017
3018 #[serde(with = "dec_format")]
3019 #[cfg_attr(feature = "schemars", schemars(with = "String"))]
3020 pub buffered_receipts_gas: u128,
3021
3022 pub receipt_bytes: u64,
3023
3024 pub allowed_shard: u16,
3025}
3026
3027impl From<CongestionInfo> for CongestionInfoView {
3028 fn from(congestion_info: CongestionInfo) -> Self {
3029 match congestion_info {
3030 CongestionInfo::V1(congestion_info) => congestion_info.into(),
3031 }
3032 }
3033}
3034
3035impl From<CongestionInfoV1> for CongestionInfoView {
3036 fn from(congestion_info: CongestionInfoV1) -> Self {
3037 Self {
3038 delayed_receipts_gas: congestion_info.delayed_receipts_gas,
3039 buffered_receipts_gas: congestion_info.buffered_receipts_gas,
3040 receipt_bytes: congestion_info.receipt_bytes,
3041 allowed_shard: congestion_info.allowed_shard,
3042 }
3043 }
3044}
3045
3046impl From<CongestionInfoView> for CongestionInfo {
3047 fn from(congestion_info: CongestionInfoView) -> Self {
3048 CongestionInfo::V1(CongestionInfoV1 {
3049 delayed_receipts_gas: congestion_info.delayed_receipts_gas,
3050 buffered_receipts_gas: congestion_info.buffered_receipts_gas,
3051 receipt_bytes: congestion_info.receipt_bytes,
3052 allowed_shard: congestion_info.allowed_shard,
3053 })
3054 }
3055}
3056
3057impl CongestionInfoView {
3058 pub fn congestion_level(&self, config_view: CongestionControlConfigView) -> f64 {
3059 let congestion_config = CongestionControlConfig::from(config_view);
3060 CongestionInfo::from(self.clone()).localized_congestion_level(&congestion_config)
3069 }
3070}
3071
3072#[cfg(test)]
3073#[cfg(not(feature = "nightly"))]
3074mod tests {
3075 use super::{ExecutionMetadataView, FinalExecutionOutcomeViewEnum};
3076 use crate::profile_data_v2::ProfileDataV2;
3077 use crate::profile_data_v3::ProfileDataV3;
3078 use crate::transaction::ExecutionMetadata;
3079 use crate::views::GlobalContractIdentifierView;
3080 use assert_matches::assert_matches;
3081 use near_primitives_core::hash::CryptoHash;
3082 use serde_json::json;
3083
3084 #[test]
3087 fn test_runtime_config_view() {
3088 use near_parameters::{RuntimeConfig, RuntimeConfigStore, RuntimeConfigView};
3089 use near_primitives_core::version::PROTOCOL_VERSION;
3090
3091 let config_store = RuntimeConfigStore::new(None);
3092 let config = config_store.get_config(PROTOCOL_VERSION);
3093 let view = RuntimeConfigView::from(RuntimeConfig::clone(config));
3094 insta::assert_json_snapshot!(&view, { ".wasm_config.vm_kind" => "<REDACTED>"});
3095 }
3096
3097 #[test]
3099 fn test_exec_metadata_v1_view() {
3100 let metadata = ExecutionMetadata::V1;
3101 let view = ExecutionMetadataView::from(metadata);
3102 insta::assert_json_snapshot!(view);
3103 }
3104
3105 #[test]
3107 fn test_exec_metadata_v2_view() {
3108 let metadata = ExecutionMetadata::V2(ProfileDataV2::test());
3109 let view = ExecutionMetadataView::from(metadata);
3110 insta::assert_json_snapshot!(view);
3111 }
3112
3113 #[test]
3115 fn test_exec_metadata_v3_view() {
3116 let metadata = ExecutionMetadata::V3(ProfileDataV3::test().into());
3117 let view = ExecutionMetadataView::from(metadata);
3118 insta::assert_json_snapshot!(view);
3119 }
3120
3121 #[test]
3124 fn test_exec_metadata_v4_view() {
3125 use crate::transaction::ExecutionMetadataV4;
3126 use near_primitives_core::account::AccountContract;
3127 let metadata = ExecutionMetadata::V4(Box::new(ExecutionMetadataV4 {
3128 profile: ProfileDataV3::test(),
3129 contracts: vec![AccountContract::None, AccountContract::Local(CryptoHash([7u8; 32]))],
3132 }));
3133 let view = ExecutionMetadataView::from(metadata);
3134 insta::assert_json_snapshot!(view);
3135 }
3136
3137 #[test]
3138 fn test_deserialize_execution_outcome_with_receipt() {
3139 let json = r#"{"final_execution_status":"FINAL","receipts":[{"predecessor_id":"system","priority":0,"receipt":{"Action":{"actions":[{"Transfer":{"deposit":"17930928991009412192152"}}],"gas_price":"0","input_data_ids":[],"is_promise_yield":false,"output_data_receivers":[],"signer_id":"btc-client.testnet","signer_public_key":"ed25519:HM7ax8jJf41JozvanXepzhtD45AeRFcwJQCuLXFuDkjA"}},"receipt_id":"8ZD92cLpoCEU46hPGFfk3VqZpU8s6DoQhZ4pCMqWwDT6","receiver_id":"btc-client.testnet"}],"receipts_outcome":[{"block_hash":"9SP8Y3sVADWNN5QoEB5CsvPUE5HT4o8YfBaCnhLss87K","id":"e2XGEosf843XMiCJHvZufvHKyw419ZYibDBdVJQr9cB","outcome":{"executor_id":"btc-client.testnet","gas_burnt":2906160054161,"logs":["Block hash: 0000000000000000ee617846a3e081ae2f30091451442e1b5fb027d8eba09b3a","Saving to mainchain"],"metadata":{"gas_profile":[{"cost":"BASE","cost_category":"WASM_HOST_COST","gas_used":"8472579552"},{"cost":"CONTRACT_LOADING_BASE","cost_category":"WASM_HOST_COST","gas_used":"35445963"},{"cost":"CONTRACT_LOADING_BYTES","cost_category":"WASM_HOST_COST","gas_used":"413841688515"},{"cost":"LOG_BASE","cost_category":"WASM_HOST_COST","gas_used":"7086626100"},{"cost":"LOG_BYTE","cost_category":"WASM_HOST_COST","gas_used":"1253885145"},{"cost":"READ_CACHED_TRIE_NODE","cost_category":"WASM_HOST_COST","gas_used":"102600000000"},{"cost":"READ_MEMORY_BASE","cost_category":"WASM_HOST_COST","gas_used":"54807127200"},{"cost":"READ_MEMORY_BYTE","cost_category":"WASM_HOST_COST","gas_used":"2873807748"},{"cost":"READ_REGISTER_BASE","cost_category":"WASM_HOST_COST","gas_used":"22654486674"},{"cost":"READ_REGISTER_BYTE","cost_category":"WASM_HOST_COST","gas_used":"51252240"},{"cost":"SHA256_BASE","cost_category":"WASM_HOST_COST","gas_used":"13622910750"},{"cost":"SHA256_BYTE","cost_category":"WASM_HOST_COST","gas_used":"3400546491"},{"cost":"STORAGE_READ_BASE","cost_category":"WASM_HOST_COST","gas_used":"450854766000"},{"cost":"STORAGE_READ_KEY_BYTE","cost_category":"WASM_HOST_COST","gas_used":"4952405280"},{"cost":"STORAGE_READ_VALUE_BYTE","cost_category":"WASM_HOST_COST","gas_used":"1806743610"},{"cost":"STORAGE_WRITE_BASE","cost_category":"WASM_HOST_COST","gas_used":"256786944000"},{"cost":"STORAGE_WRITE_EVICTED_BYTE","cost_category":"WASM_HOST_COST","gas_used":"2826323016"},{"cost":"STORAGE_WRITE_KEY_BYTE","cost_category":"WASM_HOST_COST","gas_used":"5638629360"},{"cost":"STORAGE_WRITE_VALUE_BYTE","cost_category":"WASM_HOST_COST","gas_used":"8685190920"},{"cost":"TOUCHING_TRIE_NODE","cost_category":"WASM_HOST_COST","gas_used":"434752810002"},{"cost":"UTF8_DECODING_BASE","cost_category":"WASM_HOST_COST","gas_used":"6223558122"},{"cost":"UTF8_DECODING_BYTE","cost_category":"WASM_HOST_COST","gas_used":"27700145505"},{"cost":"WASM_INSTRUCTION","cost_category":"WASM_HOST_COST","gas_used":"126491330196"},{"cost":"WRITE_MEMORY_BASE","cost_category":"WASM_HOST_COST","gas_used":"28037948610"},{"cost":"WRITE_MEMORY_BYTE","cost_category":"WASM_HOST_COST","gas_used":"1459941792"},{"cost":"WRITE_REGISTER_BASE","cost_category":"WASM_HOST_COST","gas_used":"28655224860"},{"cost":"WRITE_REGISTER_BYTE","cost_category":"WASM_HOST_COST","gas_used":"2311350912"}],"version":3},"receipt_ids":["8ZD92cLpoCEU46hPGFfk3VqZpU8s6DoQhZ4pCMqWwDT6"],"status":{"SuccessValue":""},"tokens_burnt":"290616005416100000000"},"proof":[{"direction":"Left","hash":"BoQHueiPH9e4C7fkxouV4tFpGZ4hK5fJhKQnPBWwPazS"},{"direction":"Right","hash":"Ayxj8iVFTJMzZa7estoTtuBKJaUNhoipaaM7WmTjkkiS"}]},{"block_hash":"3rEx3xmgLCRgUfSgueD71YNrJYQYNvhtkXaqVQxdmj4U","id":"8ZD92cLpoCEU46hPGFfk3VqZpU8s6DoQhZ4pCMqWwDT6","outcome":{"executor_id":"btc-client.testnet","gas_burnt":223182562500,"logs":[],"metadata":{"gas_profile":[],"version":3},"receipt_ids":[],"status":{"SuccessValue":""},"tokens_burnt":"0"},"proof":[{"direction":"Right","hash":"8yEwg14D2GyyLNnJMxdSLDJKyrKShMAL3zTnf9YpQyPW"},{"direction":"Right","hash":"2UK7BfpHf9fCCsvmfHktDfz6Rh8sFihhN6cuTU3R4BBA"}]}],"status":{"SuccessValue":""},"transaction":{"actions":[{"FunctionCall":{"args":"AQAAAABA0CKoR96WKs+KPP6zPl0flT6XC91eR3uAUgwNAAAAAAAAAAzcZU0cipmejc+wGqnRJchd5uM6qRJM5Oojp3FrkJ2HVmGyZsnyFBlkvks8","deposit":"0","gas":100000000000000,"method_name":"submit_blocks"}}],"hash":"GMUCDLHFJVvmZYXmPf9QeUVAt9r9hXcQP1yL5emPFnvx","nonce":170437577001422,"priority_fee":0,"public_key":"ed25519:HM7ax8jJf41JozvanXepzhtD45AeRFcwJQCuLXFuDkjA","receiver_id":"btc-client.testnet","signature":"ed25519:2Qe3ccPSdzPddk764vm5jt4yXcvXgYQz3WzGF3oXpZLuaRa6ggpD131nSSy3FRVPquCvxYqgMGtdum8TKX3dVqNk","signer_id":"btc-client.testnet"},"transaction_outcome":{"block_hash":"9SP8Y3sVADWNN5QoEB5CsvPUE5HT4o8YfBaCnhLss87K","id":"GMUCDLHFJVvmZYXmPf9QeUVAt9r9hXcQP1yL5emPFnvx","outcome":{"executor_id":"btc-client.testnet","gas_burnt":308276385598,"logs":[],"metadata":{"gas_profile":null,"version":1},"receipt_ids":["e2XGEosf843XMiCJHvZufvHKyw419ZYibDBdVJQr9cB"],"status":{"SuccessReceiptId":"e2XGEosf843XMiCJHvZufvHKyw419ZYibDBdVJQr9cB"},"tokens_burnt":"30827638559800000000"},"proof":[{"direction":"Right","hash":"HDgWEk2okmDdAFAVf6ffxGBH6F6vdLM1X3H5Fmaafe4S"},{"direction":"Right","hash":"Ayxj8iVFTJMzZa7estoTtuBKJaUNhoipaaM7WmTjkkiS"}]}}"#;
3142 let view: FinalExecutionOutcomeViewEnum = serde_json::from_str(json).unwrap();
3143 assert!(matches!(view, FinalExecutionOutcomeViewEnum::FinalExecutionOutcomeWithReceipt(_)));
3144 }
3145
3146 #[test]
3147 fn test_deserialize_execution_outcome_without_receipt() {
3148 let json = r#"{"final_execution_status":"FINAL","receipts_outcome":[{"block_hash":"9SP8Y3sVADWNN5QoEB5CsvPUE5HT4o8YfBaCnhLss87K","id":"e2XGEosf843XMiCJHvZufvHKyw419ZYibDBdVJQr9cB","outcome":{"executor_id":"btc-client.testnet","gas_burnt":2906160054161,"logs":["Block hash: 0000000000000000ee617846a3e081ae2f30091451442e1b5fb027d8eba09b3a","Saving to mainchain"],"metadata":{"gas_profile":[{"cost":"BASE","cost_category":"WASM_HOST_COST","gas_used":"8472579552"},{"cost":"CONTRACT_LOADING_BASE","cost_category":"WASM_HOST_COST","gas_used":"35445963"},{"cost":"CONTRACT_LOADING_BYTES","cost_category":"WASM_HOST_COST","gas_used":"413841688515"},{"cost":"LOG_BASE","cost_category":"WASM_HOST_COST","gas_used":"7086626100"},{"cost":"LOG_BYTE","cost_category":"WASM_HOST_COST","gas_used":"1253885145"},{"cost":"READ_CACHED_TRIE_NODE","cost_category":"WASM_HOST_COST","gas_used":"102600000000"},{"cost":"READ_MEMORY_BASE","cost_category":"WASM_HOST_COST","gas_used":"54807127200"},{"cost":"READ_MEMORY_BYTE","cost_category":"WASM_HOST_COST","gas_used":"2873807748"},{"cost":"READ_REGISTER_BASE","cost_category":"WASM_HOST_COST","gas_used":"22654486674"},{"cost":"READ_REGISTER_BYTE","cost_category":"WASM_HOST_COST","gas_used":"51252240"},{"cost":"SHA256_BASE","cost_category":"WASM_HOST_COST","gas_used":"13622910750"},{"cost":"SHA256_BYTE","cost_category":"WASM_HOST_COST","gas_used":"3400546491"},{"cost":"STORAGE_READ_BASE","cost_category":"WASM_HOST_COST","gas_used":"450854766000"},{"cost":"STORAGE_READ_KEY_BYTE","cost_category":"WASM_HOST_COST","gas_used":"4952405280"},{"cost":"STORAGE_READ_VALUE_BYTE","cost_category":"WASM_HOST_COST","gas_used":"1806743610"},{"cost":"STORAGE_WRITE_BASE","cost_category":"WASM_HOST_COST","gas_used":"256786944000"},{"cost":"STORAGE_WRITE_EVICTED_BYTE","cost_category":"WASM_HOST_COST","gas_used":"2826323016"},{"cost":"STORAGE_WRITE_KEY_BYTE","cost_category":"WASM_HOST_COST","gas_used":"5638629360"},{"cost":"STORAGE_WRITE_VALUE_BYTE","cost_category":"WASM_HOST_COST","gas_used":"8685190920"},{"cost":"TOUCHING_TRIE_NODE","cost_category":"WASM_HOST_COST","gas_used":"434752810002"},{"cost":"UTF8_DECODING_BASE","cost_category":"WASM_HOST_COST","gas_used":"6223558122"},{"cost":"UTF8_DECODING_BYTE","cost_category":"WASM_HOST_COST","gas_used":"27700145505"},{"cost":"WASM_INSTRUCTION","cost_category":"WASM_HOST_COST","gas_used":"126491330196"},{"cost":"WRITE_MEMORY_BASE","cost_category":"WASM_HOST_COST","gas_used":"28037948610"},{"cost":"WRITE_MEMORY_BYTE","cost_category":"WASM_HOST_COST","gas_used":"1459941792"},{"cost":"WRITE_REGISTER_BASE","cost_category":"WASM_HOST_COST","gas_used":"28655224860"},{"cost":"WRITE_REGISTER_BYTE","cost_category":"WASM_HOST_COST","gas_used":"2311350912"}],"version":3},"receipt_ids":["8ZD92cLpoCEU46hPGFfk3VqZpU8s6DoQhZ4pCMqWwDT6"],"status":{"SuccessValue":""},"tokens_burnt":"290616005416100000000"},"proof":[{"direction":"Left","hash":"BoQHueiPH9e4C7fkxouV4tFpGZ4hK5fJhKQnPBWwPazS"},{"direction":"Right","hash":"Ayxj8iVFTJMzZa7estoTtuBKJaUNhoipaaM7WmTjkkiS"}]},{"block_hash":"3rEx3xmgLCRgUfSgueD71YNrJYQYNvhtkXaqVQxdmj4U","id":"8ZD92cLpoCEU46hPGFfk3VqZpU8s6DoQhZ4pCMqWwDT6","outcome":{"executor_id":"btc-client.testnet","gas_burnt":223182562500,"logs":[],"metadata":{"gas_profile":[],"version":3},"receipt_ids":[],"status":{"SuccessValue":""},"tokens_burnt":"0"},"proof":[{"direction":"Right","hash":"8yEwg14D2GyyLNnJMxdSLDJKyrKShMAL3zTnf9YpQyPW"},{"direction":"Right","hash":"2UK7BfpHf9fCCsvmfHktDfz6Rh8sFihhN6cuTU3R4BBA"}]}],"status":{"SuccessValue":""},"transaction":{"actions":[{"FunctionCall":{"args":"AQAAAABA0CKoR96WKs+KPP6zPl0flT6XC91eR3uAUgwNAAAAAAAAAAzcZU0cipmejc+wGqnRJchd5uM6qRJM5Oojp3FrkJ2HVmGyZsnyFBlkvks8","deposit":"0","gas":100000000000000,"method_name":"submit_blocks"}}],"hash":"GMUCDLHFJVvmZYXmPf9QeUVAt9r9hXcQP1yL5emPFnvx","nonce":170437577001422,"priority_fee":0,"public_key":"ed25519:HM7ax8jJf41JozvanXepzhtD45AeRFcwJQCuLXFuDkjA","receiver_id":"btc-client.testnet","signature":"ed25519:2Qe3ccPSdzPddk764vm5jt4yXcvXgYQz3WzGF3oXpZLuaRa6ggpD131nSSy3FRVPquCvxYqgMGtdum8TKX3dVqNk","signer_id":"btc-client.testnet"},"transaction_outcome":{"block_hash":"9SP8Y3sVADWNN5QoEB5CsvPUE5HT4o8YfBaCnhLss87K","id":"GMUCDLHFJVvmZYXmPf9QeUVAt9r9hXcQP1yL5emPFnvx","outcome":{"executor_id":"btc-client.testnet","gas_burnt":308276385598,"logs":[],"metadata":{"gas_profile":null,"version":1},"receipt_ids":["e2XGEosf843XMiCJHvZufvHKyw419ZYibDBdVJQr9cB"],"status":{"SuccessReceiptId":"e2XGEosf843XMiCJHvZufvHKyw419ZYibDBdVJQr9cB"},"tokens_burnt":"30827638559800000000"},"proof":[{"direction":"Right","hash":"HDgWEk2okmDdAFAVf6ffxGBH6F6vdLM1X3H5Fmaafe4S"},{"direction":"Right","hash":"Ayxj8iVFTJMzZa7estoTtuBKJaUNhoipaaM7WmTjkkiS"}]}}"#;
3150 let view: FinalExecutionOutcomeViewEnum = serde_json::from_str(json).unwrap();
3151 assert!(matches!(view, FinalExecutionOutcomeViewEnum::FinalExecutionOutcome(_)));
3152 }
3153
3154 #[test]
3155 fn test_deserialize_global_contract_identifier_view_hash_deprecated() {
3156 assert_matches!(
3157 deserialize_global_contract_identifier(json!(
3158 "9SP8Y3sVADWNN5QoEB5CsvPUE5HT4o8YfBaCnhLss87K"
3159 )),
3160 GlobalContractIdentifierView::CodeHash(_)
3161 );
3162 }
3163
3164 #[test]
3165 fn test_deserialize_global_contract_identifier_view_account_id_deprecated() {
3166 assert_matches!(
3167 deserialize_global_contract_identifier(json!("alice.near")),
3168 GlobalContractIdentifierView::AccountId(_)
3169 );
3170 }
3171
3172 #[test]
3173 fn test_deserialize_global_contract_identifier_view_hash() {
3174 assert_matches!(
3175 deserialize_global_contract_identifier(
3176 json!({ "hash": "9SP8Y3sVADWNN5QoEB5CsvPUE5HT4o8YfBaCnhLss87K" })
3177 ),
3178 GlobalContractIdentifierView::CodeHash(_)
3179 );
3180 }
3181
3182 #[test]
3183 fn test_deserialize_global_contract_identifier_view_account_id() {
3184 assert_matches!(
3185 deserialize_global_contract_identifier(json!({ "account_id": "alice.near" })),
3186 GlobalContractIdentifierView::AccountId(_)
3187 );
3188 }
3189
3190 #[test]
3191 fn test_serialize_global_contract_identifier_view_hash() {
3192 assert_eq!(
3193 serde_json::to_value(GlobalContractIdentifierView::CodeHash(CryptoHash::hash_bytes(
3194 b"42"
3195 )))
3196 .unwrap(),
3197 json!({ "hash": "8kzzuAWtRcnhd4SnD2zeEuieq5VtuA8nsNcBgzpRaLuE" })
3198 );
3199 }
3200
3201 #[test]
3202 fn test_serialize_global_contract_identifier_view_account_id() {
3203 assert_eq!(
3204 serde_json::to_value(GlobalContractIdentifierView::AccountId(
3205 "alice.near".parse().unwrap()
3206 ))
3207 .unwrap(),
3208 json!({ "account_id": "alice.near" })
3209 );
3210 }
3211
3212 fn deserialize_global_contract_identifier(
3213 json: serde_json::Value,
3214 ) -> GlobalContractIdentifierView {
3215 serde_json::from_value(json).unwrap()
3216 }
3217}