From e72431e1e027213d9fe9b0484f349f2cb8bbaf9a Mon Sep 17 00:00:00 2001 From: Tayfun Elmas Date: Wed, 18 Sep 2024 09:07:30 -0700 Subject: [PATCH 1/8] view --- core/primitives/src/block_header.rs | 291 +++++++++++++++++++++++++--- core/primitives/src/test_utils.rs | 8 +- core/primitives/src/views.rs | 221 ++++----------------- 3 files changed, 297 insertions(+), 223 deletions(-) diff --git a/core/primitives/src/block_header.rs b/core/primitives/src/block_header.rs index c75d3bad929..b17a0b09412 100644 --- a/core/primitives/src/block_header.rs +++ b/core/primitives/src/block_header.rs @@ -593,6 +593,161 @@ impl BlockHeader { clock: near_time::Clock, chunk_endorsements: Option, ) -> Self { + Self::new_impl( + this_epoch_protocol_version, + next_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, + challenges_root, + random_value, + prev_validator_proposals, + chunk_mask, + block_ordinal, + epoch_id, + next_epoch_id, + next_gas_price, + total_supply, + challenges_result, + Some(signer), + None, // signature + last_final_block, + last_ds_final_block, + epoch_sync_data_hash, + approvals, + next_bp_hash, + block_merkle_root, + prev_height, + clock, + chunk_endorsements, + ) + } + + /// Creates a new BlockHeader from information in the view of an existing block. + /// + /// Panics if the hash of the created header does not match the `hash` in the arguments. + #[cfg(feature = "clock")] + 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, + challenges_root: MerkleHash, + random_value: CryptoHash, + prev_validator_proposals: Vec, + chunk_mask: Vec, + block_ordinal: NumBlocks, + epoch_id: EpochId, + next_epoch_id: EpochId, + next_gas_price: Balance, + total_supply: Balance, + challenges_result: ChallengesResult, + signature: Signature, + last_final_block: CryptoHash, + last_ds_final_block: CryptoHash, + epoch_sync_data_hash: Option, + approvals: Vec>>, + next_bp_hash: CryptoHash, + block_merkle_root: CryptoHash, + prev_height: BlockHeight, + chunk_endorsements: Option, + ) -> 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, + challenges_root, + random_value, + prev_validator_proposals, + chunk_mask, + block_ordinal, + epoch_id, + next_epoch_id, + next_gas_price, + total_supply, + challenges_result, + None, // signer + Some(signature), + last_final_block, + last_ds_final_block, + epoch_sync_data_hash, + approvals, + next_bp_hash, + block_merkle_root, + prev_height, + near_time::Clock::real(), + chunk_endorsements, + ); + // Note: We do not panic but only log if the hash of the created header does not match the expected hash (From the view) + // because there are tests that check if we can downgrade a BlockHeader's view a previous version, in which case the hash + // of the header changes. + 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 + } + + #[cfg(feature = "clock")] + fn new_impl( + this_epoch_protocol_version: ProtocolVersion, + next_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, + challenges_root: MerkleHash, + random_value: CryptoHash, + prev_validator_proposals: Vec, + chunk_mask: Vec, + block_ordinal: NumBlocks, + epoch_id: EpochId, + next_epoch_id: EpochId, + next_gas_price: Balance, + total_supply: Balance, + challenges_result: ChallengesResult, + signer: Option<&ValidatorSigner>, + signature: Option, + last_final_block: CryptoHash, + last_ds_final_block: CryptoHash, + epoch_sync_data_hash: Option, + approvals: Vec>>, + next_bp_hash: CryptoHash, + block_merkle_root: CryptoHash, + prev_height: BlockHeight, + clock: near_time::Clock, + chunk_endorsements: Option, + ) -> Self { + assert_ne!( + signer.is_some(), + signature.is_some(), + "Exactly one of signer or signature must be provided" + ); let inner_lite = BlockHeaderInnerLite { height, epoch_id, @@ -604,10 +759,7 @@ impl BlockHeader { block_merkle_root, }; - if chunk_endorsements.is_some() { - debug_assert!(ProtocolFeature::ChunkEndorsementsInBlockHeader - .enabled(this_epoch_protocol_version)); - let chunk_endorsements = chunk_endorsements.unwrap(); + if ProtocolFeature::ChunkEndorsementsInBlockHeader.enabled(this_epoch_protocol_version) { let inner_rest = BlockHeaderInnerRestV5 { block_body_hash, prev_chunk_outgoing_receipts_root, @@ -630,13 +782,32 @@ impl BlockHeader { next_epoch_protocol_version, clock, ), - chunk_endorsements, + chunk_endorsements: chunk_endorsements.unwrap_or_else(|| { + panic!( + "Chunk endorsements bitmap is required at protocol version {}", + this_epoch_protocol_version + ) + }), + }; + let (hash, signature) = if let Some(signer) = signer { + signer.sign_block_header_parts( + prev_hash, + &borsh::to_vec(&inner_lite).expect("Failed to serialize"), + &borsh::to_vec(&inner_rest).expect("Failed to serialize"), + ) + } else { + 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"), + ); + ( + hash, + signature.unwrap_or_else(|| { + panic!("Signature is required when signer is not provided") + }), + ) }; - let (hash, signature) = signer.sign_block_header_parts( - prev_hash, - &borsh::to_vec(&inner_lite).expect("Failed to serialize"), - &borsh::to_vec(&inner_rest).expect("Failed to serialize"), - ); Self::BlockHeaderV5(Arc::new(BlockHeaderV5 { prev_hash, inner_lite, @@ -668,11 +839,25 @@ impl BlockHeader { clock, ), }; - let (hash, signature) = signer.sign_block_header_parts( - prev_hash, - &borsh::to_vec(&inner_lite).expect("Failed to serialize"), - &borsh::to_vec(&inner_rest).expect("Failed to serialize"), - ); + let (hash, signature) = if let Some(signer) = signer { + signer.sign_block_header_parts( + prev_hash, + &borsh::to_vec(&inner_lite).expect("Failed to serialize"), + &borsh::to_vec(&inner_rest).expect("Failed to serialize"), + ) + } else { + 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"), + ); + ( + hash, + signature.unwrap_or_else(|| { + panic!("Signature is required when signer is not provided") + }), + ) + }; Self::BlockHeaderV4(Arc::new(BlockHeaderV4 { prev_hash, inner_lite, @@ -699,6 +884,7 @@ impl BlockHeader { total_supply, challenges_result, signer, + signature, last_final_block, last_ds_final_block, epoch_sync_data_hash, @@ -730,7 +916,8 @@ impl BlockHeader { next_gas_price: Balance, total_supply: Balance, challenges_result: ChallengesResult, - signer: &ValidatorSigner, + signer: Option<&ValidatorSigner>, + signature: Option, last_final_block: CryptoHash, last_ds_final_block: CryptoHash, epoch_sync_data_hash: Option, @@ -763,11 +950,25 @@ impl BlockHeader { approvals, latest_protocol_version: crate::version::PROTOCOL_VERSION, }; - let (hash, signature) = signer.sign_block_header_parts( - prev_hash, - &borsh::to_vec(&inner_lite).expect("Failed to serialize"), - &borsh::to_vec(&inner_rest).expect("Failed to serialize"), - ); + let (hash, signature) = if let Some(signer) = signer { + signer.sign_block_header_parts( + prev_hash, + &borsh::to_vec(&inner_lite).expect("Failed to serialize"), + &borsh::to_vec(&inner_rest).expect("Failed to serialize"), + ) + } else { + 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"), + ); + ( + hash, + signature.unwrap_or_else(|| { + panic!("Signature is required when signer is not provided") + }), + ) + }; Self::BlockHeaderV1(Arc::new(BlockHeaderV1 { prev_hash, inner_lite, @@ -795,11 +996,25 @@ impl BlockHeader { approvals, latest_protocol_version: crate::version::PROTOCOL_VERSION, }; - let (hash, signature) = signer.sign_block_header_parts( - prev_hash, - &borsh::to_vec(&inner_lite).expect("Failed to serialize"), - &borsh::to_vec(&inner_rest).expect("Failed to serialize"), - ); + let (hash, signature) = if let Some(signer) = signer { + signer.sign_block_header_parts( + prev_hash, + &borsh::to_vec(&inner_lite).expect("Failed to serialize"), + &borsh::to_vec(&inner_rest).expect("Failed to serialize"), + ) + } else { + 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"), + ); + ( + hash, + signature.unwrap_or_else(|| { + panic!("Signature is required when signer is not provided") + }), + ) + }; Self::BlockHeaderV2(Arc::new(BlockHeaderV2 { prev_hash, inner_lite, @@ -830,11 +1045,25 @@ impl BlockHeader { clock, ), }; - let (hash, signature) = signer.sign_block_header_parts( - prev_hash, - &borsh::to_vec(&inner_lite).expect("Failed to serialize"), - &borsh::to_vec(&inner_rest).expect("Failed to serialize"), - ); + let (hash, signature) = if let Some(signer) = signer { + signer.sign_block_header_parts( + prev_hash, + &borsh::to_vec(&inner_lite).expect("Failed to serialize"), + &borsh::to_vec(&inner_rest).expect("Failed to serialize"), + ) + } else { + 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"), + ); + ( + hash, + signature.unwrap_or_else(|| { + panic!("Signature is required when signer is not provided") + }), + ) + }; Self::BlockHeaderV3(Arc::new(BlockHeaderV3 { prev_hash, inner_lite, diff --git a/core/primitives/src/test_utils.rs b/core/primitives/src/test_utils.rs index a15b63fc08c..9d0ce31ccf4 100644 --- a/core/primitives/src/test_utils.rs +++ b/core/primitives/src/test_utils.rs @@ -417,11 +417,9 @@ impl BlockHeader { pub fn init(&mut self) { match self { - BlockHeader::BlockHeaderV1(_) - | BlockHeader::BlockHeaderV2(_) - | BlockHeader::BlockHeaderV3(_) => { - unreachable!("old header should not appear in tests") - } + BlockHeader::BlockHeaderV1(header) => Arc::make_mut(header).init(), + BlockHeader::BlockHeaderV2(header) => Arc::make_mut(header).init(), + BlockHeader::BlockHeaderV3(header) => Arc::make_mut(header).init(), BlockHeader::BlockHeaderV4(header) => Arc::make_mut(header).init(), BlockHeader::BlockHeaderV5(header) => Arc::make_mut(header).init(), } diff --git a/core/primitives/src/views.rs b/core/primitives/src/views.rs index 71f96f25ef0..1a50b02f88f 100644 --- a/core/primitives/src/views.rs +++ b/core/primitives/src/views.rs @@ -6,13 +6,8 @@ use crate::account::{AccessKey, AccessKeyPermission, Account, FunctionCallPermission}; use crate::action::delegate::{DelegateAction, SignedDelegateAction}; use crate::block::{Block, BlockHeader, Tip}; -use crate::block_header::{ - BlockHeaderInnerLite, BlockHeaderInnerRest, BlockHeaderInnerRestV2, BlockHeaderInnerRestV3, - BlockHeaderInnerRestV5, BlockHeaderV1, BlockHeaderV2, BlockHeaderV3, BlockHeaderV5, -}; -use crate::block_header::{BlockHeaderInnerRestV4, BlockHeaderV4}; +use crate::block_header::BlockHeaderInnerLite; use crate::challenge::{Challenge, ChallengesResult}; -use crate::checked_feature; use crate::congestion_info::{CongestionInfo, CongestionInfoV1}; use crate::errors::TxExecutionError; use crate::hash::{hash, CryptoHash}; @@ -46,7 +41,7 @@ use near_fmt::{AbbrBytes, Slice}; use near_parameters::config::CongestionControlConfig; use near_parameters::view::CongestionControlConfigView; use near_parameters::{ActionCosts, ExtCosts}; -use near_primitives_core::version::{ProtocolFeature, PROTOCOL_VERSION}; +use near_primitives_core::version::PROTOCOL_VERSION; use near_schema_checker_lib::ProtocolSchema; use near_time::Utc; use serde_with::base64::Base64; @@ -824,186 +819,38 @@ impl From for BlockHeaderView { impl From for BlockHeader { fn from(view: BlockHeaderView) -> Self { - // TODO(#11900): Use BlockHeader::new to build the header. - let inner_lite = BlockHeaderInnerLite { - height: view.height, - epoch_id: EpochId(view.epoch_id), - next_epoch_id: EpochId(view.next_epoch_id), - prev_state_root: view.prev_state_root, - prev_outcome_root: view.outcome_root, - timestamp: view.timestamp, - next_bp_hash: view.next_bp_hash, - block_merkle_root: view.block_merkle_root, - }; - const LAST_HEADER_V2_VERSION: ProtocolVersion = - crate::version::ProtocolFeature::BlockHeaderV3.protocol_version() - 1; - if view.latest_protocol_version <= 29 { - let validator_proposals = view - .validator_proposals - .into_iter() - .map(|v| v.into_validator_stake().into_v1()) - .collect(); - let mut header = BlockHeaderV1 { - prev_hash: view.prev_hash, - inner_lite, - inner_rest: BlockHeaderInnerRest { - prev_chunk_outgoing_receipts_root: view.chunk_receipts_root, - chunk_headers_root: view.chunk_headers_root, - chunk_tx_root: view.chunk_tx_root, - chunks_included: view.chunks_included, - challenges_root: view.challenges_root, - random_value: view.random_value, - prev_validator_proposals: validator_proposals, - chunk_mask: view.chunk_mask, - next_gas_price: view.gas_price, - total_supply: view.total_supply, - challenges_result: view.challenges_result, - last_final_block: view.last_final_block, - last_ds_final_block: view.last_ds_final_block, - approvals: view.approvals.clone(), - latest_protocol_version: view.latest_protocol_version, - }, - signature: view.signature, - hash: CryptoHash::default(), - }; - header.init(); - BlockHeader::BlockHeaderV1(Arc::new(header)) - } else if view.latest_protocol_version <= LAST_HEADER_V2_VERSION { - let validator_proposals = view - .validator_proposals - .into_iter() - .map(|v| v.into_validator_stake().into_v1()) - .collect(); - let mut header = BlockHeaderV2 { - prev_hash: view.prev_hash, - inner_lite, - inner_rest: BlockHeaderInnerRestV2 { - prev_chunk_outgoing_receipts_root: view.chunk_receipts_root, - chunk_headers_root: view.chunk_headers_root, - chunk_tx_root: view.chunk_tx_root, - challenges_root: view.challenges_root, - random_value: view.random_value, - prev_validator_proposals: validator_proposals, - chunk_mask: view.chunk_mask, - next_gas_price: view.gas_price, - total_supply: view.total_supply, - challenges_result: view.challenges_result, - last_final_block: view.last_final_block, - last_ds_final_block: view.last_ds_final_block, - approvals: view.approvals.clone(), - latest_protocol_version: view.latest_protocol_version, - }, - signature: view.signature, - hash: CryptoHash::default(), - }; - header.init(); - BlockHeader::BlockHeaderV2(Arc::new(header)) - } else if ProtocolFeature::ChunkEndorsementsInBlockHeader - .enabled(view.latest_protocol_version) - { - let chunk_endorsements = view.chunk_endorsements.map_or_else( - || ChunkEndorsementsBitmap::new(view.chunk_mask.len()), - |bytes| ChunkEndorsementsBitmap::from_bytes(bytes), - ); - let mut header = BlockHeaderV5 { - prev_hash: view.prev_hash, - inner_lite, - inner_rest: BlockHeaderInnerRestV5 { - block_body_hash: view.block_body_hash.unwrap_or_default(), - prev_chunk_outgoing_receipts_root: view.chunk_receipts_root, - chunk_headers_root: view.chunk_headers_root, - chunk_tx_root: view.chunk_tx_root, - challenges_root: view.challenges_root, - random_value: view.random_value, - prev_validator_proposals: view - .validator_proposals - .into_iter() - .map(Into::into) - .collect(), - chunk_mask: view.chunk_mask, - next_gas_price: view.gas_price, - block_ordinal: view.block_ordinal.unwrap_or(0), - total_supply: view.total_supply, - challenges_result: view.challenges_result, - last_final_block: view.last_final_block, - last_ds_final_block: view.last_ds_final_block, - prev_height: view.prev_height.unwrap_or_default(), - epoch_sync_data_hash: view.epoch_sync_data_hash, - approvals: view.approvals.clone(), - latest_protocol_version: view.latest_protocol_version, - chunk_endorsements, - }, - signature: view.signature, - hash: CryptoHash::default(), - }; - header.init(); - BlockHeader::BlockHeaderV5(Arc::new(header)) - } else if !checked_feature!("stable", BlockHeaderV4, view.latest_protocol_version) { - let mut header = BlockHeaderV3 { - prev_hash: view.prev_hash, - inner_lite, - inner_rest: BlockHeaderInnerRestV3 { - prev_chunk_outgoing_receipts_root: view.chunk_receipts_root, - chunk_headers_root: view.chunk_headers_root, - chunk_tx_root: view.chunk_tx_root, - challenges_root: view.challenges_root, - random_value: view.random_value, - prev_validator_proposals: view - .validator_proposals - .into_iter() - .map(Into::into) - .collect(), - chunk_mask: view.chunk_mask, - next_gas_price: view.gas_price, - block_ordinal: view.block_ordinal.unwrap_or(0), - total_supply: view.total_supply, - challenges_result: view.challenges_result, - last_final_block: view.last_final_block, - last_ds_final_block: view.last_ds_final_block, - prev_height: view.prev_height.unwrap_or_default(), - epoch_sync_data_hash: view.epoch_sync_data_hash, - approvals: view.approvals.clone(), - latest_protocol_version: view.latest_protocol_version, - }, - signature: view.signature, - hash: CryptoHash::default(), - }; - header.init(); - BlockHeader::BlockHeaderV3(Arc::new(header)) - } else { - let mut header = BlockHeaderV4 { - prev_hash: view.prev_hash, - inner_lite, - inner_rest: BlockHeaderInnerRestV4 { - block_body_hash: view.block_body_hash.unwrap_or_default(), - prev_chunk_outgoing_receipts_root: view.chunk_receipts_root, - chunk_headers_root: view.chunk_headers_root, - chunk_tx_root: view.chunk_tx_root, - challenges_root: view.challenges_root, - random_value: view.random_value, - prev_validator_proposals: view - .validator_proposals - .into_iter() - .map(Into::into) - .collect(), - chunk_mask: view.chunk_mask, - next_gas_price: view.gas_price, - block_ordinal: view.block_ordinal.unwrap_or(0), - total_supply: view.total_supply, - challenges_result: view.challenges_result, - last_final_block: view.last_final_block, - last_ds_final_block: view.last_ds_final_block, - prev_height: view.prev_height.unwrap_or_default(), - epoch_sync_data_hash: view.epoch_sync_data_hash, - approvals: view.approvals.clone(), - latest_protocol_version: view.latest_protocol_version, - }, - signature: view.signature, - hash: CryptoHash::default(), - }; - header.init(); - BlockHeader::BlockHeaderV4(Arc::new(header)) - } + BlockHeader::from_view( + &view.hash, + view.latest_protocol_version, + view.height, + view.prev_hash, + view.block_body_hash.unwrap_or_default(), + view.prev_state_root, + view.chunk_receipts_root, + view.chunk_headers_root, + view.chunk_tx_root, + view.outcome_root, + view.timestamp, + view.challenges_root, + view.random_value, + view.validator_proposals.into_iter().map(|v| v.into_validator_stake()).collect(), + view.chunk_mask, + view.block_ordinal.unwrap_or(0), + EpochId(view.epoch_id), + EpochId(view.next_epoch_id), + view.gas_price, + view.total_supply, + view.challenges_result, + view.signature, + view.last_final_block, + view.last_ds_final_block, + view.epoch_sync_data_hash, + view.approvals, + view.next_bp_hash, + view.block_merkle_root, + view.prev_height.unwrap_or_default(), + view.chunk_endorsements.map(|bytes| ChunkEndorsementsBitmap::from_bytes(bytes)), + ) } } From c21ffe44cf106eac2f692a07d7c971516336dcca Mon Sep 17 00:00:00 2001 From: Tayfun Elmas Date: Wed, 18 Sep 2024 10:15:47 -0700 Subject: [PATCH 2/8] genesis --- core/primitives/src/block_header.rs | 202 +++++----------------------- 1 file changed, 32 insertions(+), 170 deletions(-) diff --git a/core/primitives/src/block_header.rs b/core/primitives/src/block_header.rs index b17a0b09412..9f7e1d8043f 100644 --- a/core/primitives/src/block_header.rs +++ b/core/primitives/src/block_header.rs @@ -1089,179 +1089,41 @@ impl BlockHeader { initial_total_supply: Balance, next_bp_hash: CryptoHash, ) -> Self { - // TODO(#11900): Use BlockHeader::new to build the header. let chunks_included = if height == 0 { num_shards } else { 0 }; - let inner_lite = BlockHeaderInnerLite { + Self::new_impl( + genesis_protocol_version, + genesis_protocol_version, height, - epoch_id: EpochId::default(), - next_epoch_id: EpochId::default(), - prev_state_root: state_root, - prev_outcome_root: CryptoHash::default(), - timestamp: timestamp.unix_timestamp_nanos() as u64, + CryptoHash::default(), // prev_hash + block_body_hash, + state_root, + prev_chunk_outgoing_receipts_root, + chunk_headers_root, + chunk_tx_root, + CryptoHash::default(), // prev_outcome_root + timestamp.unix_timestamp_nanos() as u64, + challenges_root, + CryptoHash::default(), // random_value + vec![], // prev_validator_proposals + vec![true; chunks_included as usize], // chunk_mask + 1, // block_ordinal. It is guaranteed that Chain has the only Block which is Genesis + EpochId::default(), // epoch_id + EpochId::default(), // next_epoch_id + initial_gas_price, + initial_total_supply, + vec![], // challenges_result + None, // signer + Some(Signature::empty(KeyType::ED25519)), // signature + CryptoHash::default(), // last_final_block + CryptoHash::default(), // last_ds_final_block + None, // epoch_sync_data_hash. Epoch Sync cannot be executed up to Genesis + vec![], // approvals next_bp_hash, - block_merkle_root: CryptoHash::default(), - }; - let last_header_v2_version = ProtocolFeature::BlockHeaderV3.protocol_version() - 1; - if genesis_protocol_version <= 29 { - let inner_rest = BlockHeaderInnerRest { - prev_chunk_outgoing_receipts_root, - chunk_headers_root, - chunk_tx_root, - chunks_included, - challenges_root, - random_value: CryptoHash::default(), - prev_validator_proposals: vec![], - chunk_mask: vec![], - next_gas_price: initial_gas_price, - total_supply: initial_total_supply, - challenges_result: vec![], - last_final_block: CryptoHash::default(), - last_ds_final_block: CryptoHash::default(), - approvals: vec![], - latest_protocol_version: genesis_protocol_version, - }; - let hash = BlockHeader::compute_hash( - CryptoHash::default(), - &borsh::to_vec(&inner_lite).expect("Failed to serialize"), - &borsh::to_vec(&inner_rest).expect("Failed to serialize"), - ); - Self::BlockHeaderV1(Arc::new(BlockHeaderV1 { - prev_hash: CryptoHash::default(), - inner_lite, - inner_rest, - signature: Signature::empty(KeyType::ED25519), - hash, - })) - } else if genesis_protocol_version <= last_header_v2_version { - let inner_rest = BlockHeaderInnerRestV2 { - prev_chunk_outgoing_receipts_root, - chunk_headers_root, - chunk_tx_root, - challenges_root, - random_value: CryptoHash::default(), - prev_validator_proposals: vec![], - chunk_mask: vec![true; chunks_included as usize], - next_gas_price: initial_gas_price, - total_supply: initial_total_supply, - challenges_result: vec![], - last_final_block: CryptoHash::default(), - last_ds_final_block: CryptoHash::default(), - approvals: vec![], - latest_protocol_version: genesis_protocol_version, - }; - let hash = BlockHeader::compute_hash( - CryptoHash::default(), - &borsh::to_vec(&inner_lite).expect("Failed to serialize"), - &borsh::to_vec(&inner_rest).expect("Failed to serialize"), - ); - Self::BlockHeaderV2(Arc::new(BlockHeaderV2 { - prev_hash: CryptoHash::default(), - inner_lite, - inner_rest, - signature: Signature::empty(KeyType::ED25519), - hash, - })) - } else if ProtocolFeature::ChunkEndorsementsInBlockHeader.enabled(genesis_protocol_version) - { - let inner_rest = BlockHeaderInnerRestV5 { - prev_chunk_outgoing_receipts_root, - chunk_headers_root, - chunk_tx_root, - challenges_root, - block_body_hash, - random_value: CryptoHash::default(), - prev_validator_proposals: vec![], - chunk_mask: vec![true; chunks_included as usize], - block_ordinal: 1, // It is guaranteed that Chain has the only Block which is Genesis - next_gas_price: initial_gas_price, - total_supply: initial_total_supply, - challenges_result: vec![], - last_final_block: CryptoHash::default(), - last_ds_final_block: CryptoHash::default(), - prev_height: 0, - epoch_sync_data_hash: None, // Epoch Sync cannot be executed up to Genesis - approvals: vec![], - latest_protocol_version: genesis_protocol_version, - chunk_endorsements: ChunkEndorsementsBitmap::genesis(), - }; - let hash = BlockHeader::compute_hash( - CryptoHash::default(), - &borsh::to_vec(&inner_lite).expect("Failed to serialize"), - &borsh::to_vec(&inner_rest).expect("Failed to serialize"), - ); - Self::BlockHeaderV5(Arc::new(BlockHeaderV5 { - prev_hash: CryptoHash::default(), - inner_lite, - inner_rest, - signature: Signature::empty(KeyType::ED25519), - hash, - })) - } else if !ProtocolFeature::BlockHeaderV4.enabled(genesis_protocol_version) { - let inner_rest = BlockHeaderInnerRestV3 { - prev_chunk_outgoing_receipts_root, - chunk_headers_root, - chunk_tx_root, - challenges_root, - random_value: CryptoHash::default(), - prev_validator_proposals: vec![], - chunk_mask: vec![true; chunks_included as usize], - block_ordinal: 1, // It is guaranteed that Chain has the only Block which is Genesis - next_gas_price: initial_gas_price, - total_supply: initial_total_supply, - challenges_result: vec![], - last_final_block: CryptoHash::default(), - last_ds_final_block: CryptoHash::default(), - prev_height: 0, - epoch_sync_data_hash: None, // Epoch Sync cannot be executed up to Genesis - approvals: vec![], - latest_protocol_version: genesis_protocol_version, - }; - let hash = BlockHeader::compute_hash( - CryptoHash::default(), - &borsh::to_vec(&inner_lite).expect("Failed to serialize"), - &borsh::to_vec(&inner_rest).expect("Failed to serialize"), - ); - Self::BlockHeaderV3(Arc::new(BlockHeaderV3 { - prev_hash: CryptoHash::default(), - inner_lite, - inner_rest, - signature: Signature::empty(KeyType::ED25519), - hash, - })) - } else { - let inner_rest = BlockHeaderInnerRestV4 { - prev_chunk_outgoing_receipts_root, - chunk_headers_root, - chunk_tx_root, - challenges_root, - block_body_hash, - random_value: CryptoHash::default(), - prev_validator_proposals: vec![], - chunk_mask: vec![true; chunks_included as usize], - block_ordinal: 1, // It is guaranteed that Chain has the only Block which is Genesis - next_gas_price: initial_gas_price, - total_supply: initial_total_supply, - challenges_result: vec![], - last_final_block: CryptoHash::default(), - last_ds_final_block: CryptoHash::default(), - prev_height: 0, - epoch_sync_data_hash: None, // Epoch Sync cannot be executed up to Genesis - approvals: vec![], - latest_protocol_version: genesis_protocol_version, - }; - let hash = BlockHeader::compute_hash( - CryptoHash::default(), - &borsh::to_vec(&inner_lite).expect("Failed to serialize"), - &borsh::to_vec(&inner_rest).expect("Failed to serialize"), - ); - Self::BlockHeaderV4(Arc::new(BlockHeaderV4 { - prev_hash: CryptoHash::default(), - inner_lite, - inner_rest, - signature: Signature::empty(KeyType::ED25519), - hash, - })) - } + CryptoHash::default(), // block_merkle_root, + 0, // prev_height + near_time::Clock::real(), + Some(ChunkEndorsementsBitmap::genesis()), + ) } #[inline] From b9df7ccde559db5a60e42db4ab5c008457d83bb5 Mon Sep 17 00:00:00 2001 From: Tayfun Elmas Date: Thu, 19 Sep 2024 03:09:23 -0700 Subject: [PATCH 3/8] Simplify more the hash and signature computation --- core/primitives/src/block_header.rs | 152 +++++++++------------------- 1 file changed, 46 insertions(+), 106 deletions(-) diff --git a/core/primitives/src/block_header.rs b/core/primitives/src/block_header.rs index 692d26447e3..e65fb2f0c6c 100644 --- a/core/primitives/src/block_header.rs +++ b/core/primitives/src/block_header.rs @@ -743,11 +743,6 @@ impl BlockHeader { clock: near_time::Clock, chunk_endorsements: Option, ) -> Self { - assert_ne!( - signer.is_some(), - signature.is_some(), - "Exactly one of signer or signature must be provided" - ); let inner_lite = BlockHeaderInnerLite { height, epoch_id, @@ -785,32 +780,10 @@ impl BlockHeader { next_epoch_protocol_version, clock, ), - chunk_endorsements: chunk_endorsements.unwrap_or_else(|| { - panic!( - "Chunk endorsements bitmap is required at protocol version {}", - this_epoch_protocol_version - ) - }), - }; - let (hash, signature) = if let Some(signer) = signer { - signer.sign_block_header_parts( - prev_hash, - &borsh::to_vec(&inner_lite).expect("Failed to serialize"), - &borsh::to_vec(&inner_rest).expect("Failed to serialize"), - ) - } else { - 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"), - ); - ( - hash, - signature.unwrap_or_else(|| { - panic!("Signature is required when signer is not provided") - }), - ) + chunk_endorsements, }; + let (hash, signature) = + Self::compute_hash_and_sign(signer, signature, prev_hash, &inner_lite, &inner_rest); Self::BlockHeaderV5(Arc::new(BlockHeaderV5 { prev_hash, inner_lite, @@ -842,25 +815,8 @@ impl BlockHeader { clock, ), }; - let (hash, signature) = if let Some(signer) = signer { - signer.sign_block_header_parts( - prev_hash, - &borsh::to_vec(&inner_lite).expect("Failed to serialize"), - &borsh::to_vec(&inner_rest).expect("Failed to serialize"), - ) - } else { - 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"), - ); - ( - hash, - signature.unwrap_or_else(|| { - panic!("Signature is required when signer is not provided") - }), - ) - }; + let (hash, signature) = + Self::compute_hash_and_sign(signer, signature, prev_hash, &inner_lite, &inner_rest); Self::BlockHeaderV4(Arc::new(BlockHeaderV4 { prev_hash, inner_lite, @@ -953,25 +909,8 @@ impl BlockHeader { approvals, latest_protocol_version: crate::version::PROTOCOL_VERSION, }; - let (hash, signature) = if let Some(signer) = signer { - signer.sign_block_header_parts( - prev_hash, - &borsh::to_vec(&inner_lite).expect("Failed to serialize"), - &borsh::to_vec(&inner_rest).expect("Failed to serialize"), - ) - } else { - 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"), - ); - ( - hash, - signature.unwrap_or_else(|| { - panic!("Signature is required when signer is not provided") - }), - ) - }; + let (hash, signature) = + Self::compute_hash_and_sign(signer, signature, prev_hash, &inner_lite, &inner_rest); Self::BlockHeaderV1(Arc::new(BlockHeaderV1 { prev_hash, inner_lite, @@ -999,25 +938,8 @@ impl BlockHeader { approvals, latest_protocol_version: crate::version::PROTOCOL_VERSION, }; - let (hash, signature) = if let Some(signer) = signer { - signer.sign_block_header_parts( - prev_hash, - &borsh::to_vec(&inner_lite).expect("Failed to serialize"), - &borsh::to_vec(&inner_rest).expect("Failed to serialize"), - ) - } else { - 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"), - ); - ( - hash, - signature.unwrap_or_else(|| { - panic!("Signature is required when signer is not provided") - }), - ) - }; + let (hash, signature) = + Self::compute_hash_and_sign(signer, signature, prev_hash, &inner_lite, &inner_rest); Self::BlockHeaderV2(Arc::new(BlockHeaderV2 { prev_hash, inner_lite, @@ -1048,25 +970,8 @@ impl BlockHeader { clock, ), }; - let (hash, signature) = if let Some(signer) = signer { - signer.sign_block_header_parts( - prev_hash, - &borsh::to_vec(&inner_lite).expect("Failed to serialize"), - &borsh::to_vec(&inner_rest).expect("Failed to serialize"), - ) - } else { - 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"), - ); - ( - hash, - signature.unwrap_or_else(|| { - panic!("Signature is required when signer is not provided") - }), - ) - }; + let (hash, signature) = + Self::compute_hash_and_sign(signer, signature, prev_hash, &inner_lite, &inner_rest); Self::BlockHeaderV3(Arc::new(BlockHeaderV3 { prev_hash, inner_lite, @@ -1077,6 +982,41 @@ impl BlockHeader { } } + /// Helper function for `new_impl` and `old_impl` to compute the hash and signature of the hash from the block header parts. + /// Exactly one of the `signer` and `signature` must be provided. + /// If `signer` is given signs the header with given `prev_hash`, `inner_lite`, and `inner_rest` and returns the hash and signature of the header. + /// If `signature` is given, uses the signature as is and only computes the hash. + fn compute_hash_and_sign( + signer: Option<&ValidatorSigner>, + signature: Option, + prev_hash: CryptoHash, + inner_lite: &BlockHeaderInnerLite, + inner_rest: &T, + ) -> (CryptoHash, Signature) + where + T: BorshSerialize + ?Sized, + { + assert_ne!( + signer.is_some(), + signature.is_some(), + "Exactly one of signer and signature must be provided" + ); + if let Some(signer) = signer { + signer.sign_block_header_parts( + prev_hash, + &borsh::to_vec(&inner_lite).expect("Failed to serialize"), + &borsh::to_vec(&inner_rest).expect("Failed to serialize"), + ) + } else { + 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"), + ); + (hash, signature.unwrap()) + } + } + pub fn genesis( genesis_protocol_version: ProtocolVersion, height: BlockHeight, From a1b0e83685abe51a08ddf9c8361803ee028ef2a9 Mon Sep 17 00:00:00 2001 From: Tayfun Elmas Date: Thu, 19 Sep 2024 06:02:18 -0700 Subject: [PATCH 4/8] Do not set client protocol version for genesis --- core/primitives/src/block_header.rs | 36 +++++++++++------------------ 1 file changed, 13 insertions(+), 23 deletions(-) diff --git a/core/primitives/src/block_header.rs b/core/primitives/src/block_header.rs index e65fb2f0c6c..47ea0ee403d 100644 --- a/core/primitives/src/block_header.rs +++ b/core/primitives/src/block_header.rs @@ -593,9 +593,12 @@ impl BlockHeader { clock: near_time::Clock, chunk_endorsements: Option, ) -> Self { + let latest_protocol_version = + crate::version::get_protocol_version(next_epoch_protocol_version, clock); Self::new_impl( this_epoch_protocol_version, next_epoch_protocol_version, + latest_protocol_version, height, prev_hash, block_body_hash, @@ -624,7 +627,6 @@ impl BlockHeader { next_bp_hash, block_merkle_root, prev_height, - clock, chunk_endorsements, ) } @@ -632,7 +634,6 @@ impl BlockHeader { /// Creates a new BlockHeader from information in the view of an existing block. /// /// Panics if the hash of the created header does not match the `hash` in the arguments. - #[cfg(feature = "clock")] pub fn from_view( expected_hash: &CryptoHash, epoch_protocol_version: ProtocolVersion, @@ -666,6 +667,7 @@ impl BlockHeader { chunk_endorsements: Option, ) -> Self { let header = Self::new_impl( + epoch_protocol_version, epoch_protocol_version, epoch_protocol_version, height, @@ -696,7 +698,6 @@ impl BlockHeader { next_bp_hash, block_merkle_root, prev_height, - near_time::Clock::real(), chunk_endorsements, ); // Note: We do not panic but only log if the hash of the created header does not match the expected hash (From the view) @@ -708,10 +709,10 @@ impl BlockHeader { header } - #[cfg(feature = "clock")] fn new_impl( this_epoch_protocol_version: ProtocolVersion, next_epoch_protocol_version: ProtocolVersion, + latest_protocol_version: ProtocolVersion, height: BlockHeight, prev_hash: CryptoHash, block_body_hash: CryptoHash, @@ -740,7 +741,6 @@ impl BlockHeader { next_bp_hash: CryptoHash, block_merkle_root: CryptoHash, prev_height: BlockHeight, - clock: near_time::Clock, chunk_endorsements: Option, ) -> Self { let inner_lite = BlockHeaderInnerLite { @@ -776,10 +776,7 @@ impl BlockHeader { prev_height, epoch_sync_data_hash, approvals, - latest_protocol_version: crate::version::get_protocol_version( - next_epoch_protocol_version, - clock, - ), + latest_protocol_version, chunk_endorsements, }; let (hash, signature) = @@ -810,10 +807,7 @@ impl BlockHeader { prev_height, epoch_sync_data_hash, approvals, - latest_protocol_version: crate::version::get_protocol_version( - next_epoch_protocol_version, - clock, - ), + latest_protocol_version, }; let (hash, signature) = Self::compute_hash_and_sign(signer, signature, prev_hash, &inner_lite, &inner_rest); @@ -830,6 +824,7 @@ impl BlockHeader { inner_lite, this_epoch_protocol_version, next_epoch_protocol_version, + latest_protocol_version, prev_hash, prev_chunk_outgoing_receipts_root, chunk_headers_root, @@ -849,7 +844,6 @@ impl BlockHeader { epoch_sync_data_hash, approvals, prev_height, - clock, ) } } @@ -858,11 +852,11 @@ impl BlockHeader { /// This function still preserves code for old block header versions. These code are no longer /// used in production, but we still have features tests in the code that uses them. /// So we still keep the old code here. - #[cfg(feature = "clock")] fn old_impl( inner_lite: BlockHeaderInnerLite, this_epoch_protocol_version: ProtocolVersion, next_epoch_protocol_version: ProtocolVersion, + latest_protocol_version: ProtocolVersion, prev_hash: CryptoHash, prev_chunk_outgoing_receipts_root: MerkleHash, chunk_headers_root: MerkleHash, @@ -882,7 +876,6 @@ impl BlockHeader { epoch_sync_data_hash: Option, approvals: Vec>>, prev_height: BlockHeight, - clock: near_time::Clock, ) -> Self { let last_header_v2_version = ProtocolFeature::BlockHeaderV3.protocol_version() - 1; // Previously we passed next_epoch_protocol_version here, which is incorrect, but we need @@ -907,7 +900,7 @@ impl BlockHeader { last_final_block, last_ds_final_block, approvals, - latest_protocol_version: crate::version::PROTOCOL_VERSION, + latest_protocol_version, }; let (hash, signature) = Self::compute_hash_and_sign(signer, signature, prev_hash, &inner_lite, &inner_rest); @@ -936,7 +929,7 @@ impl BlockHeader { last_final_block, last_ds_final_block, approvals, - latest_protocol_version: crate::version::PROTOCOL_VERSION, + latest_protocol_version, }; let (hash, signature) = Self::compute_hash_and_sign(signer, signature, prev_hash, &inner_lite, &inner_rest); @@ -965,10 +958,7 @@ impl BlockHeader { prev_height, epoch_sync_data_hash, approvals, - latest_protocol_version: crate::version::get_protocol_version( - next_epoch_protocol_version, - clock, - ), + latest_protocol_version, }; let (hash, signature) = Self::compute_hash_and_sign(signer, signature, prev_hash, &inner_lite, &inner_rest); @@ -1034,6 +1024,7 @@ impl BlockHeader { ) -> Self { let chunks_included = if height == 0 { num_shards } else { 0 }; Self::new_impl( + genesis_protocol_version, genesis_protocol_version, genesis_protocol_version, height, @@ -1064,7 +1055,6 @@ impl BlockHeader { next_bp_hash, CryptoHash::default(), // block_merkle_root, 0, // prev_height - near_time::Clock::real(), Some(ChunkEndorsementsBitmap::genesis()), ) } From 2b8b1be09c59301e5375e5b1abce35468605eb7c Mon Sep 17 00:00:00 2001 From: Tayfun Elmas Date: Thu, 19 Sep 2024 06:06:17 -0700 Subject: [PATCH 5/8] Update comments --- core/primitives/src/block_header.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/core/primitives/src/block_header.rs b/core/primitives/src/block_header.rs index 47ea0ee403d..69cac23e61d 100644 --- a/core/primitives/src/block_header.rs +++ b/core/primitives/src/block_header.rs @@ -559,6 +559,7 @@ impl BlockHeader { combine_hash(&hash_inner, &prev_hash) } + /// Creates BlockHeader for a newly produced block. #[cfg(feature = "clock")] pub fn new( this_epoch_protocol_version: ProtocolVersion, @@ -631,9 +632,7 @@ impl BlockHeader { ) } - /// Creates a new BlockHeader from information in the view of an existing block. - /// - /// Panics if the hash of the created header does not match the `hash` in the arguments. + /// Creates a new BlockHeader from information in the view of an existing block. pub fn from_view( expected_hash: &CryptoHash, epoch_protocol_version: ProtocolVersion, @@ -709,6 +708,7 @@ impl BlockHeader { header } + /// Common logic for generating BlockHeader for different purposes, including new blocks, from views, and for genesis block fn new_impl( this_epoch_protocol_version: ProtocolVersion, next_epoch_protocol_version: ProtocolVersion, From 784a0f6399fe07ffede57dc55c4b948b498c9f06 Mon Sep 17 00:00:00 2001 From: Tayfun Elmas Date: Thu, 19 Sep 2024 07:22:04 -0700 Subject: [PATCH 6/8] Revert tesT_utils change, no longer needed. --- core/primitives/src/test_utils.rs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/core/primitives/src/test_utils.rs b/core/primitives/src/test_utils.rs index 9d0ce31ccf4..a15b63fc08c 100644 --- a/core/primitives/src/test_utils.rs +++ b/core/primitives/src/test_utils.rs @@ -417,9 +417,11 @@ impl BlockHeader { pub fn init(&mut self) { match self { - BlockHeader::BlockHeaderV1(header) => Arc::make_mut(header).init(), - BlockHeader::BlockHeaderV2(header) => Arc::make_mut(header).init(), - BlockHeader::BlockHeaderV3(header) => Arc::make_mut(header).init(), + BlockHeader::BlockHeaderV1(_) + | BlockHeader::BlockHeaderV2(_) + | BlockHeader::BlockHeaderV3(_) => { + unreachable!("old header should not appear in tests") + } BlockHeader::BlockHeaderV4(header) => Arc::make_mut(header).init(), BlockHeader::BlockHeaderV5(header) => Arc::make_mut(header).init(), } From 7610677d6dab609bc2181e08a0312dbc9e7a315a Mon Sep 17 00:00:00 2001 From: Tayfun Elmas Date: Fri, 11 Oct 2024 05:38:14 -0700 Subject: [PATCH 7/8] Add enum for signature source --- core/primitives/src/block_header.rs | 71 ++++++++++++++--------------- 1 file changed, 34 insertions(+), 37 deletions(-) diff --git a/core/primitives/src/block_header.rs b/core/primitives/src/block_header.rs index 69cac23e61d..65ba5d02dcc 100644 --- a/core/primitives/src/block_header.rs +++ b/core/primitives/src/block_header.rs @@ -533,6 +533,14 @@ impl BlockHeaderV5 { } } +/// Used in the BlockHeader::new_impl to specify the source of the block header signature. +enum SignatureSource<'a> { + /// Use the given signer to sign a new block header. + Signer(&'a ValidatorSigner), + /// Use the given signature (which was previously computed for an existing block header). + Signature(Signature), +} + /// Versioned BlockHeader data structure. /// For each next version, document what are the changes between versions. #[derive( @@ -619,8 +627,7 @@ impl BlockHeader { next_gas_price, total_supply, challenges_result, - Some(signer), - None, // signature + SignatureSource::Signer(signer), last_final_block, last_ds_final_block, epoch_sync_data_hash, @@ -688,8 +695,7 @@ impl BlockHeader { next_gas_price, total_supply, challenges_result, - None, // signer - Some(signature), + SignatureSource::Signature(signature), last_final_block, last_ds_final_block, epoch_sync_data_hash, @@ -732,8 +738,7 @@ impl BlockHeader { next_gas_price: Balance, total_supply: Balance, challenges_result: ChallengesResult, - signer: Option<&ValidatorSigner>, - signature: Option, + signature_source: SignatureSource, last_final_block: CryptoHash, last_ds_final_block: CryptoHash, epoch_sync_data_hash: Option, @@ -780,7 +785,7 @@ impl BlockHeader { chunk_endorsements, }; let (hash, signature) = - Self::compute_hash_and_sign(signer, signature, prev_hash, &inner_lite, &inner_rest); + Self::compute_hash_and_sign(signature_source, prev_hash, &inner_lite, &inner_rest); Self::BlockHeaderV5(Arc::new(BlockHeaderV5 { prev_hash, inner_lite, @@ -810,7 +815,7 @@ impl BlockHeader { latest_protocol_version, }; let (hash, signature) = - Self::compute_hash_and_sign(signer, signature, prev_hash, &inner_lite, &inner_rest); + Self::compute_hash_and_sign(signature_source, prev_hash, &inner_lite, &inner_rest); Self::BlockHeaderV4(Arc::new(BlockHeaderV4 { prev_hash, inner_lite, @@ -837,8 +842,7 @@ impl BlockHeader { next_gas_price, total_supply, challenges_result, - signer, - signature, + signature_source, last_final_block, last_ds_final_block, epoch_sync_data_hash, @@ -869,8 +873,7 @@ impl BlockHeader { next_gas_price: Balance, total_supply: Balance, challenges_result: ChallengesResult, - signer: Option<&ValidatorSigner>, - signature: Option, + signature_source: SignatureSource, last_final_block: CryptoHash, last_ds_final_block: CryptoHash, epoch_sync_data_hash: Option, @@ -903,7 +906,7 @@ impl BlockHeader { latest_protocol_version, }; let (hash, signature) = - Self::compute_hash_and_sign(signer, signature, prev_hash, &inner_lite, &inner_rest); + Self::compute_hash_and_sign(signature_source, prev_hash, &inner_lite, &inner_rest); Self::BlockHeaderV1(Arc::new(BlockHeaderV1 { prev_hash, inner_lite, @@ -932,7 +935,7 @@ impl BlockHeader { latest_protocol_version, }; let (hash, signature) = - Self::compute_hash_and_sign(signer, signature, prev_hash, &inner_lite, &inner_rest); + Self::compute_hash_and_sign(signature_source, prev_hash, &inner_lite, &inner_rest); Self::BlockHeaderV2(Arc::new(BlockHeaderV2 { prev_hash, inner_lite, @@ -961,7 +964,7 @@ impl BlockHeader { latest_protocol_version, }; let (hash, signature) = - Self::compute_hash_and_sign(signer, signature, prev_hash, &inner_lite, &inner_rest); + Self::compute_hash_and_sign(signature_source, prev_hash, &inner_lite, &inner_rest); Self::BlockHeaderV3(Arc::new(BlockHeaderV3 { prev_hash, inner_lite, @@ -977,8 +980,7 @@ impl BlockHeader { /// If `signer` is given signs the header with given `prev_hash`, `inner_lite`, and `inner_rest` and returns the hash and signature of the header. /// If `signature` is given, uses the signature as is and only computes the hash. fn compute_hash_and_sign( - signer: Option<&ValidatorSigner>, - signature: Option, + signature_source: SignatureSource, prev_hash: CryptoHash, inner_lite: &BlockHeaderInnerLite, inner_rest: &T, @@ -986,24 +988,20 @@ impl BlockHeader { where T: BorshSerialize + ?Sized, { - assert_ne!( - signer.is_some(), - signature.is_some(), - "Exactly one of signer and signature must be provided" - ); - if let Some(signer) = signer { - signer.sign_block_header_parts( - prev_hash, - &borsh::to_vec(&inner_lite).expect("Failed to serialize"), - &borsh::to_vec(&inner_rest).expect("Failed to serialize"), - ) - } else { - let hash = BlockHeader::compute_hash( + match signature_source { + SignatureSource::Signer(signer) => signer.sign_block_header_parts( prev_hash, &borsh::to_vec(&inner_lite).expect("Failed to serialize"), &borsh::to_vec(&inner_rest).expect("Failed to serialize"), - ); - (hash, signature.unwrap()) + ), + SignatureSource::Signature(signature) => { + 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"), + ); + (hash, signature) + } } } @@ -1045,11 +1043,10 @@ impl BlockHeader { EpochId::default(), // next_epoch_id initial_gas_price, initial_total_supply, - vec![], // challenges_result - None, // signer - Some(Signature::empty(KeyType::ED25519)), // signature - CryptoHash::default(), // last_final_block - CryptoHash::default(), // last_ds_final_block + vec![], // challenges_result + SignatureSource::Signature(Signature::empty(KeyType::ED25519)), + CryptoHash::default(), // last_final_block + CryptoHash::default(), // last_ds_final_block None, // epoch_sync_data_hash. Epoch Sync cannot be executed up to Genesis vec![], // approvals next_bp_hash, From f78930702c719b87b194852fd5b8503a91c4811e Mon Sep 17 00:00:00 2001 From: Tayfun Elmas Date: Fri, 11 Oct 2024 05:40:19 -0700 Subject: [PATCH 8/8] Minor change in comments. --- core/primitives/src/block_header.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/primitives/src/block_header.rs b/core/primitives/src/block_header.rs index 65ba5d02dcc..fca826d9ef5 100644 --- a/core/primitives/src/block_header.rs +++ b/core/primitives/src/block_header.rs @@ -537,7 +537,7 @@ impl BlockHeaderV5 { enum SignatureSource<'a> { /// Use the given signer to sign a new block header. Signer(&'a ValidatorSigner), - /// Use the given signature (which was previously computed for an existing block header). + /// Use a previously-computed signature (for reconstructing an already-produced block header). Signature(Signature), }