1use crate::did::*;
2use crate::transaction::Event;
3use crate::TransactionList;
4use certified_vars::hashtree::{fork, fork_hash};
5use certified_vars::{AsHashTree, Hash, HashTree, Map, Seq};
6use ic_kit::candid::CandidType;
7use ic_kit::Principal;
8use serde::{Deserialize, Serialize};
9
10#[derive(CandidType, Serialize, Deserialize)]
11pub struct Bucket {
12 bucket: TransactionList,
13 buckets: Map<TransactionId, Principal>,
14 next_canisters: Seq<BucketId>,
15 contract: TokenContractId,
16}
17
18impl Bucket {
19 pub fn new(contract: TokenContractId, offset: u64) -> Self {
21 Self {
22 bucket: TransactionList::new(contract, offset),
23 buckets: Map::new(),
24 next_canisters: Seq::new(),
25 contract,
26 }
27 }
28
29 pub fn with_transaction_list(list: TransactionList) -> Self {
30 let contract = *list.contract_id();
31 Self {
32 bucket: list,
33 buckets: Map::new(),
34 next_canisters: Seq::new(),
35 contract,
36 }
37 }
38
39 pub fn get_next_canisters(&self, arg: WithWitnessArg) -> GetNextCanistersResponse {
40 let witness = match arg.witness {
41 false => None,
42 true => Some(
43 fork(
44 HashTree::Pruned(fork_hash(
45 &self.bucket.root_hash(),
46 &self.buckets.root_hash(),
47 )),
48 self.next_canisters.as_hash_tree(),
49 )
50 .into(),
51 ),
52 };
53
54 let canisters = self.next_canisters.as_vec().clone();
55
56 GetNextCanistersResponse { canisters, witness }
57 }
58
59 pub fn get_transaction(&self, arg: WithIdArg) -> GetTransactionResponse {
60 let witness = match arg.witness {
61 false => None,
62 true => Some(
63 fork(
64 fork(
65 self.bucket.witness_transaction(arg.id),
66 HashTree::Pruned(self.buckets.root_hash()),
67 ),
68 HashTree::Pruned(self.next_canisters.root_hash()),
69 )
70 .into(),
71 ),
72 };
73
74 let event = self.bucket.get_transaction(arg.id);
75
76 GetTransactionResponse::Found(event.cloned(), witness)
79 }
80
81 pub fn get_transactions(&self, arg: GetTransactionsArg) -> GetTransactionsResponseBorrowed {
82 let page = arg
83 .page
84 .unwrap_or_else(|| self.bucket.last_page_for_contract(&self.contract));
85
86 let witness = match arg.witness {
87 false => None,
88 true => Some(
89 fork(
90 fork(
91 self.bucket
92 .witness_transactions_for_contract(&self.contract, page),
93 HashTree::Pruned(self.buckets.root_hash()),
94 ),
95 HashTree::Pruned(self.next_canisters.root_hash()),
96 )
97 .into(),
98 ),
99 };
100
101 let events = self
102 .bucket
103 .get_transactions_for_contract(&self.contract, page);
104
105 GetTransactionsResponseBorrowed {
106 data: events,
107 page,
108 witness,
109 }
110 }
111
112 pub fn get_user_transactions(
113 &self,
114 arg: GetUserTransactionsArg,
115 ) -> GetTransactionsResponseBorrowed {
116 let page = arg
117 .page
118 .unwrap_or_else(|| self.bucket.last_page_for_user(&arg.user));
119
120 let witness = match arg.witness {
121 false => None,
122 true => Some(
123 fork(
124 fork(
125 self.bucket.witness_transactions_for_user(&arg.user, page),
126 HashTree::Pruned(self.buckets.root_hash()),
127 ),
128 HashTree::Pruned(self.next_canisters.root_hash()),
129 )
130 .into(),
131 ),
132 };
133
134 let events = self.bucket.get_transactions_for_user(&arg.user, page);
135
136 GetTransactionsResponseBorrowed {
137 data: events,
138 page,
139 witness,
140 }
141 }
142
143 pub fn get_token_transactions(
144 &self,
145 arg: GetTokenTransactionsArg,
146 ) -> GetTransactionsResponseBorrowed {
147 let page = arg
148 .page
149 .unwrap_or_else(|| self.bucket.last_page_for_token(&arg.token_id));
150
151 let witness = match arg.witness {
152 false => None,
153 true => Some(
154 fork(
155 fork(
156 self.bucket
157 .witness_transactions_for_token(&arg.token_id, page),
158 HashTree::Pruned(self.buckets.root_hash()),
159 ),
160 HashTree::Pruned(self.next_canisters.root_hash()),
161 )
162 .into(),
163 ),
164 };
165
166 let events = self.bucket.get_transactions_for_token(&arg.token_id, page);
167
168 GetTransactionsResponseBorrowed {
169 data: events,
170 page,
171 witness,
172 }
173 }
174
175 pub fn get_bucket_for(&self, arg: WithIdArg) -> GetBucketResponse {
176 let id_witness = self.buckets.witness(&arg.id);
177 let id = id_witness
178 .get_leaf_values()
179 .get(0)
180 .map(|bytes| Principal::from_slice(bytes))
181 .unwrap_or_else(ic_kit::ic::id);
182
183 let witness = match arg.witness {
184 false => None,
185 true => Some(
186 fork(
187 fork(HashTree::Pruned(self.bucket.root_hash()), id_witness),
188 HashTree::Pruned(self.next_canisters.root_hash()),
189 )
190 .into(),
191 ),
192 };
193
194 GetBucketResponse {
195 canister: id,
196 witness,
197 }
198 }
199
200 pub fn size(&self) -> u64 {
201 self.bucket.size()
202 }
203
204 pub fn contract_id(&self) -> &Principal {
205 &self.contract
206 }
207
208 #[inline]
209 pub fn insert(&mut self, event: Event) -> u64 {
210 self.bucket.insert(event)
211 }
212
213 #[inline]
214 pub fn set_next_canisters(&mut self, canisters: Vec<Principal>) {
215 self.next_canisters = canisters.into();
216 }
217}
218
219impl AsHashTree for Bucket {
220 fn root_hash(&self) -> Hash {
221 fork_hash(
222 &fork_hash(&self.bucket.root_hash(), &self.buckets.root_hash()),
223 &self.next_canisters.root_hash(),
224 )
225 }
226
227 fn as_hash_tree(&self) -> HashTree<'_> {
228 fork(
229 fork(self.bucket.as_hash_tree(), self.buckets.as_hash_tree()),
230 self.next_canisters.as_hash_tree(),
231 )
232 }
233}