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