1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
use crate::{
api::{BlockchainApi, ErrorApi, ManagedTypeApi, StorageReadApi, StorageWriteApi},
contract_base::{BlockchainWrapper, ExitCodecErrorHandler, ManagedSerializer},
err_msg,
io::ManagedResultArgLoader,
storage::StorageKey,
storage_clear, storage_get, storage_set,
types::{ManagedBuffer, ManagedType},
};
use elrond_codec::{
elrond_codec_derive::{TopDecode, TopEncode},
TopEncodeMulti,
};
use super::ManagedArgBuffer;
pub const CALLBACK_CLOSURE_STORAGE_BASE_KEY: &[u8] = b"CB_CLOSURE";
#[derive(TopEncode)]
pub struct CallbackClosure<M: ManagedTypeApi + ErrorApi> {
pub(super) callback_name: &'static str,
pub(super) closure_args: ManagedArgBuffer<M>,
}
pub fn new_callback_call<A>(callback_name: &'static str) -> CallbackClosure<A>
where
A: ManagedTypeApi + ErrorApi,
{
CallbackClosure::new(callback_name)
}
impl<M: ManagedTypeApi + ErrorApi> CallbackClosure<M> {
pub fn new(callback_name: &'static str) -> Self {
CallbackClosure {
callback_name,
closure_args: ManagedArgBuffer::new(),
}
}
pub fn push_endpoint_arg<T: TopEncodeMulti>(&mut self, endpoint_arg: &T) {
let h = ExitCodecErrorHandler::<M>::from(err_msg::CONTRACT_CALL_ENCODE_ERROR);
let Ok(()) = endpoint_arg.multi_encode_or_handle_err(&mut self.closure_args, h);
}
pub fn save_to_storage<A: BlockchainApi + StorageWriteApi>(&self) {
let storage_key = cb_closure_storage_key::<A>();
storage_set(storage_key.as_ref(), self);
}
}
pub(super) fn cb_closure_storage_key<A: BlockchainApi>() -> StorageKey<A> {
let tx_hash = BlockchainWrapper::<A>::new().get_tx_hash();
let mut storage_key = StorageKey::new(CALLBACK_CLOSURE_STORAGE_BASE_KEY);
storage_key.append_managed_buffer(tx_hash.as_managed_buffer());
storage_key
}
#[derive(TopDecode)]
pub struct CallbackClosureForDeser<M: ManagedTypeApi + ErrorApi> {
callback_name: ManagedBuffer<M>,
closure_args: ManagedArgBuffer<M>,
}
impl<M: ManagedTypeApi + ErrorApi> CallbackClosureForDeser<M> {
pub fn no_callback() -> Self {
CallbackClosureForDeser {
callback_name: ManagedBuffer::new(),
closure_args: ManagedArgBuffer::new(),
}
}
pub fn storage_load_and_clear<A: BlockchainApi + StorageReadApi + StorageWriteApi>(
) -> Option<Self> {
let storage_key = cb_closure_storage_key::<A>();
let storage_value_raw: ManagedBuffer<A> = storage_get(storage_key.as_ref());
if !storage_value_raw.is_empty() {
let serializer = ManagedSerializer::<A>::new();
let closure = serializer.top_decode_from_managed_buffer(&storage_value_raw);
storage_clear(storage_key.as_ref());
Some(closure)
} else {
None
}
}
pub fn matcher<const CB_NAME_MAX_LENGTH: usize>(
&self,
) -> CallbackClosureMatcher<CB_NAME_MAX_LENGTH> {
CallbackClosureMatcher::new(&self.callback_name)
}
pub fn into_arg_loader(self) -> ManagedResultArgLoader<M> {
ManagedResultArgLoader::new(self.closure_args.data)
}
}
pub struct CallbackClosureMatcher<const CB_NAME_MAX_LENGTH: usize> {
name_len: usize,
compare_buffer: [u8; CB_NAME_MAX_LENGTH],
}
impl<const CB_NAME_MAX_LENGTH: usize> CallbackClosureMatcher<CB_NAME_MAX_LENGTH> {
pub fn new<M: ManagedTypeApi + ErrorApi>(callback_name: &ManagedBuffer<M>) -> Self {
let mut compare_buffer = [0u8; CB_NAME_MAX_LENGTH];
let name_len = callback_name.len();
let _ = callback_name.load_slice(0, &mut compare_buffer[..name_len]);
CallbackClosureMatcher {
name_len,
compare_buffer,
}
}
pub fn new_from_unmanaged(callback_name: &[u8]) -> Self {
let mut compare_buffer = [0u8; CB_NAME_MAX_LENGTH];
let name_len = callback_name.len();
compare_buffer[..name_len].copy_from_slice(callback_name);
CallbackClosureMatcher {
name_len,
compare_buffer,
}
}
pub fn matches_empty(&self) -> bool {
self.name_len == 0
}
pub fn name_matches(&self, name_match: &[u8]) -> bool {
if self.name_len != name_match.len() {
false
} else {
&self.compare_buffer[..self.name_len] == name_match
}
}
}