ferrum_interfaces/vnext/model/
checkpoint.rs1use serde::{Deserialize, Deserializer, Serialize};
5
6use super::{ContractVersion, StateLifetime, VNextError};
7
8mod inputs;
9pub use inputs::{ProgramCheckpointInputs, PROGRAM_CHECKPOINT_INPUTS_VERSION};
10
11pub const STATE_CHECKPOINT_CONTRACT_VERSION: ContractVersion = ContractVersion::new(1, 0);
12
13#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
18#[serde(rename_all = "snake_case")]
19pub enum CheckpointInputDependency {
20 ExactTokenPrefix,
23 EntireTokenInput,
26}
27
28#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
32#[serde(rename_all = "snake_case")]
33pub enum StateCheckpointContents {
34 PrefixPositions,
37 BoundaryValue,
40}
41
42#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize)]
46pub struct StateCheckpointContract {
47 contract_version: ContractVersion,
48 contents: StateCheckpointContents,
49 input_dependency: CheckpointInputDependency,
50}
51
52#[derive(Deserialize)]
53#[serde(deny_unknown_fields)]
54struct StateCheckpointContractWire {
55 contract_version: ContractVersion,
56 contents: StateCheckpointContents,
57 input_dependency: CheckpointInputDependency,
58}
59
60impl<'de> Deserialize<'de> for StateCheckpointContract {
61 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
62 where
63 D: Deserializer<'de>,
64 {
65 let wire = StateCheckpointContractWire::deserialize(deserializer)?;
66 if wire.contract_version != STATE_CHECKPOINT_CONTRACT_VERSION {
67 return Err(serde::de::Error::custom(format!(
68 "state checkpoint contract version {} is unsupported",
69 wire.contract_version
70 )));
71 }
72 Ok(Self::new(wire.contents, wire.input_dependency))
73 }
74}
75
76impl StateCheckpointContract {
77 pub const fn new(
78 contents: StateCheckpointContents,
79 input_dependency: CheckpointInputDependency,
80 ) -> Self {
81 Self {
82 contract_version: STATE_CHECKPOINT_CONTRACT_VERSION,
83 contents,
84 input_dependency,
85 }
86 }
87
88 pub const fn contract_version(&self) -> ContractVersion {
89 self.contract_version
90 }
91
92 pub const fn contents(&self) -> StateCheckpointContents {
93 self.contents
94 }
95
96 pub const fn input_dependency(&self) -> CheckpointInputDependency {
97 self.input_dependency
98 }
99}
100
101#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
105#[serde(rename_all = "snake_case", deny_unknown_fields)]
106pub enum StateCheckpointCapability {
107 #[default]
108 Unsupported,
109 CompletedBoundary(StateCheckpointContract),
110}
111
112impl StateCheckpointCapability {
113 pub const fn is_unsupported(&self) -> bool {
114 matches!(self, Self::Unsupported)
115 }
116
117 pub(super) fn validate_lifetime(self, lifetime: StateLifetime) -> Result<(), VNextError> {
118 if !self.is_unsupported() && lifetime != StateLifetime::Sequence {
119 return Err(VNextError::InvalidExecutionPlan {
120 reason: "checkpoint contracts currently support only Sequence state; Request/Step state requires a separate closure contract".to_owned(),
121 });
122 }
123 Ok(())
124 }
125}
126
127#[cfg(test)]
128mod tests;