use crate::challenge::Challenge;
use crate::sharding::ShardChunkHeader;
use crate::stateless_validation::spice_chunk_endorsement::SpiceEndorsementCoreStatement;
use crate::types::{ChunkExecutionResult, SpiceChunkId};
use borsh::{BorshDeserialize, BorshSerialize};
use near_crypto::Signature;
use near_crypto::vrf::{Proof, Value};
use near_primitives_core::hash::CryptoHash;
use near_schema_checker_lib::ProtocolSchema;
#[derive(BorshSerialize, BorshDeserialize, Debug, Clone, Eq, PartialEq, ProtocolSchema)]
pub struct BlockBodyV1 {
pub chunks: Vec<ShardChunkHeader>,
#[deprecated]
pub challenges: Vec<Challenge>,
pub vrf_value: Value,
pub vrf_proof: Proof,
}
impl BlockBodyV1 {
pub fn compute_hash(&self) -> CryptoHash {
CryptoHash::hash_borsh(self)
}
}
#[derive(BorshSerialize, BorshDeserialize, Debug, Clone, Eq, PartialEq, ProtocolSchema)]
pub struct BlockBodyV2 {
pub chunks: Vec<ShardChunkHeader>,
#[deprecated]
pub challenges: Vec<Challenge>,
pub vrf_value: Value,
pub vrf_proof: Proof,
pub chunk_endorsements: Vec<ChunkEndorsementSignatures>,
}
pub type ChunkEndorsementSignatures = Vec<Option<Box<Signature>>>;
#[derive(BorshSerialize, BorshDeserialize, Debug, Clone, Eq, PartialEq, ProtocolSchema)]
pub struct SpiceBlockBodyV3 {
pub chunks: Vec<ShardChunkHeader>,
pub vrf_value: Value,
pub vrf_proof: Proof,
pub core_statements: SpiceCoreStatements,
}
#[derive(BorshSerialize, BorshDeserialize, Debug, Clone, Eq, PartialEq, ProtocolSchema)]
pub enum SpiceCoreStatement {
Endorsement(SpiceEndorsementCoreStatement),
ChunkExecutionResult { chunk_id: SpiceChunkId, execution_result: ChunkExecutionResult },
}
impl SpiceCoreStatement {
pub fn chunk_id(&self) -> &SpiceChunkId {
match self {
SpiceCoreStatement::Endorsement(endorsement) => endorsement.chunk_id(),
SpiceCoreStatement::ChunkExecutionResult { chunk_id, .. } => &chunk_id,
}
}
}
#[derive(BorshSerialize, BorshDeserialize, Debug, Clone, Eq, PartialEq, ProtocolSchema)]
pub struct SpiceCoreStatements(Vec<SpiceCoreStatement>);
impl SpiceCoreStatements {
pub fn empty() -> &'static Self {
static EMPTY: SpiceCoreStatements = SpiceCoreStatements(Vec::new());
&EMPTY
}
pub fn new(statements: Vec<SpiceCoreStatement>) -> Self {
Self(statements)
}
pub fn iter(&self) -> std::slice::Iter<'_, SpiceCoreStatement> {
self.0.iter()
}
pub fn iter_execution_results(
&self,
) -> impl Iterator<Item = (&SpiceChunkId, &ChunkExecutionResult)> {
self.0.iter().filter_map(|s| match s {
SpiceCoreStatement::ChunkExecutionResult { chunk_id, execution_result } => {
Some((chunk_id, execution_result))
}
_ => None,
})
}
pub fn iter_endorsements(&self) -> impl Iterator<Item = &SpiceEndorsementCoreStatement> {
self.0.iter().filter_map(|s| match s {
SpiceCoreStatement::Endorsement(e) => Some(e),
_ => None,
})
}
}
impl<'a> IntoIterator for &'a SpiceCoreStatements {
type Item = &'a SpiceCoreStatement;
type IntoIter = std::slice::Iter<'a, SpiceCoreStatement>;
fn into_iter(self) -> Self::IntoIter {
self.0.iter()
}
}
#[derive(BorshSerialize, BorshDeserialize, Clone, PartialEq, Eq, Debug, ProtocolSchema)]
#[borsh(use_discriminant = true)]
#[repr(u8)]
pub enum BlockBody {
V1(BlockBodyV1) = 0,
V2(BlockBodyV2) = 1,
V3(SpiceBlockBodyV3) = 2,
}
impl BlockBody {
pub fn new(
chunks: Vec<ShardChunkHeader>,
vrf_value: Value,
vrf_proof: Proof,
chunk_endorsements: Vec<ChunkEndorsementSignatures>,
) -> Self {
#[allow(deprecated)]
BlockBody::V2(BlockBodyV2 {
chunks,
challenges: vec![],
vrf_value,
vrf_proof,
chunk_endorsements,
})
}
pub fn new_for_spice(
chunks: Vec<ShardChunkHeader>,
vrf_value: Value,
vrf_proof: Proof,
core_statements: SpiceCoreStatements,
) -> Self {
BlockBody::V3(SpiceBlockBodyV3 { chunks, vrf_value, vrf_proof, core_statements })
}
#[inline]
pub fn chunks(&self) -> &[ShardChunkHeader] {
match self {
BlockBody::V1(body) => &body.chunks,
BlockBody::V2(body) => &body.chunks,
BlockBody::V3(body) => &body.chunks,
}
}
#[inline]
pub fn vrf_value(&self) -> &Value {
match self {
BlockBody::V1(body) => &body.vrf_value,
BlockBody::V2(body) => &body.vrf_value,
BlockBody::V3(body) => &body.vrf_value,
}
}
#[inline]
pub fn vrf_proof(&self) -> &Proof {
match self {
BlockBody::V1(body) => &body.vrf_proof,
BlockBody::V2(body) => &body.vrf_proof,
BlockBody::V3(body) => &body.vrf_proof,
}
}
#[inline]
pub fn chunk_endorsements(&self) -> &[ChunkEndorsementSignatures] {
match self {
BlockBody::V1(_) => &[],
BlockBody::V2(body) => &body.chunk_endorsements,
BlockBody::V3(_) => &[],
}
}
#[inline]
pub fn spice_core_statements(&self) -> &SpiceCoreStatements {
match self {
BlockBody::V1(_) | BlockBody::V2(_) => SpiceCoreStatements::empty(),
BlockBody::V3(body) => &body.core_statements,
}
}
#[inline]
pub fn is_spice_block(&self) -> bool {
match self {
BlockBody::V1(_) | BlockBody::V2(_) => false,
BlockBody::V3(_) => true,
}
}
pub fn compute_hash(&self) -> CryptoHash {
match self {
BlockBody::V1(body) => body.compute_hash(),
BlockBody::V2(_) | BlockBody::V3(_) => CryptoHash::hash_borsh(self),
}
}
}