use crate::sharding::{EncodedShardChunkBody, ReceiptProof};
use crate::state::PartialState;
use crate::stateless_validation::contract_distribution::{CodeBytes, CodeHash};
use crate::transaction::SignedTransaction;
use crate::types::{ChunkExecutionResultHash, SpiceChunkId};
use borsh::{BorshDeserialize, BorshSerialize};
use near_primitives_core::hash::CryptoHash;
use near_primitives_core::types::ShardId;
use near_schema_checker_lib::ProtocolSchema;
use std::collections::{HashMap, HashSet};
use std::fmt::Debug;
pub fn compute_contract_accesses_hash(accesses: &HashSet<CodeHash>) -> CryptoHash {
let mut sorted: Vec<_> = accesses.iter().collect();
sorted.sort();
let mut buf = Vec::with_capacity(sorted.len() * CryptoHash::LENGTH);
for h in &sorted {
buf.extend_from_slice(h.0.as_bytes());
}
CryptoHash::hash_bytes(&buf)
}
#[derive(Debug, Clone, PartialEq, Eq, BorshSerialize, BorshDeserialize, ProtocolSchema)]
#[borsh(use_discriminant = true)]
#[repr(u8)]
pub enum SpiceChunkStateWitness {
V1(SpiceChunkStateWitnessV1) = 0,
}
#[derive(
Debug, Default, Clone, PartialEq, Eq, BorshSerialize, BorshDeserialize, ProtocolSchema,
)]
pub struct SpiceChunkStateTransition {
pub base_state: PartialState,
pub post_state_root: CryptoHash,
}
impl SpiceChunkStateTransition {
pub fn merge_contracts(&mut self, contracts: Vec<CodeBytes>) {
let PartialState::TrieValues(values) = &mut self.base_state;
values.extend(contracts.into_iter().map(|code| code.0));
}
}
#[derive(Debug, Clone, PartialEq, Eq, BorshSerialize, BorshDeserialize, ProtocolSchema)]
pub struct SpiceChunkStateWitnessV1 {
pub chunk_id: SpiceChunkId,
pub main_state_transition: SpiceChunkStateTransition,
pub source_receipt_proofs: HashMap<ShardId, ReceiptProof>,
pub applied_receipts_hash: CryptoHash,
pub transactions: Vec<SignedTransaction>,
pub execution_result_hash: ChunkExecutionResultHash,
pub contract_accesses_hash: CryptoHash,
pub proof_of_invalid_chunk: Option<Box<EncodedShardChunkBody>>,
}
impl SpiceChunkStateWitness {
pub fn new(
chunk_id: SpiceChunkId,
main_state_transition: SpiceChunkStateTransition,
source_receipt_proofs: HashMap<ShardId, ReceiptProof>,
applied_receipts_hash: CryptoHash,
transactions: Vec<SignedTransaction>,
execution_result_hash: ChunkExecutionResultHash,
contract_accesses_hash: CryptoHash,
proof_of_invalid_chunk: Option<Box<EncodedShardChunkBody>>,
) -> Self {
Self::V1(SpiceChunkStateWitnessV1 {
chunk_id,
main_state_transition,
source_receipt_proofs,
applied_receipts_hash,
transactions,
execution_result_hash,
contract_accesses_hash,
proof_of_invalid_chunk,
})
}
pub fn chunk_id(&self) -> &SpiceChunkId {
match self {
Self::V1(witness) => &witness.chunk_id,
}
}
pub fn main_state_transition(&self) -> &SpiceChunkStateTransition {
match self {
Self::V1(witness) => &witness.main_state_transition,
}
}
pub fn mut_main_state_transition(&mut self) -> &mut SpiceChunkStateTransition {
match self {
Self::V1(witness) => &mut witness.main_state_transition,
}
}
pub fn source_receipt_proofs(&self) -> &HashMap<ShardId, ReceiptProof> {
match self {
Self::V1(witness) => &witness.source_receipt_proofs,
}
}
pub fn applied_receipts_hash(&self) -> &CryptoHash {
match self {
Self::V1(witness) => &witness.applied_receipts_hash,
}
}
pub fn transactions(&self) -> &[SignedTransaction] {
match self {
Self::V1(witness) => &witness.transactions,
}
}
pub fn execution_result_hash(&self) -> &ChunkExecutionResultHash {
match self {
Self::V1(witness) => &witness.execution_result_hash,
}
}
pub fn contract_accesses_hash(&self) -> &CryptoHash {
match self {
Self::V1(witness) => &witness.contract_accesses_hash,
}
}
pub fn proof_of_invalid_chunk(&self) -> Option<&EncodedShardChunkBody> {
match self {
Self::V1(witness) => witness.proof_of_invalid_chunk.as_deref(),
}
}
}