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:";
14
15#[must_use]
16pub fn is_canic_owned_intent_resource_key(resource_key: &IntentResourceKey) -> bool {
17 resource_key.starts_with(CANIC_INTENT_RESOURCE_PREFIX)
18}
19
20#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
22pub struct PayloadBinding {
23 pub schema_version: u32,
24 pub digest: [u8; 32],
25}
26
27impl PayloadBinding {
28 #[must_use]
29 pub const fn new(digest: [u8; 32]) -> Self {
30 Self {
31 schema_version: PAYLOAD_BINDING_SCHEMA_VERSION,
32 digest,
33 }
34 }
35}
36
37#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
39pub enum TerminalEvidenceDecision {
40 Committed,
41 RolledBack,
42}
43
44#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
46pub struct TerminalEvidence {
47 pub source_canister: Principal,
48 pub schema_version: u32,
49 pub decision: TerminalEvidenceDecision,
50 pub fingerprint: [u8; 32],
51}
52
53impl TerminalEvidence {
54 #[must_use]
55 pub const fn new(
56 source_canister: Principal,
57 decision: TerminalEvidenceDecision,
58 fingerprint: [u8; 32],
59 ) -> Self {
60 Self {
61 source_canister,
62 schema_version: TERMINAL_EVIDENCE_SCHEMA_VERSION,
63 decision,
64 fingerprint,
65 }
66 }
67}
68
69#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
71pub enum ReceiptBackedIntentState {
72 Pending,
73 Committed { evidence: TerminalEvidence },
74 RolledBack { evidence: TerminalEvidence },
75}
76
77#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
79pub struct ReceiptBackedIntent {
80 pub schema_version: u32,
81 pub operation_id: OperationId,
82 pub payload_binding: PayloadBinding,
83 pub resource_key: IntentResourceKey,
84 pub quantity: u64,
85 pub state: ReceiptBackedIntentState,
86 pub revision: u64,
87 pub created_at_ns: u64,
88 pub updated_at_ns: u64,
89}
90
91#[derive(Clone, Debug, Eq, PartialEq)]
93pub struct BeginLocalIntentInput {
94 pub resource_key: IntentResourceKey,
95 pub quantity: u64,
96 pub ttl_secs: Option<u64>,
97 pub reservation_limit: Option<u64>,
98}
99
100#[derive(Clone, Debug, Eq, PartialEq)]
102pub struct BeginReceiptBackedIntentInput {
103 pub operation_id: OperationId,
104 pub payload_binding: PayloadBinding,
105 pub resource_key: IntentResourceKey,
106 pub quantity: u64,
107 pub reservation_limit: u64,
108}
109
110#[derive(Clone, Debug, Eq, PartialEq)]
112pub enum BeginReceiptBackedIntentResult {
113 Created {
114 revision: u64,
115 },
116 ExistingPending {
117 revision: u64,
118 },
119 ExistingCommitted {
120 revision: u64,
121 evidence: TerminalEvidence,
122 },
123 ExistingRolledBack {
124 revision: u64,
125 evidence: TerminalEvidence,
126 },
127 BindingConflict,
128 CapacityExceeded {
129 current_quantity: u64,
130 requested_quantity: u64,
131 limit: u64,
132 },
133 StoreCapacityReached {
134 current_records: u64,
135 limit: u64,
136 },
137}
138
139#[derive(Clone, Debug, Eq, PartialEq)]
141pub struct SettleReceiptBackedIntentInput {
142 pub operation_id: OperationId,
143 pub expected_revision: u64,
144 pub expected_payload_binding: PayloadBinding,
145 pub evidence: TerminalEvidence,
146}
147
148#[derive(Clone, Copy, Debug, Eq, PartialEq)]
150pub enum SettleReceiptBackedIntentResult {
151 Settled {
152 revision: u64,
153 state: ReceiptBackedIntentState,
154 },
155 AlreadySettled {
156 revision: u64,
157 state: ReceiptBackedIntentState,
158 },
159 NotFound,
160 RevisionConflict {
161 actual_revision: u64,
162 },
163 BindingConflict,
164}
165
166#[derive(Clone, Debug, Eq, PartialEq)]
168pub struct RemoveTerminalReceiptBackedIntentInput {
169 pub operation_id: OperationId,
170 pub expected_revision: u64,
171 pub expected_payload_binding: PayloadBinding,
172}
173
174#[derive(Clone, Copy, Debug, Eq, PartialEq)]
176pub enum RemoveTerminalReceiptBackedIntentResult {
177 Removed,
178 NotFound,
179 NotTerminal,
180 RevisionConflict { actual_revision: u64 },
181 BindingConflict,
182}