1pub mod call_stack_elements;
2
3use alloc::{collections::BTreeMap, vec::Vec};
4
5use num_derive::{FromPrimitive, ToPrimitive};
6use num_traits::FromPrimitive;
7
8use crate::{
9 account::AccountHash,
10 bytesrepr::{self, FromBytes, ToBytes, U8_SERIALIZED_LENGTH},
11 package::PackageHash,
12 CLType, CLTyped, CLValue, CLValueError, EntityAddr, HashAddr,
13};
14
15use crate::{
16 bytesrepr::Error,
17 contracts::{ContractHash, ContractPackageHash},
18};
19pub use call_stack_elements::CallStackElement;
20
21#[derive(FromPrimitive, ToPrimitive)]
23#[repr(u8)]
24pub enum CallerTag {
25 Initiator = 0,
27 Entity,
29 SmartContract,
31}
32
33const ACCOUNT: u8 = 0;
34const PACKAGE: u8 = 1;
35const CONTRACT_PACKAGE: u8 = 2;
36const ENTITY: u8 = 3;
37const CONTRACT: u8 = 4;
38
39#[derive(Clone, Debug, PartialEq, Eq)]
40pub struct CallerInfo {
41 kind: u8,
42 fields: BTreeMap<u8, CLValue>,
43}
44
45impl CLTyped for CallerInfo {
46 fn cl_type() -> CLType {
47 CLType::Any
48 }
49}
50
51impl CallerInfo {
52 pub fn kind(&self) -> u8 {
53 self.kind
54 }
55
56 pub fn get_field_by_index(&self, index: u8) -> Option<&CLValue> {
57 self.fields.get(&index)
58 }
59}
60
61impl ToBytes for CallerInfo {
62 fn to_bytes(&self) -> Result<Vec<u8>, Error> {
63 let mut result = bytesrepr::allocate_buffer(self)?;
64 result.append(&mut self.kind.to_bytes()?);
65 result.append(&mut self.fields.to_bytes()?);
66 Ok(result)
67 }
68
69 fn serialized_length(&self) -> usize {
70 U8_SERIALIZED_LENGTH + self.fields.serialized_length()
71 }
72}
73
74impl FromBytes for CallerInfo {
75 fn from_bytes(bytes: &[u8]) -> Result<(Self, &[u8]), Error> {
76 let (kind, remainder) = u8::from_bytes(bytes)?;
77 let (fields, remainder) = BTreeMap::from_bytes(remainder)?;
78 Ok((CallerInfo { kind, fields }, remainder))
79 }
80}
81
82impl TryFrom<Caller> for CallerInfo {
83 type Error = CLValueError;
84
85 fn try_from(value: Caller) -> Result<Self, Self::Error> {
86 match value {
87 Caller::Initiator { account_hash } => {
88 let kind = ACCOUNT;
89
90 let mut ret = BTreeMap::new();
91 ret.insert(ACCOUNT, CLValue::from_t(Some(account_hash))?);
92 ret.insert(PACKAGE, CLValue::from_t(Option::<PackageHash>::None)?);
93 ret.insert(
94 CONTRACT_PACKAGE,
95 CLValue::from_t(Option::<ContractPackageHash>::None)?,
96 );
97 ret.insert(ENTITY, CLValue::from_t(Option::<EntityAddr>::None)?);
98 ret.insert(CONTRACT, CLValue::from_t(Option::<ContractHash>::None)?);
99 Ok(CallerInfo { kind, fields: ret })
100 }
101 Caller::Entity {
102 package_hash,
103 entity_addr,
104 } => {
105 let kind = ENTITY;
106
107 let mut ret = BTreeMap::new();
108 ret.insert(ACCOUNT, CLValue::from_t(Option::<AccountHash>::None)?);
109 ret.insert(PACKAGE, CLValue::from_t(Some(package_hash))?);
110 ret.insert(
111 CONTRACT_PACKAGE,
112 CLValue::from_t(Option::<ContractPackageHash>::None)?,
113 );
114 ret.insert(ENTITY, CLValue::from_t(Some(entity_addr))?);
115 ret.insert(CONTRACT, CLValue::from_t(Option::<ContractHash>::None)?);
116 Ok(CallerInfo { kind, fields: ret })
117 }
118 Caller::SmartContract {
119 contract_package_hash,
120 contract_hash,
121 } => {
122 let kind = CONTRACT;
123
124 let mut ret = BTreeMap::new();
125 ret.insert(ACCOUNT, CLValue::from_t(Option::<AccountHash>::None)?);
126 ret.insert(PACKAGE, CLValue::from_t(Option::<PackageHash>::None)?);
127 ret.insert(
128 CONTRACT_PACKAGE,
129 CLValue::from_t(Some(contract_package_hash))?,
130 );
131
132 ret.insert(ENTITY, CLValue::from_t(Option::<EntityAddr>::None)?);
133 ret.insert(CONTRACT, CLValue::from_t(Some(contract_hash))?);
134 Ok(CallerInfo { kind, fields: ret })
135 }
136 }
137 }
138}
139
140#[derive(Clone, Copy, Debug, PartialEq, Eq)]
142pub enum Caller {
143 Initiator {
145 account_hash: AccountHash,
147 },
148 Entity {
150 package_hash: PackageHash,
152 entity_addr: EntityAddr,
154 },
155 SmartContract {
156 contract_package_hash: ContractPackageHash,
158 contract_hash: ContractHash,
160 },
161}
162
163impl Caller {
164 pub fn initiator(account_hash: AccountHash) -> Self {
167 Caller::Initiator { account_hash }
168 }
169
170 pub fn entity(package_hash: PackageHash, entity_addr: EntityAddr) -> Self {
173 Caller::Entity {
174 package_hash,
175 entity_addr,
176 }
177 }
178
179 pub fn smart_contract(
180 contract_package_hash: ContractPackageHash,
181 contract_hash: ContractHash,
182 ) -> Self {
183 Caller::SmartContract {
184 contract_package_hash,
185 contract_hash,
186 }
187 }
188
189 pub fn tag(&self) -> CallerTag {
191 match self {
192 Caller::Initiator { .. } => CallerTag::Initiator,
193 Caller::Entity { .. } => CallerTag::Entity,
194 Caller::SmartContract { .. } => CallerTag::SmartContract,
195 }
196 }
197
198 pub fn contract_hash(&self) -> Option<HashAddr> {
200 match self {
201 Caller::Initiator { .. } => None,
202 Caller::Entity { entity_addr, .. } => Some(entity_addr.value()),
203 Caller::SmartContract { contract_hash, .. } => Some(contract_hash.value()),
204 }
205 }
206}
207
208impl ToBytes for Caller {
209 fn to_bytes(&self) -> Result<Vec<u8>, bytesrepr::Error> {
210 let mut result = bytesrepr::allocate_buffer(self)?;
211 result.push(self.tag() as u8);
212 match self {
213 Caller::Initiator { account_hash } => result.append(&mut account_hash.to_bytes()?),
214
215 Caller::Entity {
216 package_hash,
217 entity_addr,
218 } => {
219 result.append(&mut package_hash.to_bytes()?);
220 result.append(&mut entity_addr.to_bytes()?);
221 }
222 Caller::SmartContract {
223 contract_package_hash,
224 contract_hash,
225 } => {
226 result.append(&mut contract_package_hash.to_bytes()?);
227 result.append(&mut contract_hash.to_bytes()?);
228 }
229 };
230 Ok(result)
231 }
232
233 fn serialized_length(&self) -> usize {
234 U8_SERIALIZED_LENGTH
235 + match self {
236 Caller::Initiator { account_hash } => account_hash.serialized_length(),
237 Caller::Entity {
238 package_hash,
239 entity_addr,
240 } => package_hash.serialized_length() + entity_addr.serialized_length(),
241 Caller::SmartContract {
242 contract_package_hash,
243 contract_hash,
244 } => contract_package_hash.serialized_length() + contract_hash.serialized_length(),
245 }
246 }
247}
248
249impl FromBytes for Caller {
250 fn from_bytes(bytes: &[u8]) -> Result<(Self, &[u8]), bytesrepr::Error> {
251 let (tag, remainder): (u8, &[u8]) = FromBytes::from_bytes(bytes)?;
252 let tag = CallerTag::from_u8(tag).ok_or(bytesrepr::Error::Formatting)?;
253 match tag {
254 CallerTag::Initiator => {
255 let (account_hash, remainder) = AccountHash::from_bytes(remainder)?;
256 Ok((Caller::Initiator { account_hash }, remainder))
257 }
258 CallerTag::Entity => {
259 let (package_hash, remainder) = PackageHash::from_bytes(remainder)?;
260 let (entity_addr, remainder) = EntityAddr::from_bytes(remainder)?;
261 Ok((
262 Caller::Entity {
263 package_hash,
264 entity_addr,
265 },
266 remainder,
267 ))
268 }
269 CallerTag::SmartContract => {
270 let (contract_package_hash, remainder) =
271 ContractPackageHash::from_bytes(remainder)?;
272 let (contract_hash, remainder) = ContractHash::from_bytes(remainder)?;
273 Ok((
274 Caller::SmartContract {
275 contract_package_hash,
276 contract_hash,
277 },
278 remainder,
279 ))
280 }
281 }
282 }
283}
284
285impl CLTyped for Caller {
286 fn cl_type() -> CLType {
287 CLType::Any
288 }
289}
290
291impl From<&Caller> for CallStackElement {
292 fn from(caller: &Caller) -> Self {
293 match caller {
294 Caller::Initiator { account_hash } => CallStackElement::Session {
295 account_hash: *account_hash,
296 },
297 Caller::Entity {
298 package_hash,
299 entity_addr: entity_hash,
300 } => CallStackElement::StoredContract {
301 contract_package_hash: ContractPackageHash::new(package_hash.value()),
302 contract_hash: ContractHash::new(entity_hash.value()),
303 },
304 Caller::SmartContract {
305 contract_package_hash,
306 contract_hash,
307 } => CallStackElement::StoredContract {
308 contract_package_hash: *contract_package_hash,
309 contract_hash: *contract_hash,
310 },
311 }
312 }
313}