1use crate::{cdk::types::Principal, ids::IntentResourceKey, model::replay::OperationId};
8use serde::{Deserialize, Serialize};
9
10pub const PAYLOAD_BINDING_SCHEMA_VERSION: u32 = 1;
11pub const RECEIPT_BACKED_INTENT_SCHEMA_VERSION: u32 = 1;
12pub const TERMINAL_EVIDENCE_SCHEMA_VERSION: u32 = 1;
13pub const CANIC_INTENT_RESOURCE_PREFIX: &str = "canic:";
14pub const MAX_RECEIPT_BACKED_INTENT_REPLAY_WINDOW_NS: u64 = 24 * 60 * 60 * 1_000_000_000;
15
16#[derive(Clone, Copy, Debug, Eq, PartialEq)]
18pub enum ReceiptReplayWindowDecision {
19 Open,
20 Closed,
21 TooLong { remaining_ns: u64 },
22}
23
24#[must_use]
25pub fn is_canic_owned_intent_resource_key(resource_key: &IntentResourceKey) -> bool {
26 resource_key.starts_with(CANIC_INTENT_RESOURCE_PREFIX)
27}
28
29#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
31pub struct PayloadBinding {
32 pub schema_version: u32,
33 pub digest: [u8; 32],
34}
35
36impl PayloadBinding {
37 #[must_use]
38 pub const fn new(digest: [u8; 32]) -> Self {
39 Self {
40 schema_version: PAYLOAD_BINDING_SCHEMA_VERSION,
41 digest,
42 }
43 }
44}
45
46#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
48pub enum TerminalEvidenceDecision {
49 Committed,
50 RolledBack,
51}
52
53#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
55pub struct TerminalEvidence {
56 pub source_canister: Principal,
57 pub schema_version: u32,
58 pub decision: TerminalEvidenceDecision,
59 pub fingerprint: [u8; 32],
60}
61
62impl TerminalEvidence {
63 #[must_use]
64 pub const fn new(
65 source_canister: Principal,
66 decision: TerminalEvidenceDecision,
67 fingerprint: [u8; 32],
68 ) -> Self {
69 Self {
70 source_canister,
71 schema_version: TERMINAL_EVIDENCE_SCHEMA_VERSION,
72 decision,
73 fingerprint,
74 }
75 }
76}
77
78#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
80pub enum ReceiptBackedIntentState {
81 Pending,
82 Committed { evidence: TerminalEvidence },
83 RolledBack { evidence: TerminalEvidence },
84}
85
86#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
88pub struct ReceiptBackedIntent {
89 pub schema_version: u32,
90 pub operation_id: OperationId,
91 pub payload_binding: PayloadBinding,
92 pub resource_key: IntentResourceKey,
93 pub quantity: u64,
94 pub state: ReceiptBackedIntentState,
95 pub revision: u64,
96 pub created_at_ns: u64,
97 pub updated_at_ns: u64,
98}
99
100#[derive(Clone, Debug, Eq, PartialEq)]
102pub struct BeginLocalIntentInput {
103 pub resource_key: IntentResourceKey,
104 pub quantity: u64,
105 pub ttl_secs: Option<u64>,
106 pub reservation_limit: Option<u64>,
107}
108
109#[derive(Clone, Debug, Eq, PartialEq)]
111pub struct BeginReceiptBackedIntentInput {
112 pub operation_id: OperationId,
113 pub payload_binding: PayloadBinding,
114 pub resource_key: IntentResourceKey,
115 pub quantity: u64,
116 pub reservation_limit: u64,
117 pub replay_deadline_ns: u64,
118}
119
120#[derive(Clone, Debug, Eq, PartialEq)]
122pub struct BeginPlacementReceiptBackedIntentInput {
123 pub operation_id: OperationId,
124 pub payload_binding: PayloadBinding,
125 pub resource_key: IntentResourceKey,
126 pub quantity: u64,
127 pub reservation_limit: u64,
128}
129
130#[derive(Clone, Debug, Eq, PartialEq)]
132pub enum BeginReceiptBackedIntentResult {
133 Created {
134 revision: u64,
135 },
136 ExistingPending {
137 revision: u64,
138 },
139 ExistingCommitted {
140 revision: u64,
141 evidence: TerminalEvidence,
142 },
143 ExistingRolledBack {
144 revision: u64,
145 evidence: TerminalEvidence,
146 },
147 BindingConflict,
148 ReplayWindowClosed {
149 replay_deadline_ns: u64,
150 },
151 ReplayWindowTooLong {
152 remaining_ns: u64,
153 maximum_ns: u64,
154 },
155 CapacityExceeded {
156 current_quantity: u64,
157 requested_quantity: u64,
158 limit: u64,
159 },
160 StoreCapacityReached {
161 current_records: u64,
162 limit: u64,
163 },
164}
165
166#[derive(Clone, Debug, Eq, PartialEq)]
168pub struct SettleReceiptBackedIntentInput {
169 pub operation_id: OperationId,
170 pub expected_revision: u64,
171 pub expected_payload_binding: PayloadBinding,
172 pub evidence: TerminalEvidence,
173}
174
175#[derive(Clone, Copy, Debug, Eq, PartialEq)]
177pub enum SettleReceiptBackedIntentResult {
178 Settled {
179 revision: u64,
180 state: ReceiptBackedIntentState,
181 },
182 AlreadySettled {
183 revision: u64,
184 state: ReceiptBackedIntentState,
185 },
186 NotFound,
187 RevisionConflict {
188 actual_revision: u64,
189 },
190 BindingConflict,
191}
192
193#[derive(Clone, Debug, Eq, PartialEq)]
195pub struct RemoveTerminalReceiptBackedIntentInput {
196 pub operation_id: OperationId,
197 pub expected_revision: u64,
198 pub expected_payload_binding: PayloadBinding,
199}
200
201#[derive(Clone, Copy, Debug, Eq, PartialEq)]
203pub enum RemoveTerminalReceiptBackedIntentResult {
204 Removed,
205 NotFound,
206 NotTerminal,
207 RevisionConflict { actual_revision: u64 },
208 BindingConflict,
209}