1use std::collections::HashSet;
2use std::sync::Arc;
3
4use borsh::{BorshDeserialize, BorshSerialize};
5use bytesize::ByteSize;
6use near_crypto::{PublicKey, Signature};
7use near_primitives_core::code::ContractCode;
8use near_primitives_core::hash::{CryptoHash, hash};
9use near_primitives_core::types::{AccountId, ShardId};
10use near_schema_checker_lib::ProtocolSchema;
11
12use super::ChunkProductionKey;
13#[cfg(feature = "solomon")]
14use crate::reed_solomon::{ReedSolomonEncoderDeserialize, ReedSolomonEncoderSerialize};
15use crate::types::SignatureDifferentiator;
16use crate::{utils::compression::CompressedData, validator_signer::ValidatorSigner};
17
18#[derive(Debug, Clone, PartialEq, Eq, BorshSerialize, BorshDeserialize, ProtocolSchema)]
24pub enum ChunkContractAccesses {
25 V1(ChunkContractAccessesV1),
26}
27
28#[derive(Debug, Clone, PartialEq, Eq, BorshSerialize, BorshDeserialize, ProtocolSchema)]
30pub struct MainTransitionKey {
31 pub block_hash: CryptoHash,
32 pub shard_id: ShardId,
33}
34
35impl ChunkContractAccesses {
36 pub fn new(
37 next_chunk: ChunkProductionKey,
38 contracts: HashSet<CodeHash>,
39 main_transition: MainTransitionKey,
40 signer: &ValidatorSigner,
41 ) -> Self {
42 Self::V1(ChunkContractAccessesV1::new(next_chunk, contracts, main_transition, signer))
43 }
44
45 pub fn contracts(&self) -> &[CodeHash] {
46 match self {
47 Self::V1(accesses) => &accesses.inner.contracts,
48 }
49 }
50
51 pub fn chunk_production_key(&self) -> &ChunkProductionKey {
52 match self {
53 Self::V1(accesses) => &accesses.inner.next_chunk,
54 }
55 }
56
57 pub fn main_transition(&self) -> &MainTransitionKey {
58 match self {
59 Self::V1(accesses) => &accesses.inner.main_transition,
60 }
61 }
62
63 pub fn verify_signature(&self, public_key: &PublicKey) -> bool {
64 match self {
65 Self::V1(accesses) => accesses.verify_signature(public_key),
66 }
67 }
68}
69
70#[derive(Debug, Clone, PartialEq, Eq, BorshSerialize, BorshDeserialize, ProtocolSchema)]
71pub struct ChunkContractAccessesV1 {
72 inner: ChunkContractAccessesInner,
73 signature: Signature,
75}
76
77impl ChunkContractAccessesV1 {
78 fn new(
79 next_chunk: ChunkProductionKey,
80 contracts: HashSet<CodeHash>,
81 main_transition: MainTransitionKey,
82 signer: &ValidatorSigner,
83 ) -> Self {
84 let inner = ChunkContractAccessesInner::new(next_chunk, contracts, main_transition);
85 let signature = signer.sign_bytes(&borsh::to_vec(&inner).unwrap());
86 Self { inner, signature }
87 }
88
89 fn verify_signature(&self, public_key: &PublicKey) -> bool {
90 self.signature.verify(&borsh::to_vec(&self.inner).unwrap(), public_key)
91 }
92}
93
94#[derive(Debug, Clone, PartialEq, Eq, BorshSerialize, BorshDeserialize, ProtocolSchema)]
95pub struct ChunkContractAccessesInner {
96 next_chunk: ChunkProductionKey,
101 contracts: Vec<CodeHash>,
103 main_transition: MainTransitionKey,
105 signature_differentiator: SignatureDifferentiator,
106}
107
108impl ChunkContractAccessesInner {
109 fn new(
110 next_chunk: ChunkProductionKey,
111 contracts: HashSet<CodeHash>,
112 main_transition: MainTransitionKey,
113 ) -> Self {
114 Self {
115 next_chunk,
116 contracts: contracts.into_iter().collect(),
117 main_transition,
118 signature_differentiator: "ChunkContractAccessesInner".to_owned(),
119 }
120 }
121}
122
123#[derive(Debug, Clone, PartialEq, Eq, BorshSerialize, BorshDeserialize, ProtocolSchema)]
128pub enum ContractCodeRequest {
129 V1(ContractCodeRequestV1),
130}
131
132impl ContractCodeRequest {
133 pub fn new(
134 next_chunk: ChunkProductionKey,
135 contracts: HashSet<CodeHash>,
136 main_transition: MainTransitionKey,
137 signer: &ValidatorSigner,
138 ) -> Self {
139 Self::V1(ContractCodeRequestV1::new(next_chunk, contracts, main_transition, signer))
140 }
141
142 pub fn requester(&self) -> &AccountId {
143 match self {
144 Self::V1(request) => &request.inner.requester,
145 }
146 }
147
148 pub fn contracts(&self) -> &[CodeHash] {
149 match self {
150 Self::V1(request) => &request.inner.contracts,
151 }
152 }
153
154 pub fn chunk_production_key(&self) -> &ChunkProductionKey {
155 match self {
156 Self::V1(request) => &request.inner.next_chunk,
157 }
158 }
159
160 pub fn main_transition(&self) -> &MainTransitionKey {
161 match self {
162 Self::V1(request) => &request.inner.main_transition,
163 }
164 }
165
166 pub fn verify_signature(&self, public_key: &PublicKey) -> bool {
167 match self {
168 Self::V1(v1) => v1.verify_signature(public_key),
169 }
170 }
171}
172
173#[derive(Debug, Clone, PartialEq, Eq, BorshSerialize, BorshDeserialize, ProtocolSchema)]
174pub struct ContractCodeRequestV1 {
175 inner: ContractCodeRequestInner,
176 signature: Signature,
178}
179
180impl ContractCodeRequestV1 {
181 fn new(
182 next_chunk: ChunkProductionKey,
183 contracts: HashSet<CodeHash>,
184 main_transition: MainTransitionKey,
185 signer: &ValidatorSigner,
186 ) -> Self {
187 let inner = ContractCodeRequestInner::new(
188 signer.validator_id().clone(),
189 next_chunk,
190 contracts,
191 main_transition,
192 );
193 let signature = signer.sign_bytes(&borsh::to_vec(&inner).unwrap());
194 Self { inner, signature }
195 }
196
197 pub fn verify_signature(&self, public_key: &PublicKey) -> bool {
198 self.signature.verify(&borsh::to_vec(&self.inner).unwrap(), public_key)
199 }
200}
201
202#[derive(Debug, Clone, PartialEq, Eq, BorshSerialize, BorshDeserialize, ProtocolSchema)]
203pub struct ContractCodeRequestInner {
204 requester: AccountId,
207 next_chunk: ChunkProductionKey,
212 contracts: Vec<CodeHash>,
214 main_transition: MainTransitionKey,
215 signature_differentiator: SignatureDifferentiator,
216}
217
218impl ContractCodeRequestInner {
219 fn new(
220 requester: AccountId,
221 next_chunk: ChunkProductionKey,
222 contracts: HashSet<CodeHash>,
223 main_transition: MainTransitionKey,
224 ) -> Self {
225 Self {
226 requester,
227 next_chunk,
228 contracts: contracts.into_iter().collect(),
229 main_transition,
230 signature_differentiator: "ContractCodeRequestInner".to_owned(),
231 }
232 }
233}
234
235#[derive(Debug, Clone, PartialEq, Eq, BorshSerialize, BorshDeserialize, ProtocolSchema)]
238pub enum ContractCodeResponse {
239 V1(ContractCodeResponseV1),
240}
241
242impl ContractCodeResponse {
243 pub fn encode(
244 next_chunk: ChunkProductionKey,
245 contracts: &Vec<CodeBytes>,
246 ) -> std::io::Result<Self> {
247 ContractCodeResponseV1::encode(next_chunk, contracts).map(|v1| Self::V1(v1))
248 }
249
250 pub fn chunk_production_key(&self) -> &ChunkProductionKey {
251 match self {
252 Self::V1(v1) => &v1.next_chunk,
253 }
254 }
255
256 pub fn decompress_contracts(&self) -> std::io::Result<Vec<CodeBytes>> {
257 let compressed_contracts = match self {
258 Self::V1(v1) => &v1.compressed_contracts,
259 };
260 compressed_contracts.decode().map(|(data, _size)| data)
261 }
262}
263
264#[derive(Debug, Clone, PartialEq, Eq, BorshSerialize, BorshDeserialize, ProtocolSchema)]
265pub struct ContractCodeResponseV1 {
266 next_chunk: ChunkProductionKey,
268 compressed_contracts: CompressedContractCode,
270}
271
272impl ContractCodeResponseV1 {
273 pub fn encode(
274 next_chunk: ChunkProductionKey,
275 contracts: &Vec<CodeBytes>,
276 ) -> std::io::Result<Self> {
277 let (compressed_contracts, _size) = CompressedContractCode::encode(&contracts)?;
278 Ok(Self { next_chunk, compressed_contracts })
279 }
280}
281
282const MAX_UNCOMPRESSED_CONTRACT_CODE_RESPONSE_SIZE: u64 =
285 ByteSize::mib(if cfg!(feature = "test_features") { 512 } else { 64 }).0;
286const CONTRACT_CODE_RESPONSE_COMPRESSION_LEVEL: i32 = 3;
287
288#[derive(
290 Debug,
291 Clone,
292 PartialEq,
293 Eq,
294 BorshSerialize,
295 BorshDeserialize,
296 ProtocolSchema,
297 derive_more::From,
298 derive_more::AsRef,
299)]
300struct CompressedContractCode(Box<[u8]>);
301
302impl
303 CompressedData<
304 Vec<CodeBytes>,
305 MAX_UNCOMPRESSED_CONTRACT_CODE_RESPONSE_SIZE,
306 CONTRACT_CODE_RESPONSE_COMPRESSION_LEVEL,
307 > for CompressedContractCode
308{
309}
310
311#[derive(
313 Debug,
314 Clone,
315 Hash,
316 PartialEq,
317 Eq,
318 Ord,
319 PartialOrd,
320 BorshSerialize,
321 BorshDeserialize,
322 serde::Serialize,
323 serde::Deserialize,
324 ProtocolSchema,
325)]
326pub struct CodeHash(pub CryptoHash);
327
328impl From<CryptoHash> for CodeHash {
329 fn from(crypto_hash: CryptoHash) -> Self {
330 Self(crypto_hash)
331 }
332}
333
334impl Into<CryptoHash> for CodeHash {
335 fn into(self) -> CryptoHash {
336 self.0
337 }
338}
339
340#[derive(
342 Debug,
343 Clone,
344 PartialEq,
345 Eq,
346 BorshSerialize,
347 BorshDeserialize,
348 serde::Serialize,
349 serde::Deserialize,
350 ProtocolSchema,
351)]
352pub struct CodeBytes(pub Arc<[u8]>);
353
354impl CodeBytes {
355 pub fn hash(&self) -> CodeHash {
356 hash(self.0.as_ref()).into()
357 }
358}
359
360impl From<ContractCode> for CodeBytes {
361 fn from(code: ContractCode) -> Self {
362 Self(code.take_code().into())
363 }
364}
365
366impl Into<ContractCode> for CodeBytes {
367 fn into(self) -> ContractCode {
368 ContractCode::new(self.0.to_vec(), None)
369 }
370}
371
372#[derive(Debug, Default, Clone)]
374pub struct ContractUpdates {
375 pub contract_accesses: HashSet<CodeHash>,
377 pub contract_deploys: Vec<ContractCode>,
379}
380
381impl ContractUpdates {
382 pub fn contract_deploy_hashes(&self) -> HashSet<CodeHash> {
384 self.contract_deploys.iter().map(|contract| (*contract.hash()).into()).collect()
385 }
386}
387
388#[derive(Clone, BorshSerialize, BorshDeserialize, ProtocolSchema)]
391pub struct ChunkContractDeploys {
392 compressed_contracts: CompressedContractCode,
393}
394
395impl ChunkContractDeploys {
396 pub fn compress_contracts(contracts: &Vec<CodeBytes>) -> std::io::Result<Self> {
397 CompressedContractCode::encode(contracts)
398 .map(|(compressed_contracts, _size)| Self { compressed_contracts })
399 }
400
401 pub fn decompress_contracts(&self) -> std::io::Result<Vec<CodeBytes>> {
402 self.compressed_contracts.decode().map(|(data, _size)| data)
403 }
404}
405
406#[cfg(feature = "solomon")]
407impl ReedSolomonEncoderSerialize for ChunkContractDeploys {}
408#[cfg(feature = "solomon")]
409impl ReedSolomonEncoderDeserialize for ChunkContractDeploys {}
410
411#[derive(Clone, Debug, PartialEq, Eq, BorshSerialize, BorshDeserialize, ProtocolSchema)]
412pub enum PartialEncodedContractDeploys {
413 V1(PartialEncodedContractDeploysV1),
414}
415
416impl PartialEncodedContractDeploys {
417 pub fn new(
418 key: ChunkProductionKey,
419 part: PartialEncodedContractDeploysPart,
420 signer: &ValidatorSigner,
421 ) -> Self {
422 Self::V1(PartialEncodedContractDeploysV1::new(key, part, signer))
423 }
424
425 pub fn chunk_production_key(&self) -> &ChunkProductionKey {
426 match &self {
427 Self::V1(v1) => &v1.inner.next_chunk,
428 }
429 }
430
431 pub fn part(&self) -> &PartialEncodedContractDeploysPart {
432 match &self {
433 Self::V1(v1) => &v1.inner.part,
434 }
435 }
436
437 pub fn verify_signature(&self, public_key: &PublicKey) -> bool {
438 match self {
439 Self::V1(accesses) => accesses.verify_signature(public_key),
440 }
441 }
442}
443
444impl Into<(ChunkProductionKey, PartialEncodedContractDeploysPart)>
445 for PartialEncodedContractDeploys
446{
447 fn into(self) -> (ChunkProductionKey, PartialEncodedContractDeploysPart) {
448 match self {
449 Self::V1(PartialEncodedContractDeploysV1 { inner, .. }) => {
450 (inner.next_chunk, inner.part)
451 }
452 }
453 }
454}
455
456#[derive(Clone, Debug, PartialEq, Eq, BorshSerialize, BorshDeserialize, ProtocolSchema)]
457pub struct PartialEncodedContractDeploysV1 {
458 inner: PartialEncodedContractDeploysInner,
459 signature: Signature,
460}
461
462impl PartialEncodedContractDeploysV1 {
463 pub fn new(
464 key: ChunkProductionKey,
465 part: PartialEncodedContractDeploysPart,
466 signer: &ValidatorSigner,
467 ) -> Self {
468 let inner = PartialEncodedContractDeploysInner::new(key, part);
469 let signature = signer.sign_bytes(&borsh::to_vec(&inner).unwrap());
470 Self { inner, signature }
471 }
472
473 pub fn verify_signature(&self, public_key: &PublicKey) -> bool {
474 self.signature.verify(&borsh::to_vec(&self.inner).unwrap(), public_key)
475 }
476}
477
478#[derive(Clone, PartialEq, Eq, BorshSerialize, BorshDeserialize, ProtocolSchema)]
479pub struct PartialEncodedContractDeploysPart {
480 pub part_ord: usize,
481 pub data: Box<[u8]>,
482 pub encoded_length: usize,
483}
484
485impl std::fmt::Debug for PartialEncodedContractDeploysPart {
486 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
487 f.debug_struct("PartialEncodedContractDeploysPart")
488 .field("part_ord", &self.part_ord)
489 .field("data_size", &self.data.len())
490 .field("encoded_length", &self.encoded_length)
491 .finish()
492 }
493}
494
495#[derive(Clone, Debug, PartialEq, Eq, BorshSerialize, BorshDeserialize, ProtocolSchema)]
496pub struct PartialEncodedContractDeploysInner {
497 next_chunk: ChunkProductionKey,
498 part: PartialEncodedContractDeploysPart,
499 signature_differentiator: SignatureDifferentiator,
500}
501
502impl PartialEncodedContractDeploysInner {
503 fn new(next_chunk: ChunkProductionKey, part: PartialEncodedContractDeploysPart) -> Self {
504 Self {
505 next_chunk,
506 part,
507 signature_differentiator: "PartialEncodedContractDeploysInner".to_owned(),
508 }
509 }
510}