1use crate::action::{GlobalContractIdentifier, base64};
2use crate::errors::EpochError;
3use crate::hash::CryptoHash;
4use crate::serialize::dec_format;
5use crate::shard_layout::ShardLayout;
6use crate::transaction::{Action, TransferAction};
7use crate::types::{AccountId, Balance, BlockHeight, ShardId};
8use borsh::{BorshDeserialize, BorshSerialize};
9use itertools::Itertools;
10use near_crypto::{KeyType, PublicKey};
11use near_fmt::AbbrBytes;
12use near_primitives_core::types::Gas;
13use near_schema_checker_lib::ProtocolSchema;
14use serde_with::base64::Base64;
15use serde_with::serde_as;
16use std::borrow::Cow;
17use std::collections::{BTreeMap, HashMap};
18use std::fmt;
19use std::io::{self, Read};
20use std::io::{Error, ErrorKind};
21use std::sync::Arc;
22
23#[derive(
26 BorshSerialize,
27 BorshDeserialize,
28 Hash,
29 Clone,
30 Debug,
31 PartialEq,
32 Eq,
33 serde::Serialize,
34 serde::Deserialize,
35 ProtocolSchema,
36)]
37#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
38pub struct DataReceiver {
39 pub data_id: CryptoHash,
40 pub receiver_id: AccountId,
41}
42
43#[derive(
46 BorshSerialize,
47 BorshDeserialize,
48 Debug,
49 PartialEq,
50 Eq,
51 Clone,
52 serde::Serialize,
53 serde::Deserialize,
54 ProtocolSchema,
55)]
56#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
57pub struct ReceiptV0 {
58 pub predecessor_id: AccountId,
61 pub receiver_id: AccountId,
63 pub receipt_id: CryptoHash,
65 pub receipt: ReceiptEnum,
67}
68
69#[derive(
70 BorshSerialize,
71 BorshDeserialize,
72 Debug,
73 PartialEq,
74 Eq,
75 Clone,
76 serde::Serialize,
77 serde::Deserialize,
78 ProtocolSchema,
79)]
80#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
81pub struct ReceiptV1 {
82 pub predecessor_id: AccountId,
85 pub receiver_id: AccountId,
87 pub receipt_id: CryptoHash,
89 pub receipt: ReceiptEnum,
91 pub priority: u64,
93}
94
95#[derive(Debug, PartialEq, Eq, Clone, serde::Serialize, serde::Deserialize, ProtocolSchema)]
96#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
97#[serde(untagged)]
98pub enum Receipt {
99 V0(ReceiptV0),
100 V1(ReceiptV1),
101}
102
103#[derive(PartialEq, Eq, Debug, ProtocolSchema)]
113pub enum StateStoredReceipt<'a> {
114 V0(StateStoredReceiptV0<'a>),
115 V1(StateStoredReceiptV1<'a>),
116}
117
118#[derive(BorshDeserialize, BorshSerialize, PartialEq, Eq, Debug, ProtocolSchema)]
120pub struct StateStoredReceiptV0<'a> {
121 pub receipt: Cow<'a, Receipt>,
123 pub metadata: StateStoredReceiptMetadata,
124}
125
126#[derive(BorshDeserialize, BorshSerialize, PartialEq, Eq, Debug, ProtocolSchema)]
133pub struct StateStoredReceiptV1<'a> {
134 pub receipt: Cow<'a, Receipt>,
135 pub metadata: StateStoredReceiptMetadata,
136}
137
138#[derive(BorshDeserialize, BorshSerialize, PartialEq, Eq, Debug, ProtocolSchema)]
140pub struct StateStoredReceiptMetadata {
141 pub congestion_gas: Gas,
144 pub congestion_size: u64,
147}
148
149const STATE_STORED_RECEIPT_TAG: u8 = u8::MAX;
151
152#[derive(PartialEq, Eq, Debug, ProtocolSchema)]
166pub enum ReceiptOrStateStoredReceipt<'a> {
167 Receipt(Cow<'a, Receipt>),
168 StateStoredReceipt(StateStoredReceipt<'a>),
169}
170
171impl ReceiptOrStateStoredReceipt<'_> {
172 pub fn into_receipt(self) -> Receipt {
173 match self {
174 ReceiptOrStateStoredReceipt::Receipt(receipt) => receipt.into_owned(),
175 ReceiptOrStateStoredReceipt::StateStoredReceipt(receipt) => receipt.into_receipt(),
176 }
177 }
178
179 pub fn get_receipt(&self) -> &Receipt {
180 match self {
181 ReceiptOrStateStoredReceipt::Receipt(receipt) => receipt,
182 ReceiptOrStateStoredReceipt::StateStoredReceipt(receipt) => receipt.get_receipt(),
183 }
184 }
185
186 pub fn should_update_outgoing_metadatas(&self) -> bool {
187 match self {
188 ReceiptOrStateStoredReceipt::Receipt(_) => false,
189 ReceiptOrStateStoredReceipt::StateStoredReceipt(state_stored_receipt) => {
190 state_stored_receipt.should_update_outgoing_metadatas()
191 }
192 }
193 }
194}
195
196impl<'a> StateStoredReceipt<'a> {
197 pub fn new_owned(receipt: Receipt, metadata: StateStoredReceiptMetadata) -> Self {
198 let receipt = Cow::Owned(receipt);
199 Self::V1(StateStoredReceiptV1 { receipt, metadata })
200 }
201
202 pub fn new_borrowed(receipt: &'a Receipt, metadata: StateStoredReceiptMetadata) -> Self {
203 let receipt = Cow::Borrowed(receipt);
204
205 Self::V1(StateStoredReceiptV1 { receipt, metadata })
206 }
207
208 pub fn into_receipt(self) -> Receipt {
209 match self {
210 StateStoredReceipt::V0(v0) => v0.receipt.into_owned(),
211 StateStoredReceipt::V1(v1) => v1.receipt.into_owned(),
212 }
213 }
214
215 pub fn get_receipt(&self) -> &Receipt {
216 match self {
217 StateStoredReceipt::V0(v0) => &v0.receipt,
218 StateStoredReceipt::V1(v1) => &v1.receipt,
219 }
220 }
221
222 pub fn metadata(&self) -> &StateStoredReceiptMetadata {
223 match self {
224 StateStoredReceipt::V0(v0) => &v0.metadata,
225 StateStoredReceipt::V1(v1) => &v1.metadata,
226 }
227 }
228
229 pub fn should_update_outgoing_metadatas(&self) -> bool {
230 match self {
231 StateStoredReceipt::V0(_) => false,
232 StateStoredReceipt::V1(_) => true,
233 }
234 }
235}
236
237impl BorshSerialize for Receipt {
238 fn serialize<W: io::Write>(&self, writer: &mut W) -> io::Result<()> {
239 match self {
240 Receipt::V0(receipt) => BorshSerialize::serialize(&receipt, writer),
241 Receipt::V1(receipt) => {
242 BorshSerialize::serialize(&1_u8, writer)?;
243 BorshSerialize::serialize(&receipt, writer)
244 }
245 }
246 }
247}
248
249impl BorshDeserialize for Receipt {
250 fn deserialize_reader<R: Read>(reader: &mut R) -> std::io::Result<Self> {
253 let u1 = u8::deserialize_reader(reader)?;
261 let u2 = u8::deserialize_reader(reader)?;
262 let is_v0 = u2 == 0;
263
264 let prefix = if is_v0 { vec![u1, u2] } else { vec![u2] };
265 let mut reader = prefix.chain(reader);
266
267 let receipt = if is_v0 {
268 Receipt::V0(ReceiptV0::deserialize_reader(&mut reader)?)
269 } else {
270 Receipt::V1(ReceiptV1::deserialize_reader(&mut reader)?)
271 };
272 Ok(receipt)
273 }
274}
275
276impl BorshSerialize for StateStoredReceipt<'_> {
277 fn serialize<W: io::Write>(&self, writer: &mut W) -> io::Result<()> {
278 BorshSerialize::serialize(&STATE_STORED_RECEIPT_TAG, writer)?;
285 BorshSerialize::serialize(&STATE_STORED_RECEIPT_TAG, writer)?;
286 match self {
287 StateStoredReceipt::V0(v0) => {
288 BorshSerialize::serialize(&0_u8, writer)?;
289 BorshSerialize::serialize(&v0, writer)?;
290 }
291 StateStoredReceipt::V1(v1) => {
292 BorshSerialize::serialize(&1_u8, writer)?;
293 BorshSerialize::serialize(&v1, writer)?;
294 }
295 }
296 Ok(())
297 }
298}
299
300impl BorshDeserialize for StateStoredReceipt<'_> {
301 fn deserialize_reader<R: Read>(reader: &mut R) -> io::Result<Self> {
302 let u1 = u8::deserialize_reader(reader)?;
303 let u2 = u8::deserialize_reader(reader)?;
304 let u3 = u8::deserialize_reader(reader)?;
305
306 if u1 != STATE_STORED_RECEIPT_TAG || u2 != STATE_STORED_RECEIPT_TAG {
307 let error = format!(
308 "Invalid tag found when deserializing StateStoredReceipt. Found: {}, {}. Expected: {}, {}",
309 u1, u2, STATE_STORED_RECEIPT_TAG, STATE_STORED_RECEIPT_TAG
310 );
311 let error = Error::new(ErrorKind::Other, error);
312 return Err(io::Error::new(ErrorKind::InvalidData, error));
313 }
314
315 match u3 {
316 0 => {
317 let v0 = StateStoredReceiptV0::deserialize_reader(reader)?;
318 Ok(StateStoredReceipt::V0(v0))
319 }
320 1 => {
321 let v1 = StateStoredReceiptV1::deserialize_reader(reader)?;
322 Ok(StateStoredReceipt::V1(v1))
323 }
324 v => {
325 let error = format!(
326 "Invalid version found when deserializing StateStoredReceipt. Found: {}. Expected: 0",
327 v
328 );
329 let error = Error::new(ErrorKind::Other, error);
330 Err(io::Error::new(ErrorKind::InvalidData, error))
331 }
332 }
333 }
334}
335
336impl BorshSerialize for ReceiptOrStateStoredReceipt<'_> {
337 fn serialize<W: io::Write>(&self, writer: &mut W) -> io::Result<()> {
338 match self {
343 ReceiptOrStateStoredReceipt::Receipt(receipt) => {
344 BorshSerialize::serialize(receipt, writer)
345 }
346 ReceiptOrStateStoredReceipt::StateStoredReceipt(receipt) => {
347 BorshSerialize::serialize(receipt, writer)
348 }
349 }
350 }
351}
352
353impl BorshDeserialize for ReceiptOrStateStoredReceipt<'_> {
354 fn deserialize_reader<R: Read>(reader: &mut R) -> io::Result<Self> {
355 let u1 = u8::deserialize_reader(reader)?;
367 let u2 = u8::deserialize_reader(reader)?;
368
369 let prefix = [u1, u2];
371 let mut reader = prefix.chain(reader);
372
373 if u1 == STATE_STORED_RECEIPT_TAG && u2 == STATE_STORED_RECEIPT_TAG {
374 let receipt = StateStoredReceipt::deserialize_reader(&mut reader)?;
375 Ok(ReceiptOrStateStoredReceipt::StateStoredReceipt(receipt))
376 } else {
377 let receipt = Receipt::deserialize_reader(&mut reader)?;
378 let receipt = Cow::Owned(receipt);
379 Ok(ReceiptOrStateStoredReceipt::Receipt(receipt))
380 }
381 }
382}
383
384pub enum ReceiptPriority {
385 Priority(u64),
387 NoPriority,
389}
390
391impl ReceiptPriority {
392 pub fn value(&self) -> u64 {
393 match self {
394 ReceiptPriority::Priority(value) => *value,
395 ReceiptPriority::NoPriority => 0,
396 }
397 }
398}
399
400impl Receipt {
401 pub fn receiver_id(&self) -> &AccountId {
402 match self {
403 Receipt::V0(receipt) => &receipt.receiver_id,
404 Receipt::V1(receipt) => &receipt.receiver_id,
405 }
406 }
407
408 pub fn set_receiver_id(&mut self, receiver_id: AccountId) {
409 match self {
410 Receipt::V0(receipt) => receipt.receiver_id = receiver_id,
411 Receipt::V1(receipt) => receipt.receiver_id = receiver_id,
412 }
413 }
414
415 pub fn predecessor_id(&self) -> &AccountId {
416 match self {
417 Receipt::V0(receipt) => &receipt.predecessor_id,
418 Receipt::V1(receipt) => &receipt.predecessor_id,
419 }
420 }
421
422 pub fn set_predecessor_id(&mut self, predecessor_id: AccountId) {
423 match self {
424 Receipt::V0(receipt) => receipt.predecessor_id = predecessor_id,
425 Receipt::V1(receipt) => receipt.predecessor_id = predecessor_id,
426 }
427 }
428
429 pub fn receipt(&self) -> &ReceiptEnum {
430 match self {
431 Receipt::V0(receipt) => &receipt.receipt,
432 Receipt::V1(receipt) => &receipt.receipt,
433 }
434 }
435
436 pub fn receipt_mut(&mut self) -> &mut ReceiptEnum {
437 match self {
438 Receipt::V0(receipt) => &mut receipt.receipt,
439 Receipt::V1(receipt) => &mut receipt.receipt,
440 }
441 }
442
443 pub fn take_receipt(self) -> ReceiptEnum {
444 match self {
445 Receipt::V0(receipt) => receipt.receipt,
446 Receipt::V1(receipt) => receipt.receipt,
447 }
448 }
449
450 pub fn receipt_id(&self) -> &CryptoHash {
451 match self {
452 Receipt::V0(receipt) => &receipt.receipt_id,
453 Receipt::V1(receipt) => &receipt.receipt_id,
454 }
455 }
456
457 pub fn set_receipt_id(&mut self, receipt_id: CryptoHash) {
458 match self {
459 Receipt::V0(receipt) => receipt.receipt_id = receipt_id,
460 Receipt::V1(receipt) => receipt.receipt_id = receipt_id,
461 }
462 }
463
464 pub fn priority(&self) -> ReceiptPriority {
465 match self {
466 Receipt::V0(_) => ReceiptPriority::NoPriority,
467 Receipt::V1(receipt) => ReceiptPriority::Priority(receipt.priority),
468 }
469 }
470
471 pub fn get_hash(&self) -> CryptoHash {
473 *self.receipt_id()
474 }
475
476 pub fn receiver_shard_id(&self, shard_layout: &ShardLayout) -> Result<ShardId, EpochError> {
477 let shard_id = match self.receipt() {
478 ReceiptEnum::Action(_)
479 | ReceiptEnum::Data(_)
480 | ReceiptEnum::PromiseYield(_)
481 | ReceiptEnum::PromiseResume(_) => {
482 shard_layout.account_id_to_shard_id(self.receiver_id())
483 }
484 ReceiptEnum::GlobalContractDistribution(receipt) => {
485 let target_shard = receipt.target_shard();
486 if shard_layout.shard_ids().contains(&target_shard) {
487 target_shard
488 } else {
489 let Some(children_shards) = shard_layout.get_children_shards_ids(target_shard)
490 else {
491 return Err(EpochError::ShardingError(format!(
492 "Shard {target_shard} does not exist in the parent shard layout",
493 )));
494 };
495 children_shards[0]
498 }
499 }
500 };
501 Ok(shard_id)
502 }
503
504 pub fn new_balance_refund(
508 receiver_id: &AccountId,
509 refund: Balance,
510 priority: ReceiptPriority,
511 ) -> Self {
512 match priority {
513 ReceiptPriority::Priority(priority) => Receipt::V1(ReceiptV1 {
514 predecessor_id: "system".parse().unwrap(),
515 receiver_id: receiver_id.clone(),
516 receipt_id: CryptoHash::default(),
517
518 receipt: ReceiptEnum::Action(ActionReceipt {
519 signer_id: "system".parse().unwrap(),
520 signer_public_key: PublicKey::empty(KeyType::ED25519),
521 gas_price: 0,
522 output_data_receivers: vec![],
523 input_data_ids: vec![],
524 actions: vec![Action::Transfer(TransferAction { deposit: refund })],
525 }),
526 priority,
527 }),
528 ReceiptPriority::NoPriority => Receipt::V0(ReceiptV0 {
529 predecessor_id: "system".parse().unwrap(),
530 receiver_id: receiver_id.clone(),
531 receipt_id: CryptoHash::default(),
532
533 receipt: ReceiptEnum::Action(ActionReceipt {
534 signer_id: "system".parse().unwrap(),
535 signer_public_key: PublicKey::empty(KeyType::ED25519),
536 gas_price: 0,
537 output_data_receivers: vec![],
538 input_data_ids: vec![],
539 actions: vec![Action::Transfer(TransferAction { deposit: refund })],
540 }),
541 }),
542 }
543 }
544
545 pub fn new_gas_refund(
553 receiver_id: &AccountId,
554 refund: Balance,
555 signer_public_key: PublicKey,
556 priority: ReceiptPriority,
557 ) -> Self {
558 match priority {
559 ReceiptPriority::Priority(priority) => Receipt::V1(ReceiptV1 {
560 predecessor_id: "system".parse().unwrap(),
561 receiver_id: receiver_id.clone(),
562 receipt_id: CryptoHash::default(),
563
564 receipt: ReceiptEnum::Action(ActionReceipt {
565 signer_id: receiver_id.clone(),
566 signer_public_key,
567 gas_price: 0,
568 output_data_receivers: vec![],
569 input_data_ids: vec![],
570 actions: vec![Action::Transfer(TransferAction { deposit: refund })],
571 }),
572 priority,
573 }),
574 ReceiptPriority::NoPriority => Receipt::V0(ReceiptV0 {
575 predecessor_id: "system".parse().unwrap(),
576 receiver_id: receiver_id.clone(),
577 receipt_id: CryptoHash::default(),
578
579 receipt: ReceiptEnum::Action(ActionReceipt {
580 signer_id: receiver_id.clone(),
581 signer_public_key,
582 gas_price: 0,
583 output_data_receivers: vec![],
584 input_data_ids: vec![],
585 actions: vec![Action::Transfer(TransferAction { deposit: refund })],
586 }),
587 }),
588 }
589 }
590
591 pub fn new_global_contract_distribution(
592 predecessor_id: AccountId,
593 receipt: GlobalContractDistributionReceipt,
594 ) -> Self {
595 Self::V0(ReceiptV0 {
596 predecessor_id,
597 receiver_id: "system".parse().unwrap(),
598 receipt_id: CryptoHash::default(),
599 receipt: ReceiptEnum::GlobalContractDistribution(receipt),
600 })
601 }
602}
603
604#[derive(
606 BorshSerialize,
607 BorshDeserialize,
608 Clone,
609 Debug,
610 PartialEq,
611 Eq,
612 serde::Serialize,
613 serde::Deserialize,
614 ProtocolSchema,
615)]
616#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
617pub enum ReceiptEnum {
618 Action(ActionReceipt),
619 Data(DataReceipt),
620 PromiseYield(ActionReceipt),
621 PromiseResume(DataReceipt),
622 GlobalContractDistribution(GlobalContractDistributionReceipt),
623}
624
625#[derive(
627 BorshSerialize,
628 BorshDeserialize,
629 Debug,
630 PartialEq,
631 Eq,
632 Clone,
633 serde::Serialize,
634 serde::Deserialize,
635 ProtocolSchema,
636)]
637#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
638pub struct ActionReceipt {
639 pub signer_id: AccountId,
641 pub signer_public_key: PublicKey,
643 #[serde(with = "dec_format")]
645 #[cfg_attr(feature = "schemars", schemars(with = "String"))]
646 pub gas_price: Balance,
647 pub output_data_receivers: Vec<DataReceiver>,
649 pub input_data_ids: Vec<CryptoHash>,
655 pub actions: Vec<Action>,
657}
658
659#[serde_as]
662#[derive(
663 BorshSerialize,
664 BorshDeserialize,
665 Hash,
666 PartialEq,
667 Eq,
668 Clone,
669 serde::Serialize,
670 serde::Deserialize,
671 ProtocolSchema,
672)]
673#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
674pub struct DataReceipt {
675 pub data_id: CryptoHash,
676 #[serde_as(as = "Option<Base64>")]
677 #[cfg_attr(feature = "schemars", schemars(with = "Option<String>"))]
678 pub data: Option<Vec<u8>>,
679}
680
681impl fmt::Debug for DataReceipt {
682 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
683 f.debug_struct("DataReceipt")
684 .field("data_id", &self.data_id)
685 .field("data", &format_args!("{}", AbbrBytes(self.data.as_deref())))
686 .finish()
687 }
688}
689
690#[derive(BorshSerialize, BorshDeserialize, Hash, PartialEq, Eq, Clone, ProtocolSchema)]
695pub struct ReceivedData {
696 pub data: Option<Vec<u8>>,
697}
698
699impl fmt::Debug for ReceivedData {
700 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
701 f.debug_struct("ReceivedData")
702 .field("data", &format_args!("{}", AbbrBytes(self.data.as_deref())))
703 .finish()
704 }
705}
706
707#[derive(
708 BorshSerialize,
709 BorshDeserialize,
710 Hash,
711 PartialEq,
712 Eq,
713 Clone,
714 Debug,
715 serde::Deserialize,
716 serde::Serialize,
717 ProtocolSchema,
718)]
719#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
720pub enum GlobalContractDistributionReceipt {
721 V1(GlobalContractDistributionReceiptV1),
722}
723
724impl GlobalContractDistributionReceipt {
725 pub fn new(
726 id: GlobalContractIdentifier,
727 target_shard: ShardId,
728 already_delivered_shards: Vec<ShardId>,
729 code: Arc<[u8]>,
730 ) -> Self {
731 Self::V1(GlobalContractDistributionReceiptV1 {
732 id,
733 target_shard,
734 already_delivered_shards,
735 code,
736 })
737 }
738
739 pub fn id(&self) -> &GlobalContractIdentifier {
740 match &self {
741 Self::V1(v1) => &v1.id,
742 }
743 }
744
745 pub fn target_shard(&self) -> ShardId {
746 match &self {
747 Self::V1(v1) => v1.target_shard,
748 }
749 }
750
751 pub fn already_delivered_shards(&self) -> &[ShardId] {
752 match &self {
753 Self::V1(v1) => &v1.already_delivered_shards,
754 }
755 }
756
757 pub fn code(&self) -> &Arc<[u8]> {
758 match &self {
759 Self::V1(v1) => &v1.code,
760 }
761 }
762}
763
764#[serde_as]
765#[derive(
766 BorshSerialize,
767 BorshDeserialize,
768 Hash,
769 PartialEq,
770 Eq,
771 Clone,
772 serde::Deserialize,
773 serde::Serialize,
774 ProtocolSchema,
775)]
776#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
777pub struct GlobalContractDistributionReceiptV1 {
778 id: GlobalContractIdentifier,
779 target_shard: ShardId,
780 already_delivered_shards: Vec<ShardId>,
781 #[serde_as(as = "Base64")]
782 #[cfg_attr(feature = "schemars", schemars(with = "String"))]
783 code: Arc<[u8]>,
784}
785
786impl fmt::Debug for GlobalContractDistributionReceiptV1 {
787 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
788 f.debug_struct("GlobalContractDistributionReceipt")
789 .field("id", &self.id)
790 .field("target_shard", &self.target_shard)
791 .field("already_delivered_shards", &self.already_delivered_shards)
792 .field("code", &format_args!("{}", base64(&self.code)))
793 .finish()
794 }
795}
796
797#[derive(Default, BorshSerialize, BorshDeserialize, Clone, PartialEq, Debug, ProtocolSchema)]
799pub struct DelayedReceiptIndices {
800 pub first_index: u64,
802 pub next_available_index: u64,
804}
805
806impl DelayedReceiptIndices {
807 pub fn len(&self) -> u64 {
808 self.next_available_index - self.first_index
809 }
810}
811
812#[derive(Default, BorshSerialize, BorshDeserialize, Clone, PartialEq, Debug, ProtocolSchema)]
814pub struct PromiseYieldIndices {
815 pub first_index: u64,
817 pub next_available_index: u64,
819}
820
821impl PromiseYieldIndices {
822 pub fn len(&self) -> u64 {
823 self.next_available_index - self.first_index
824 }
825}
826
827#[derive(BorshSerialize, BorshDeserialize, Clone, PartialEq, Debug, ProtocolSchema)]
829pub struct PromiseYieldTimeout {
830 pub account_id: AccountId,
832 pub data_id: CryptoHash,
834 pub expires_at: BlockHeight,
836}
837
838#[derive(Default, BorshSerialize, BorshDeserialize, Clone, PartialEq, Debug, ProtocolSchema)]
840pub struct TrieQueueIndices {
841 pub first_index: u64,
843 pub next_available_index: u64,
845}
846
847impl TrieQueueIndices {
848 pub fn len(&self) -> u64 {
849 self.next_available_index - self.first_index
850 }
851
852 pub fn is_default(&self) -> bool {
853 self.next_available_index == 0
854 }
855}
856
857impl From<DelayedReceiptIndices> for TrieQueueIndices {
858 fn from(other: DelayedReceiptIndices) -> Self {
859 Self { first_index: other.first_index, next_available_index: other.next_available_index }
860 }
861}
862
863impl From<TrieQueueIndices> for DelayedReceiptIndices {
864 fn from(other: TrieQueueIndices) -> Self {
865 Self { first_index: other.first_index, next_available_index: other.next_available_index }
866 }
867}
868
869#[derive(Default, BorshSerialize, BorshDeserialize, Clone, PartialEq, Debug, ProtocolSchema)]
875pub struct BufferedReceiptIndices {
876 pub shard_buffers: BTreeMap<ShardId, TrieQueueIndices>,
877}
878
879pub type ReceiptResult = HashMap<ShardId, Vec<Receipt>>;
881
882#[cfg(test)]
883mod tests {
884 use super::*;
885
886 fn get_receipt_v0() -> Receipt {
887 let receipt_v0 = Receipt::V0(ReceiptV0 {
888 predecessor_id: "predecessor_id".parse().unwrap(),
889 receiver_id: "receiver_id".parse().unwrap(),
890 receipt_id: CryptoHash::default(),
891 receipt: ReceiptEnum::Action(ActionReceipt {
892 signer_id: "signer_id".parse().unwrap(),
893 signer_public_key: PublicKey::empty(KeyType::ED25519),
894 gas_price: 0,
895 output_data_receivers: vec![],
896 input_data_ids: vec![],
897 actions: vec![Action::Transfer(TransferAction { deposit: 0 })],
898 }),
899 });
900 receipt_v0
901 }
902
903 fn get_receipt_v1() -> Receipt {
904 let receipt_v1 = Receipt::V1(ReceiptV1 {
905 predecessor_id: "predecessor_id".parse().unwrap(),
906 receiver_id: "receiver_id".parse().unwrap(),
907 receipt_id: CryptoHash::default(),
908 receipt: ReceiptEnum::Action(ActionReceipt {
909 signer_id: "signer_id".parse().unwrap(),
910 signer_public_key: PublicKey::empty(KeyType::ED25519),
911 gas_price: 0,
912 output_data_receivers: vec![],
913 input_data_ids: vec![],
914 actions: vec![Action::Transfer(TransferAction { deposit: 0 })],
915 }),
916 priority: 1,
917 });
918 receipt_v1
919 }
920
921 #[test]
922 fn test_receipt_v0_serialization() {
923 let receipt_v0 = get_receipt_v0();
924 let serialized_receipt = borsh::to_vec(&receipt_v0).unwrap();
925 let receipt2 = Receipt::try_from_slice(&serialized_receipt).unwrap();
926 assert_eq!(receipt_v0, receipt2);
927 }
928
929 #[test]
930 fn test_receipt_v1_serialization() {
931 let receipt_v1 = get_receipt_v1();
932 let serialized_receipt = borsh::to_vec(&receipt_v1).unwrap();
933 let receipt2 = Receipt::try_from_slice(&serialized_receipt).unwrap();
934 assert_eq!(receipt_v1, receipt2);
935 }
936
937 fn test_state_stored_receipt_serialization_impl(receipt: Receipt) {
938 let metadata = StateStoredReceiptMetadata { congestion_gas: 42, congestion_size: 43 };
939 let receipt = StateStoredReceipt::new_owned(receipt, metadata);
940
941 let serialized_receipt = borsh::to_vec(&receipt).unwrap();
942 let deserialized_receipt = StateStoredReceipt::try_from_slice(&serialized_receipt).unwrap();
943
944 assert_eq!(receipt, deserialized_receipt);
945 }
946
947 #[test]
948 fn test_state_stored_receipt_serialization_v0() {
949 let receipt = get_receipt_v0();
950 test_state_stored_receipt_serialization_impl(receipt);
951 }
952
953 #[test]
954 fn test_state_stored_receipt_serialization_v1() {
955 let receipt = get_receipt_v1();
956 test_state_stored_receipt_serialization_impl(receipt);
957 }
958
959 #[test]
960 fn test_receipt_or_state_stored_receipt_serialization() {
961 {
964 let receipt = get_receipt_v0();
965 let receipt = Cow::Owned(receipt);
966
967 let serialized_receipt = borsh::to_vec(&receipt).unwrap();
968 let deserialized_receipt =
969 ReceiptOrStateStoredReceipt::try_from_slice(&serialized_receipt).unwrap();
970
971 assert_eq!(ReceiptOrStateStoredReceipt::Receipt(receipt), deserialized_receipt);
972 }
973
974 {
977 let receipt = get_receipt_v1();
978 let receipt = Cow::Owned(receipt);
979
980 let serialized_receipt = borsh::to_vec(&receipt).unwrap();
981 let deserialized_receipt =
982 ReceiptOrStateStoredReceipt::try_from_slice(&serialized_receipt).unwrap();
983
984 assert_eq!(ReceiptOrStateStoredReceipt::Receipt(receipt), deserialized_receipt);
985 }
986
987 {
990 let receipt = get_receipt_v0();
991 let metadata = StateStoredReceiptMetadata { congestion_gas: 42, congestion_size: 43 };
992 let state_stored_receipt = StateStoredReceipt::new_owned(receipt, metadata);
993
994 let serialized_receipt = borsh::to_vec(&state_stored_receipt).unwrap();
995 let deserialized_receipt =
996 ReceiptOrStateStoredReceipt::try_from_slice(&serialized_receipt).unwrap();
997
998 assert_eq!(
999 ReceiptOrStateStoredReceipt::StateStoredReceipt(state_stored_receipt),
1000 deserialized_receipt
1001 );
1002 }
1003
1004 {
1007 let receipt = get_receipt_v0();
1008 let receipt = Cow::Owned(receipt);
1009
1010 let receipt_or_state_stored_receipt = ReceiptOrStateStoredReceipt::Receipt(receipt);
1011
1012 let serialized_receipt = borsh::to_vec(&receipt_or_state_stored_receipt).unwrap();
1013 let deserialized_receipt =
1014 ReceiptOrStateStoredReceipt::try_from_slice(&serialized_receipt).unwrap();
1015
1016 assert_eq!(receipt_or_state_stored_receipt, deserialized_receipt);
1017 }
1018
1019 {
1022 let receipt = get_receipt_v0();
1023 let metadata = StateStoredReceiptMetadata { congestion_gas: 42, congestion_size: 43 };
1024 let state_stored_receipt = StateStoredReceipt::new_owned(receipt, metadata);
1025 let receipt_or_state_stored_receipt =
1026 ReceiptOrStateStoredReceipt::StateStoredReceipt(state_stored_receipt);
1027
1028 let serialized_receipt = borsh::to_vec(&receipt_or_state_stored_receipt).unwrap();
1029 let deserialized_receipt =
1030 ReceiptOrStateStoredReceipt::try_from_slice(&serialized_receipt).unwrap();
1031
1032 assert_eq!(receipt_or_state_stored_receipt, deserialized_receipt);
1033 }
1034 }
1035}