-
Notifications
You must be signed in to change notification settings - Fork 24
Expand file tree
/
Copy pathblock_state_interface.rs
More file actions
354 lines (317 loc) · 13.9 KB
/
Copy pathblock_state_interface.rs
File metadata and controls
354 lines (317 loc) · 13.9 KB
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
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
use crate::entity::accounts::AccountWithCanonicalAddress;
use crate::entity::block_state::{LockNotFoundByIdError, TokenNotFoundByIdError};
use crate::entity::protocol_level_locks::p11::LockP11;
use crate::entity::protocol_level_tokens::p11::TokenP11;
use crate::entity::{EntityContext, EntityContextTypes};
use crate::external::{
AccountNotFoundByAddressError, AccountNotFoundByIndexError, OverflowError, RawTokenAmountDelta,
TokenAccountState,
};
use crate::persistent::protocol_level_locks::p11::LockConfiguration;
use crate::persistent::protocol_level_tokens::p9::TokenConfiguration;
use concordium_base::base::{AccountIndex, ProtocolVersion};
use concordium_base::contracts_common::AccountAddress;
use concordium_base::protocol_level_locks::LockId;
use concordium_base::protocol_level_tokens::TokenId;
use plt_scheduler_types::types::tokens::RawTokenAmount;
// todo delete as part of https://linear.app/concordium/issue/COR-2398/push-block-state-entity-model-into-the-scheduler
/// Key in the key-value state.
#[derive(Debug, Clone, Hash, Eq, PartialEq, Ord, PartialOrd)]
pub struct TokenStateKey(pub Vec<u8>);
/// Value in the key-value state.
#[derive(Debug, Clone, Hash, Eq, PartialEq)]
pub struct TokenStateValue(pub Vec<u8>);
// todo remove as part of https://linear.app/concordium/issue/COR-2398/push-block-state-entity-model-into-the-scheduler
/// Queries on the state of a block in the chain.
pub trait BlockStateQuery {
/// Opaque type that represents the thawed (mutable) token key-value map.
type MutableTokenKeyValueState;
/// Opaque type that represents an account on chain.
/// The account is guaranteed to exist on chain, when holding an instance of this type.
type Account;
/// Opaque type that represents a token on chain.
/// The token is guaranteed to exist on chain, when holding an instance of this type.
type Token;
type EntityContextTypes: EntityContextTypes;
/// Get entity context.
fn context(&self) -> &EntityContext<Self::EntityContextTypes>;
/// Get the [`TokenId`]s of all protocol-level tokens registered on the chain.
///
/// If the protocol version does not support protocol-level tokens, this will return the empty
/// list.
fn plt_list(&self) -> impl ExactSizeIterator<Item = TokenId>;
/// Get the token associated with a [`TokenId`] (if it exists).
/// The token ID is case-insensitive when looking up tokens by token ID.
///
/// # Arguments
///
/// - `token_id` The token id to get the [`Self::Token`] of.
fn token_by_id(&self, token_id: &TokenId) -> Result<Self::Token, TokenNotFoundByIdError>;
/// Convert a persistent token key-value state to a mutable (thawed) one that can be updated by the scheduler.
///
/// Updates to this state will only persist in the block state using [`BlockStateOperations::set_token_key_value_state`].
///
/// # Arguments
///
/// - `token` The token to thaw the token key-value state for.
fn mutable_token_key_value_state(&self, token: &Self::Token)
-> Self::MutableTokenKeyValueState;
/// Get the configuration of a protocol-level token.
///
/// # Arguments
///
/// - `token` The token to get the config for.
fn token_configuration(&self, token: &Self::Token) -> TokenConfiguration;
/// Get token P11 entity.
fn token_p11(&self, token: &Self::Token) -> TokenP11;
/// Get the circulating supply of a protocol-level token.
///
/// # Arguments
///
/// - `token` The token to get the circulating supply.
fn token_circulating_supply(&self, token: &Self::Token) -> RawTokenAmount;
/// Lookup the value for the given key in the given token key-value state. Returns `None` if
/// no value exists for the given key.
///
/// # Arguments
///
/// - `token_key_value` The token key-value state to look up the value in.
/// - `key` The token state key.
fn lookup_token_state_value(
&self,
token_key_value: &Self::MutableTokenKeyValueState,
key: &TokenStateKey,
) -> Option<TokenStateValue>;
/// Get iterator over key-value pairs with the given prefix in the
/// token key-value state.
///
/// # Arguments
///
/// - `token_key_value` The token key-value state to iterator values in.
/// - `prefix` The token state key prefix to iterate over.
fn iter_token_state_prefix<'a>(
&'a self,
token_key_value: &Self::MutableTokenKeyValueState,
prefix: &TokenStateKey,
) -> impl Iterator<Item = (TokenStateKey, TokenStateValue)> + use<'a, Self>;
/// Update the value for the given key in the given thawed token key-value state. If `None` is
/// specified as value, the entry is removed.
///
/// # Arguments
///
/// - `token_key_value` The thawed (mutable) token module state to update the value in.
/// - `key` The token state key.
/// - `value` The value to set. If `None`, the entry with the given key is removed.
fn update_token_state_value(
&self,
token_key_value: &mut Self::MutableTokenKeyValueState,
key: &TokenStateKey,
value: Option<TokenStateValue>,
);
/// Lookup the account using an account address.
fn account_by_address(
&self,
address: &AccountAddress,
) -> Result<Self::Account, AccountNotFoundByAddressError>;
/// Lookup the account using an account index. Returns both the opaque account
/// representation and the account canonical address.
fn account_by_index(
&self,
index: AccountIndex,
) -> Result<AccountWithCanonicalAddress, AccountNotFoundByIndexError>;
/// Get the account index for the account.
fn account_index(&self, account: &Self::Account) -> AccountIndex;
/// Get the token balance of the account.
fn account_token_balance(&self, account: &Self::Account, token: &Self::Token)
-> RawTokenAmount;
/// Get token account states. It returns states for all tokens
/// that the account holds.
fn token_account_states(
&self,
account: &Self::Account,
) -> impl Iterator<Item = (Self::Token, TokenAccountState)>;
/// Query the protocol version of the block state.
fn protocol_version(&self) -> ProtocolVersion;
/// Get the [`LockId`]s of all protocol-level locks registered on the chain at the
/// end of the block.
///
/// If the protocol version does not support protocol-level locks, this will return the empty
/// list.
fn lock_list(&self) -> impl ExactSizeIterator<Item = LockId>;
/// Get the lock associated with a [`LockId`] (if it exists). If the protocol
/// version does not support protocol-level locks, this will always return
/// `Err(LockNotFoundByIdError(lock_id.clone()))`.
///
/// # Arguments
///
/// - `lock_id` The lock id to get the [`LockP11`] of.
fn lock_by_id(&self, lock_id: &LockId) -> Result<LockP11, LockNotFoundByIdError>;
/// Get the configuration of a protocol-level lock.
///
/// # Arguments
///
/// - `lock` The lock to get the configuration for.
///
/// # Precondition
///
/// - The `lock` MUST exist in the block state, i.e. `s.lock_by_id(lock.lock_id()).expect("lock exists")`.
fn lock_configuration(&self, lock: &LockP11) -> LockConfiguration;
/// Get the set of account/token balances currently tracked under a lock.
///
/// Each returned pair identifies an account and token for which the lock may
/// hold a non-zero locked balance. The corresponding amount is tracked in the
/// token module state.
///
/// # Arguments
///
/// - `lock` The lock to get the tracked locked balances for.
///
/// # Precondition
///
/// - The `lock` MUST exist in the block state, i.e. `s.lock_by_id(lock.lock_id()).expect("lock exists")`.
fn lock_balances(&self, lock: &LockP11) -> impl Iterator<Item = (AccountIndex, Self::Token)>;
}
// todo remove as part of https://linear.app/concordium/issue/COR-2398/push-block-state-entity-model-into-the-scheduler
/// Operations on the state of a block in the chain.
pub trait BlockStateOperations: BlockStateQuery {
/// Set the recorded total circulating supply for a protocol-level token.
///
/// This should always be kept up-to-date with the total balance held in accounts.
///
/// # Arguments
///
/// - `token` The token.
/// - `circulation_supply` The new total circulating supply for the token.
fn set_token_circulating_supply(
&mut self,
token: &Self::Token,
circulating_supply: RawTokenAmount,
);
/// Create a new token with the given configuration. The initial state will be empty
/// and the initial supply will be 0. Returns representation of the created token.
///
/// # Arguments
///
/// - `configuration` The configuration for the token.
///
/// # Preconditions
///
/// The caller must ensure the following conditions are true, and failing to do so results in
/// undefined behavior.
///
/// - The `token` of the given configuration MUST NOT already be in use by a protocol-level
/// token, i.e. `assert_eq!(s.get_token_index(configuration.token_id), None)`.
fn create_token(&mut self, configuration: TokenConfiguration) -> Self::Token;
/// Update the token balance of an account.
///
/// # Arguments
///
/// - `token` The token to update.
/// - `account` The account to update.
/// - `amount_delta` The token balance delta.
///
/// # Errors
///
/// - [`OverflowError`] The update would overflow or underflow (result in negative balance)
/// the token balance on the account.
fn update_token_account_balance(
&mut self,
token: &Self::Token,
account: &Self::Account,
amount_delta: RawTokenAmountDelta,
) -> Result<(), OverflowError>;
/// Initialize the balance of the given account to zero if it didn't have a balance before.
/// It has the observable effect that the token is then returned when querying the tokens
/// for an account. Should be called if the token module account state is set,
/// in order to make sure the token is returned when querying token account info.
///
/// If the account already has a balance for the token in context, the operation has no effect
///
/// # Arguments
///
/// - `token` The token to touch state for in the account.
/// - `account` The account to touch token state for.
fn touch_token_account(&mut self, token: &Self::Token, account: &Self::Account);
/// Increment the update sequence number for Protocol Level Tokens (PLT).
///
/// Unlike the other chain updates this is a separate function, since there is no queue associated with PLTs.
fn increment_plt_update_instruction_sequence_number(&mut self);
/// Convert a mutable token key-value state into a persistent state and store it in the block state.
///
/// The mutable state should not be used after this call.
///
/// # Arguments
///
/// - `token` The token index to update.
/// - `mutable_token_module_state` The mutated state to set as the current token state.
fn set_token_key_value_state(
&mut self,
token: &Self::Token,
token_key_value_state: Self::MutableTokenKeyValueState,
);
/// Create a new PLT lock with the given configuration. The initial state will be empty.
///
/// # Arguments
///
/// - `lock_id` The ID of the PLT lock.
/// - `configuration` The configuration for the PLT lock.
///
/// # Preconditions
///
/// The caller must ensure the following conditions are true, and failing to do so results in
/// undefined behavior.
///
/// - The `lock` of the given configuration MUST NOT already be in use by a protocol-level
/// lock, i.e. `assert_eq!(s.lock_by_id(lock_id).ok(), None)`.
/// - The protocol version of the block state MUST support PLT locks.
fn create_lock(&mut self, lock_id: LockId, configuration: LockConfiguration);
/// Delete a PLT lock with the given Lock ID. Returns the lock if it existed, or `None`
/// if it did not exist.
///
/// # Arguments
///
/// - `lock_id` The ID of the PLT lock.
///
/// # Preconditions
///
/// This function may panic if the protocol version does not support locks.
fn delete_lock(&mut self, lock_id: &LockId) -> Option<LockP11>;
/// Track that a lock holds a balance for the given account and token.
///
/// This records the account/token pair in the lock state so it can later be
/// queried through [`BlockStateQuery::lock_balances`].
///
/// # Arguments
///
/// - `lock` The lock to update.
/// - `account` The account whose locked balance is tracked.
/// - `token` The token whose locked balance is tracked.
///
/// The caller must ensure the following conditions are true, and failing to do so results in
/// undefined behavior.
///
/// - The `lock` MUST already exist in the block state, i.e.
/// `s.lock_by_id(lock_id).expect("lock exists")`.
fn add_lock_balance_ref(&mut self, lock: &LockId, account: &Self::Account, token: &Self::Token);
/// Stop tracking that a lock holds a balance for the given account and token.
///
/// This removes the account/token pair from the lock state, so it will no longer be
/// returned by [`BlockStateQuery::lock_balances`].
///
/// # Arguments
/// - `lock` The lock to update.
/// - `account` The account whose locked balance is no longer tracked.
/// - `token` The token whose locked balance is no longer tracked.
///
/// The caller must ensure the following conditions are true, and failing to do so results in
/// undefined behavior.
///
/// - The `lock` MUST already exist in the block state, i.e.
/// `s.lock_by_id(lock_id).expect("lock exists")`.
fn remove_lock_balance_ref(
&mut self,
lock: &LockId,
account: &Self::Account,
token: &Self::Token,
);
}