use crate::account::{AccessKey, Account};
use crate::action::RegisterRsa2048KeysAction;
use crate::challenge::ChallengesResult;
use crate::errors::EpochError;
pub use crate::hash::CryptoHash;
use crate::receipt::Receipt;
use crate::serialize::dec_format;
use crate::trie_key::TrieKey;
use borsh::{BorshDeserialize, BorshSerialize};
use unc_crypto::PublicKey;
pub use unc_primitives_core::types::*;
pub use unc_vm_runner::logic::TrieNodesCount;
use once_cell::sync::Lazy;
use serde_with::base64::Base64;
use serde_with::serde_as;
use std::sync::Arc;
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 = "unc-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(with = "dec_format")]
pub power: Power,
#[serde(with = "dec_format")]
pub locked: 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, BorshSerialize, BorshDeserialize)]
pub enum StateChangeKind {
AccountTouched { account_id: AccountId },
AccessKeyTouched { account_id: AccountId },
DataTouched { account_id: AccountId },
ContractCodeTouched { account_id: AccountId },
RsaKeyTouched { 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 }))
}
TrieKey::Rsa2048Keys { account_id, .. } => {
Some(Ok(StateChangeKind::RsaKeyTouched { account_id }))
}
_ => None,
}
})
.collect()
}
}
#[derive(Debug, Clone, BorshSerialize, BorshDeserialize, PartialEq)]
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,
Resharding,
}
#[derive(Debug, Clone, BorshSerialize, BorshDeserialize)]
pub struct RawStateChange {
pub cause: StateChangeCause,
pub data: Option<Vec<u8>>,
}
#[derive(Debug, Clone, BorshSerialize, BorshDeserialize)]
pub struct RawStateChangesWithTrieKey {
pub trie_key: TrieKey,
pub changes: Vec<RawStateChange>,
}
#[derive(Debug, Clone, BorshSerialize, BorshDeserialize)]
pub struct ConsolidatedStateChange {
pub trie_key: TrieKey,
pub value: Option<Vec<u8>>,
}
#[derive(Debug, Clone, BorshSerialize, BorshDeserialize)]
pub struct StateChangesForResharding {
pub changes: Vec<ConsolidatedStateChange>,
pub processed_delayed_receipts: Vec<Receipt>,
}
impl StateChangesForResharding {
pub fn from_raw_state_changes(
changes: &[RawStateChangesWithTrieKey],
processed_delayed_receipts: Vec<Receipt>,
) -> Self {
let changes = changes
.iter()
.map(|RawStateChangesWithTrieKey { trie_key, changes }| {
let value = changes.last().expect("state_changes must not be empty").data.clone();
ConsolidatedStateChange { trie_key: trie_key.clone(), value }
})
.collect();
Self { changes, processed_delayed_receipts }
}
}
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 },
RsaKeyUpdate { account_id: AccountId, public_key: PublicKey, rsa_key: RegisterRsa2048KeysAction },
RsaKeyDeletion { account_id: AccountId, public_key: PublicKey },
}
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::RsaKeyUpdate { account_id, .. }
| StateChangeValue::RsaKeyDeletion { 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::Rsa2048Keys { 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(),
}
},
},
))
}
}
}
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)]
pub struct StateRootNode {
pub data: Arc<[u8]>,
pub memory_usage: u64,
}
impl StateRootNode {
pub fn empty() -> Self {
static EMPTY: Lazy<Arc<[u8]>> = Lazy::new(|| Arc::new([]));
StateRootNode { data: EMPTY.clone(), memory_usage: 0 }
}
}
#[derive(
Debug,
Clone,
Default,
Hash,
Eq,
PartialEq,
PartialOrd,
Ord,
derive_more::AsRef,
BorshSerialize,
BorshDeserialize,
serde::Serialize,
serde::Deserialize,
arbitrary::Arbitrary,
)]
#[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(BorshSerialize, BorshDeserialize, serde::Serialize, Debug, Clone, PartialEq, Eq)]
pub struct ApprovalFrozen {
pub account_id: AccountId,
pub public_key: PublicKey,
pub frozen_this_epoch: Balance,
pub frozen_next_epoch: Balance,
}
pub mod validator_power_and_frozen {
use borsh::{BorshDeserialize, BorshSerialize};
use unc_crypto::PublicKey;
use unc_primitives_core::types::{AccountId, Balance, Power};
use serde::Serialize;
use crate::types::{ApprovalFrozen};
pub use super::ValidatorPowerAndFrozenV1;
#[derive(BorshSerialize, BorshDeserialize, Serialize, Debug, Clone, PartialEq, Eq, PartialOrd)]
#[serde(tag = "validator_power_and_frozen_struct_version")]
pub enum ValidatorPowerAndFrozen {
V1(ValidatorPowerAndFrozenV1),
}
#[derive(Clone)]
pub struct ValidatorPowerAndFrozenIter<'a> {
collection: ValidatorPowerAndFrozenIterSource<'a>,
curr_index: usize,
len: usize,
}
impl<'a> ValidatorPowerAndFrozenIter<'a> {
pub fn empty() -> Self {
Self { collection: ValidatorPowerAndFrozenIterSource::V2(&[]), curr_index: 0, len: 0 }
}
pub fn v1(collection: &'a [ValidatorPowerAndFrozenV1]) -> Self {
Self {
collection: ValidatorPowerAndFrozenIterSource::V1(collection),
curr_index: 0,
len: collection.len(),
}
}
pub fn new(collection: &'a [ValidatorPowerAndFrozen]) -> Self {
Self {
collection: ValidatorPowerAndFrozenIterSource::V2(collection),
curr_index: 0,
len: collection.len(),
}
}
pub fn len(&self) -> usize {
self.len
}
}
impl<'a> Iterator for ValidatorPowerAndFrozenIter<'a> {
type Item = ValidatorPowerAndFrozen;
fn next(&mut self) -> Option<Self::Item> {
if self.curr_index < self.len {
let item = match self.collection {
ValidatorPowerAndFrozenIterSource::V1(collection) => {
ValidatorPowerAndFrozen::V1(collection[self.curr_index].clone())
}
ValidatorPowerAndFrozenIterSource::V2(collection) => {
collection[self.curr_index].clone()
}
};
self.curr_index += 1;
Some(item)
} else {
None
}
}
}
#[derive(Clone)]
enum ValidatorPowerAndFrozenIterSource<'a> {
V1(&'a [ValidatorPowerAndFrozenV1]),
V2(&'a [ValidatorPowerAndFrozen]),
}
impl ValidatorPowerAndFrozen {
pub fn new_v1(
account_id: AccountId,
public_key: PublicKey,
power: Power,
frozen: Balance,
) -> Self {
Self::V1(ValidatorPowerAndFrozenV1 { account_id, public_key, power, frozen })
}
pub fn new(
account_id: AccountId,
public_key: PublicKey,
power: Power,
frozen: Balance,
) -> Self {
Self::new_v1(account_id, public_key, power, frozen)
}
pub fn into_v1(self) -> ValidatorPowerAndFrozenV1 {
match self {
Self::V1(v1) => v1,
}
}
#[inline]
pub fn account_and_frozen(self) -> (AccountId, Balance) {
match self {
Self::V1(v1) => (v1.account_id, v1.frozen),
}
}
#[inline]
pub fn account_and_power(self) -> (AccountId, Power) {
match self {
Self::V1(v1) => (v1.account_id, v1.power),
}
}
#[inline]
pub fn destructure(self) -> (AccountId, PublicKey, Power, Balance) {
match self {
Self::V1(v1) => (v1.account_id, v1.public_key, v1.power, v1.frozen),
}
}
#[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 power(&self) -> Power {
match self {
Self::V1(v1) => v1.power,
}
}
#[inline]
pub fn power_mut(&mut self) -> &mut Power {
match self {
Self::V1(v1) => &mut v1.power,
}
}
#[inline]
pub fn frozen(&self) -> Balance {
match self {
Self::V1(v1) => v1.frozen,
}
}
pub fn get_approval_frozen(&self, is_next_epoch: bool) -> ApprovalFrozen {
ApprovalFrozen {
account_id: self.account_id().clone(),
public_key: self.public_key().clone(),
frozen_this_epoch: if is_next_epoch { 0 } else { self.frozen() },
frozen_next_epoch: if is_next_epoch { self.frozen() } else { 0 },
}
}
pub fn num_mandates(&self, frozen_per_mandate: Balance) -> u16 {
u16::try_from(self.frozen() / frozen_per_mandate)
.expect("number of mandats should fit u16")
}
pub fn partial_mandate_weight(&self, frozen_per_mandate: Balance) -> Balance {
self.frozen() % frozen_per_mandate
}
}
}
pub mod validator_frozen {
use borsh::{BorshDeserialize, BorshSerialize};
use unc_crypto::PublicKey;
use unc_primitives_core::types::{AccountId, Balance};
use serde::Serialize;
pub use super::ValidatorFrozenV1;
#[derive(BorshSerialize, BorshDeserialize, Serialize, Debug, Clone, PartialEq, Eq)]
#[serde(tag = "validator_validator_struct_version")]
pub enum ValidatorFrozen {
V1(ValidatorFrozenV1),
}
pub struct ValidatorFrozenIter<'a> {
collection: ValidatorFrozenIterSource<'a>,
curr_index: usize,
len: usize,
}
impl<'a> ValidatorFrozenIter<'a> {
pub fn empty() -> Self {
Self { collection: ValidatorFrozenIterSource::V2(&[]), curr_index: 0, len: 0 }
}
pub fn v1(collection: &'a [ValidatorFrozenV1]) -> Self {
Self {
collection: ValidatorFrozenIterSource::V1(collection),
curr_index: 0,
len: collection.len(),
}
}
pub fn new(collection: &'a [ValidatorFrozen]) -> Self {
Self {
collection: ValidatorFrozenIterSource::V2(collection),
curr_index: 0,
len: collection.len(),
}
}
pub fn len(&self) -> usize {
self.len
}
}
impl<'a> Iterator for ValidatorFrozenIter<'a> {
type Item = ValidatorFrozen;
fn next(&mut self) -> Option<Self::Item> {
if self.curr_index < self.len {
let item = match self.collection {
ValidatorFrozenIterSource::V1(collection) => {
ValidatorFrozen::V1(collection[self.curr_index].clone())
}
ValidatorFrozenIterSource::V2(collection) => collection[self.curr_index].clone(),
};
self.curr_index += 1;
Some(item)
} else {
None
}
}
}
enum ValidatorFrozenIterSource<'a> {
V1(&'a [ValidatorFrozenV1]),
V2(&'a [ValidatorFrozen]),
}
impl ValidatorFrozen {
pub fn new_v1(account_id: AccountId, public_key: PublicKey, frozen: Balance) -> Self {
Self::V1(ValidatorFrozenV1 { account_id, public_key, frozen })
}
pub fn new(account_id: AccountId, public_key: PublicKey, frozen: Balance) -> Self {
Self::new_v1(account_id, public_key, frozen)
}
pub fn into_v1(self) -> ValidatorFrozenV1 {
match self {
Self::V1(v1) => v1,
}
}
#[inline]
pub fn account_and_frozen(self) -> (AccountId, Balance) {
match self {
Self::V1(v1) => (v1.account_id, v1.frozen),
}
}
#[inline]
pub fn destructure(self) -> (AccountId, PublicKey, Balance) {
match self {
Self::V1(v1) => (v1.account_id, v1.public_key, v1.frozen),
}
}
#[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 frozen(&self) -> Balance {
match self {
Self::V1(v1) => v1.frozen,
}
}
#[inline]
pub fn frozen_mut(&mut self) -> &mut Balance {
match self {
Self::V1(v1) => &mut v1.frozen,
}
}
}
}
#[derive(BorshSerialize, BorshDeserialize, serde::Serialize, Debug, Clone, PartialEq, Eq)]
pub struct ApprovalPower {
pub account_id: AccountId,
pub public_key: PublicKey,
pub power_this_epoch: Power,
pub power_next_epoch: Power,
}
pub mod validator_power {
use crate::types::ApprovalPower;
use borsh::{BorshDeserialize, BorshSerialize};
use unc_crypto::PublicKey;
use unc_primitives_core::types::{AccountId, Power};
use serde::Serialize;
pub use super::ValidatorPowerV1;
#[derive(BorshSerialize, BorshDeserialize, Serialize, Debug, Clone, PartialEq, Eq)]
#[serde(tag = "validator_power_struct_version")]
pub enum ValidatorPower {
V1(ValidatorPowerV1),
}
pub struct ValidatorPowerIter<'a> {
collection: ValidatorPowerIterSource<'a>,
curr_index: usize,
len: usize,
}
impl<'a> ValidatorPowerIter<'a> {
pub fn empty() -> Self {
Self { collection: ValidatorPowerIterSource::V2(&[]), curr_index: 0, len: 0 }
}
pub fn v1(collection: &'a [ValidatorPowerV1]) -> Self {
Self {
collection: ValidatorPowerIterSource::V1(collection),
curr_index: 0,
len: collection.len(),
}
}
pub fn new(collection: &'a [ValidatorPower]) -> Self {
Self {
collection: ValidatorPowerIterSource::V2(collection),
curr_index: 0,
len: collection.len(),
}
}
pub fn len(&self) -> usize {
self.len
}
}
impl<'a> Iterator for ValidatorPowerIter<'a> {
type Item = ValidatorPower;
fn next(&mut self) -> Option<Self::Item> {
if self.curr_index < self.len {
let item = match self.collection {
ValidatorPowerIterSource::V1(collection) => {
ValidatorPower::V1(collection[self.curr_index].clone())
}
ValidatorPowerIterSource::V2(collection) => collection[self.curr_index].clone(),
};
self.curr_index += 1;
Some(item)
} else {
None
}
}
}
enum ValidatorPowerIterSource<'a> {
V1(&'a [ValidatorPowerV1]),
V2(&'a [ValidatorPower]),
}
impl ValidatorPower {
pub fn new_v1(account_id: AccountId, public_key: PublicKey, power: Power) -> Self {
Self::V1(ValidatorPowerV1 { account_id, public_key, power})
}
pub fn new(account_id: AccountId, public_key: PublicKey, power: Power) -> Self {
Self::new_v1(account_id, public_key, power)
}
pub fn into_v1(self) -> ValidatorPowerV1 {
match self {
Self::V1(v1) => v1,
}
}
#[inline]
pub fn account_and_power(self) -> (AccountId, Power) {
match self {
Self::V1(v1) => (v1.account_id, v1.power),
}
}
#[inline]
pub fn destructure(self) -> (AccountId, PublicKey, Power) {
match self {
Self::V1(v1) => (v1.account_id, v1.public_key, v1.power),
}
}
#[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 power(&self) -> Power {
match self {
Self::V1(v1) => v1.power,
}
}
#[inline]
pub fn power_mut(&mut self) -> &mut Power {
match self {
Self::V1(v1) => &mut v1.power,
}
}
pub fn get_approval_power(&self, is_next_epoch: bool) -> ApprovalPower {
ApprovalPower {
account_id: self.account_id().clone(),
public_key: self.public_key().clone(),
power_this_epoch: if is_next_epoch { 0 } else { self.power() },
power_next_epoch: if is_next_epoch { self.power() } else { 0 },
}
}
}
}
#[derive(BorshSerialize, BorshDeserialize, serde::Serialize, Debug, Clone, PartialEq, Eq, PartialOrd)]
pub struct ValidatorPowerAndFrozenV1 {
pub account_id: AccountId,
pub public_key: PublicKey,
pub power: Power,
pub frozen: Balance,
}
#[derive(BorshSerialize, BorshDeserialize, serde::Serialize, Debug, Clone, PartialEq, Eq)]
pub struct ValidatorFrozenV1 {
pub account_id: AccountId,
pub public_key: PublicKey,
pub frozen: Balance,
}
#[derive(BorshSerialize, BorshDeserialize, serde::Serialize, Debug, Clone, PartialEq, Eq)]
pub struct ValidatorPowerV1 {
pub account_id: AccountId,
pub public_key: PublicKey,
pub power: Power,
}
#[derive(Debug, PartialEq, BorshSerialize, BorshDeserialize, Clone, Eq)]
pub struct BlockExtra {
pub challenges_result: ChallengesResult,
}
pub mod chunk_extra {
use crate::types::validator_power::{ValidatorPower, ValidatorPowerIter};
use crate::types::validator_frozen::{ValidatorFrozen, ValidatorFrozenIter};
use crate::types::StateRoot;
use borsh::{BorshDeserialize, BorshSerialize};
use unc_primitives_core::hash::CryptoHash;
use unc_primitives_core::types::{Balance, Gas};
pub use super::ChunkExtraV1;
#[derive(Debug, PartialEq, BorshSerialize, BorshDeserialize, Clone, Eq)]
pub enum ChunkExtra {
V1(ChunkExtraV1),
V2(ChunkExtraV2),
}
#[derive(Debug, PartialEq, BorshSerialize, BorshDeserialize, Clone, Eq)]
pub struct ChunkExtraV2 {
pub state_root: StateRoot,
pub outcome_root: CryptoHash,
pub validator_power_proposals: Vec<ValidatorPower>,
pub validator_frozen_proposals: Vec<ValidatorFrozen>,
pub gas_used: Gas,
pub gas_limit: Gas,
pub balance_burnt: Balance,
}
impl ChunkExtra {
pub fn new_with_only_state_root(state_root: &StateRoot) -> Self {
Self::new(state_root, CryptoHash::default(), vec![], vec![], 0, 0,0)
}
pub fn new(
state_root: &StateRoot,
outcome_root: CryptoHash,
validator_power_proposals: Vec<ValidatorPower>,
validator_frozen_proposals: Vec<ValidatorFrozen>,
gas_used: Gas,
gas_limit: Gas,
balance_burnt: Balance,
) -> Self {
Self::V2(ChunkExtraV2 {
state_root: *state_root,
outcome_root,
validator_power_proposals,
validator_frozen_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,
}
}
#[inline]
pub fn state_root(&self) -> &StateRoot {
match self {
Self::V1(v1) => &v1.state_root,
Self::V2(v2) => &v2.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,
}
}
#[inline]
pub fn validator_power_proposals(&self) -> ValidatorPowerIter {
match self {
Self::V1(v1) => ValidatorPowerIter::v1(&v1.validator_power_proposals),
Self::V2(v2) => ValidatorPowerIter::new(&v2.validator_power_proposals),
}
}
#[inline]
pub fn validator_frozen_proposals(&self) -> ValidatorFrozenIter {
match self {
Self::V1(v1) => ValidatorFrozenIter::v1(&v1.validator_frozen_proposals),
Self::V2(v2) => ValidatorFrozenIter::new(&v2.validator_frozen_proposals),
}
}
#[inline]
pub fn gas_limit(&self) -> Gas {
match self {
Self::V1(v1) => v1.gas_limit,
Self::V2(v2) => v2.gas_limit,
}
}
#[inline]
pub fn gas_used(&self) -> Gas {
match self {
Self::V1(v1) => v1.gas_used,
Self::V2(v2) => v2.gas_used,
}
}
#[inline]
pub fn balance_burnt(&self) -> Balance {
match self {
Self::V1(v1) => v1.balance_burnt,
Self::V2(v2) => v2.balance_burnt,
}
}
}
}
#[derive(Debug, PartialEq, BorshSerialize, BorshDeserialize, Clone, Eq)]
pub struct ChunkExtraV1 {
pub state_root: StateRoot,
pub outcome_root: CryptoHash,
pub validator_power_proposals: Vec<ValidatorPowerV1>,
pub validator_frozen_proposals: Vec<ValidatorFrozenV1>,
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)]
pub struct ValidatorStats {
pub produced: NumBlocks,
pub expected: NumBlocks,
}
#[derive(Debug, BorshSerialize, BorshDeserialize, PartialEq, Eq)]
pub struct BlockChunkValidatorStats {
pub block_stats: ValidatorStats,
pub chunk_stats: ValidatorStats,
}
#[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(Debug)]
pub enum ValidatorInfoIdentifier {
EpochId(EpochId),
BlockHash(CryptoHash),
}
#[derive(
BorshSerialize,
BorshDeserialize,
serde::Serialize,
serde::Deserialize,
Clone,
Debug,
PartialEq,
Eq,
)]
pub enum ValidatorKickoutReason {
Slashed,
NotEnoughBlocks { produced: NumBlocks, expected: NumBlocks },
NotEnoughChunks { produced: NumBlocks, expected: NumBlocks },
Unpowered,
NotEnoughPower {
#[serde(with = "dec_format", rename = "power_u128")]
power: Power,
#[serde(with = "dec_format", rename = "power_threshold_u128")]
threshold: Power,
},
Unfrozen,
NotEnoughFrozen {
#[serde(with = "dec_format", rename = "frozen_u128")]
frozen: Balance,
#[serde(with = "dec_format", rename = "frozen_threshold_u128")]
threshold: Balance,
},
DidNotGetASeat,
}
#[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 {
fn validator_power(
&self,
epoch_id: &EpochId,
last_block_hash: &CryptoHash,
account_id: &AccountId,
) -> Result<Option<Power>, EpochError>;
fn validator_total_power(
&self,
epoch_id: &EpochId,
last_block_hash: &CryptoHash,
) -> Result<Power, EpochError>;
fn minimum_power(&self, prev_block_hash: &CryptoHash) -> Result<Power, EpochError>;
fn validator_frozen(
&self,
epoch_id: &EpochId,
last_block_hash: &CryptoHash,
account_id: &AccountId,
) -> Result<Option<Balance>, EpochError>;
fn validator_total_frozen(
&self,
epoch_id: &EpochId,
last_block_hash: &CryptoHash,
) -> Result<Balance, EpochError>;
fn minimum_frozen(&self, prev_block_hash: &CryptoHash) -> Result<Balance, 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 unc_crypto::{KeyType, PublicKey};
use unc_primitives_core::types::{Balance, Power};
use super::validator_power::ValidatorPower;
fn new_validator_power(power: Power) -> ValidatorPower {
ValidatorPower::new(
"test_account".parse().unwrap(),
PublicKey::empty(KeyType::ED25519),
power,
)
}
#[test]
fn test_validator_power_num_mandates() {
assert_eq!(new_validator_power(0).num_mandates(5), 0);
assert_eq!(new_validator_power(10).num_mandates(5), 2);
assert_eq!(new_validator_power(12).num_mandates(5), 2);
}
#[test]
fn test_validator_partial_mandate_weight() {
assert_eq!(new_validator_power(0).partial_mandate_weight(5), 0);
assert_eq!(new_validator_power(10).partial_mandate_weight(5), 0);
assert_eq!(new_validator_power(12).partial_mandate_weight(5), 2);
}
}