near_primitives/spice/
partial_data.rs1use crate::merkle::MerklePath;
2use crate::types::StaticSignatureDifferentiator;
3use crate::validator_signer::ValidatorSigner;
4use near_crypto::{PublicKey, Signature};
5use near_primitives_core::hash::CryptoHash;
6use near_primitives_core::types::{AccountId, MerkleHash, ShardId};
7
8#[derive(borsh::BorshSerialize, borsh::BorshDeserialize, Debug, Clone, PartialEq, Eq, Hash)]
9pub enum SpiceDataIdentifier {
10 ReceiptProof { block_hash: CryptoHash, from_shard_id: ShardId, to_shard_id: ShardId },
11 Witness { block_hash: CryptoHash, shard_id: ShardId },
12}
13
14impl SpiceDataIdentifier {
15 pub fn block_hash(&self) -> &CryptoHash {
16 match self {
17 SpiceDataIdentifier::ReceiptProof { block_hash, .. } => block_hash,
18 SpiceDataIdentifier::Witness { block_hash, .. } => block_hash,
19 }
20 }
21}
22
23#[derive(borsh::BorshSerialize, borsh::BorshDeserialize, Debug, Clone, PartialEq, Eq, Hash)]
24pub struct SpiceDataCommitment {
25 pub hash: CryptoHash,
26 pub root: MerkleHash,
27 pub encoded_length: u64,
28}
29
30#[derive(borsh::BorshSerialize, borsh::BorshDeserialize, Debug, Clone, PartialEq, Eq)]
31pub struct SpiceDataPart {
32 pub part_ord: u64,
33 pub part: Box<[u8]>,
34 pub merkle_proof: MerklePath,
35}
36
37#[derive(borsh::BorshSerialize, borsh::BorshDeserialize, Debug, Clone, PartialEq, Eq)]
40pub struct SpicePartialData {
41 inner: SpicePartialDataInner,
42 sender: AccountId,
43 signature: Signature,
44}
45
46impl SpicePartialData {
47 pub fn new(
48 id: SpiceDataIdentifier,
49 commitment: SpiceDataCommitment,
50 parts: Vec<SpiceDataPart>,
51 signer: &ValidatorSigner,
52 ) -> Self {
53 let inner = SpicePartialDataInner { id, commitment, parts };
54 let signature = signer.sign_bytes(&inner.serialize_for_signing());
55 Self { inner, signature, sender: signer.validator_id().clone() }
56 }
57
58 pub fn block_hash(&self) -> &CryptoHash {
59 self.inner.id.block_hash()
60 }
61
62 pub fn sender(&self) -> &AccountId {
63 &self.sender
64 }
65
66 pub fn into_verified(self, public_key: &PublicKey) -> Option<SpiceVerifiedPartialData> {
67 let data = self.inner.serialize_for_signing();
68 if !self.signature.verify(&data, public_key) {
69 return None;
70 }
71 Some(SpiceVerifiedPartialData {
72 id: self.inner.id,
73 commitment: self.inner.commitment,
74 parts: self.inner.parts,
75 sender: self.sender,
76 })
77 }
78}
79
80#[derive(borsh::BorshSerialize, borsh::BorshDeserialize, Debug, Clone, PartialEq, Eq)]
81struct SpicePartialDataInner {
82 id: SpiceDataIdentifier,
84 commitment: SpiceDataCommitment,
85 parts: Vec<SpiceDataPart>,
86}
87
88impl SpicePartialDataInner {
89 fn serialize_for_signing(&self) -> Vec<u8> {
90 static SIGNATURE_DIFFERENTIATOR: StaticSignatureDifferentiator = "SpicePartialData";
91 let data = (self, SIGNATURE_DIFFERENTIATOR);
92 borsh::to_vec(&data).unwrap()
93 }
94}
95
96#[derive(borsh::BorshSerialize, borsh::BorshDeserialize, Debug, Clone, PartialEq, Eq)]
98pub struct SpiceVerifiedPartialData {
99 pub id: SpiceDataIdentifier,
100 pub commitment: SpiceDataCommitment,
101 pub parts: Vec<SpiceDataPart>,
102 pub sender: AccountId,
103}
104
105pub fn testonly_create_spice_partial_data(
107 id: SpiceDataIdentifier,
108 commitment: SpiceDataCommitment,
109 parts: Vec<SpiceDataPart>,
110 signature: Signature,
111 sender: AccountId,
112) -> SpicePartialData {
113 SpicePartialData { inner: SpicePartialDataInner { id, commitment, parts }, signature, sender }
114}