use crate::account::{AccessKey, Account};
use crate::challenge::ChallengesResult;
use crate::errors::EpochError;
use crate::hash::CryptoHash;
use crate::serialize::dec_format;
use crate::trie_key::TrieKey;
use borsh::{BorshDeserialize, BorshSerialize};
use near_crypto::PublicKey;
pub use near_primitives_core::types::*;
use near_schema_checker_lib::ProtocolSchema;
use serde_with::base64::Base64;
use serde_with::serde_as;
use std::sync::Arc;
use std::sync::LazyLock;
mod chunk_validator_stats;
pub use chunk_validator_stats::ChunkStats;
pub type StateRoot = CryptoHash;
#[derive(
serde::Serialize, serde::Deserialize, Default, Clone, Debug, PartialEq, Eq, arbitrary::Arbitrary,
)]
pub enum Finality {
#[serde(rename = "optimistic")]
None,
#[serde(rename = "near-final")]
DoomSlug,
#[serde(rename = "final")]
#[default]
Final,
}
#[derive(Debug, serde::Serialize, serde::Deserialize)]
pub struct AccountWithPublicKey {
pub account_id: AccountId,
pub public_key: PublicKey,
}
#[derive(serde::Serialize, serde::Deserialize, Clone, Debug, Eq, PartialEq)]
pub struct AccountInfo {
pub account_id: AccountId,
pub public_key: PublicKey,
#[serde(with = "dec_format")]
pub amount: Balance,
}
#[serde_as]
#[derive(
serde::Serialize,
serde::Deserialize,
Clone,
Debug,
PartialEq,
Eq,
derive_more::Deref,
derive_more::From,
derive_more::Into,
BorshSerialize,
BorshDeserialize,
)]
#[serde(transparent)]
pub struct StoreKey(#[serde_as(as = "Base64")] Vec<u8>);
#[serde_as]
#[derive(
serde::Serialize,
serde::Deserialize,
Clone,
Debug,
PartialEq,
Eq,
derive_more::Deref,
derive_more::From,
derive_more::Into,
BorshSerialize,
BorshDeserialize,
)]
#[serde(transparent)]
pub struct StoreValue(#[serde_as(as = "Base64")] Vec<u8>);
#[serde_as]
#[derive(
serde::Serialize,
serde::Deserialize,
Clone,
Debug,
PartialEq,
Eq,
derive_more::Deref,
derive_more::From,
derive_more::Into,
BorshSerialize,
BorshDeserialize,
)]
#[serde(transparent)]
pub struct FunctionArgs(#[serde_as(as = "Base64")] Vec<u8>);
#[derive(Debug, Clone)]
pub enum StateChangeKind {
AccountTouched { account_id: AccountId },
AccessKeyTouched { account_id: AccountId },
DataTouched { account_id: AccountId },
ContractCodeTouched { account_id: AccountId },
}
pub type StateChangesKinds = Vec<StateChangeKind>;
#[easy_ext::ext(StateChangesKindsExt)]
impl StateChangesKinds {
pub fn from_changes(
raw_changes: &mut dyn Iterator<Item = Result<RawStateChangesWithTrieKey, std::io::Error>>,
) -> Result<StateChangesKinds, std::io::Error> {
raw_changes
.filter_map(|raw_change| {
let RawStateChangesWithTrieKey { trie_key, .. } = match raw_change {
Ok(p) => p,
Err(e) => return Some(Err(e)),
};
match trie_key {
TrieKey::Account { account_id } => {
Some(Ok(StateChangeKind::AccountTouched { account_id }))
}
TrieKey::ContractCode { account_id } => {
Some(Ok(StateChangeKind::ContractCodeTouched { account_id }))
}
TrieKey::AccessKey { account_id, .. } => {
Some(Ok(StateChangeKind::AccessKeyTouched { account_id }))
}
TrieKey::ContractData { account_id, .. } => {
Some(Ok(StateChangeKind::DataTouched { account_id }))
}
_ => None,
}
})
.collect()
}
}
#[derive(Debug, Clone, BorshSerialize, BorshDeserialize, PartialEq, ProtocolSchema)]
pub enum StateChangeCause {
NotWritableToDisk,
InitialState,
TransactionProcessing { tx_hash: CryptoHash },
ActionReceiptProcessingStarted { receipt_hash: CryptoHash },
ActionReceiptGasReward { receipt_hash: CryptoHash },
ReceiptProcessing { receipt_hash: CryptoHash },
PostponedReceipt { receipt_hash: CryptoHash },
UpdatedDelayedReceipts,
ValidatorAccountsUpdate,
Migration,
ReshardingV2,
}
#[derive(Debug, Clone, BorshSerialize, BorshDeserialize, ProtocolSchema)]
pub struct RawStateChange {
pub cause: StateChangeCause,
pub data: Option<Vec<u8>>,
}
#[derive(Debug, Clone, BorshSerialize, BorshDeserialize, ProtocolSchema)]
pub struct RawStateChangesWithTrieKey {
pub trie_key: TrieKey,
pub changes: Vec<RawStateChange>,
}
#[derive(BorshSerialize, BorshDeserialize, Debug, Clone, ProtocolSchema)]
pub struct ConsolidatedStateChange {
pub trie_key: TrieKey,
pub value: Option<Vec<u8>>,
}
pub type RawStateChanges = std::collections::BTreeMap<Vec<u8>, RawStateChangesWithTrieKey>;
#[derive(Debug)]
pub enum StateChangesRequest {
AccountChanges { account_ids: Vec<AccountId> },
SingleAccessKeyChanges { keys: Vec<AccountWithPublicKey> },
AllAccessKeyChanges { account_ids: Vec<AccountId> },
ContractCodeChanges { account_ids: Vec<AccountId> },
DataChanges { account_ids: Vec<AccountId>, key_prefix: StoreKey },
}
#[derive(Debug)]
pub enum StateChangeValue {
AccountUpdate { account_id: AccountId, account: Account },
AccountDeletion { account_id: AccountId },
AccessKeyUpdate { account_id: AccountId, public_key: PublicKey, access_key: AccessKey },
AccessKeyDeletion { account_id: AccountId, public_key: PublicKey },
DataUpdate { account_id: AccountId, key: StoreKey, value: StoreValue },
DataDeletion { account_id: AccountId, key: StoreKey },
ContractCodeUpdate { account_id: AccountId, code: Vec<u8> },
ContractCodeDeletion { account_id: AccountId },
}
impl StateChangeValue {
pub fn affected_account_id(&self) -> &AccountId {
match &self {
StateChangeValue::AccountUpdate { account_id, .. }
| StateChangeValue::AccountDeletion { account_id }
| StateChangeValue::AccessKeyUpdate { account_id, .. }
| StateChangeValue::AccessKeyDeletion { account_id, .. }
| StateChangeValue::DataUpdate { account_id, .. }
| StateChangeValue::DataDeletion { account_id, .. }
| StateChangeValue::ContractCodeUpdate { account_id, .. }
| StateChangeValue::ContractCodeDeletion { account_id } => account_id,
}
}
}
#[derive(Debug)]
pub struct StateChangeWithCause {
pub cause: StateChangeCause,
pub value: StateChangeValue,
}
pub type StateChanges = Vec<StateChangeWithCause>;
#[easy_ext::ext(StateChangesExt)]
impl StateChanges {
pub fn from_changes(
raw_changes: impl Iterator<Item = Result<RawStateChangesWithTrieKey, std::io::Error>>,
) -> Result<StateChanges, std::io::Error> {
let mut state_changes = Self::new();
for raw_change in raw_changes {
let RawStateChangesWithTrieKey { trie_key, changes } = raw_change?;
match trie_key {
TrieKey::Account { account_id } => state_changes.extend(changes.into_iter().map(
|RawStateChange { cause, data }| StateChangeWithCause {
cause,
value: if let Some(change_data) = data {
StateChangeValue::AccountUpdate {
account_id: account_id.clone(),
account: <_>::try_from_slice(&change_data).expect(
"Failed to parse internally stored account information",
),
}
} else {
StateChangeValue::AccountDeletion { account_id: account_id.clone() }
},
},
)),
TrieKey::AccessKey { account_id, public_key } => {
state_changes.extend(changes.into_iter().map(
|RawStateChange { cause, data }| StateChangeWithCause {
cause,
value: if let Some(change_data) = data {
StateChangeValue::AccessKeyUpdate {
account_id: account_id.clone(),
public_key: public_key.clone(),
access_key: <_>::try_from_slice(&change_data)
.expect("Failed to parse internally stored access key"),
}
} else {
StateChangeValue::AccessKeyDeletion {
account_id: account_id.clone(),
public_key: public_key.clone(),
}
},
},
))
}
TrieKey::ContractCode { account_id } => {
state_changes.extend(changes.into_iter().map(
|RawStateChange { cause, data }| StateChangeWithCause {
cause,
value: match data {
Some(change_data) => StateChangeValue::ContractCodeUpdate {
account_id: account_id.clone(),
code: change_data,
},
None => StateChangeValue::ContractCodeDeletion {
account_id: account_id.clone(),
},
},
},
));
}
TrieKey::ContractData { account_id, key } => {
state_changes.extend(changes.into_iter().map(
|RawStateChange { cause, data }| StateChangeWithCause {
cause,
value: if let Some(change_data) = data {
StateChangeValue::DataUpdate {
account_id: account_id.clone(),
key: key.to_vec().into(),
value: change_data.into(),
}
} else {
StateChangeValue::DataDeletion {
account_id: account_id.clone(),
key: key.to_vec().into(),
}
},
},
));
}
TrieKey::ReceivedData { .. } => {}
TrieKey::PostponedReceiptId { .. } => {}
TrieKey::PendingDataCount { .. } => {}
TrieKey::PostponedReceipt { .. } => {}
TrieKey::DelayedReceiptIndices => {}
TrieKey::DelayedReceipt { .. } => {}
TrieKey::PromiseYieldIndices => {}
TrieKey::PromiseYieldTimeout { .. } => {}
TrieKey::PromiseYieldReceipt { .. } => {}
TrieKey::BufferedReceiptIndices => {}
TrieKey::BufferedReceipt { .. } => {}
}
}
Ok(state_changes)
}
pub fn from_account_changes(
raw_changes: impl Iterator<Item = Result<RawStateChangesWithTrieKey, std::io::Error>>,
) -> Result<StateChanges, std::io::Error> {
let state_changes = Self::from_changes(raw_changes)?;
Ok(state_changes
.into_iter()
.filter(|state_change| {
matches!(
state_change.value,
StateChangeValue::AccountUpdate { .. }
| StateChangeValue::AccountDeletion { .. }
)
})
.collect())
}
pub fn from_access_key_changes(
raw_changes: impl Iterator<Item = Result<RawStateChangesWithTrieKey, std::io::Error>>,
) -> Result<StateChanges, std::io::Error> {
let state_changes = Self::from_changes(raw_changes)?;
Ok(state_changes
.into_iter()
.filter(|state_change| {
matches!(
state_change.value,
StateChangeValue::AccessKeyUpdate { .. }
| StateChangeValue::AccessKeyDeletion { .. }
)
})
.collect())
}
pub fn from_contract_code_changes(
raw_changes: impl Iterator<Item = Result<RawStateChangesWithTrieKey, std::io::Error>>,
) -> Result<StateChanges, std::io::Error> {
let state_changes = Self::from_changes(raw_changes)?;
Ok(state_changes
.into_iter()
.filter(|state_change| {
matches!(
state_change.value,
StateChangeValue::ContractCodeUpdate { .. }
| StateChangeValue::ContractCodeDeletion { .. }
)
})
.collect())
}
pub fn from_data_changes(
raw_changes: impl Iterator<Item = Result<RawStateChangesWithTrieKey, std::io::Error>>,
) -> Result<StateChanges, std::io::Error> {
let state_changes = Self::from_changes(raw_changes)?;
Ok(state_changes
.into_iter()
.filter(|state_change| {
matches!(
state_change.value,
StateChangeValue::DataUpdate { .. } | StateChangeValue::DataDeletion { .. }
)
})
.collect())
}
}
#[derive(
PartialEq, Eq, Clone, Debug, BorshSerialize, BorshDeserialize, serde::Serialize, ProtocolSchema,
)]
pub struct StateRootNode {
pub data: Arc<[u8]>,
pub memory_usage: u64,
}
impl StateRootNode {
pub fn empty() -> Self {
static EMPTY: LazyLock<Arc<[u8]>> = LazyLock::new(|| Arc::new([]));
StateRootNode { data: EMPTY.clone(), memory_usage: 0 }
}
}
#[derive(
Debug,
Clone,
Copy,
Default,
Hash,
Eq,
PartialEq,
PartialOrd,
Ord,
derive_more::AsRef,
BorshSerialize,
BorshDeserialize,
serde::Serialize,
serde::Deserialize,
arbitrary::Arbitrary,
ProtocolSchema,
)]
#[as_ref(forward)]
pub struct EpochId(pub CryptoHash);
impl std::str::FromStr for EpochId {
type Err = Box<dyn std::error::Error + Send + Sync>;
fn from_str(epoch_id_str: &str) -> Result<Self, Self::Err> {
Ok(EpochId(CryptoHash::from_str(epoch_id_str)?))
}
}
#[derive(serde::Serialize, Debug, Clone, PartialEq, Eq)]
pub struct ApprovalStake {
pub account_id: AccountId,
pub public_key: PublicKey,
pub stake_this_epoch: Balance,
pub stake_next_epoch: Balance,
}
pub mod validator_stake {
use crate::types::ApprovalStake;
use borsh::{BorshDeserialize, BorshSerialize};
use near_crypto::{KeyType, PublicKey};
use near_primitives_core::types::{AccountId, Balance};
use serde::Serialize;
pub use super::ValidatorStakeV1;
#[derive(BorshSerialize, BorshDeserialize, Serialize, Debug, Clone, PartialEq, Eq)]
#[serde(tag = "validator_stake_struct_version")]
pub enum ValidatorStake {
V1(ValidatorStakeV1),
}
pub struct ValidatorStakeIter<'a> {
collection: ValidatorStakeIterSource<'a>,
curr_index: usize,
len: usize,
}
impl<'a> ValidatorStakeIter<'a> {
pub fn empty() -> Self {
Self { collection: ValidatorStakeIterSource::V2(&[]), curr_index: 0, len: 0 }
}
pub fn v1(collection: &'a [ValidatorStakeV1]) -> Self {
Self {
collection: ValidatorStakeIterSource::V1(collection),
curr_index: 0,
len: collection.len(),
}
}
pub fn new(collection: &'a [ValidatorStake]) -> Self {
Self {
collection: ValidatorStakeIterSource::V2(collection),
curr_index: 0,
len: collection.len(),
}
}
pub fn len(&self) -> usize {
self.len
}
}
impl<'a> Iterator for ValidatorStakeIter<'a> {
type Item = ValidatorStake;
fn next(&mut self) -> Option<Self::Item> {
if self.curr_index < self.len {
let item = match self.collection {
ValidatorStakeIterSource::V1(collection) => {
ValidatorStake::V1(collection[self.curr_index].clone())
}
ValidatorStakeIterSource::V2(collection) => collection[self.curr_index].clone(),
};
self.curr_index += 1;
Some(item)
} else {
None
}
}
}
enum ValidatorStakeIterSource<'a> {
V1(&'a [ValidatorStakeV1]),
V2(&'a [ValidatorStake]),
}
impl ValidatorStake {
pub fn new_v1(account_id: AccountId, public_key: PublicKey, stake: Balance) -> Self {
Self::V1(ValidatorStakeV1 { account_id, public_key, stake })
}
pub fn new(account_id: AccountId, public_key: PublicKey, stake: Balance) -> Self {
Self::new_v1(account_id, public_key, stake)
}
pub fn test(account_id: AccountId) -> Self {
Self::new_v1(account_id, PublicKey::empty(KeyType::ED25519), 0)
}
pub fn into_v1(self) -> ValidatorStakeV1 {
match self {
Self::V1(v1) => v1,
}
}
#[inline]
pub fn account_and_stake(self) -> (AccountId, Balance) {
match self {
Self::V1(v1) => (v1.account_id, v1.stake),
}
}
#[inline]
pub fn destructure(self) -> (AccountId, PublicKey, Balance) {
match self {
Self::V1(v1) => (v1.account_id, v1.public_key, v1.stake),
}
}
#[inline]
pub fn take_account_id(self) -> AccountId {
match self {
Self::V1(v1) => v1.account_id,
}
}
#[inline]
pub fn account_id(&self) -> &AccountId {
match self {
Self::V1(v1) => &v1.account_id,
}
}
#[inline]
pub fn take_public_key(self) -> PublicKey {
match self {
Self::V1(v1) => v1.public_key,
}
}
#[inline]
pub fn public_key(&self) -> &PublicKey {
match self {
Self::V1(v1) => &v1.public_key,
}
}
#[inline]
pub fn stake(&self) -> Balance {
match self {
Self::V1(v1) => v1.stake,
}
}
#[inline]
pub fn stake_mut(&mut self) -> &mut Balance {
match self {
Self::V1(v1) => &mut v1.stake,
}
}
pub fn get_approval_stake(&self, is_next_epoch: bool) -> ApprovalStake {
ApprovalStake {
account_id: self.account_id().clone(),
public_key: self.public_key().clone(),
stake_this_epoch: if is_next_epoch { 0 } else { self.stake() },
stake_next_epoch: if is_next_epoch { self.stake() } else { 0 },
}
}
pub fn num_mandates(&self, stake_per_mandate: Balance) -> u16 {
u16::try_from(self.stake() / stake_per_mandate)
.expect("number of mandats should fit u16")
}
pub fn partial_mandate_weight(&self, stake_per_mandate: Balance) -> Balance {
self.stake() % stake_per_mandate
}
}
}
#[derive(
BorshSerialize, BorshDeserialize, serde::Serialize, Debug, Clone, PartialEq, Eq, ProtocolSchema,
)]
pub struct ValidatorStakeV1 {
pub account_id: AccountId,
pub public_key: PublicKey,
pub stake: Balance,
}
#[derive(Debug, PartialEq, BorshSerialize, BorshDeserialize, Clone, Eq, ProtocolSchema)]
pub struct BlockExtra {
pub challenges_result: ChallengesResult,
}
pub mod chunk_extra {
use crate::congestion_info::CongestionInfo;
use crate::types::validator_stake::{ValidatorStake, ValidatorStakeIter};
use crate::types::StateRoot;
use borsh::{BorshDeserialize, BorshSerialize};
use near_primitives_core::hash::CryptoHash;
use near_primitives_core::types::{Balance, Gas, ProtocolVersion};
use near_primitives_core::version::{ProtocolFeature, PROTOCOL_VERSION};
pub use super::ChunkExtraV1;
#[derive(Debug, PartialEq, BorshSerialize, BorshDeserialize, Clone, Eq, serde::Serialize)]
pub enum ChunkExtra {
V1(ChunkExtraV1),
V2(ChunkExtraV2),
V3(ChunkExtraV3),
}
#[derive(Debug, PartialEq, BorshSerialize, BorshDeserialize, Clone, Eq, serde::Serialize)]
pub struct ChunkExtraV2 {
pub state_root: StateRoot,
pub outcome_root: CryptoHash,
pub validator_proposals: Vec<ValidatorStake>,
pub gas_used: Gas,
pub gas_limit: Gas,
pub balance_burnt: Balance,
}
#[derive(Debug, PartialEq, BorshSerialize, BorshDeserialize, Clone, Eq, serde::Serialize)]
pub struct ChunkExtraV3 {
pub state_root: StateRoot,
pub outcome_root: CryptoHash,
pub validator_proposals: Vec<ValidatorStake>,
pub gas_used: Gas,
pub gas_limit: Gas,
pub balance_burnt: Balance,
congestion_info: CongestionInfo,
}
impl ChunkExtra {
pub fn new_with_only_state_root(state_root: &StateRoot) -> Self {
let congestion_control = if ProtocolFeature::CongestionControl.enabled(PROTOCOL_VERSION)
{
Some(CongestionInfo::default())
} else {
None
};
Self::new(
PROTOCOL_VERSION,
state_root,
CryptoHash::default(),
vec![],
0,
0,
0,
congestion_control,
)
}
pub fn new(
protocol_version: ProtocolVersion,
state_root: &StateRoot,
outcome_root: CryptoHash,
validator_proposals: Vec<ValidatorStake>,
gas_used: Gas,
gas_limit: Gas,
balance_burnt: Balance,
congestion_info: Option<CongestionInfo>,
) -> Self {
if ProtocolFeature::CongestionControl.enabled(protocol_version) {
assert!(congestion_info.is_some());
Self::V3(ChunkExtraV3 {
state_root: *state_root,
outcome_root,
validator_proposals,
gas_used,
gas_limit,
balance_burnt,
congestion_info: congestion_info.unwrap(),
})
} else {
assert!(congestion_info.is_none());
Self::V2(ChunkExtraV2 {
state_root: *state_root,
outcome_root,
validator_proposals,
gas_used,
gas_limit,
balance_burnt,
})
}
}
#[inline]
pub fn outcome_root(&self) -> &StateRoot {
match self {
Self::V1(v1) => &v1.outcome_root,
Self::V2(v2) => &v2.outcome_root,
Self::V3(v3) => &v3.outcome_root,
}
}
#[inline]
pub fn state_root(&self) -> &StateRoot {
match self {
Self::V1(v1) => &v1.state_root,
Self::V2(v2) => &v2.state_root,
Self::V3(v3) => &v3.state_root,
}
}
#[inline]
pub fn state_root_mut(&mut self) -> &mut StateRoot {
match self {
Self::V1(v1) => &mut v1.state_root,
Self::V2(v2) => &mut v2.state_root,
Self::V3(v3) => &mut v3.state_root,
}
}
#[inline]
pub fn validator_proposals(&self) -> ValidatorStakeIter {
match self {
Self::V1(v1) => ValidatorStakeIter::v1(&v1.validator_proposals),
Self::V2(v2) => ValidatorStakeIter::new(&v2.validator_proposals),
Self::V3(v3) => ValidatorStakeIter::new(&v3.validator_proposals),
}
}
#[inline]
pub fn gas_limit(&self) -> Gas {
match self {
Self::V1(v1) => v1.gas_limit,
Self::V2(v2) => v2.gas_limit,
Self::V3(v3) => v3.gas_limit,
}
}
#[inline]
pub fn gas_used(&self) -> Gas {
match self {
Self::V1(v1) => v1.gas_used,
Self::V2(v2) => v2.gas_used,
Self::V3(v3) => v3.gas_used,
}
}
#[inline]
pub fn balance_burnt(&self) -> Balance {
match self {
Self::V1(v1) => v1.balance_burnt,
Self::V2(v2) => v2.balance_burnt,
Self::V3(v3) => v3.balance_burnt,
}
}
#[inline]
pub fn congestion_info(&self) -> Option<CongestionInfo> {
match self {
Self::V1(_) => None,
Self::V2(_) => None,
Self::V3(v3) => v3.congestion_info.into(),
}
}
}
}
#[derive(
Debug, PartialEq, BorshSerialize, BorshDeserialize, Clone, Eq, ProtocolSchema, serde::Serialize,
)]
pub struct ChunkExtraV1 {
pub state_root: StateRoot,
pub outcome_root: CryptoHash,
pub validator_proposals: Vec<ValidatorStakeV1>,
pub gas_used: Gas,
pub gas_limit: Gas,
pub balance_burnt: Balance,
}
#[derive(
Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize, arbitrary::Arbitrary,
)]
#[serde(untagged)]
pub enum BlockId {
Height(BlockHeight),
Hash(CryptoHash),
}
pub type MaybeBlockId = Option<BlockId>;
#[derive(
Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize, arbitrary::Arbitrary,
)]
#[serde(rename_all = "snake_case")]
pub enum SyncCheckpoint {
Genesis,
EarliestAvailable,
}
#[derive(
Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize, arbitrary::Arbitrary,
)]
#[serde(rename_all = "snake_case")]
pub enum BlockReference {
BlockId(BlockId),
Finality(Finality),
SyncCheckpoint(SyncCheckpoint),
}
impl BlockReference {
pub fn latest() -> Self {
Self::Finality(Finality::None)
}
}
impl From<BlockId> for BlockReference {
fn from(block_id: BlockId) -> Self {
Self::BlockId(block_id)
}
}
impl From<Finality> for BlockReference {
fn from(finality: Finality) -> Self {
Self::Finality(finality)
}
}
#[derive(
Default,
BorshSerialize,
BorshDeserialize,
Clone,
Debug,
PartialEq,
Eq,
ProtocolSchema,
serde::Serialize,
)]
pub struct ValidatorStats {
pub produced: NumBlocks,
pub expected: NumBlocks,
}
impl ValidatorStats {
pub fn less_than(&self, threshold: u8) -> bool {
self.produced * 100 < u64::from(threshold) * self.expected
}
}
#[derive(Debug, BorshSerialize, BorshDeserialize, PartialEq, Eq, ProtocolSchema)]
pub struct BlockChunkValidatorStats {
pub block_stats: ValidatorStats,
pub chunk_stats: ChunkStats,
}
#[derive(serde::Deserialize, Debug, arbitrary::Arbitrary, PartialEq, Eq)]
#[serde(rename_all = "snake_case")]
pub enum EpochReference {
EpochId(EpochId),
BlockId(BlockId),
Latest,
}
impl serde::Serialize for EpochReference {
fn serialize<S>(&self, s: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
match self {
EpochReference::EpochId(epoch_id) => {
s.serialize_newtype_variant("EpochReference", 0, "epoch_id", epoch_id)
}
EpochReference::BlockId(block_id) => {
s.serialize_newtype_variant("EpochReference", 1, "block_id", block_id)
}
EpochReference::Latest => {
s.serialize_newtype_variant("EpochReference", 2, "latest", &())
}
}
}
}
#[derive(Clone, Debug)]
pub enum ValidatorInfoIdentifier {
EpochId(EpochId),
BlockHash(CryptoHash),
}
#[derive(
BorshSerialize,
BorshDeserialize,
serde::Serialize,
serde::Deserialize,
Clone,
Debug,
PartialEq,
Eq,
ProtocolSchema,
)]
pub enum ValidatorKickoutReason {
Slashed,
NotEnoughBlocks { produced: NumBlocks, expected: NumBlocks },
NotEnoughChunks { produced: NumBlocks, expected: NumBlocks },
Unstaked,
NotEnoughStake {
#[serde(with = "dec_format", rename = "stake_u128")]
stake: Balance,
#[serde(with = "dec_format", rename = "threshold_u128")]
threshold: Balance,
},
DidNotGetASeat,
NotEnoughChunkEndorsements { produced: NumBlocks, expected: NumBlocks },
}
#[derive(serde::Serialize, serde::Deserialize, Clone, Debug)]
#[serde(tag = "type", rename_all = "snake_case")]
pub enum TransactionOrReceiptId {
Transaction { transaction_hash: CryptoHash, sender_id: AccountId },
Receipt { receipt_id: CryptoHash, receiver_id: AccountId },
}
pub trait EpochInfoProvider: Send + Sync {
fn validator_stake(
&self,
epoch_id: &EpochId,
last_block_hash: &CryptoHash,
account_id: &AccountId,
) -> Result<Option<Balance>, EpochError>;
fn validator_total_stake(
&self,
epoch_id: &EpochId,
last_block_hash: &CryptoHash,
) -> Result<Balance, EpochError>;
fn minimum_stake(&self, prev_block_hash: &CryptoHash) -> Result<Balance, EpochError>;
fn chain_id(&self) -> String;
fn account_id_to_shard_id(
&self,
account_id: &AccountId,
epoch_id: &EpochId,
) -> Result<ShardId, EpochError>;
}
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum TrieCacheMode {
CachingShard,
CachingChunk,
}
#[derive(borsh::BorshDeserialize, borsh::BorshSerialize)]
pub struct StateChangesForBlockRange {
pub blocks: Vec<StateChangesForBlock>,
}
#[derive(borsh::BorshDeserialize, borsh::BorshSerialize)]
pub struct StateChangesForBlock {
pub block_hash: CryptoHash,
pub state_changes: Vec<StateChangesForShard>,
}
#[derive(borsh::BorshDeserialize, borsh::BorshSerialize)]
pub struct StateChangesForShard {
pub shard_id: ShardId,
pub state_changes: Vec<RawStateChangesWithTrieKey>,
}
#[cfg(test)]
mod tests {
use near_crypto::{KeyType, PublicKey};
use near_primitives_core::types::Balance;
use super::validator_stake::ValidatorStake;
fn new_validator_stake(stake: Balance) -> ValidatorStake {
ValidatorStake::new(
"test_account".parse().unwrap(),
PublicKey::empty(KeyType::ED25519),
stake,
)
}
#[test]
fn test_validator_stake_num_mandates() {
assert_eq!(new_validator_stake(0).num_mandates(5), 0);
assert_eq!(new_validator_stake(10).num_mandates(5), 2);
assert_eq!(new_validator_stake(12).num_mandates(5), 2);
}
#[test]
fn test_validator_partial_mandate_weight() {
assert_eq!(new_validator_stake(0).partial_mandate_weight(5), 0);
assert_eq!(new_validator_stake(10).partial_mandate_weight(5), 0);
assert_eq!(new_validator_stake(12).partial_mandate_weight(5), 2);
}
}