1use crate::account::{AccessKey, Account};
2use crate::errors::EpochError;
3use crate::hash::CryptoHash;
4use crate::shard_layout::ShardLayout;
5use crate::stateless_validation::spice_chunk_endorsement::SpiceStoredVerifiedEndorsement;
6use crate::trie_key::TrieKey;
7use borsh::{BorshDeserialize, BorshSerialize};
8pub use chunk_validator_stats::ChunkStats;
9use near_crypto::PublicKey;
10use near_primitives_core::account::GasKey;
11use near_primitives_core::hash::hash;
12pub use near_primitives_core::types::*;
14use near_schema_checker_lib::ProtocolSchema;
15use serde_with::base64::Base64;
16use serde_with::serde_as;
17use std::collections::HashMap;
18use std::sync::Arc;
19use std::sync::LazyLock;
20
21use self::chunk_extra::ChunkExtra;
22
23mod chunk_validator_stats;
24
25pub type StateRoot = CryptoHash;
27
28pub(crate) type SignatureDifferentiator = String;
35pub(crate) type StaticSignatureDifferentiator = &'static str;
36
37#[derive(
39 serde::Serialize, serde::Deserialize, Default, Clone, Debug, PartialEq, Eq, arbitrary::Arbitrary,
40)]
41#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
42pub enum Finality {
43 #[serde(rename = "optimistic")]
44 None,
45 #[serde(rename = "near-final")]
46 DoomSlug,
47 #[serde(rename = "final")]
48 #[default]
49 Final,
50}
51
52#[derive(Debug, serde::Serialize, serde::Deserialize)]
54#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
55pub struct AccountWithPublicKey {
56 pub account_id: AccountId,
57 pub public_key: PublicKey,
58}
59
60#[derive(serde::Serialize, serde::Deserialize, Clone, Debug, Eq, PartialEq)]
62#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
63pub struct AccountInfo {
64 pub account_id: AccountId,
65 pub public_key: PublicKey,
66 pub amount: Balance,
67}
68
69#[serde_as]
74#[derive(
75 serde::Serialize,
76 serde::Deserialize,
77 Clone,
78 Debug,
79 PartialEq,
80 Eq,
81 derive_more::Deref,
82 derive_more::From,
83 derive_more::Into,
84 BorshSerialize,
85 BorshDeserialize,
86)]
87#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
88#[serde(transparent)]
89pub struct StoreKey(
90 #[serde_as(as = "Base64")]
91 #[cfg_attr(feature = "schemars", schemars(schema_with = "crate::serialize::base64_schema"))]
92 Vec<u8>,
93);
94
95#[serde_as]
100#[derive(
101 serde::Serialize,
102 serde::Deserialize,
103 Clone,
104 Debug,
105 PartialEq,
106 Eq,
107 derive_more::Deref,
108 derive_more::From,
109 derive_more::Into,
110 BorshSerialize,
111 BorshDeserialize,
112)]
113#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
114#[serde(transparent)]
115pub struct StoreValue(
116 #[serde_as(as = "Base64")]
117 #[cfg_attr(feature = "schemars", schemars(schema_with = "crate::serialize::base64_schema"))]
118 Vec<u8>,
119);
120
121#[serde_as]
127#[derive(
128 serde::Serialize,
129 serde::Deserialize,
130 Clone,
131 Debug,
132 PartialEq,
133 Eq,
134 derive_more::Deref,
135 derive_more::From,
136 derive_more::Into,
137 BorshSerialize,
138 BorshDeserialize,
139)]
140#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
141#[serde(transparent)]
142pub struct FunctionArgs(
143 #[serde_as(as = "Base64")]
144 #[cfg_attr(feature = "schemars", schemars(schema_with = "crate::serialize::base64_schema"))]
145 Vec<u8>,
146);
147
148#[derive(Debug, Clone)]
150pub enum StateChangeKind {
151 AccountTouched { account_id: AccountId },
152 AccessKeyTouched { account_id: AccountId },
153 DataTouched { account_id: AccountId },
154 ContractCodeTouched { account_id: AccountId },
155}
156
157pub type StateChangesKinds = Vec<StateChangeKind>;
158
159#[easy_ext::ext(StateChangesKindsExt)]
160impl StateChangesKinds {
161 pub fn from_changes(
162 raw_changes: &mut dyn Iterator<Item = Result<RawStateChangesWithTrieKey, std::io::Error>>,
163 ) -> Result<StateChangesKinds, std::io::Error> {
164 raw_changes
165 .filter_map(|raw_change| {
166 let RawStateChangesWithTrieKey { trie_key, .. } = match raw_change {
167 Ok(p) => p,
168 Err(e) => return Some(Err(e)),
169 };
170 match trie_key {
171 TrieKey::Account { account_id } => {
172 Some(Ok(StateChangeKind::AccountTouched { account_id }))
173 }
174 TrieKey::ContractCode { account_id } => {
175 Some(Ok(StateChangeKind::ContractCodeTouched { account_id }))
176 }
177 TrieKey::AccessKey { account_id, .. } => {
178 Some(Ok(StateChangeKind::AccessKeyTouched { account_id }))
179 }
180 TrieKey::ContractData { account_id, .. } => {
181 Some(Ok(StateChangeKind::DataTouched { account_id }))
182 }
183 _ => None,
184 }
185 })
186 .collect()
187 }
188}
189
190#[derive(Debug, Clone, BorshSerialize, BorshDeserialize, PartialEq, ProtocolSchema)]
192#[borsh(use_discriminant = true)]
193#[repr(u8)]
194pub enum StateChangeCause {
195 NotWritableToDisk = 0,
199 InitialState = 1,
202 TransactionProcessing { tx_hash: CryptoHash } = 2,
204 ActionReceiptProcessingStarted { receipt_hash: CryptoHash } = 3,
207 ActionReceiptGasReward { receipt_hash: CryptoHash } = 4,
209 ReceiptProcessing { receipt_hash: CryptoHash } = 5,
211 PostponedReceipt { receipt_hash: CryptoHash } = 6,
216 UpdatedDelayedReceipts = 7,
219 ValidatorAccountsUpdate = 8,
222 Migration = 9,
225 _UnusedReshardingV2 = 10,
227 BandwidthSchedulerStateUpdate = 11,
229}
230
231#[derive(Debug, Clone, BorshSerialize, BorshDeserialize, ProtocolSchema)]
233pub struct RawStateChange {
234 pub cause: StateChangeCause,
235 pub data: Option<Vec<u8>>,
236}
237
238#[derive(Debug, Clone, BorshSerialize, BorshDeserialize, ProtocolSchema)]
240pub struct RawStateChangesWithTrieKey {
241 pub trie_key: TrieKey,
242 pub changes: Vec<RawStateChange>,
243}
244
245#[derive(BorshSerialize, BorshDeserialize, Debug, Clone, ProtocolSchema)]
247pub struct ConsolidatedStateChange {
248 pub trie_key: TrieKey,
249 pub value: Option<Vec<u8>>,
250}
251
252pub type RawStateChanges = std::collections::BTreeMap<Vec<u8>, RawStateChangesWithTrieKey>;
254
255#[derive(Debug)]
256pub enum StateChangesRequest {
257 AccountChanges { account_ids: Vec<AccountId> },
258 SingleAccessKeyChanges { keys: Vec<AccountWithPublicKey> },
259 SingleGasKeyChanges { keys: Vec<AccountWithPublicKey> },
260 AllAccessKeyChanges { account_ids: Vec<AccountId> },
261 AllGasKeyChanges { account_ids: Vec<AccountId> },
262 ContractCodeChanges { account_ids: Vec<AccountId> },
263 DataChanges { account_ids: Vec<AccountId>, key_prefix: StoreKey },
264}
265
266#[derive(Debug)]
267pub enum StateChangeValue {
268 AccountUpdate { account_id: AccountId, account: Account },
269 AccountDeletion { account_id: AccountId },
270 AccessKeyUpdate { account_id: AccountId, public_key: PublicKey, access_key: AccessKey },
271 AccessKeyDeletion { account_id: AccountId, public_key: PublicKey },
272 GasKeyUpdate { account_id: AccountId, public_key: PublicKey, gas_key: GasKey },
273 GasKeyNonceUpdate { account_id: AccountId, public_key: PublicKey, index: u32, nonce: u64 },
274 GasKeyDeletion { account_id: AccountId, public_key: PublicKey },
275 DataUpdate { account_id: AccountId, key: StoreKey, value: StoreValue },
276 DataDeletion { account_id: AccountId, key: StoreKey },
277 ContractCodeUpdate { account_id: AccountId, code: Vec<u8> },
278 ContractCodeDeletion { account_id: AccountId },
279}
280
281impl StateChangeValue {
282 pub fn affected_account_id(&self) -> &AccountId {
283 match &self {
284 StateChangeValue::AccountUpdate { account_id, .. }
285 | StateChangeValue::AccountDeletion { account_id }
286 | StateChangeValue::AccessKeyUpdate { account_id, .. }
287 | StateChangeValue::AccessKeyDeletion { account_id, .. }
288 | StateChangeValue::GasKeyUpdate { account_id, .. }
289 | StateChangeValue::GasKeyNonceUpdate { account_id, .. }
290 | StateChangeValue::GasKeyDeletion { account_id, .. }
291 | StateChangeValue::DataUpdate { account_id, .. }
292 | StateChangeValue::DataDeletion { account_id, .. }
293 | StateChangeValue::ContractCodeUpdate { account_id, .. }
294 | StateChangeValue::ContractCodeDeletion { account_id } => account_id,
295 }
296 }
297}
298
299#[derive(Debug)]
300pub struct StateChangeWithCause {
301 pub cause: StateChangeCause,
302 pub value: StateChangeValue,
303}
304
305pub type StateChanges = Vec<StateChangeWithCause>;
306
307#[easy_ext::ext(StateChangesExt)]
308impl StateChanges {
309 pub fn from_changes(
310 raw_changes: impl Iterator<Item = Result<RawStateChangesWithTrieKey, std::io::Error>>,
311 ) -> Result<StateChanges, std::io::Error> {
312 let mut state_changes = Self::new();
313
314 for raw_change in raw_changes {
315 let RawStateChangesWithTrieKey { trie_key, changes } = raw_change?;
316
317 match trie_key {
318 TrieKey::Account { account_id } => state_changes.extend(changes.into_iter().map(
319 |RawStateChange { cause, data }| StateChangeWithCause {
320 cause,
321 value: if let Some(change_data) = data {
322 StateChangeValue::AccountUpdate {
323 account_id: account_id.clone(),
324 account: <_>::try_from_slice(&change_data).expect(
325 "Failed to parse internally stored account information",
326 ),
327 }
328 } else {
329 StateChangeValue::AccountDeletion { account_id: account_id.clone() }
330 },
331 },
332 )),
333 TrieKey::AccessKey { account_id, public_key } => {
334 state_changes.extend(changes.into_iter().map(
335 |RawStateChange { cause, data }| StateChangeWithCause {
336 cause,
337 value: if let Some(change_data) = data {
338 StateChangeValue::AccessKeyUpdate {
339 account_id: account_id.clone(),
340 public_key: public_key.clone(),
341 access_key: <_>::try_from_slice(&change_data)
342 .expect("Failed to parse internally stored access key"),
343 }
344 } else {
345 StateChangeValue::AccessKeyDeletion {
346 account_id: account_id.clone(),
347 public_key: public_key.clone(),
348 }
349 },
350 },
351 ))
352 }
353 TrieKey::GasKey { account_id, public_key, index } => {
354 if let Some(index) = index {
355 state_changes.extend(changes.into_iter().filter_map(
356 |RawStateChange { cause, data }| {
357 if let Some(change_data) = data {
358 Some(StateChangeWithCause {
359 cause,
360 value: StateChangeValue::GasKeyNonceUpdate {
361 account_id: account_id.clone(),
362 public_key: public_key.clone(),
363 index,
364 nonce: <_>::try_from_slice(&change_data).expect(
365 "Failed to parse internally stored gas key nonce",
366 ),
367 },
368 })
369 } else {
370 None
373 }
374 },
375 ));
376 } else {
377 state_changes.extend(changes.into_iter().map(
378 |RawStateChange { cause, data }| StateChangeWithCause {
379 cause,
380 value: if let Some(change_data) = data {
381 StateChangeValue::GasKeyUpdate {
382 account_id: account_id.clone(),
383 public_key: public_key.clone(),
384 gas_key: <_>::try_from_slice(&change_data)
385 .expect("Failed to parse internally stored gas key"),
386 }
387 } else {
388 StateChangeValue::GasKeyDeletion {
389 account_id: account_id.clone(),
390 public_key: public_key.clone(),
391 }
392 },
393 },
394 ));
395 }
396 }
397 TrieKey::ContractCode { account_id } => {
398 state_changes.extend(changes.into_iter().map(
399 |RawStateChange { cause, data }| StateChangeWithCause {
400 cause,
401 value: match data {
402 Some(change_data) => StateChangeValue::ContractCodeUpdate {
403 account_id: account_id.clone(),
404 code: change_data,
405 },
406 None => StateChangeValue::ContractCodeDeletion {
407 account_id: account_id.clone(),
408 },
409 },
410 },
411 ));
412 }
413 TrieKey::ContractData { account_id, key } => {
414 state_changes.extend(changes.into_iter().map(
415 |RawStateChange { cause, data }| StateChangeWithCause {
416 cause,
417 value: if let Some(change_data) = data {
418 StateChangeValue::DataUpdate {
419 account_id: account_id.clone(),
420 key: key.to_vec().into(),
421 value: change_data.into(),
422 }
423 } else {
424 StateChangeValue::DataDeletion {
425 account_id: account_id.clone(),
426 key: key.to_vec().into(),
427 }
428 },
429 },
430 ));
431 }
432 TrieKey::ReceivedData { .. } => {}
434 TrieKey::PostponedReceiptId { .. } => {}
435 TrieKey::PendingDataCount { .. } => {}
436 TrieKey::PostponedReceipt { .. } => {}
437 TrieKey::DelayedReceiptIndices => {}
438 TrieKey::DelayedReceipt { .. } => {}
439 TrieKey::PromiseYieldIndices => {}
440 TrieKey::PromiseYieldTimeout { .. } => {}
441 TrieKey::PromiseYieldReceipt { .. } => {}
442 TrieKey::BufferedReceiptIndices => {}
443 TrieKey::BufferedReceipt { .. } => {}
444 TrieKey::BandwidthSchedulerState => {}
445 TrieKey::BufferedReceiptGroupsQueueData { .. } => {}
446 TrieKey::BufferedReceiptGroupsQueueItem { .. } => {}
447 TrieKey::GlobalContractCode { .. } => {}
449 }
450 }
451
452 Ok(state_changes)
453 }
454 pub fn from_account_changes(
455 raw_changes: impl Iterator<Item = Result<RawStateChangesWithTrieKey, std::io::Error>>,
456 ) -> Result<StateChanges, std::io::Error> {
457 let state_changes = Self::from_changes(raw_changes)?;
458
459 Ok(state_changes
460 .into_iter()
461 .filter(|state_change| {
462 matches!(
463 state_change.value,
464 StateChangeValue::AccountUpdate { .. }
465 | StateChangeValue::AccountDeletion { .. }
466 )
467 })
468 .collect())
469 }
470
471 pub fn from_access_key_changes(
472 raw_changes: impl Iterator<Item = Result<RawStateChangesWithTrieKey, std::io::Error>>,
473 ) -> Result<StateChanges, std::io::Error> {
474 let state_changes = Self::from_changes(raw_changes)?;
475
476 Ok(state_changes
477 .into_iter()
478 .filter(|state_change| {
479 matches!(
480 state_change.value,
481 StateChangeValue::AccessKeyUpdate { .. }
482 | StateChangeValue::AccessKeyDeletion { .. }
483 )
484 })
485 .collect())
486 }
487
488 pub fn from_gas_key_changes(
489 raw_changes: impl Iterator<Item = Result<RawStateChangesWithTrieKey, std::io::Error>>,
490 ) -> Result<StateChanges, std::io::Error> {
491 let state_changes = Self::from_changes(raw_changes)?;
492
493 Ok(state_changes
494 .into_iter()
495 .filter(|state_change| {
496 matches!(
497 state_change.value,
498 StateChangeValue::GasKeyUpdate { .. }
499 | StateChangeValue::GasKeyNonceUpdate { .. }
500 | StateChangeValue::GasKeyDeletion { .. }
501 )
502 })
503 .collect())
504 }
505
506 pub fn from_contract_code_changes(
507 raw_changes: impl Iterator<Item = Result<RawStateChangesWithTrieKey, std::io::Error>>,
508 ) -> Result<StateChanges, std::io::Error> {
509 let state_changes = Self::from_changes(raw_changes)?;
510
511 Ok(state_changes
512 .into_iter()
513 .filter(|state_change| {
514 matches!(
515 state_change.value,
516 StateChangeValue::ContractCodeUpdate { .. }
517 | StateChangeValue::ContractCodeDeletion { .. }
518 )
519 })
520 .collect())
521 }
522
523 pub fn from_data_changes(
524 raw_changes: impl Iterator<Item = Result<RawStateChangesWithTrieKey, std::io::Error>>,
525 ) -> Result<StateChanges, std::io::Error> {
526 let state_changes = Self::from_changes(raw_changes)?;
527
528 Ok(state_changes
529 .into_iter()
530 .filter(|state_change| {
531 matches!(
532 state_change.value,
533 StateChangeValue::DataUpdate { .. } | StateChangeValue::DataDeletion { .. }
534 )
535 })
536 .collect())
537 }
538}
539
540#[derive(
541 PartialEq, Eq, Clone, Debug, BorshSerialize, BorshDeserialize, serde::Serialize, ProtocolSchema,
542)]
543pub struct StateRootNode {
544 pub data: Arc<[u8]>,
550
551 pub memory_usage: u64,
553}
554
555impl StateRootNode {
556 pub fn empty() -> Self {
557 static EMPTY: LazyLock<Arc<[u8]>> = LazyLock::new(|| Arc::new([]));
558 StateRootNode { data: EMPTY.clone(), memory_usage: 0 }
559 }
560}
561
562#[derive(
566 Debug,
567 Clone,
568 Copy,
569 Default,
570 Hash,
571 Eq,
572 PartialEq,
573 PartialOrd,
574 Ord,
575 derive_more::AsRef,
576 BorshSerialize,
577 BorshDeserialize,
578 serde::Serialize,
579 serde::Deserialize,
580 arbitrary::Arbitrary,
581 ProtocolSchema,
582)]
583#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
584#[as_ref(forward)]
585pub struct EpochId(pub CryptoHash);
586
587impl std::str::FromStr for EpochId {
588 type Err = Box<dyn std::error::Error + Send + Sync>;
589
590 fn from_str(epoch_id_str: &str) -> Result<Self, Self::Err> {
592 Ok(EpochId(CryptoHash::from_str(epoch_id_str)?))
593 }
594}
595
596#[derive(serde::Serialize, Debug, Clone, PartialEq, Eq)]
600pub struct ApprovalStake {
601 pub account_id: AccountId,
603 pub public_key: PublicKey,
605 pub stake_this_epoch: Balance,
607 pub stake_next_epoch: Balance,
608}
609
610pub mod validator_stake {
611 use crate::types::ApprovalStake;
612 use borsh::{BorshDeserialize, BorshSerialize};
613 use near_crypto::{KeyType, PublicKey};
614 use near_primitives_core::types::{AccountId, Balance};
615 use serde::Serialize;
616
617 pub use super::ValidatorStakeV1;
618
619 #[derive(BorshSerialize, BorshDeserialize, Serialize, Debug, Clone, PartialEq, Eq)]
621 #[serde(tag = "validator_stake_struct_version")]
622 #[borsh(use_discriminant = true)]
623 #[repr(u8)]
624 pub enum ValidatorStake {
625 V1(ValidatorStakeV1) = 0,
626 }
632
633 pub struct ValidatorStakeIter<'a> {
634 collection: ValidatorStakeIterSource<'a>,
635 curr_index: usize,
636 len: usize,
637 }
638
639 impl<'a> ValidatorStakeIter<'a> {
640 pub fn empty() -> Self {
641 Self { collection: ValidatorStakeIterSource::V2(&[]), curr_index: 0, len: 0 }
642 }
643
644 pub fn v1(collection: &'a [ValidatorStakeV1]) -> Self {
645 Self {
646 collection: ValidatorStakeIterSource::V1(collection),
647 curr_index: 0,
648 len: collection.len(),
649 }
650 }
651
652 pub fn new(collection: &'a [ValidatorStake]) -> Self {
653 Self {
654 collection: ValidatorStakeIterSource::V2(collection),
655 curr_index: 0,
656 len: collection.len(),
657 }
658 }
659
660 pub fn len(&self) -> usize {
661 self.len
662 }
663 }
664
665 impl<'a> Iterator for ValidatorStakeIter<'a> {
666 type Item = ValidatorStake;
667
668 fn next(&mut self) -> Option<Self::Item> {
669 if self.curr_index < self.len {
670 let item = match self.collection {
671 ValidatorStakeIterSource::V1(collection) => {
672 ValidatorStake::V1(collection[self.curr_index].clone())
673 }
674 ValidatorStakeIterSource::V2(collection) => collection[self.curr_index].clone(),
675 };
676 self.curr_index += 1;
677 Some(item)
678 } else {
679 None
680 }
681 }
682 }
683
684 enum ValidatorStakeIterSource<'a> {
685 V1(&'a [ValidatorStakeV1]),
686 V2(&'a [ValidatorStake]),
687 }
688
689 impl ValidatorStake {
690 pub fn new_v1(account_id: AccountId, public_key: PublicKey, stake: Balance) -> Self {
691 Self::V1(ValidatorStakeV1 { account_id, public_key, stake })
692 }
693
694 pub fn new(account_id: AccountId, public_key: PublicKey, stake: Balance) -> Self {
695 Self::new_v1(account_id, public_key, stake)
696 }
697
698 pub fn test(account_id: AccountId) -> Self {
699 Self::new_v1(account_id, PublicKey::empty(KeyType::ED25519), Balance::ZERO)
700 }
701
702 pub fn into_v1(self) -> ValidatorStakeV1 {
703 match self {
704 Self::V1(v1) => v1,
705 }
706 }
707
708 #[inline]
709 pub fn account_and_stake(self) -> (AccountId, Balance) {
710 match self {
711 Self::V1(v1) => (v1.account_id, v1.stake),
712 }
713 }
714
715 #[inline]
716 pub fn destructure(self) -> (AccountId, PublicKey, Balance) {
717 match self {
718 Self::V1(v1) => (v1.account_id, v1.public_key, v1.stake),
719 }
720 }
721
722 #[inline]
723 pub fn take_account_id(self) -> AccountId {
724 match self {
725 Self::V1(v1) => v1.account_id,
726 }
727 }
728
729 #[inline]
730 pub fn account_id(&self) -> &AccountId {
731 match self {
732 Self::V1(v1) => &v1.account_id,
733 }
734 }
735
736 #[inline]
737 pub fn take_public_key(self) -> PublicKey {
738 match self {
739 Self::V1(v1) => v1.public_key,
740 }
741 }
742
743 #[inline]
744 pub fn public_key(&self) -> &PublicKey {
745 match self {
746 Self::V1(v1) => &v1.public_key,
747 }
748 }
749
750 #[inline]
751 pub fn stake(&self) -> Balance {
752 match self {
753 Self::V1(v1) => v1.stake,
754 }
755 }
756
757 #[inline]
758 pub fn stake_mut(&mut self) -> &mut Balance {
759 match self {
760 Self::V1(v1) => &mut v1.stake,
761 }
762 }
763
764 pub fn get_approval_stake(&self, is_next_epoch: bool) -> ApprovalStake {
765 ApprovalStake {
766 account_id: self.account_id().clone(),
767 public_key: self.public_key().clone(),
768 stake_this_epoch: if is_next_epoch { Balance::ZERO } else { self.stake() },
769 stake_next_epoch: if is_next_epoch { self.stake() } else { Balance::ZERO },
770 }
771 }
772
773 pub fn num_mandates(&self, stake_per_mandate: Balance) -> u16 {
794 u16::try_from(self.stake().as_yoctonear() / stake_per_mandate.as_yoctonear())
795 .expect("number of mandates should fit u16")
796 }
797
798 pub fn partial_mandate_weight(&self, stake_per_mandate: Balance) -> Balance {
812 Balance::from_yoctonear(self.stake().as_yoctonear() % stake_per_mandate.as_yoctonear())
813 }
814 }
815}
816
817#[derive(
819 BorshSerialize, BorshDeserialize, serde::Serialize, Debug, Clone, PartialEq, Eq, ProtocolSchema,
820)]
821pub struct ValidatorStakeV1 {
822 pub account_id: AccountId,
824 pub public_key: PublicKey,
826 pub stake: Balance,
828}
829
830pub mod chunk_extra {
831 use crate::bandwidth_scheduler::BandwidthRequests;
832 use crate::congestion_info::CongestionInfo;
833 use crate::types::StateRoot;
834 use crate::types::validator_stake::{ValidatorStake, ValidatorStakeIter};
835 use borsh::{BorshDeserialize, BorshSerialize};
836 use near_primitives_core::hash::CryptoHash;
837 use near_primitives_core::types::{Balance, Gas};
838
839 pub use super::ChunkExtraV1;
840
841 #[derive(Debug, PartialEq, BorshSerialize, BorshDeserialize, Clone, Eq, serde::Serialize)]
843 #[borsh(use_discriminant = true)]
844 #[repr(u8)]
845 pub enum ChunkExtra {
846 V1(ChunkExtraV1) = 0,
847 V2(ChunkExtraV2) = 1,
848 V3(ChunkExtraV3) = 2,
849 V4(ChunkExtraV4) = 3,
850 }
851
852 #[derive(Debug, PartialEq, BorshSerialize, BorshDeserialize, Clone, Eq, serde::Serialize)]
853 pub struct ChunkExtraV2 {
854 pub state_root: StateRoot,
856 pub outcome_root: CryptoHash,
858 pub validator_proposals: Vec<ValidatorStake>,
860 pub gas_used: Gas,
862 pub gas_limit: Gas,
864 pub balance_burnt: Balance,
866 }
867
868 #[derive(Debug, PartialEq, BorshSerialize, BorshDeserialize, Clone, Eq, serde::Serialize)]
870 pub struct ChunkExtraV3 {
871 pub state_root: StateRoot,
873 pub outcome_root: CryptoHash,
875 pub validator_proposals: Vec<ValidatorStake>,
877 pub gas_used: Gas,
879 pub gas_limit: Gas,
881 pub balance_burnt: Balance,
883 congestion_info: CongestionInfo,
885 }
886
887 #[derive(Debug, PartialEq, BorshSerialize, BorshDeserialize, Clone, Eq, serde::Serialize)]
889 pub struct ChunkExtraV4 {
890 pub state_root: StateRoot,
892 pub outcome_root: CryptoHash,
894 pub validator_proposals: Vec<ValidatorStake>,
896 pub gas_used: Gas,
898 pub gas_limit: Gas,
900 pub balance_burnt: Balance,
902 congestion_info: CongestionInfo,
904 pub bandwidth_requests: BandwidthRequests,
906 }
907
908 impl ChunkExtra {
909 pub fn new_with_only_state_root(state_root: &StateRoot) -> Self {
913 let congestion_control = Some(CongestionInfo::default());
915 Self::new(
916 state_root,
917 CryptoHash::default(),
918 vec![],
919 Gas::ZERO,
920 Gas::ZERO,
921 Balance::ZERO,
922 congestion_control,
923 BandwidthRequests::empty(),
924 )
925 }
926
927 pub fn new(
928 state_root: &StateRoot,
929 outcome_root: CryptoHash,
930 validator_proposals: Vec<ValidatorStake>,
931 gas_used: Gas,
932 gas_limit: Gas,
933 balance_burnt: Balance,
934 congestion_info: Option<CongestionInfo>,
935 bandwidth_requests: BandwidthRequests,
936 ) -> Self {
937 Self::V4(ChunkExtraV4 {
938 state_root: *state_root,
939 outcome_root,
940 validator_proposals,
941 gas_used,
942 gas_limit,
943 balance_burnt,
944 congestion_info: congestion_info.unwrap(),
945 bandwidth_requests,
946 })
947 }
948
949 #[inline]
950 pub fn outcome_root(&self) -> &StateRoot {
951 match self {
952 Self::V1(v1) => &v1.outcome_root,
953 Self::V2(v2) => &v2.outcome_root,
954 Self::V3(v3) => &v3.outcome_root,
955 Self::V4(v4) => &v4.outcome_root,
956 }
957 }
958
959 #[inline]
960 pub fn state_root(&self) -> &StateRoot {
961 match self {
962 Self::V1(v1) => &v1.state_root,
963 Self::V2(v2) => &v2.state_root,
964 Self::V3(v3) => &v3.state_root,
965 Self::V4(v4) => &v4.state_root,
966 }
967 }
968
969 #[inline]
970 pub fn state_root_mut(&mut self) -> &mut StateRoot {
971 match self {
972 Self::V1(v1) => &mut v1.state_root,
973 Self::V2(v2) => &mut v2.state_root,
974 Self::V3(v3) => &mut v3.state_root,
975 Self::V4(v4) => &mut v4.state_root,
976 }
977 }
978
979 #[inline]
980 pub fn validator_proposals(&self) -> ValidatorStakeIter {
981 match self {
982 Self::V1(v1) => ValidatorStakeIter::v1(&v1.validator_proposals),
983 Self::V2(v2) => ValidatorStakeIter::new(&v2.validator_proposals),
984 Self::V3(v3) => ValidatorStakeIter::new(&v3.validator_proposals),
985 Self::V4(v4) => ValidatorStakeIter::new(&v4.validator_proposals),
986 }
987 }
988
989 #[inline]
990 pub fn gas_limit(&self) -> Gas {
991 match self {
992 Self::V1(v1) => v1.gas_limit,
993 Self::V2(v2) => v2.gas_limit,
994 Self::V3(v3) => v3.gas_limit,
995 Self::V4(v4) => v4.gas_limit,
996 }
997 }
998
999 #[inline]
1000 pub fn gas_used(&self) -> Gas {
1001 match self {
1002 Self::V1(v1) => v1.gas_used,
1003 Self::V2(v2) => v2.gas_used,
1004 Self::V3(v3) => v3.gas_used,
1005 Self::V4(v4) => v4.gas_used,
1006 }
1007 }
1008
1009 #[inline]
1010 pub fn balance_burnt(&self) -> Balance {
1011 match self {
1012 Self::V1(v1) => v1.balance_burnt,
1013 Self::V2(v2) => v2.balance_burnt,
1014 Self::V3(v3) => v3.balance_burnt,
1015 Self::V4(v4) => v4.balance_burnt,
1016 }
1017 }
1018
1019 #[inline]
1020 pub fn congestion_info(&self) -> CongestionInfo {
1021 match self {
1022 Self::V1(_) | Self::V2(_) => {
1023 debug_assert!(false, "Calling congestion_info on V1 or V2 header version");
1024 Default::default()
1025 }
1026 Self::V3(v3) => v3.congestion_info,
1027 Self::V4(v4) => v4.congestion_info,
1028 }
1029 }
1030
1031 #[inline]
1032 pub fn congestion_info_mut(&mut self) -> &mut CongestionInfo {
1033 match self {
1034 Self::V1(_) | Self::V2(_) => panic!("Calling congestion_info_mut on V1 or V2"),
1035 Self::V3(v3) => &mut v3.congestion_info,
1036 Self::V4(v4) => &mut v4.congestion_info,
1037 }
1038 }
1039
1040 #[inline]
1041 pub fn bandwidth_requests(&self) -> Option<&BandwidthRequests> {
1042 match self {
1043 Self::V1(_) | Self::V2(_) | Self::V3(_) => None,
1044 Self::V4(extra) => Some(&extra.bandwidth_requests),
1045 }
1046 }
1047 }
1048}
1049
1050#[derive(
1052 Debug, PartialEq, BorshSerialize, BorshDeserialize, Clone, Eq, ProtocolSchema, serde::Serialize,
1053)]
1054pub struct ChunkExtraV1 {
1055 pub state_root: StateRoot,
1057 pub outcome_root: CryptoHash,
1059 pub validator_proposals: Vec<ValidatorStakeV1>,
1061 pub gas_used: Gas,
1063 pub gas_limit: Gas,
1065 pub balance_burnt: Balance,
1067}
1068
1069#[derive(
1070 Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize, arbitrary::Arbitrary,
1071)]
1072#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1073#[serde(untagged)]
1074pub enum BlockId {
1075 #[cfg_attr(feature = "schemars", schemars(title = "block_height"))]
1076 Height(BlockHeight),
1077 Hash(CryptoHash),
1078}
1079
1080pub type MaybeBlockId = Option<BlockId>;
1081
1082#[derive(
1083 Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize, arbitrary::Arbitrary,
1084)]
1085#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1086#[serde(rename_all = "snake_case")]
1087pub enum SyncCheckpoint {
1088 Genesis,
1089 EarliestAvailable,
1090}
1091
1092#[derive(
1093 Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize, arbitrary::Arbitrary,
1094)]
1095#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1096#[serde(rename_all = "snake_case")]
1097pub enum BlockReference {
1098 BlockId(BlockId),
1099 Finality(Finality),
1100 SyncCheckpoint(SyncCheckpoint),
1101}
1102
1103impl BlockReference {
1104 pub fn latest() -> Self {
1105 Self::Finality(Finality::None)
1106 }
1107}
1108
1109impl From<BlockId> for BlockReference {
1110 fn from(block_id: BlockId) -> Self {
1111 Self::BlockId(block_id)
1112 }
1113}
1114
1115impl From<Finality> for BlockReference {
1116 fn from(finality: Finality) -> Self {
1117 Self::Finality(finality)
1118 }
1119}
1120
1121#[derive(
1122 Default,
1123 BorshSerialize,
1124 BorshDeserialize,
1125 Clone,
1126 Debug,
1127 PartialEq,
1128 Eq,
1129 ProtocolSchema,
1130 serde::Serialize,
1131)]
1132pub struct ValidatorStats {
1133 pub produced: NumBlocks,
1134 pub expected: NumBlocks,
1135}
1136
1137impl ValidatorStats {
1138 pub fn less_than(&self, threshold: u8) -> bool {
1141 self.produced * 100 < u64::from(threshold) * self.expected
1142 }
1143}
1144
1145#[derive(Debug, BorshSerialize, BorshDeserialize, PartialEq, Eq, ProtocolSchema)]
1146pub struct BlockChunkValidatorStats {
1147 pub block_stats: ValidatorStats,
1148 pub chunk_stats: ChunkStats,
1149}
1150
1151#[derive(serde::Deserialize, Debug, arbitrary::Arbitrary, PartialEq, Eq)]
1152#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1153#[serde(rename_all = "snake_case")]
1154pub enum EpochReference {
1155 EpochId(EpochId),
1156 BlockId(BlockId),
1157 Latest,
1158}
1159
1160impl serde::Serialize for EpochReference {
1161 fn serialize<S>(&self, s: S) -> Result<S::Ok, S::Error>
1162 where
1163 S: serde::Serializer,
1164 {
1165 match self {
1167 EpochReference::EpochId(epoch_id) => {
1168 s.serialize_newtype_variant("EpochReference", 0, "epoch_id", epoch_id)
1169 }
1170 EpochReference::BlockId(block_id) => {
1171 s.serialize_newtype_variant("EpochReference", 1, "block_id", block_id)
1172 }
1173 EpochReference::Latest => {
1174 s.serialize_newtype_variant("EpochReference", 2, "latest", &())
1175 }
1176 }
1177 }
1178}
1179
1180#[derive(Clone, Debug)]
1186pub enum ValidatorInfoIdentifier {
1187 EpochId(EpochId),
1188 BlockHash(CryptoHash),
1189}
1190
1191#[derive(
1193 BorshSerialize,
1194 BorshDeserialize,
1195 serde::Serialize,
1196 serde::Deserialize,
1197 Clone,
1198 Debug,
1199 PartialEq,
1200 Eq,
1201 ProtocolSchema,
1202)]
1203#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1204#[borsh(use_discriminant = true)]
1205#[repr(u8)]
1206pub enum ValidatorKickoutReason {
1207 _UnusedSlashed = 0,
1209 NotEnoughBlocks { produced: NumBlocks, expected: NumBlocks } = 1,
1211 NotEnoughChunks { produced: NumBlocks, expected: NumBlocks } = 2,
1213 Unstaked = 3,
1215 NotEnoughStake {
1217 #[serde(rename = "stake_u128")]
1218 stake: Balance,
1219 #[serde(rename = "threshold_u128")]
1220 threshold: Balance,
1221 } = 4,
1222 DidNotGetASeat = 5,
1224 NotEnoughChunkEndorsements { produced: NumBlocks, expected: NumBlocks } = 6,
1226 ProtocolVersionTooOld { version: ProtocolVersion, network_version: ProtocolVersion } = 7,
1229}
1230
1231#[derive(serde::Serialize, serde::Deserialize, Clone, Debug)]
1232#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1233#[serde(tag = "type", rename_all = "snake_case")]
1234pub enum TransactionOrReceiptId {
1235 Transaction { transaction_hash: CryptoHash, sender_id: AccountId },
1236 Receipt { receipt_id: CryptoHash, receiver_id: AccountId },
1237}
1238
1239pub trait EpochInfoProvider: Send + Sync {
1242 fn validator_stake(
1245 &self,
1246 epoch_id: &EpochId,
1247 account_id: &AccountId,
1248 ) -> Result<Option<Balance>, EpochError>;
1249
1250 fn validator_total_stake(&self, epoch_id: &EpochId) -> Result<Balance, EpochError>;
1252
1253 fn minimum_stake(&self, prev_block_hash: &CryptoHash) -> Result<Balance, EpochError>;
1254
1255 fn chain_id(&self) -> String;
1257
1258 fn shard_layout(&self, epoch_id: &EpochId) -> Result<ShardLayout, EpochError>;
1259}
1260
1261#[derive(borsh::BorshDeserialize, borsh::BorshSerialize)]
1264pub struct StateChangesForBlockRange {
1265 pub blocks: Vec<StateChangesForBlock>,
1266}
1267
1268#[derive(borsh::BorshDeserialize, borsh::BorshSerialize)]
1271pub struct StateChangesForBlock {
1272 pub block_hash: CryptoHash,
1273 pub state_changes: Vec<StateChangesForShard>,
1274}
1275
1276#[derive(borsh::BorshDeserialize, borsh::BorshSerialize)]
1278pub struct StateChangesForShard {
1279 pub shard_id: ShardId,
1280 pub state_changes: Vec<RawStateChangesWithTrieKey>,
1281}
1282
1283#[derive(Debug, Clone, Hash, PartialEq, Eq, BorshSerialize, BorshDeserialize, ProtocolSchema)]
1286pub struct SpiceChunkId {
1287 pub block_hash: CryptoHash,
1288 pub shard_id: ShardId,
1289}
1290
1291#[derive(Debug, Clone, PartialEq, Eq, BorshSerialize, BorshDeserialize, ProtocolSchema)]
1293pub struct ChunkExecutionResult {
1294 pub chunk_extra: ChunkExtra,
1295 pub outgoing_receipts_root: CryptoHash,
1296}
1297
1298pub struct BlockExecutionResults(pub HashMap<ShardId, Arc<ChunkExecutionResult>>);
1300
1301#[derive(BorshSerialize, BorshDeserialize, Debug, Clone, PartialEq, Eq, Hash)]
1302pub struct ChunkExecutionResultHash(pub CryptoHash);
1303
1304impl ChunkExecutionResult {
1305 pub fn compute_hash(&self) -> ChunkExecutionResultHash {
1306 let bytes = borsh::to_vec(self).expect("Failed to serialize");
1307 ChunkExecutionResultHash(hash(&bytes))
1308 }
1309}
1310
1311#[derive(BorshSerialize, BorshDeserialize, Debug, Clone, PartialEq, Eq)]
1312pub struct SpiceUncertifiedChunkInfo {
1313 pub chunk_id: SpiceChunkId,
1314 pub missing_endorsements: Vec<AccountId>,
1315 pub present_endorsements: Vec<(AccountId, SpiceStoredVerifiedEndorsement)>,
1316}
1317
1318#[cfg(test)]
1319mod tests {
1320 use near_crypto::{KeyType, PublicKey};
1321 use near_primitives_core::types::Balance;
1322
1323 use super::validator_stake::ValidatorStake;
1324
1325 fn new_validator_stake(stake: Balance) -> ValidatorStake {
1326 ValidatorStake::new(
1327 "test_account".parse().unwrap(),
1328 PublicKey::empty(KeyType::ED25519),
1329 stake,
1330 )
1331 }
1332
1333 #[test]
1334 fn test_validator_stake_num_mandates() {
1335 assert_eq!(new_validator_stake(Balance::ZERO).num_mandates(Balance::from_yoctonear(5)), 0);
1336 assert_eq!(
1337 new_validator_stake(Balance::from_yoctonear(10))
1338 .num_mandates(Balance::from_yoctonear(5)),
1339 2
1340 );
1341 assert_eq!(
1342 new_validator_stake(Balance::from_yoctonear(12))
1343 .num_mandates(Balance::from_yoctonear(5)),
1344 2
1345 );
1346 }
1347
1348 #[test]
1349 fn test_validator_partial_mandate_weight() {
1350 assert_eq!(
1351 new_validator_stake(Balance::ZERO).partial_mandate_weight(Balance::from_yoctonear(5)),
1352 Balance::ZERO
1353 );
1354 assert_eq!(
1355 new_validator_stake(Balance::from_yoctonear(10))
1356 .partial_mandate_weight(Balance::from_yoctonear(5)),
1357 Balance::ZERO
1358 );
1359 assert_eq!(
1360 new_validator_stake(Balance::from_yoctonear(12))
1361 .partial_mandate_weight(Balance::from_yoctonear(5)),
1362 Balance::from_yoctonear(2)
1363 );
1364 }
1365}