use crate::challenge::SlashedValidator;
use crate::hash::{CryptoHash, hash};
use crate::merkle::combine_hash;
use crate::network::PeerId;
use crate::stateless_validation::chunk_endorsements_bitmap::ChunkEndorsementsBitmap;
use crate::types::validator_stake::{ValidatorStake, ValidatorStakeIter, ValidatorStakeV1};
use crate::types::{AccountId, Balance, BlockHeight, EpochId, MerkleHash, NumBlocks, ShardId};
use crate::validator_signer::ValidatorSigner;
use crate::version::ProtocolVersion;
use borsh::{BorshDeserialize, BorshSerialize};
use near_crypto::{KeyType, PublicKey, Signature};
use near_primitives_core::version::ProtocolFeature;
use near_schema_checker_lib::ProtocolSchema;
use near_time::Utc;
#[derive(
BorshSerialize,
BorshDeserialize,
serde::Serialize,
Debug,
Clone,
Eq,
PartialEq,
Default,
ProtocolSchema,
)]
pub struct BlockHeaderInnerLite {
pub height: BlockHeight,
pub epoch_id: EpochId,
pub next_epoch_id: EpochId,
pub prev_state_root: MerkleHash,
pub prev_outcome_root: MerkleHash,
pub timestamp: u64,
pub next_bp_hash: CryptoHash,
pub block_merkle_root: CryptoHash,
}
#[derive(
BorshSerialize, BorshDeserialize, serde::Serialize, Debug, Clone, Eq, PartialEq, ProtocolSchema,
)]
pub struct BlockHeaderInnerRest {
pub prev_chunk_outgoing_receipts_root: MerkleHash,
pub chunk_headers_root: MerkleHash,
pub chunk_tx_root: MerkleHash,
pub chunks_included: u64,
#[deprecated]
pub challenges_root: MerkleHash,
pub random_value: CryptoHash,
pub prev_validator_proposals: Vec<ValidatorStakeV1>,
pub chunk_mask: Vec<bool>,
pub next_gas_price: Balance,
pub total_supply: Balance,
#[deprecated]
pub challenges_result: Vec<SlashedValidator>,
pub last_final_block: CryptoHash,
pub last_ds_final_block: CryptoHash,
pub approvals: Vec<Option<Box<Signature>>>,
pub latest_protocol_version: ProtocolVersion,
}
#[derive(
BorshSerialize, BorshDeserialize, serde::Serialize, Debug, Clone, Eq, PartialEq, ProtocolSchema,
)]
pub struct BlockHeaderInnerRestV2 {
pub prev_chunk_outgoing_receipts_root: MerkleHash,
pub chunk_headers_root: MerkleHash,
pub chunk_tx_root: MerkleHash,
#[deprecated]
pub challenges_root: MerkleHash,
pub random_value: CryptoHash,
pub prev_validator_proposals: Vec<ValidatorStakeV1>,
pub chunk_mask: Vec<bool>,
pub next_gas_price: Balance,
pub total_supply: Balance,
#[deprecated]
pub challenges_result: Vec<SlashedValidator>,
pub last_final_block: CryptoHash,
pub last_ds_final_block: CryptoHash,
pub approvals: Vec<Option<Box<Signature>>>,
pub latest_protocol_version: ProtocolVersion,
}
#[derive(
BorshSerialize, BorshDeserialize, serde::Serialize, Debug, Clone, Eq, PartialEq, ProtocolSchema,
)]
pub struct BlockHeaderInnerRestV3 {
pub prev_chunk_outgoing_receipts_root: MerkleHash,
pub chunk_headers_root: MerkleHash,
pub chunk_tx_root: MerkleHash,
#[deprecated]
pub challenges_root: MerkleHash,
pub random_value: CryptoHash,
pub prev_validator_proposals: Vec<ValidatorStake>,
pub chunk_mask: Vec<bool>,
pub next_gas_price: Balance,
pub total_supply: Balance,
#[deprecated]
pub challenges_result: Vec<SlashedValidator>,
pub last_final_block: CryptoHash,
pub last_ds_final_block: CryptoHash,
pub block_ordinal: NumBlocks,
pub prev_height: BlockHeight,
pub epoch_sync_data_hash: Option<CryptoHash>,
pub approvals: Vec<Option<Box<Signature>>>,
pub latest_protocol_version: ProtocolVersion,
}
#[derive(
BorshSerialize,
BorshDeserialize,
serde::Serialize,
Debug,
Clone,
Eq,
PartialEq,
Default,
ProtocolSchema,
)]
pub struct BlockHeaderInnerRestV4 {
pub block_body_hash: CryptoHash,
pub prev_chunk_outgoing_receipts_root: MerkleHash,
pub chunk_headers_root: MerkleHash,
pub chunk_tx_root: MerkleHash,
#[deprecated]
pub challenges_root: MerkleHash,
pub random_value: CryptoHash,
pub prev_validator_proposals: Vec<ValidatorStake>,
pub chunk_mask: Vec<bool>,
pub next_gas_price: Balance,
pub total_supply: Balance,
#[deprecated]
pub challenges_result: Vec<SlashedValidator>,
pub last_final_block: CryptoHash,
pub last_ds_final_block: CryptoHash,
pub block_ordinal: NumBlocks,
pub prev_height: BlockHeight,
pub epoch_sync_data_hash: Option<CryptoHash>,
pub approvals: Vec<Option<Box<Signature>>>,
pub latest_protocol_version: ProtocolVersion,
}
#[derive(
BorshSerialize,
BorshDeserialize,
serde::Serialize,
Debug,
Clone,
Eq,
PartialEq,
Default,
ProtocolSchema,
)]
pub struct BlockHeaderInnerRestV5 {
pub block_body_hash: CryptoHash,
pub prev_chunk_outgoing_receipts_root: MerkleHash,
pub chunk_headers_root: MerkleHash,
pub chunk_tx_root: MerkleHash,
#[deprecated]
pub challenges_root: MerkleHash,
pub random_value: CryptoHash,
pub prev_validator_proposals: Vec<ValidatorStake>,
pub chunk_mask: Vec<bool>,
pub next_gas_price: Balance,
pub total_supply: Balance,
#[deprecated]
pub challenges_result: Vec<SlashedValidator>,
pub last_final_block: CryptoHash,
pub last_ds_final_block: CryptoHash,
pub block_ordinal: NumBlocks,
pub prev_height: BlockHeight,
pub epoch_sync_data_hash: Option<CryptoHash>,
pub approvals: Vec<Option<Box<Signature>>>,
pub latest_protocol_version: ProtocolVersion,
pub chunk_endorsements: ChunkEndorsementsBitmap,
}
#[derive(
BorshSerialize,
BorshDeserialize,
serde::Serialize,
Debug,
Clone,
Eq,
PartialEq,
Default,
ProtocolSchema,
)]
pub struct BlockHeaderInnerRestV6 {
pub block_body_hash: CryptoHash,
pub prev_chunk_outgoing_receipts_root: MerkleHash,
pub chunk_headers_root: MerkleHash,
pub chunk_tx_root: MerkleHash,
pub random_value: CryptoHash,
pub prev_validator_proposals: Vec<ValidatorStake>,
pub chunk_mask: Vec<bool>,
pub next_gas_price: Balance,
pub total_supply: Balance,
pub last_final_block: CryptoHash,
pub last_ds_final_block: CryptoHash,
pub block_ordinal: NumBlocks,
pub prev_height: BlockHeight,
pub epoch_sync_data_hash: Option<CryptoHash>,
pub approvals: Vec<Option<Box<Signature>>>,
pub latest_protocol_version: ProtocolVersion,
pub chunk_endorsements: ChunkEndorsementsBitmap,
pub shard_split: Option<(ShardId, AccountId)>,
}
#[derive(
BorshSerialize,
BorshDeserialize,
serde::Serialize,
Debug,
Clone,
PartialEq,
Eq,
Hash,
ProtocolSchema,
)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
pub enum ApprovalInner {
Endorsement(CryptoHash),
Skip(BlockHeight),
}
#[derive(
BorshSerialize, BorshDeserialize, serde::Serialize, Debug, Clone, PartialEq, Eq, ProtocolSchema,
)]
pub struct Approval {
pub inner: ApprovalInner,
pub target_height: BlockHeight,
pub signature: Signature,
pub account_id: AccountId,
}
#[derive(PartialEq, Eq, Debug)]
pub enum ApprovalType {
SelfApproval,
PeerApproval(PeerId),
}
#[derive(
BorshSerialize, BorshDeserialize, serde::Serialize, Debug, Clone, PartialEq, Eq, ProtocolSchema,
)]
pub struct ApprovalMessage {
pub approval: Approval,
pub target: AccountId,
}
impl ApprovalInner {
pub fn new(
parent_hash: &CryptoHash,
parent_height: BlockHeight,
target_height: BlockHeight,
) -> Self {
if target_height == parent_height + 1 {
ApprovalInner::Endorsement(*parent_hash)
} else {
ApprovalInner::Skip(parent_height)
}
}
}
impl Approval {
pub fn new(
parent_hash: CryptoHash,
parent_height: BlockHeight,
target_height: BlockHeight,
signer: &ValidatorSigner,
) -> Self {
let inner = ApprovalInner::new(&parent_hash, parent_height, target_height);
let signature = signer.sign_bytes(&Approval::get_data_for_sig(&inner, target_height));
Approval { inner, target_height, signature, account_id: signer.validator_id().clone() }
}
pub fn get_data_for_sig(inner: &ApprovalInner, target_height: BlockHeight) -> Vec<u8> {
[borsh::to_vec(&inner).unwrap().as_ref(), target_height.to_le_bytes().as_ref()].concat()
}
}
impl ApprovalMessage {
pub fn new(approval: Approval, target: AccountId) -> Self {
ApprovalMessage { approval, target }
}
}
#[derive(
BorshSerialize, BorshDeserialize, serde::Serialize, Debug, Clone, Eq, PartialEq, ProtocolSchema,
)]
#[borsh(init=init)]
pub struct BlockHeaderV1 {
pub prev_hash: CryptoHash,
pub inner_lite: BlockHeaderInnerLite,
pub inner_rest: BlockHeaderInnerRest,
pub signature: Signature,
#[borsh(skip)]
pub hash: CryptoHash,
}
impl BlockHeaderV1 {
pub fn init(&mut self) {
self.hash = BlockHeader::compute_hash(
self.prev_hash,
&borsh::to_vec(&self.inner_lite).expect("Failed to serialize"),
&borsh::to_vec(&self.inner_rest).expect("Failed to serialize"),
);
}
}
#[derive(
BorshSerialize, BorshDeserialize, serde::Serialize, Debug, Clone, Eq, PartialEq, ProtocolSchema,
)]
#[borsh(init=init)]
pub struct BlockHeaderV2 {
pub prev_hash: CryptoHash,
pub inner_lite: BlockHeaderInnerLite,
pub inner_rest: BlockHeaderInnerRestV2,
pub signature: Signature,
#[borsh(skip)]
pub hash: CryptoHash,
}
#[derive(
BorshSerialize, BorshDeserialize, serde::Serialize, Debug, Clone, Eq, PartialEq, ProtocolSchema,
)]
#[borsh(init=init)]
pub struct BlockHeaderV3 {
pub prev_hash: CryptoHash,
pub inner_lite: BlockHeaderInnerLite,
pub inner_rest: BlockHeaderInnerRestV3,
pub signature: Signature,
#[borsh(skip)]
pub hash: CryptoHash,
}
#[derive(
BorshSerialize,
BorshDeserialize,
serde::Serialize,
Debug,
Clone,
Eq,
PartialEq,
Default,
ProtocolSchema,
)]
#[borsh(init=init)]
pub struct BlockHeaderV4 {
pub prev_hash: CryptoHash,
pub inner_lite: BlockHeaderInnerLite,
pub inner_rest: BlockHeaderInnerRestV4,
pub signature: Signature,
#[borsh(skip)]
pub hash: CryptoHash,
}
#[derive(
BorshSerialize,
BorshDeserialize,
serde::Serialize,
Debug,
Clone,
Eq,
PartialEq,
Default,
ProtocolSchema,
)]
#[borsh(init=init)]
pub struct BlockHeaderV5 {
pub prev_hash: CryptoHash,
pub inner_lite: BlockHeaderInnerLite,
pub inner_rest: BlockHeaderInnerRestV5,
pub signature: Signature,
#[borsh(skip)]
pub hash: CryptoHash,
}
#[derive(
BorshSerialize,
BorshDeserialize,
serde::Serialize,
Debug,
Clone,
Eq,
PartialEq,
Default,
ProtocolSchema,
)]
#[borsh(init=init)]
pub struct BlockHeaderV6 {
pub prev_hash: CryptoHash,
pub inner_lite: BlockHeaderInnerLite,
pub inner_rest: BlockHeaderInnerRestV6,
pub signature: Signature,
#[borsh(skip)]
pub hash: CryptoHash,
}
impl BlockHeaderV2 {
pub fn init(&mut self) {
self.hash = BlockHeader::compute_hash(
self.prev_hash,
&borsh::to_vec(&self.inner_lite).expect("Failed to serialize"),
&borsh::to_vec(&self.inner_rest).expect("Failed to serialize"),
);
}
}
impl BlockHeaderV3 {
pub fn init(&mut self) {
self.hash = BlockHeader::compute_hash(
self.prev_hash,
&borsh::to_vec(&self.inner_lite).expect("Failed to serialize"),
&borsh::to_vec(&self.inner_rest).expect("Failed to serialize"),
);
}
}
impl BlockHeaderV4 {
pub fn init(&mut self) {
self.hash = BlockHeader::compute_hash(
self.prev_hash,
&borsh::to_vec(&self.inner_lite).expect("Failed to serialize"),
&borsh::to_vec(&self.inner_rest).expect("Failed to serialize"),
);
}
}
impl BlockHeaderV5 {
pub fn init(&mut self) {
self.hash = BlockHeader::compute_hash(
self.prev_hash,
&borsh::to_vec(&self.inner_lite).expect("Failed to serialize"),
&borsh::to_vec(&self.inner_rest).expect("Failed to serialize"),
);
}
}
impl BlockHeaderV6 {
pub fn init(&mut self) {
self.hash = BlockHeader::compute_hash(
self.prev_hash,
&borsh::to_vec(&self.inner_lite).expect("Failed to serialize"),
&borsh::to_vec(&self.inner_rest).expect("Failed to serialize"),
);
}
}
enum SignatureSource<'a> {
#[allow(dead_code)]
Signer(&'a ValidatorSigner),
Signature(Signature),
}
#[derive(
BorshSerialize, BorshDeserialize, serde::Serialize, Debug, Clone, Eq, PartialEq, ProtocolSchema,
)]
pub enum BlockHeader {
BlockHeaderV1(BlockHeaderV1),
BlockHeaderV2(BlockHeaderV2),
BlockHeaderV3(BlockHeaderV3),
BlockHeaderV4(BlockHeaderV4),
BlockHeaderV5(BlockHeaderV5),
BlockHeaderV6(BlockHeaderV6),
}
impl BlockHeader {
pub fn compute_inner_hash(inner_lite: &[u8], inner_rest: &[u8]) -> CryptoHash {
let hash_lite = hash(inner_lite);
let hash_rest = hash(inner_rest);
combine_hash(&hash_lite, &hash_rest)
}
pub fn compute_hash(prev_hash: CryptoHash, inner_lite: &[u8], inner_rest: &[u8]) -> CryptoHash {
let hash_inner = BlockHeader::compute_inner_hash(inner_lite, inner_rest);
combine_hash(&hash_inner, &prev_hash)
}
pub fn new(
current_protocol_version: ProtocolVersion,
latest_protocol_version: ProtocolVersion,
height: BlockHeight,
prev_hash: CryptoHash,
block_body_hash: CryptoHash,
prev_state_root: MerkleHash,
prev_chunk_outgoing_receipts_root: MerkleHash,
chunk_headers_root: MerkleHash,
chunk_tx_root: MerkleHash,
outcome_root: MerkleHash,
timestamp: u64,
random_value: CryptoHash,
prev_validator_proposals: Vec<ValidatorStake>,
chunk_mask: Vec<bool>,
block_ordinal: NumBlocks,
epoch_id: EpochId,
next_epoch_id: EpochId,
next_gas_price: Balance,
total_supply: Balance,
signer: &ValidatorSigner,
last_final_block: CryptoHash,
last_ds_final_block: CryptoHash,
epoch_sync_data_hash: Option<CryptoHash>,
approvals: Vec<Option<Box<Signature>>>,
next_bp_hash: CryptoHash,
block_merkle_root: CryptoHash,
prev_height: BlockHeight,
chunk_endorsements: Option<ChunkEndorsementsBitmap>,
shard_split: Option<(ShardId, AccountId)>,
) -> Self {
Self::new_impl(
current_protocol_version,
latest_protocol_version,
height,
prev_hash,
block_body_hash,
prev_state_root,
prev_chunk_outgoing_receipts_root,
chunk_headers_root,
chunk_tx_root,
outcome_root,
timestamp,
random_value,
prev_validator_proposals,
chunk_mask,
block_ordinal,
epoch_id,
next_epoch_id,
next_gas_price,
total_supply,
SignatureSource::Signer(signer),
last_final_block,
last_ds_final_block,
epoch_sync_data_hash,
approvals,
next_bp_hash,
block_merkle_root,
prev_height,
chunk_endorsements,
shard_split,
)
}
pub fn from_view(
expected_hash: &CryptoHash,
epoch_protocol_version: ProtocolVersion,
height: BlockHeight,
prev_hash: CryptoHash,
block_body_hash: CryptoHash,
prev_state_root: MerkleHash,
prev_chunk_outgoing_receipts_root: MerkleHash,
chunk_headers_root: MerkleHash,
chunk_tx_root: MerkleHash,
outcome_root: MerkleHash,
timestamp: u64,
random_value: CryptoHash,
prev_validator_proposals: Vec<ValidatorStake>,
chunk_mask: Vec<bool>,
block_ordinal: NumBlocks,
epoch_id: EpochId,
next_epoch_id: EpochId,
next_gas_price: Balance,
total_supply: Balance,
signature: Signature,
last_final_block: CryptoHash,
last_ds_final_block: CryptoHash,
epoch_sync_data_hash: Option<CryptoHash>,
approvals: Vec<Option<Box<Signature>>>,
next_bp_hash: CryptoHash,
block_merkle_root: CryptoHash,
prev_height: BlockHeight,
chunk_endorsements: Option<ChunkEndorsementsBitmap>,
shard_split: Option<(ShardId, AccountId)>,
) -> Self {
let header = Self::new_impl(
epoch_protocol_version,
epoch_protocol_version,
height,
prev_hash,
block_body_hash,
prev_state_root,
prev_chunk_outgoing_receipts_root,
chunk_headers_root,
chunk_tx_root,
outcome_root,
timestamp,
random_value,
prev_validator_proposals,
chunk_mask,
block_ordinal,
epoch_id,
next_epoch_id,
next_gas_price,
total_supply,
SignatureSource::Signature(signature),
last_final_block,
last_ds_final_block,
epoch_sync_data_hash,
approvals,
next_bp_hash,
block_merkle_root,
prev_height,
chunk_endorsements,
shard_split,
);
if header.hash() != expected_hash {
tracing::debug!(height, header_hash=?header.hash(), ?expected_hash, "hash of the created header does not match expected hash");
}
header
}
fn new_impl(
current_protocol_version: ProtocolVersion,
latest_protocol_version: ProtocolVersion,
height: BlockHeight,
prev_hash: CryptoHash,
block_body_hash: CryptoHash,
prev_state_root: MerkleHash,
prev_chunk_outgoing_receipts_root: MerkleHash,
chunk_headers_root: MerkleHash,
chunk_tx_root: MerkleHash,
outcome_root: MerkleHash,
timestamp: u64,
random_value: CryptoHash,
prev_validator_proposals: Vec<ValidatorStake>,
chunk_mask: Vec<bool>,
block_ordinal: NumBlocks,
epoch_id: EpochId,
next_epoch_id: EpochId,
next_gas_price: Balance,
total_supply: Balance,
signature_source: SignatureSource,
last_final_block: CryptoHash,
last_ds_final_block: CryptoHash,
epoch_sync_data_hash: Option<CryptoHash>,
approvals: Vec<Option<Box<Signature>>>,
next_bp_hash: CryptoHash,
block_merkle_root: CryptoHash,
prev_height: BlockHeight,
chunk_endorsements: Option<ChunkEndorsementsBitmap>,
shard_split: Option<(ShardId, AccountId)>,
) -> Self {
let inner_lite = BlockHeaderInnerLite {
height,
epoch_id,
next_epoch_id,
prev_state_root,
prev_outcome_root: outcome_root,
timestamp,
next_bp_hash,
block_merkle_root,
};
let chunk_endorsements = chunk_endorsements.unwrap_or_else(|| {
panic!(
"BlockHeaderV5 (or newer) is enabled but chunk endorsement bitmap is not provided"
)
});
if ProtocolFeature::DynamicResharding.enabled(current_protocol_version) {
let inner_rest = BlockHeaderInnerRestV6 {
block_body_hash,
prev_chunk_outgoing_receipts_root,
chunk_headers_root,
chunk_tx_root,
random_value,
prev_validator_proposals,
chunk_mask,
next_gas_price,
block_ordinal,
total_supply,
last_final_block,
last_ds_final_block,
prev_height,
epoch_sync_data_hash,
approvals,
latest_protocol_version,
chunk_endorsements,
shard_split,
};
let (hash, signature) =
Self::compute_hash_and_sign(signature_source, prev_hash, &inner_lite, &inner_rest);
Self::BlockHeaderV6(BlockHeaderV6 {
prev_hash,
inner_lite,
inner_rest,
signature,
hash,
})
} else {
#[allow(deprecated)]
let inner_rest = BlockHeaderInnerRestV5 {
block_body_hash,
prev_chunk_outgoing_receipts_root,
chunk_headers_root,
chunk_tx_root,
challenges_root: Default::default(),
random_value,
prev_validator_proposals,
chunk_mask,
next_gas_price,
total_supply,
challenges_result: vec![],
last_final_block,
last_ds_final_block,
block_ordinal,
prev_height,
epoch_sync_data_hash,
approvals,
latest_protocol_version,
chunk_endorsements,
};
let (hash, signature) =
Self::compute_hash_and_sign(signature_source, prev_hash, &inner_lite, &inner_rest);
Self::BlockHeaderV5(BlockHeaderV5 {
prev_hash,
inner_lite,
inner_rest,
signature,
hash,
})
}
}
fn compute_hash_and_sign<T>(
signature_source: SignatureSource,
prev_hash: CryptoHash,
inner_lite: &BlockHeaderInnerLite,
inner_rest: &T,
) -> (CryptoHash, Signature)
where
T: BorshSerialize + ?Sized,
{
let hash = BlockHeader::compute_hash(
prev_hash,
&borsh::to_vec(&inner_lite).expect("Failed to serialize"),
&borsh::to_vec(&inner_rest).expect("Failed to serialize"),
);
match signature_source {
SignatureSource::Signer(signer) => (hash, signer.sign_bytes(hash.as_ref())),
SignatureSource::Signature(signature) => (hash, signature),
}
}
pub fn genesis(
genesis_protocol_version: ProtocolVersion,
height: BlockHeight,
state_root: MerkleHash,
block_body_hash: CryptoHash,
prev_chunk_outgoing_receipts_root: MerkleHash,
chunk_headers_root: MerkleHash,
chunk_tx_root: MerkleHash,
num_shards: u64,
timestamp: Utc,
initial_gas_price: Balance,
initial_total_supply: Balance,
next_bp_hash: CryptoHash,
) -> Self {
let chunks_included = if height == 0 { num_shards } else { 0 };
Self::new_impl(
genesis_protocol_version,
genesis_protocol_version,
height,
CryptoHash::default(), block_body_hash,
state_root,
prev_chunk_outgoing_receipts_root,
chunk_headers_root,
chunk_tx_root,
CryptoHash::default(), timestamp.unix_timestamp_nanos() as u64,
CryptoHash::default(), vec![], vec![true; chunks_included as usize], 1, EpochId::default(), EpochId::default(), initial_gas_price,
initial_total_supply,
SignatureSource::Signature(Signature::empty(KeyType::ED25519)),
CryptoHash::default(), CryptoHash::default(), None, vec![], next_bp_hash,
CryptoHash::default(), 0, Some(ChunkEndorsementsBitmap::genesis()),
None, )
}
#[inline]
pub fn is_genesis(&self) -> bool {
self.prev_hash() == &CryptoHash::default()
}
#[inline]
pub fn hash(&self) -> &CryptoHash {
match self {
BlockHeader::BlockHeaderV1(header) => &header.hash,
BlockHeader::BlockHeaderV2(header) => &header.hash,
BlockHeader::BlockHeaderV3(header) => &header.hash,
BlockHeader::BlockHeaderV4(header) => &header.hash,
BlockHeader::BlockHeaderV5(header) => &header.hash,
BlockHeader::BlockHeaderV6(header) => &header.hash,
}
}
#[inline]
pub fn prev_hash(&self) -> &CryptoHash {
match self {
BlockHeader::BlockHeaderV1(header) => &header.prev_hash,
BlockHeader::BlockHeaderV2(header) => &header.prev_hash,
BlockHeader::BlockHeaderV3(header) => &header.prev_hash,
BlockHeader::BlockHeaderV4(header) => &header.prev_hash,
BlockHeader::BlockHeaderV5(header) => &header.prev_hash,
BlockHeader::BlockHeaderV6(header) => &header.prev_hash,
}
}
#[inline]
pub fn signature(&self) -> &Signature {
match self {
BlockHeader::BlockHeaderV1(header) => &header.signature,
BlockHeader::BlockHeaderV2(header) => &header.signature,
BlockHeader::BlockHeaderV3(header) => &header.signature,
BlockHeader::BlockHeaderV4(header) => &header.signature,
BlockHeader::BlockHeaderV5(header) => &header.signature,
BlockHeader::BlockHeaderV6(header) => &header.signature,
}
}
#[inline]
pub fn height(&self) -> BlockHeight {
match self {
BlockHeader::BlockHeaderV1(header) => header.inner_lite.height,
BlockHeader::BlockHeaderV2(header) => header.inner_lite.height,
BlockHeader::BlockHeaderV3(header) => header.inner_lite.height,
BlockHeader::BlockHeaderV4(header) => header.inner_lite.height,
BlockHeader::BlockHeaderV5(header) => header.inner_lite.height,
BlockHeader::BlockHeaderV6(header) => header.inner_lite.height,
}
}
#[inline]
pub fn prev_height(&self) -> Option<BlockHeight> {
match self {
BlockHeader::BlockHeaderV1(_) => None,
BlockHeader::BlockHeaderV2(_) => None,
BlockHeader::BlockHeaderV3(header) => Some(header.inner_rest.prev_height),
BlockHeader::BlockHeaderV4(header) => Some(header.inner_rest.prev_height),
BlockHeader::BlockHeaderV5(header) => Some(header.inner_rest.prev_height),
BlockHeader::BlockHeaderV6(header) => Some(header.inner_rest.prev_height),
}
}
#[inline]
pub fn epoch_id(&self) -> &EpochId {
match self {
BlockHeader::BlockHeaderV1(header) => &header.inner_lite.epoch_id,
BlockHeader::BlockHeaderV2(header) => &header.inner_lite.epoch_id,
BlockHeader::BlockHeaderV3(header) => &header.inner_lite.epoch_id,
BlockHeader::BlockHeaderV4(header) => &header.inner_lite.epoch_id,
BlockHeader::BlockHeaderV5(header) => &header.inner_lite.epoch_id,
BlockHeader::BlockHeaderV6(header) => &header.inner_lite.epoch_id,
}
}
#[inline]
pub fn next_epoch_id(&self) -> &EpochId {
match self {
BlockHeader::BlockHeaderV1(header) => &header.inner_lite.next_epoch_id,
BlockHeader::BlockHeaderV2(header) => &header.inner_lite.next_epoch_id,
BlockHeader::BlockHeaderV3(header) => &header.inner_lite.next_epoch_id,
BlockHeader::BlockHeaderV4(header) => &header.inner_lite.next_epoch_id,
BlockHeader::BlockHeaderV5(header) => &header.inner_lite.next_epoch_id,
BlockHeader::BlockHeaderV6(header) => &header.inner_lite.next_epoch_id,
}
}
#[inline]
pub fn prev_state_root(&self) -> &MerkleHash {
match self {
BlockHeader::BlockHeaderV1(header) => &header.inner_lite.prev_state_root,
BlockHeader::BlockHeaderV2(header) => &header.inner_lite.prev_state_root,
BlockHeader::BlockHeaderV3(header) => &header.inner_lite.prev_state_root,
BlockHeader::BlockHeaderV4(header) => &header.inner_lite.prev_state_root,
BlockHeader::BlockHeaderV5(header) => &header.inner_lite.prev_state_root,
BlockHeader::BlockHeaderV6(header) => &header.inner_lite.prev_state_root,
}
}
#[inline]
pub fn prev_chunk_outgoing_receipts_root(&self) -> &MerkleHash {
match self {
BlockHeader::BlockHeaderV1(header) => {
&header.inner_rest.prev_chunk_outgoing_receipts_root
}
BlockHeader::BlockHeaderV2(header) => {
&header.inner_rest.prev_chunk_outgoing_receipts_root
}
BlockHeader::BlockHeaderV3(header) => {
&header.inner_rest.prev_chunk_outgoing_receipts_root
}
BlockHeader::BlockHeaderV4(header) => {
&header.inner_rest.prev_chunk_outgoing_receipts_root
}
BlockHeader::BlockHeaderV5(header) => {
&header.inner_rest.prev_chunk_outgoing_receipts_root
}
BlockHeader::BlockHeaderV6(header) => {
&header.inner_rest.prev_chunk_outgoing_receipts_root
}
}
}
#[inline]
pub fn chunk_headers_root(&self) -> &MerkleHash {
match self {
BlockHeader::BlockHeaderV1(header) => &header.inner_rest.chunk_headers_root,
BlockHeader::BlockHeaderV2(header) => &header.inner_rest.chunk_headers_root,
BlockHeader::BlockHeaderV3(header) => &header.inner_rest.chunk_headers_root,
BlockHeader::BlockHeaderV4(header) => &header.inner_rest.chunk_headers_root,
BlockHeader::BlockHeaderV5(header) => &header.inner_rest.chunk_headers_root,
BlockHeader::BlockHeaderV6(header) => &header.inner_rest.chunk_headers_root,
}
}
#[inline]
pub fn chunk_tx_root(&self) -> &MerkleHash {
match self {
BlockHeader::BlockHeaderV1(header) => &header.inner_rest.chunk_tx_root,
BlockHeader::BlockHeaderV2(header) => &header.inner_rest.chunk_tx_root,
BlockHeader::BlockHeaderV3(header) => &header.inner_rest.chunk_tx_root,
BlockHeader::BlockHeaderV4(header) => &header.inner_rest.chunk_tx_root,
BlockHeader::BlockHeaderV5(header) => &header.inner_rest.chunk_tx_root,
BlockHeader::BlockHeaderV6(header) => &header.inner_rest.chunk_tx_root,
}
}
pub fn chunks_included(&self) -> u64 {
let mask = match self {
BlockHeader::BlockHeaderV1(header) => return header.inner_rest.chunks_included,
BlockHeader::BlockHeaderV2(header) => &header.inner_rest.chunk_mask,
BlockHeader::BlockHeaderV3(header) => &header.inner_rest.chunk_mask,
BlockHeader::BlockHeaderV4(header) => &header.inner_rest.chunk_mask,
BlockHeader::BlockHeaderV5(header) => &header.inner_rest.chunk_mask,
BlockHeader::BlockHeaderV6(header) => &header.inner_rest.chunk_mask,
};
mask.iter().map(|&x| u64::from(x)).sum::<u64>()
}
#[inline]
pub fn outcome_root(&self) -> &MerkleHash {
match self {
BlockHeader::BlockHeaderV1(header) => &header.inner_lite.prev_outcome_root,
BlockHeader::BlockHeaderV2(header) => &header.inner_lite.prev_outcome_root,
BlockHeader::BlockHeaderV3(header) => &header.inner_lite.prev_outcome_root,
BlockHeader::BlockHeaderV4(header) => &header.inner_lite.prev_outcome_root,
BlockHeader::BlockHeaderV5(header) => &header.inner_lite.prev_outcome_root,
BlockHeader::BlockHeaderV6(header) => &header.inner_lite.prev_outcome_root,
}
}
#[inline]
pub fn block_body_hash(&self) -> Option<CryptoHash> {
match self {
BlockHeader::BlockHeaderV1(_) => None,
BlockHeader::BlockHeaderV2(_) => None,
BlockHeader::BlockHeaderV3(_) => None,
BlockHeader::BlockHeaderV4(header) => Some(header.inner_rest.block_body_hash),
BlockHeader::BlockHeaderV5(header) => Some(header.inner_rest.block_body_hash),
BlockHeader::BlockHeaderV6(header) => Some(header.inner_rest.block_body_hash),
}
}
#[inline]
pub fn raw_timestamp(&self) -> u64 {
match self {
BlockHeader::BlockHeaderV1(header) => header.inner_lite.timestamp,
BlockHeader::BlockHeaderV2(header) => header.inner_lite.timestamp,
BlockHeader::BlockHeaderV3(header) => header.inner_lite.timestamp,
BlockHeader::BlockHeaderV4(header) => header.inner_lite.timestamp,
BlockHeader::BlockHeaderV5(header) => header.inner_lite.timestamp,
BlockHeader::BlockHeaderV6(header) => header.inner_lite.timestamp,
}
}
#[inline]
pub fn prev_validator_proposals(&self) -> ValidatorStakeIter {
match self {
BlockHeader::BlockHeaderV1(header) => {
ValidatorStakeIter::v1(&header.inner_rest.prev_validator_proposals)
}
BlockHeader::BlockHeaderV2(header) => {
ValidatorStakeIter::v1(&header.inner_rest.prev_validator_proposals)
}
BlockHeader::BlockHeaderV3(header) => {
ValidatorStakeIter::new(&header.inner_rest.prev_validator_proposals)
}
BlockHeader::BlockHeaderV4(header) => {
ValidatorStakeIter::new(&header.inner_rest.prev_validator_proposals)
}
BlockHeader::BlockHeaderV5(header) => {
ValidatorStakeIter::new(&header.inner_rest.prev_validator_proposals)
}
BlockHeader::BlockHeaderV6(header) => {
ValidatorStakeIter::new(&header.inner_rest.prev_validator_proposals)
}
}
}
#[inline]
pub fn chunk_mask(&self) -> &[bool] {
match self {
BlockHeader::BlockHeaderV1(header) => &header.inner_rest.chunk_mask,
BlockHeader::BlockHeaderV2(header) => &header.inner_rest.chunk_mask,
BlockHeader::BlockHeaderV3(header) => &header.inner_rest.chunk_mask,
BlockHeader::BlockHeaderV4(header) => &header.inner_rest.chunk_mask,
BlockHeader::BlockHeaderV5(header) => &header.inner_rest.chunk_mask,
BlockHeader::BlockHeaderV6(header) => &header.inner_rest.chunk_mask,
}
}
#[inline]
pub fn block_ordinal(&self) -> NumBlocks {
match self {
BlockHeader::BlockHeaderV1(_) => 0, BlockHeader::BlockHeaderV2(_) => 0, BlockHeader::BlockHeaderV3(header) => header.inner_rest.block_ordinal,
BlockHeader::BlockHeaderV4(header) => header.inner_rest.block_ordinal,
BlockHeader::BlockHeaderV5(header) => header.inner_rest.block_ordinal,
BlockHeader::BlockHeaderV6(header) => header.inner_rest.block_ordinal,
}
}
#[inline]
pub fn next_gas_price(&self) -> Balance {
match self {
BlockHeader::BlockHeaderV1(header) => header.inner_rest.next_gas_price,
BlockHeader::BlockHeaderV2(header) => header.inner_rest.next_gas_price,
BlockHeader::BlockHeaderV3(header) => header.inner_rest.next_gas_price,
BlockHeader::BlockHeaderV4(header) => header.inner_rest.next_gas_price,
BlockHeader::BlockHeaderV5(header) => header.inner_rest.next_gas_price,
BlockHeader::BlockHeaderV6(header) => header.inner_rest.next_gas_price,
}
}
#[inline]
pub fn total_supply(&self) -> Balance {
match self {
BlockHeader::BlockHeaderV1(header) => header.inner_rest.total_supply,
BlockHeader::BlockHeaderV2(header) => header.inner_rest.total_supply,
BlockHeader::BlockHeaderV3(header) => header.inner_rest.total_supply,
BlockHeader::BlockHeaderV4(header) => header.inner_rest.total_supply,
BlockHeader::BlockHeaderV5(header) => header.inner_rest.total_supply,
BlockHeader::BlockHeaderV6(header) => header.inner_rest.total_supply,
}
}
#[inline]
pub fn random_value(&self) -> &CryptoHash {
match self {
BlockHeader::BlockHeaderV1(header) => &header.inner_rest.random_value,
BlockHeader::BlockHeaderV2(header) => &header.inner_rest.random_value,
BlockHeader::BlockHeaderV3(header) => &header.inner_rest.random_value,
BlockHeader::BlockHeaderV4(header) => &header.inner_rest.random_value,
BlockHeader::BlockHeaderV5(header) => &header.inner_rest.random_value,
BlockHeader::BlockHeaderV6(header) => &header.inner_rest.random_value,
}
}
#[inline]
pub fn last_final_block(&self) -> &CryptoHash {
match self {
BlockHeader::BlockHeaderV1(header) => &header.inner_rest.last_final_block,
BlockHeader::BlockHeaderV2(header) => &header.inner_rest.last_final_block,
BlockHeader::BlockHeaderV3(header) => &header.inner_rest.last_final_block,
BlockHeader::BlockHeaderV4(header) => &header.inner_rest.last_final_block,
BlockHeader::BlockHeaderV5(header) => &header.inner_rest.last_final_block,
BlockHeader::BlockHeaderV6(header) => &header.inner_rest.last_final_block,
}
}
#[inline]
pub fn last_final_block_for_height(&self, target_height: BlockHeight) -> &CryptoHash {
if target_height == self.height() + 1 && self.last_ds_final_block() == self.prev_hash() {
self.prev_hash()
} else {
self.last_final_block()
}
}
#[inline]
pub fn last_ds_final_block(&self) -> &CryptoHash {
match self {
BlockHeader::BlockHeaderV1(header) => &header.inner_rest.last_ds_final_block,
BlockHeader::BlockHeaderV2(header) => &header.inner_rest.last_ds_final_block,
BlockHeader::BlockHeaderV3(header) => &header.inner_rest.last_ds_final_block,
BlockHeader::BlockHeaderV4(header) => &header.inner_rest.last_ds_final_block,
BlockHeader::BlockHeaderV5(header) => &header.inner_rest.last_ds_final_block,
BlockHeader::BlockHeaderV6(header) => &header.inner_rest.last_ds_final_block,
}
}
#[inline]
pub fn next_bp_hash(&self) -> &CryptoHash {
match self {
BlockHeader::BlockHeaderV1(header) => &header.inner_lite.next_bp_hash,
BlockHeader::BlockHeaderV2(header) => &header.inner_lite.next_bp_hash,
BlockHeader::BlockHeaderV3(header) => &header.inner_lite.next_bp_hash,
BlockHeader::BlockHeaderV4(header) => &header.inner_lite.next_bp_hash,
BlockHeader::BlockHeaderV5(header) => &header.inner_lite.next_bp_hash,
BlockHeader::BlockHeaderV6(header) => &header.inner_lite.next_bp_hash,
}
}
#[inline]
pub fn block_merkle_root(&self) -> &CryptoHash {
match self {
BlockHeader::BlockHeaderV1(header) => &header.inner_lite.block_merkle_root,
BlockHeader::BlockHeaderV2(header) => &header.inner_lite.block_merkle_root,
BlockHeader::BlockHeaderV3(header) => &header.inner_lite.block_merkle_root,
BlockHeader::BlockHeaderV4(header) => &header.inner_lite.block_merkle_root,
BlockHeader::BlockHeaderV5(header) => &header.inner_lite.block_merkle_root,
BlockHeader::BlockHeaderV6(header) => &header.inner_lite.block_merkle_root,
}
}
#[inline]
pub fn epoch_sync_data_hash(&self) -> Option<CryptoHash> {
match self {
BlockHeader::BlockHeaderV1(_) => None,
BlockHeader::BlockHeaderV2(_) => None,
BlockHeader::BlockHeaderV3(header) => header.inner_rest.epoch_sync_data_hash,
BlockHeader::BlockHeaderV4(header) => header.inner_rest.epoch_sync_data_hash,
BlockHeader::BlockHeaderV5(header) => header.inner_rest.epoch_sync_data_hash,
BlockHeader::BlockHeaderV6(header) => header.inner_rest.epoch_sync_data_hash,
}
}
#[inline]
pub fn approvals(&self) -> &[Option<Box<Signature>>] {
match self {
BlockHeader::BlockHeaderV1(header) => &header.inner_rest.approvals,
BlockHeader::BlockHeaderV2(header) => &header.inner_rest.approvals,
BlockHeader::BlockHeaderV3(header) => &header.inner_rest.approvals,
BlockHeader::BlockHeaderV4(header) => &header.inner_rest.approvals,
BlockHeader::BlockHeaderV5(header) => &header.inner_rest.approvals,
BlockHeader::BlockHeaderV6(header) => &header.inner_rest.approvals,
}
}
pub fn verify_block_producer(&self, public_key: &PublicKey) -> bool {
self.signature().verify(self.hash().as_ref(), public_key)
}
pub fn timestamp(&self) -> Utc {
Utc::from_unix_timestamp_nanos(self.raw_timestamp() as i128).unwrap()
}
pub fn num_approvals(&self) -> u64 {
self.approvals().iter().filter(|x| x.is_some()).count() as u64
}
pub fn verify_chunks_included(&self) -> bool {
match self {
BlockHeader::BlockHeaderV1(header) => {
header.inner_rest.chunk_mask.iter().map(|&x| u64::from(x)).sum::<u64>()
== header.inner_rest.chunks_included
}
BlockHeader::BlockHeaderV2(_header) => true,
BlockHeader::BlockHeaderV3(_header) => true,
BlockHeader::BlockHeaderV4(_header) => true,
BlockHeader::BlockHeaderV5(_header) => true,
BlockHeader::BlockHeaderV6(_header) => true,
}
}
#[inline]
pub fn latest_protocol_version(&self) -> u32 {
match self {
BlockHeader::BlockHeaderV1(header) => header.inner_rest.latest_protocol_version,
BlockHeader::BlockHeaderV2(header) => header.inner_rest.latest_protocol_version,
BlockHeader::BlockHeaderV3(header) => header.inner_rest.latest_protocol_version,
BlockHeader::BlockHeaderV4(header) => header.inner_rest.latest_protocol_version,
BlockHeader::BlockHeaderV5(header) => header.inner_rest.latest_protocol_version,
BlockHeader::BlockHeaderV6(header) => header.inner_rest.latest_protocol_version,
}
}
pub fn inner_lite_bytes(&self) -> Vec<u8> {
match self {
BlockHeader::BlockHeaderV1(header) => {
borsh::to_vec(&header.inner_lite).expect("Failed to serialize")
}
BlockHeader::BlockHeaderV2(header) => {
borsh::to_vec(&header.inner_lite).expect("Failed to serialize")
}
BlockHeader::BlockHeaderV3(header) => {
borsh::to_vec(&header.inner_lite).expect("Failed to serialize")
}
BlockHeader::BlockHeaderV4(header) => {
borsh::to_vec(&header.inner_lite).expect("Failed to serialize")
}
BlockHeader::BlockHeaderV5(header) => {
borsh::to_vec(&header.inner_lite).expect("Failed to serialize")
}
BlockHeader::BlockHeaderV6(header) => {
borsh::to_vec(&header.inner_lite).expect("Failed to serialize")
}
}
}
pub fn inner_rest_bytes(&self) -> Vec<u8> {
match self {
BlockHeader::BlockHeaderV1(header) => {
borsh::to_vec(&header.inner_rest).expect("Failed to serialize")
}
BlockHeader::BlockHeaderV2(header) => {
borsh::to_vec(&header.inner_rest).expect("Failed to serialize")
}
BlockHeader::BlockHeaderV3(header) => {
borsh::to_vec(&header.inner_rest).expect("Failed to serialize")
}
BlockHeader::BlockHeaderV4(header) => {
borsh::to_vec(&header.inner_rest).expect("Failed to serialize")
}
BlockHeader::BlockHeaderV5(header) => {
borsh::to_vec(&header.inner_rest).expect("Failed to serialize")
}
BlockHeader::BlockHeaderV6(header) => {
borsh::to_vec(&header.inner_rest).expect("Failed to serialize")
}
}
}
#[inline]
pub fn chunk_endorsements(&self) -> Option<&ChunkEndorsementsBitmap> {
match self {
BlockHeader::BlockHeaderV1(_) => None,
BlockHeader::BlockHeaderV2(_) => None,
BlockHeader::BlockHeaderV3(_) => None,
BlockHeader::BlockHeaderV4(_) => None,
BlockHeader::BlockHeaderV5(header) => Some(&header.inner_rest.chunk_endorsements),
BlockHeader::BlockHeaderV6(header) => Some(&header.inner_rest.chunk_endorsements),
}
}
#[inline]
pub fn inner_lite(&self) -> &BlockHeaderInnerLite {
match self {
BlockHeader::BlockHeaderV1(header) => &header.inner_lite,
BlockHeader::BlockHeaderV2(header) => &header.inner_lite,
BlockHeader::BlockHeaderV3(header) => &header.inner_lite,
BlockHeader::BlockHeaderV4(header) => &header.inner_lite,
BlockHeader::BlockHeaderV5(header) => &header.inner_lite,
BlockHeader::BlockHeaderV6(header) => &header.inner_lite,
}
}
pub fn challenges_present(&self) -> bool {
#[allow(deprecated)]
let (challenges_root, challenges_result) = match self {
Self::BlockHeaderV1(header) => {
(&header.inner_rest.challenges_root, &header.inner_rest.challenges_result)
}
Self::BlockHeaderV2(header) => {
(&header.inner_rest.challenges_root, &header.inner_rest.challenges_result)
}
Self::BlockHeaderV3(header) => {
(&header.inner_rest.challenges_root, &header.inner_rest.challenges_result)
}
Self::BlockHeaderV4(header) => {
(&header.inner_rest.challenges_root, &header.inner_rest.challenges_result)
}
Self::BlockHeaderV5(header) => {
(&header.inner_rest.challenges_root, &header.inner_rest.challenges_result)
}
Self::BlockHeaderV6(_) => return false,
};
!challenges_result.is_empty() || challenges_root != &MerkleHash::default()
}
#[inline]
pub fn shard_split(&self) -> Option<&(ShardId, AccountId)> {
match self {
BlockHeader::BlockHeaderV1(_) => None,
BlockHeader::BlockHeaderV2(_) => None,
BlockHeader::BlockHeaderV3(_) => None,
BlockHeader::BlockHeaderV4(_) => None,
BlockHeader::BlockHeaderV5(_) => None,
BlockHeader::BlockHeaderV6(header) => header.inner_rest.shard_split.as_ref(),
}
}
}
pub fn compute_bp_hash_from_validator_stakes(
validator_stakes: &Vec<ValidatorStake>,
use_versioned_bp_hash_format: bool,
) -> CryptoHash {
if use_versioned_bp_hash_format {
CryptoHash::hash_borsh_iter(validator_stakes)
} else {
let stakes = validator_stakes.into_iter().map(|stake| stake.clone().into_v1());
CryptoHash::hash_borsh_iter(stakes)
}
}