1use crate::account::{AccessKey, Account};
2use crate::errors::EpochError;
3use crate::hash::CryptoHash;
4use crate::serialize::dec_format;
5use crate::shard_layout::ShardLayout;
6use crate::trie_key::TrieKey;
7use borsh::{BorshDeserialize, BorshSerialize};
8pub use chunk_validator_stats::ChunkStats;
9use near_crypto::PublicKey;
10pub use near_primitives_core::types::*;
12use near_schema_checker_lib::ProtocolSchema;
13use serde_with::base64::Base64;
14use serde_with::serde_as;
15use std::sync::Arc;
16use std::sync::LazyLock;
17
18mod chunk_validator_stats;
19
20pub type StateRoot = CryptoHash;
22
23pub(crate) type SignatureDifferentiator = String;
30
31#[derive(
33 serde::Serialize, serde::Deserialize, Default, Clone, Debug, PartialEq, Eq, arbitrary::Arbitrary,
34)]
35#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
36pub enum Finality {
37 #[serde(rename = "optimistic")]
38 None,
39 #[serde(rename = "near-final")]
40 DoomSlug,
41 #[serde(rename = "final")]
42 #[default]
43 Final,
44}
45
46#[derive(Debug, serde::Serialize, serde::Deserialize)]
47#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
48pub struct AccountWithPublicKey {
49 pub account_id: AccountId,
50 pub public_key: PublicKey,
51}
52
53#[derive(serde::Serialize, serde::Deserialize, Clone, Debug, Eq, PartialEq)]
55#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
56pub struct AccountInfo {
57 pub account_id: AccountId,
58 pub public_key: PublicKey,
59 #[serde(with = "dec_format")]
60 #[cfg_attr(feature = "schemars", schemars(with = "String"))]
61 pub amount: Balance,
62}
63
64#[serde_as]
69#[derive(
70 serde::Serialize,
71 serde::Deserialize,
72 Clone,
73 Debug,
74 PartialEq,
75 Eq,
76 derive_more::Deref,
77 derive_more::From,
78 derive_more::Into,
79 BorshSerialize,
80 BorshDeserialize,
81)]
82#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
83#[serde(transparent)]
84pub struct StoreKey(
85 #[serde_as(as = "Base64")]
86 #[cfg_attr(feature = "schemars", schemars(schema_with = "crate::serialize::base64_schema"))]
87 Vec<u8>,
88);
89
90#[serde_as]
95#[derive(
96 serde::Serialize,
97 serde::Deserialize,
98 Clone,
99 Debug,
100 PartialEq,
101 Eq,
102 derive_more::Deref,
103 derive_more::From,
104 derive_more::Into,
105 BorshSerialize,
106 BorshDeserialize,
107)]
108#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
109#[serde(transparent)]
110pub struct StoreValue(
111 #[serde_as(as = "Base64")]
112 #[cfg_attr(feature = "schemars", schemars(schema_with = "crate::serialize::base64_schema"))]
113 Vec<u8>,
114);
115
116#[serde_as]
122#[derive(
123 serde::Serialize,
124 serde::Deserialize,
125 Clone,
126 Debug,
127 PartialEq,
128 Eq,
129 derive_more::Deref,
130 derive_more::From,
131 derive_more::Into,
132 BorshSerialize,
133 BorshDeserialize,
134)]
135#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
136#[serde(transparent)]
137pub struct FunctionArgs(
138 #[serde_as(as = "Base64")]
139 #[cfg_attr(feature = "schemars", schemars(schema_with = "crate::serialize::base64_schema"))]
140 Vec<u8>,
141);
142
143#[derive(Debug, Clone)]
145pub enum StateChangeKind {
146 AccountTouched { account_id: AccountId },
147 AccessKeyTouched { account_id: AccountId },
148 DataTouched { account_id: AccountId },
149 ContractCodeTouched { account_id: AccountId },
150}
151
152pub type StateChangesKinds = Vec<StateChangeKind>;
153
154#[easy_ext::ext(StateChangesKindsExt)]
155impl StateChangesKinds {
156 pub fn from_changes(
157 raw_changes: &mut dyn Iterator<Item = Result<RawStateChangesWithTrieKey, std::io::Error>>,
158 ) -> Result<StateChangesKinds, std::io::Error> {
159 raw_changes
160 .filter_map(|raw_change| {
161 let RawStateChangesWithTrieKey { trie_key, .. } = match raw_change {
162 Ok(p) => p,
163 Err(e) => return Some(Err(e)),
164 };
165 match trie_key {
166 TrieKey::Account { account_id } => {
167 Some(Ok(StateChangeKind::AccountTouched { account_id }))
168 }
169 TrieKey::ContractCode { account_id } => {
170 Some(Ok(StateChangeKind::ContractCodeTouched { account_id }))
171 }
172 TrieKey::AccessKey { account_id, .. } => {
173 Some(Ok(StateChangeKind::AccessKeyTouched { account_id }))
174 }
175 TrieKey::ContractData { account_id, .. } => {
176 Some(Ok(StateChangeKind::DataTouched { account_id }))
177 }
178 _ => None,
179 }
180 })
181 .collect()
182 }
183}
184
185#[derive(Debug, Clone, BorshSerialize, BorshDeserialize, PartialEq, ProtocolSchema)]
187pub enum StateChangeCause {
188 NotWritableToDisk,
192 InitialState,
195 TransactionProcessing { tx_hash: CryptoHash },
197 ActionReceiptProcessingStarted { receipt_hash: CryptoHash },
200 ActionReceiptGasReward { receipt_hash: CryptoHash },
202 ReceiptProcessing { receipt_hash: CryptoHash },
204 PostponedReceipt { receipt_hash: CryptoHash },
209 UpdatedDelayedReceipts,
212 ValidatorAccountsUpdate,
215 Migration,
218 _UnusedReshardingV2,
220 BandwidthSchedulerStateUpdate,
222}
223
224#[derive(Debug, Clone, BorshSerialize, BorshDeserialize, ProtocolSchema)]
226pub struct RawStateChange {
227 pub cause: StateChangeCause,
228 pub data: Option<Vec<u8>>,
229}
230
231#[derive(Debug, Clone, BorshSerialize, BorshDeserialize, ProtocolSchema)]
233pub struct RawStateChangesWithTrieKey {
234 pub trie_key: TrieKey,
235 pub changes: Vec<RawStateChange>,
236}
237
238#[derive(BorshSerialize, BorshDeserialize, Debug, Clone, ProtocolSchema)]
240pub struct ConsolidatedStateChange {
241 pub trie_key: TrieKey,
242 pub value: Option<Vec<u8>>,
243}
244
245pub type RawStateChanges = std::collections::BTreeMap<Vec<u8>, RawStateChangesWithTrieKey>;
247
248#[derive(Debug)]
249pub enum StateChangesRequest {
250 AccountChanges { account_ids: Vec<AccountId> },
251 SingleAccessKeyChanges { keys: Vec<AccountWithPublicKey> },
252 AllAccessKeyChanges { account_ids: Vec<AccountId> },
253 ContractCodeChanges { account_ids: Vec<AccountId> },
254 DataChanges { account_ids: Vec<AccountId>, key_prefix: StoreKey },
255}
256
257#[derive(Debug)]
258pub enum StateChangeValue {
259 AccountUpdate { account_id: AccountId, account: Account },
260 AccountDeletion { account_id: AccountId },
261 AccessKeyUpdate { account_id: AccountId, public_key: PublicKey, access_key: AccessKey },
262 AccessKeyDeletion { account_id: AccountId, public_key: PublicKey },
263 DataUpdate { account_id: AccountId, key: StoreKey, value: StoreValue },
264 DataDeletion { account_id: AccountId, key: StoreKey },
265 ContractCodeUpdate { account_id: AccountId, code: Vec<u8> },
266 ContractCodeDeletion { account_id: AccountId },
267}
268
269impl StateChangeValue {
270 pub fn affected_account_id(&self) -> &AccountId {
271 match &self {
272 StateChangeValue::AccountUpdate { account_id, .. }
273 | StateChangeValue::AccountDeletion { account_id }
274 | StateChangeValue::AccessKeyUpdate { account_id, .. }
275 | StateChangeValue::AccessKeyDeletion { account_id, .. }
276 | StateChangeValue::DataUpdate { account_id, .. }
277 | StateChangeValue::DataDeletion { account_id, .. }
278 | StateChangeValue::ContractCodeUpdate { account_id, .. }
279 | StateChangeValue::ContractCodeDeletion { account_id } => account_id,
280 }
281 }
282}
283
284#[derive(Debug)]
285pub struct StateChangeWithCause {
286 pub cause: StateChangeCause,
287 pub value: StateChangeValue,
288}
289
290pub type StateChanges = Vec<StateChangeWithCause>;
291
292#[easy_ext::ext(StateChangesExt)]
293impl StateChanges {
294 pub fn from_changes(
295 raw_changes: impl Iterator<Item = Result<RawStateChangesWithTrieKey, std::io::Error>>,
296 ) -> Result<StateChanges, std::io::Error> {
297 let mut state_changes = Self::new();
298
299 for raw_change in raw_changes {
300 let RawStateChangesWithTrieKey { trie_key, changes } = raw_change?;
301
302 match trie_key {
303 TrieKey::Account { account_id } => state_changes.extend(changes.into_iter().map(
304 |RawStateChange { cause, data }| StateChangeWithCause {
305 cause,
306 value: if let Some(change_data) = data {
307 StateChangeValue::AccountUpdate {
308 account_id: account_id.clone(),
309 account: <_>::try_from_slice(&change_data).expect(
310 "Failed to parse internally stored account information",
311 ),
312 }
313 } else {
314 StateChangeValue::AccountDeletion { account_id: account_id.clone() }
315 },
316 },
317 )),
318 TrieKey::AccessKey { account_id, public_key } => {
319 state_changes.extend(changes.into_iter().map(
320 |RawStateChange { cause, data }| StateChangeWithCause {
321 cause,
322 value: if let Some(change_data) = data {
323 StateChangeValue::AccessKeyUpdate {
324 account_id: account_id.clone(),
325 public_key: public_key.clone(),
326 access_key: <_>::try_from_slice(&change_data)
327 .expect("Failed to parse internally stored access key"),
328 }
329 } else {
330 StateChangeValue::AccessKeyDeletion {
331 account_id: account_id.clone(),
332 public_key: public_key.clone(),
333 }
334 },
335 },
336 ))
337 }
338 TrieKey::ContractCode { account_id } => {
339 state_changes.extend(changes.into_iter().map(
340 |RawStateChange { cause, data }| StateChangeWithCause {
341 cause,
342 value: match data {
343 Some(change_data) => StateChangeValue::ContractCodeUpdate {
344 account_id: account_id.clone(),
345 code: change_data,
346 },
347 None => StateChangeValue::ContractCodeDeletion {
348 account_id: account_id.clone(),
349 },
350 },
351 },
352 ));
353 }
354 TrieKey::ContractData { account_id, key } => {
355 state_changes.extend(changes.into_iter().map(
356 |RawStateChange { cause, data }| StateChangeWithCause {
357 cause,
358 value: if let Some(change_data) = data {
359 StateChangeValue::DataUpdate {
360 account_id: account_id.clone(),
361 key: key.to_vec().into(),
362 value: change_data.into(),
363 }
364 } else {
365 StateChangeValue::DataDeletion {
366 account_id: account_id.clone(),
367 key: key.to_vec().into(),
368 }
369 },
370 },
371 ));
372 }
373 TrieKey::ReceivedData { .. } => {}
375 TrieKey::PostponedReceiptId { .. } => {}
376 TrieKey::PendingDataCount { .. } => {}
377 TrieKey::PostponedReceipt { .. } => {}
378 TrieKey::DelayedReceiptIndices => {}
379 TrieKey::DelayedReceipt { .. } => {}
380 TrieKey::PromiseYieldIndices => {}
381 TrieKey::PromiseYieldTimeout { .. } => {}
382 TrieKey::PromiseYieldReceipt { .. } => {}
383 TrieKey::BufferedReceiptIndices => {}
384 TrieKey::BufferedReceipt { .. } => {}
385 TrieKey::BandwidthSchedulerState => {}
386 TrieKey::BufferedReceiptGroupsQueueData { .. } => {}
387 TrieKey::BufferedReceiptGroupsQueueItem { .. } => {}
388 TrieKey::GlobalContractCode { .. } => {}
390 }
391 }
392
393 Ok(state_changes)
394 }
395 pub fn from_account_changes(
396 raw_changes: impl Iterator<Item = Result<RawStateChangesWithTrieKey, std::io::Error>>,
397 ) -> Result<StateChanges, std::io::Error> {
398 let state_changes = Self::from_changes(raw_changes)?;
399
400 Ok(state_changes
401 .into_iter()
402 .filter(|state_change| {
403 matches!(
404 state_change.value,
405 StateChangeValue::AccountUpdate { .. }
406 | StateChangeValue::AccountDeletion { .. }
407 )
408 })
409 .collect())
410 }
411
412 pub fn from_access_key_changes(
413 raw_changes: impl Iterator<Item = Result<RawStateChangesWithTrieKey, std::io::Error>>,
414 ) -> Result<StateChanges, std::io::Error> {
415 let state_changes = Self::from_changes(raw_changes)?;
416
417 Ok(state_changes
418 .into_iter()
419 .filter(|state_change| {
420 matches!(
421 state_change.value,
422 StateChangeValue::AccessKeyUpdate { .. }
423 | StateChangeValue::AccessKeyDeletion { .. }
424 )
425 })
426 .collect())
427 }
428
429 pub fn from_contract_code_changes(
430 raw_changes: impl Iterator<Item = Result<RawStateChangesWithTrieKey, std::io::Error>>,
431 ) -> Result<StateChanges, std::io::Error> {
432 let state_changes = Self::from_changes(raw_changes)?;
433
434 Ok(state_changes
435 .into_iter()
436 .filter(|state_change| {
437 matches!(
438 state_change.value,
439 StateChangeValue::ContractCodeUpdate { .. }
440 | StateChangeValue::ContractCodeDeletion { .. }
441 )
442 })
443 .collect())
444 }
445
446 pub fn from_data_changes(
447 raw_changes: impl Iterator<Item = Result<RawStateChangesWithTrieKey, std::io::Error>>,
448 ) -> Result<StateChanges, std::io::Error> {
449 let state_changes = Self::from_changes(raw_changes)?;
450
451 Ok(state_changes
452 .into_iter()
453 .filter(|state_change| {
454 matches!(
455 state_change.value,
456 StateChangeValue::DataUpdate { .. } | StateChangeValue::DataDeletion { .. }
457 )
458 })
459 .collect())
460 }
461}
462
463#[derive(
464 PartialEq, Eq, Clone, Debug, BorshSerialize, BorshDeserialize, serde::Serialize, ProtocolSchema,
465)]
466pub struct StateRootNode {
467 pub data: Arc<[u8]>,
473
474 pub memory_usage: u64,
476}
477
478impl StateRootNode {
479 pub fn empty() -> Self {
480 static EMPTY: LazyLock<Arc<[u8]>> = LazyLock::new(|| Arc::new([]));
481 StateRootNode { data: EMPTY.clone(), memory_usage: 0 }
482 }
483}
484
485#[derive(
489 Debug,
490 Clone,
491 Copy,
492 Default,
493 Hash,
494 Eq,
495 PartialEq,
496 PartialOrd,
497 Ord,
498 derive_more::AsRef,
499 BorshSerialize,
500 BorshDeserialize,
501 serde::Serialize,
502 serde::Deserialize,
503 arbitrary::Arbitrary,
504 ProtocolSchema,
505)]
506#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
507#[as_ref(forward)]
508pub struct EpochId(pub CryptoHash);
509
510impl std::str::FromStr for EpochId {
511 type Err = Box<dyn std::error::Error + Send + Sync>;
512
513 fn from_str(epoch_id_str: &str) -> Result<Self, Self::Err> {
515 Ok(EpochId(CryptoHash::from_str(epoch_id_str)?))
516 }
517}
518
519#[derive(serde::Serialize, Debug, Clone, PartialEq, Eq)]
523pub struct ApprovalStake {
524 pub account_id: AccountId,
526 pub public_key: PublicKey,
528 pub stake_this_epoch: Balance,
530 pub stake_next_epoch: Balance,
531}
532
533pub mod validator_stake {
534 use crate::types::ApprovalStake;
535 use borsh::{BorshDeserialize, BorshSerialize};
536 use near_crypto::{KeyType, PublicKey};
537 use near_primitives_core::types::{AccountId, Balance};
538 use serde::Serialize;
539
540 pub use super::ValidatorStakeV1;
541
542 #[derive(BorshSerialize, BorshDeserialize, Serialize, Debug, Clone, PartialEq, Eq)]
544 #[serde(tag = "validator_stake_struct_version")]
545 pub enum ValidatorStake {
546 V1(ValidatorStakeV1),
547 }
553
554 pub struct ValidatorStakeIter<'a> {
555 collection: ValidatorStakeIterSource<'a>,
556 curr_index: usize,
557 len: usize,
558 }
559
560 impl<'a> ValidatorStakeIter<'a> {
561 pub fn empty() -> Self {
562 Self { collection: ValidatorStakeIterSource::V2(&[]), curr_index: 0, len: 0 }
563 }
564
565 pub fn v1(collection: &'a [ValidatorStakeV1]) -> Self {
566 Self {
567 collection: ValidatorStakeIterSource::V1(collection),
568 curr_index: 0,
569 len: collection.len(),
570 }
571 }
572
573 pub fn new(collection: &'a [ValidatorStake]) -> Self {
574 Self {
575 collection: ValidatorStakeIterSource::V2(collection),
576 curr_index: 0,
577 len: collection.len(),
578 }
579 }
580
581 pub fn len(&self) -> usize {
582 self.len
583 }
584 }
585
586 impl<'a> Iterator for ValidatorStakeIter<'a> {
587 type Item = ValidatorStake;
588
589 fn next(&mut self) -> Option<Self::Item> {
590 if self.curr_index < self.len {
591 let item = match self.collection {
592 ValidatorStakeIterSource::V1(collection) => {
593 ValidatorStake::V1(collection[self.curr_index].clone())
594 }
595 ValidatorStakeIterSource::V2(collection) => collection[self.curr_index].clone(),
596 };
597 self.curr_index += 1;
598 Some(item)
599 } else {
600 None
601 }
602 }
603 }
604
605 enum ValidatorStakeIterSource<'a> {
606 V1(&'a [ValidatorStakeV1]),
607 V2(&'a [ValidatorStake]),
608 }
609
610 impl ValidatorStake {
611 pub fn new_v1(account_id: AccountId, public_key: PublicKey, stake: Balance) -> Self {
612 Self::V1(ValidatorStakeV1 { account_id, public_key, stake })
613 }
614
615 pub fn new(account_id: AccountId, public_key: PublicKey, stake: Balance) -> Self {
616 Self::new_v1(account_id, public_key, stake)
617 }
618
619 pub fn test(account_id: AccountId) -> Self {
620 Self::new_v1(account_id, PublicKey::empty(KeyType::ED25519), 0)
621 }
622
623 pub fn into_v1(self) -> ValidatorStakeV1 {
624 match self {
625 Self::V1(v1) => v1,
626 }
627 }
628
629 #[inline]
630 pub fn account_and_stake(self) -> (AccountId, Balance) {
631 match self {
632 Self::V1(v1) => (v1.account_id, v1.stake),
633 }
634 }
635
636 #[inline]
637 pub fn destructure(self) -> (AccountId, PublicKey, Balance) {
638 match self {
639 Self::V1(v1) => (v1.account_id, v1.public_key, v1.stake),
640 }
641 }
642
643 #[inline]
644 pub fn take_account_id(self) -> AccountId {
645 match self {
646 Self::V1(v1) => v1.account_id,
647 }
648 }
649
650 #[inline]
651 pub fn account_id(&self) -> &AccountId {
652 match self {
653 Self::V1(v1) => &v1.account_id,
654 }
655 }
656
657 #[inline]
658 pub fn take_public_key(self) -> PublicKey {
659 match self {
660 Self::V1(v1) => v1.public_key,
661 }
662 }
663
664 #[inline]
665 pub fn public_key(&self) -> &PublicKey {
666 match self {
667 Self::V1(v1) => &v1.public_key,
668 }
669 }
670
671 #[inline]
672 pub fn stake(&self) -> Balance {
673 match self {
674 Self::V1(v1) => v1.stake,
675 }
676 }
677
678 #[inline]
679 pub fn stake_mut(&mut self) -> &mut Balance {
680 match self {
681 Self::V1(v1) => &mut v1.stake,
682 }
683 }
684
685 pub fn get_approval_stake(&self, is_next_epoch: bool) -> ApprovalStake {
686 ApprovalStake {
687 account_id: self.account_id().clone(),
688 public_key: self.public_key().clone(),
689 stake_this_epoch: if is_next_epoch { 0 } else { self.stake() },
690 stake_next_epoch: if is_next_epoch { self.stake() } else { 0 },
691 }
692 }
693
694 pub fn num_mandates(&self, stake_per_mandate: Balance) -> u16 {
715 u16::try_from(self.stake() / stake_per_mandate)
718 .expect("number of mandates should fit u16")
719 }
720
721 pub fn partial_mandate_weight(&self, stake_per_mandate: Balance) -> Balance {
735 self.stake() % stake_per_mandate
736 }
737 }
738}
739
740#[derive(
742 BorshSerialize, BorshDeserialize, serde::Serialize, Debug, Clone, PartialEq, Eq, ProtocolSchema,
743)]
744pub struct ValidatorStakeV1 {
745 pub account_id: AccountId,
747 pub public_key: PublicKey,
749 pub stake: Balance,
751}
752
753pub mod chunk_extra {
754 use crate::bandwidth_scheduler::BandwidthRequests;
755 use crate::congestion_info::CongestionInfo;
756 use crate::types::StateRoot;
757 use crate::types::validator_stake::{ValidatorStake, ValidatorStakeIter};
758 use borsh::{BorshDeserialize, BorshSerialize};
759 use near_primitives_core::hash::CryptoHash;
760 use near_primitives_core::types::{Balance, Gas};
761
762 pub use super::ChunkExtraV1;
763
764 #[derive(Debug, PartialEq, BorshSerialize, BorshDeserialize, Clone, Eq, serde::Serialize)]
766 pub enum ChunkExtra {
767 V1(ChunkExtraV1),
768 V2(ChunkExtraV2),
769 V3(ChunkExtraV3),
770 V4(ChunkExtraV4),
771 }
772
773 #[derive(Debug, PartialEq, BorshSerialize, BorshDeserialize, Clone, Eq, serde::Serialize)]
774 pub struct ChunkExtraV2 {
775 pub state_root: StateRoot,
777 pub outcome_root: CryptoHash,
779 pub validator_proposals: Vec<ValidatorStake>,
781 pub gas_used: Gas,
783 pub gas_limit: Gas,
785 pub balance_burnt: Balance,
787 }
788
789 #[derive(Debug, PartialEq, BorshSerialize, BorshDeserialize, Clone, Eq, serde::Serialize)]
791 pub struct ChunkExtraV3 {
792 pub state_root: StateRoot,
794 pub outcome_root: CryptoHash,
796 pub validator_proposals: Vec<ValidatorStake>,
798 pub gas_used: Gas,
800 pub gas_limit: Gas,
802 pub balance_burnt: Balance,
804 congestion_info: CongestionInfo,
806 }
807
808 #[derive(Debug, PartialEq, BorshSerialize, BorshDeserialize, Clone, Eq, serde::Serialize)]
810 pub struct ChunkExtraV4 {
811 pub state_root: StateRoot,
813 pub outcome_root: CryptoHash,
815 pub validator_proposals: Vec<ValidatorStake>,
817 pub gas_used: Gas,
819 pub gas_limit: Gas,
821 pub balance_burnt: Balance,
823 congestion_info: CongestionInfo,
825 pub bandwidth_requests: BandwidthRequests,
827 }
828
829 impl ChunkExtra {
830 pub fn new_with_only_state_root(state_root: &StateRoot) -> Self {
834 let congestion_control = Some(CongestionInfo::default());
836 Self::new(
837 state_root,
838 CryptoHash::default(),
839 vec![],
840 0,
841 0,
842 0,
843 congestion_control,
844 BandwidthRequests::empty(),
845 )
846 }
847
848 pub fn new(
849 state_root: &StateRoot,
850 outcome_root: CryptoHash,
851 validator_proposals: Vec<ValidatorStake>,
852 gas_used: Gas,
853 gas_limit: Gas,
854 balance_burnt: Balance,
855 congestion_info: Option<CongestionInfo>,
856 bandwidth_requests: BandwidthRequests,
857 ) -> Self {
858 Self::V4(ChunkExtraV4 {
859 state_root: *state_root,
860 outcome_root,
861 validator_proposals,
862 gas_used,
863 gas_limit,
864 balance_burnt,
865 congestion_info: congestion_info.unwrap(),
866 bandwidth_requests,
867 })
868 }
869
870 #[inline]
871 pub fn outcome_root(&self) -> &StateRoot {
872 match self {
873 Self::V1(v1) => &v1.outcome_root,
874 Self::V2(v2) => &v2.outcome_root,
875 Self::V3(v3) => &v3.outcome_root,
876 Self::V4(v4) => &v4.outcome_root,
877 }
878 }
879
880 #[inline]
881 pub fn state_root(&self) -> &StateRoot {
882 match self {
883 Self::V1(v1) => &v1.state_root,
884 Self::V2(v2) => &v2.state_root,
885 Self::V3(v3) => &v3.state_root,
886 Self::V4(v4) => &v4.state_root,
887 }
888 }
889
890 #[inline]
891 pub fn state_root_mut(&mut self) -> &mut StateRoot {
892 match self {
893 Self::V1(v1) => &mut v1.state_root,
894 Self::V2(v2) => &mut v2.state_root,
895 Self::V3(v3) => &mut v3.state_root,
896 Self::V4(v4) => &mut v4.state_root,
897 }
898 }
899
900 #[inline]
901 pub fn validator_proposals(&self) -> ValidatorStakeIter {
902 match self {
903 Self::V1(v1) => ValidatorStakeIter::v1(&v1.validator_proposals),
904 Self::V2(v2) => ValidatorStakeIter::new(&v2.validator_proposals),
905 Self::V3(v3) => ValidatorStakeIter::new(&v3.validator_proposals),
906 Self::V4(v4) => ValidatorStakeIter::new(&v4.validator_proposals),
907 }
908 }
909
910 #[inline]
911 pub fn gas_limit(&self) -> Gas {
912 match self {
913 Self::V1(v1) => v1.gas_limit,
914 Self::V2(v2) => v2.gas_limit,
915 Self::V3(v3) => v3.gas_limit,
916 Self::V4(v4) => v4.gas_limit,
917 }
918 }
919
920 #[inline]
921 pub fn gas_used(&self) -> Gas {
922 match self {
923 Self::V1(v1) => v1.gas_used,
924 Self::V2(v2) => v2.gas_used,
925 Self::V3(v3) => v3.gas_used,
926 Self::V4(v4) => v4.gas_used,
927 }
928 }
929
930 #[inline]
931 pub fn balance_burnt(&self) -> Balance {
932 match self {
933 Self::V1(v1) => v1.balance_burnt,
934 Self::V2(v2) => v2.balance_burnt,
935 Self::V3(v3) => v3.balance_burnt,
936 Self::V4(v4) => v4.balance_burnt,
937 }
938 }
939
940 #[inline]
941 pub fn congestion_info(&self) -> CongestionInfo {
942 match self {
943 Self::V1(_) | Self::V2(_) => {
944 debug_assert!(false, "Calling congestion_info on V1 or V2 header version");
945 Default::default()
946 }
947 Self::V3(v3) => v3.congestion_info,
948 Self::V4(v4) => v4.congestion_info,
949 }
950 }
951
952 #[inline]
953 pub fn congestion_info_mut(&mut self) -> &mut CongestionInfo {
954 match self {
955 Self::V1(_) | Self::V2(_) => panic!("Calling congestion_info_mut on V1 or V2"),
956 Self::V3(v3) => &mut v3.congestion_info,
957 Self::V4(v4) => &mut v4.congestion_info,
958 }
959 }
960
961 #[inline]
962 pub fn bandwidth_requests(&self) -> Option<&BandwidthRequests> {
963 match self {
964 Self::V1(_) | Self::V2(_) | Self::V3(_) => None,
965 Self::V4(extra) => Some(&extra.bandwidth_requests),
966 }
967 }
968 }
969}
970
971#[derive(
973 Debug, PartialEq, BorshSerialize, BorshDeserialize, Clone, Eq, ProtocolSchema, serde::Serialize,
974)]
975pub struct ChunkExtraV1 {
976 pub state_root: StateRoot,
978 pub outcome_root: CryptoHash,
980 pub validator_proposals: Vec<ValidatorStakeV1>,
982 pub gas_used: Gas,
984 pub gas_limit: Gas,
986 pub balance_burnt: Balance,
988}
989
990#[derive(
991 Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize, arbitrary::Arbitrary,
992)]
993#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
994#[serde(untagged)]
995pub enum BlockId {
996 Height(BlockHeight),
997 Hash(CryptoHash),
998}
999
1000pub type MaybeBlockId = Option<BlockId>;
1001
1002#[derive(
1003 Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize, arbitrary::Arbitrary,
1004)]
1005#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1006#[serde(rename_all = "snake_case")]
1007pub enum SyncCheckpoint {
1008 Genesis,
1009 EarliestAvailable,
1010}
1011
1012#[derive(
1013 Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize, arbitrary::Arbitrary,
1014)]
1015#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1016#[serde(rename_all = "snake_case")]
1017pub enum BlockReference {
1018 BlockId(BlockId),
1019 Finality(Finality),
1020 SyncCheckpoint(SyncCheckpoint),
1021}
1022
1023impl BlockReference {
1024 pub fn latest() -> Self {
1025 Self::Finality(Finality::None)
1026 }
1027}
1028
1029impl From<BlockId> for BlockReference {
1030 fn from(block_id: BlockId) -> Self {
1031 Self::BlockId(block_id)
1032 }
1033}
1034
1035impl From<Finality> for BlockReference {
1036 fn from(finality: Finality) -> Self {
1037 Self::Finality(finality)
1038 }
1039}
1040
1041#[derive(
1042 Default,
1043 BorshSerialize,
1044 BorshDeserialize,
1045 Clone,
1046 Debug,
1047 PartialEq,
1048 Eq,
1049 ProtocolSchema,
1050 serde::Serialize,
1051)]
1052pub struct ValidatorStats {
1053 pub produced: NumBlocks,
1054 pub expected: NumBlocks,
1055}
1056
1057impl ValidatorStats {
1058 pub fn less_than(&self, threshold: u8) -> bool {
1061 self.produced * 100 < u64::from(threshold) * self.expected
1062 }
1063}
1064
1065#[derive(Debug, BorshSerialize, BorshDeserialize, PartialEq, Eq, ProtocolSchema)]
1066pub struct BlockChunkValidatorStats {
1067 pub block_stats: ValidatorStats,
1068 pub chunk_stats: ChunkStats,
1069}
1070
1071#[derive(serde::Deserialize, Debug, arbitrary::Arbitrary, PartialEq, Eq)]
1072#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1073#[serde(rename_all = "snake_case")]
1074pub enum EpochReference {
1075 EpochId(EpochId),
1076 BlockId(BlockId),
1077 Latest,
1078}
1079
1080impl serde::Serialize for EpochReference {
1081 fn serialize<S>(&self, s: S) -> Result<S::Ok, S::Error>
1082 where
1083 S: serde::Serializer,
1084 {
1085 match self {
1087 EpochReference::EpochId(epoch_id) => {
1088 s.serialize_newtype_variant("EpochReference", 0, "epoch_id", epoch_id)
1089 }
1090 EpochReference::BlockId(block_id) => {
1091 s.serialize_newtype_variant("EpochReference", 1, "block_id", block_id)
1092 }
1093 EpochReference::Latest => {
1094 s.serialize_newtype_variant("EpochReference", 2, "latest", &())
1095 }
1096 }
1097 }
1098}
1099
1100#[derive(Clone, Debug)]
1106pub enum ValidatorInfoIdentifier {
1107 EpochId(EpochId),
1108 BlockHash(CryptoHash),
1109}
1110
1111#[derive(
1113 BorshSerialize,
1114 BorshDeserialize,
1115 serde::Serialize,
1116 serde::Deserialize,
1117 Clone,
1118 Debug,
1119 PartialEq,
1120 Eq,
1121 ProtocolSchema,
1122)]
1123#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1124pub enum ValidatorKickoutReason {
1125 _UnusedSlashed,
1127 NotEnoughBlocks { produced: NumBlocks, expected: NumBlocks },
1129 NotEnoughChunks { produced: NumBlocks, expected: NumBlocks },
1131 Unstaked,
1133 NotEnoughStake {
1135 #[serde(with = "dec_format", rename = "stake_u128")]
1136 #[cfg_attr(feature = "schemars", schemars(with = "String"))]
1137 stake: Balance,
1138 #[serde(with = "dec_format", rename = "threshold_u128")]
1139 #[cfg_attr(feature = "schemars", schemars(with = "String"))]
1140 threshold: Balance,
1141 },
1142 DidNotGetASeat,
1144 NotEnoughChunkEndorsements { produced: NumBlocks, expected: NumBlocks },
1146 ProtocolVersionTooOld { version: ProtocolVersion, network_version: ProtocolVersion },
1149}
1150
1151#[derive(serde::Serialize, serde::Deserialize, Clone, Debug)]
1152#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1153#[serde(tag = "type", rename_all = "snake_case")]
1154pub enum TransactionOrReceiptId {
1155 Transaction { transaction_hash: CryptoHash, sender_id: AccountId },
1156 Receipt { receipt_id: CryptoHash, receiver_id: AccountId },
1157}
1158
1159pub trait EpochInfoProvider: Send + Sync {
1162 fn validator_stake(
1165 &self,
1166 epoch_id: &EpochId,
1167 account_id: &AccountId,
1168 ) -> Result<Option<Balance>, EpochError>;
1169
1170 fn validator_total_stake(&self, epoch_id: &EpochId) -> Result<Balance, EpochError>;
1172
1173 fn minimum_stake(&self, prev_block_hash: &CryptoHash) -> Result<Balance, EpochError>;
1174
1175 fn chain_id(&self) -> String;
1177
1178 fn shard_layout(&self, epoch_id: &EpochId) -> Result<ShardLayout, EpochError>;
1179}
1180
1181#[derive(borsh::BorshDeserialize, borsh::BorshSerialize)]
1184pub struct StateChangesForBlockRange {
1185 pub blocks: Vec<StateChangesForBlock>,
1186}
1187
1188#[derive(borsh::BorshDeserialize, borsh::BorshSerialize)]
1191pub struct StateChangesForBlock {
1192 pub block_hash: CryptoHash,
1193 pub state_changes: Vec<StateChangesForShard>,
1194}
1195
1196#[derive(borsh::BorshDeserialize, borsh::BorshSerialize)]
1198pub struct StateChangesForShard {
1199 pub shard_id: ShardId,
1200 pub state_changes: Vec<RawStateChangesWithTrieKey>,
1201}
1202
1203#[cfg(test)]
1204mod tests {
1205 use near_crypto::{KeyType, PublicKey};
1206 use near_primitives_core::types::Balance;
1207
1208 use super::validator_stake::ValidatorStake;
1209
1210 fn new_validator_stake(stake: Balance) -> ValidatorStake {
1211 ValidatorStake::new(
1212 "test_account".parse().unwrap(),
1213 PublicKey::empty(KeyType::ED25519),
1214 stake,
1215 )
1216 }
1217
1218 #[test]
1219 fn test_validator_stake_num_mandates() {
1220 assert_eq!(new_validator_stake(0).num_mandates(5), 0);
1221 assert_eq!(new_validator_stake(10).num_mandates(5), 2);
1222 assert_eq!(new_validator_stake(12).num_mandates(5), 2);
1223 }
1224
1225 #[test]
1226 fn test_validator_partial_mandate_weight() {
1227 assert_eq!(new_validator_stake(0).partial_mandate_weight(5), 0);
1228 assert_eq!(new_validator_stake(10).partial_mandate_weight(5), 0);
1229 assert_eq!(new_validator_stake(12).partial_mandate_weight(5), 2);
1230 }
1231}