Skip to content

Commit

Permalink
feat(optimistic_block): Introduce the optimistic block struct (#12730)
Browse files Browse the repository at this point in the history
This PR introduces the shape of the optimistic block described in
#10584.
Along with it I have added the functions to create and sign it. In the
next PR,
I will link this in the path of the block production.
  • Loading branch information
VanBarbascu authored Jan 20, 2025
1 parent b12af57 commit 9b626a7
Show file tree
Hide file tree
Showing 9 changed files with 99 additions and 16 deletions.
1 change: 1 addition & 0 deletions core/primitives/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ pub mod epoch_sync;
pub mod errors;
pub mod merkle;
pub mod network;
pub mod optimistic_block;
pub mod profile_data_v2;
pub mod profile_data_v3;
pub mod rand;
Expand Down
80 changes: 80 additions & 0 deletions core/primitives/src/optimistic_block.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
use borsh::{BorshDeserialize, BorshSerialize};
use near_crypto::Signature;
use near_schema_checker_lib::ProtocolSchema;

use crate::block::BlockHeader;
use crate::hash::{hash, CryptoHash};
use crate::types::{BlockHeight, SignatureDifferentiator};

#[derive(BorshSerialize, BorshDeserialize, Clone, Debug, Eq, PartialEq, ProtocolSchema)]
pub struct OptimisticBlockInner {
pub prev_block_hash: CryptoHash,
pub block_height: BlockHeight,
pub block_timestamp: u64,
// Data to confirm the correctness of randomness beacon output
pub random_value: CryptoHash,
pub vrf_value: near_crypto::vrf::Value,
pub vrf_proof: near_crypto::vrf::Proof,
signature_differentiator: SignatureDifferentiator,
}

/// An optimistic block is independent of specific chunks and can be generated
/// and distributed immediately after the previous block is processed.
/// This block is shared with the validators and used to optimistically process
/// chunks before they get included in the block.
#[derive(BorshSerialize, BorshDeserialize, Clone, Debug, Eq, PartialEq, ProtocolSchema)]
#[borsh(init=init)]
pub struct OptimisticBlock {
pub inner: OptimisticBlockInner,
/// Signature of the block producer.
pub signature: Signature,
#[borsh(skip)]
pub hash: CryptoHash,
}

impl OptimisticBlock {
#[cfg(feature = "clock")]
pub fn produce(
prev_block_header: &BlockHeader,
height: BlockHeight,
signer: &crate::validator_signer::ValidatorSigner,
clock: near_time::Clock,
sandbox_delta_time: Option<near_time::Duration>,
) -> Self {
let prev_block_hash = *prev_block_header.hash();
let (vrf_value, vrf_proof) =
signer.compute_vrf_with_proof(prev_block_header.random_value().as_ref());
let random_value = hash(vrf_value.0.as_ref());

let now = clock.now_utc().unix_timestamp_nanos() as u64;
#[cfg(feature = "sandbox")]
let now = now + sandbox_delta_time.unwrap().whole_nanoseconds() as u64;
#[cfg(not(feature = "sandbox"))]
debug_assert!(sandbox_delta_time.is_none());
let time = if now <= prev_block_header.raw_timestamp() {
prev_block_header.raw_timestamp() + 1
} else {
now
};

let inner = OptimisticBlockInner {
prev_block_hash,
block_height: height,
block_timestamp: time,
random_value,
vrf_value,
vrf_proof,
signature_differentiator: "OptimisticBlock".to_owned(),
};

let hash = hash(&borsh::to_vec(&inner).expect("Failed to serialize"));
let signature = signer.sign_bytes(hash.as_ref());

Self { inner, signature, hash }
}

/// Recompute the hash after deserialization.
pub fn init(&mut self) {
self.hash = hash(&borsh::to_vec(&self.inner).expect("Failed to serialize"));
}
}
4 changes: 2 additions & 2 deletions core/primitives/src/stateless_validation/chunk_endorsement.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
use std::fmt::Debug;

use crate::sharding::{ChunkHash, ShardChunkHeader};
use crate::types::EpochId;
use crate::types::{EpochId, SignatureDifferentiator};
use crate::validator_signer::ValidatorSigner;
use borsh::{BorshDeserialize, BorshSerialize};
use near_crypto::{PublicKey, Signature};
use near_primitives_core::types::{AccountId, BlockHeight, ShardId};
use near_schema_checker_lib::ProtocolSchema;

use super::{ChunkProductionKey, SignatureDifferentiator};
use super::ChunkProductionKey;

/// The endorsement of a chunk by a chunk validator. By providing this, a
/// chunk validator has verified that the chunk state witness is correct.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,12 @@ use near_primitives_core::hash::{hash, CryptoHash};
use near_primitives_core::types::{AccountId, ShardId};
use near_schema_checker_lib::ProtocolSchema;

use super::ChunkProductionKey;
#[cfg(feature = "solomon")]
use crate::reed_solomon::{ReedSolomonEncoderDeserialize, ReedSolomonEncoderSerialize};
use crate::types::SignatureDifferentiator;
use crate::{utils::compression::CompressedData, validator_signer::ValidatorSigner};

use super::{ChunkProductionKey, SignatureDifferentiator};

// Data structures for chunk producers to send accessesed contracts to chunk validators.

/// Contains contracts (as code-hashes) accessed during the application of a chunk.
Expand Down
8 changes: 0 additions & 8 deletions core/primitives/src/stateless_validation/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,6 @@ pub mod state_witness;
pub mod stored_chunk_state_transition_data;
pub mod validator_assignment;

/// An arbitrary static string to make sure that this struct cannot be
/// serialized to look identical to another serialized struct. For chunk
/// production we are signing a chunk hash, so we need to make sure that
/// this signature means something different.
///
/// This is a messy workaround until we know what to do with NEP 483.
type SignatureDifferentiator = String;

/// This struct contains combination of fields that uniquely identify chunk production.
/// It means that for a given instance only one chunk could be produced.
#[derive(Debug, Hash, PartialEq, Eq, Clone, BorshSerialize, BorshDeserialize, ProtocolSchema)]
Expand Down
4 changes: 2 additions & 2 deletions core/primitives/src/stateless_validation/partial_witness.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
use std::fmt::{Debug, Formatter};

use super::{ChunkProductionKey, SignatureDifferentiator};
use super::ChunkProductionKey;
use crate::sharding::ShardChunkHeader;
use crate::types::EpochId;
use crate::types::{EpochId, SignatureDifferentiator};
use crate::validator_signer::ValidatorSigner;
use borsh::{BorshDeserialize, BorshSerialize};
use bytesize::ByteSize;
Expand Down
4 changes: 2 additions & 2 deletions core/primitives/src/stateless_validation/state_witness.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
use std::collections::HashMap;
use std::fmt::Debug;

use super::{ChunkProductionKey, SignatureDifferentiator};
use super::ChunkProductionKey;
use crate::bandwidth_scheduler::BandwidthRequests;
use crate::challenge::PartialState;
use crate::congestion_info::CongestionInfo;
#[cfg(feature = "solomon")]
use crate::reed_solomon::{ReedSolomonEncoderDeserialize, ReedSolomonEncoderSerialize};
use crate::sharding::{ChunkHash, ReceiptProof, ShardChunkHeader, ShardChunkHeaderV3};
use crate::transaction::SignedTransaction;
use crate::types::EpochId;
use crate::types::{EpochId, SignatureDifferentiator};
use crate::utils::compression::CompressedData;
use crate::validator_signer::EmptyValidatorSigner;
use borsh::{BorshDeserialize, BorshSerialize};
Expand Down
8 changes: 8 additions & 0 deletions core/primitives/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,14 @@ pub use chunk_validator_stats::ChunkStats;
/// Hash used by to store state root.
pub type StateRoot = CryptoHash;

/// An arbitrary static string to make sure that this struct cannot be
/// serialized to look identical to another serialized struct. For chunk
/// production we are signing a chunk hash, so we need to make sure that
/// this signature means something different.
///
/// This is a messy workaround until we know what to do with NEP 483.
pub(crate) type SignatureDifferentiator = String;

/// Different types of finality.
#[derive(
serde::Serialize, serde::Deserialize, Default, Clone, Debug, PartialEq, Eq, arbitrary::Arbitrary,
Expand Down
2 changes: 2 additions & 0 deletions tools/protocol-schema-check/res/protocol_schema.toml
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,8 @@ MethodResolveError = 1206790835
MissingTrieValueContext = 2666011379
NextEpochValidatorInfo = 3660299258
NonDelegateAction = 2970737551
OptimisticBlock = 1384126355
OptimisticBlockInner = 1534008891
ParentSplitParameters = 2945469052
PartialEdgeInfo = 1350359189
PartialEncodedChunk = 2321210648
Expand Down

0 comments on commit 9b626a7

Please sign in to comment.