1#[cfg(test)]
4mod tests;
5
6use std::{
7 cell::RefCell,
8 collections::BTreeSet,
9 convert::{TryFrom, TryInto},
10 fmt::Debug,
11 rc::Rc,
12};
13
14use tracing::error;
15
16use casper_storage::{
17 global_state::{error::Error as GlobalStateError, state::StateReader},
18 tracking_copy::{
19 AddResult, TrackingCopy, TrackingCopyCache, TrackingCopyEntityExt, TrackingCopyError,
20 TrackingCopyExt,
21 },
22 AddressGenerator,
23};
24
25use casper_types::{
26 account::{
27 Account, AccountHash, AddKeyFailure, RemoveKeyFailure, SetThresholdFailure,
28 UpdateKeyFailure,
29 },
30 addressable_entity::{
31 ActionType, EntityKindTag, MessageTopicError, MessageTopics, NamedKeyAddr, NamedKeyValue,
32 Weight,
33 },
34 bytesrepr::ToBytes,
35 contract_messages::{Message, MessageAddr, MessageTopicSummary, Messages, TopicNameHash},
36 contracts::{ContractHash, ContractPackage, ContractPackageHash, NamedKeys},
37 execution::Effects,
38 handle_stored_dictionary_value,
39 system::auction::EraInfo,
40 AccessRights, AddressableEntity, AddressableEntityHash, BlockTime, CLType, CLValue,
41 CLValueDictionary, ContextAccessRights, Contract, EntityAddr, EntryPointAddr, EntryPointType,
42 EntryPointValue, EntryPoints, Gas, GrantedAccess, HashAddr, Key, KeyTag, Motes, Package,
43 PackageHash, Phase, ProtocolVersion, RuntimeArgs, RuntimeFootprint, StoredValue,
44 StoredValueTypeMismatch, SystemHashRegistry, TransactionHash, Transfer, URef, URefAddr,
45 DICTIONARY_ITEM_KEY_MAX_LENGTH, KEY_HASH_LENGTH, U512,
46};
47
48use crate::{
49 engine_state::{BlockInfo, EngineConfig},
50 execution::ExecError,
51};
52
53pub const RANDOM_BYTES_COUNT: usize = 32;
55
56#[derive(Copy, Clone, PartialEq, Eq, Debug)]
58pub enum AllowInstallUpgrade {
59 Allowed,
61 Forbidden,
63}
64
65pub struct RuntimeContext<'a, R> {
67 tracking_copy: Rc<RefCell<TrackingCopy<R>>>,
68 named_keys: &'a mut NamedKeys,
70 access_rights: ContextAccessRights,
72 args: RuntimeArgs,
73 authorization_keys: BTreeSet<AccountHash>,
74 block_info: BlockInfo,
75 transaction_hash: TransactionHash,
76 gas_limit: Gas,
77 gas_counter: Gas,
78 address_generator: Rc<RefCell<AddressGenerator>>,
79 phase: Phase,
80 engine_config: EngineConfig,
81 entry_point_type: EntryPointType,
82 transfers: Vec<Transfer>,
83 remaining_spending_limit: U512,
84
85 runtime_footprint: Rc<RefCell<RuntimeFootprint>>,
87 context_key: Key,
89 account_hash: AccountHash,
90 emit_message_cost: U512,
91 allow_install_upgrade: AllowInstallUpgrade,
92 payment_purse: Option<URef>,
93}
94
95impl<'a, R> RuntimeContext<'a, R>
96where
97 R: StateReader<Key, StoredValue, Error = GlobalStateError>,
98{
99 #[allow(clippy::too_many_arguments)]
103 pub fn new(
104 named_keys: &'a mut NamedKeys,
105 runtime_footprint: Rc<RefCell<RuntimeFootprint>>,
106 context_key: Key,
107 authorization_keys: BTreeSet<AccountHash>,
108 access_rights: ContextAccessRights,
109 account_hash: AccountHash,
110 address_generator: Rc<RefCell<AddressGenerator>>,
111 tracking_copy: Rc<RefCell<TrackingCopy<R>>>,
112 engine_config: EngineConfig,
113 block_info: BlockInfo,
114 transaction_hash: TransactionHash,
115 phase: Phase,
116 args: RuntimeArgs,
117 gas_limit: Gas,
118 gas_counter: Gas,
119 transfers: Vec<Transfer>,
120 remaining_spending_limit: U512,
121 entry_point_type: EntryPointType,
122 allow_install_upgrade: AllowInstallUpgrade,
123 ) -> Self {
124 let emit_message_cost = (*engine_config.wasm_config().v1())
125 .take_host_function_costs()
126 .emit_message
127 .cost()
128 .into();
129 RuntimeContext {
130 tracking_copy,
131 entry_point_type,
132 named_keys,
133 access_rights,
134 args,
135 runtime_footprint,
136 context_key,
137 authorization_keys,
138 account_hash,
139 block_info,
140 transaction_hash,
141 gas_limit,
142 gas_counter,
143 address_generator,
144 phase,
145 engine_config,
146 transfers,
147 remaining_spending_limit,
148 emit_message_cost,
149 allow_install_upgrade,
150 payment_purse: None,
151 }
152 }
153
154 #[allow(clippy::too_many_arguments)]
156 pub fn new_from_self(
157 &self,
158 context_key: Key,
159 entry_point_type: EntryPointType,
160 named_keys: &'a mut NamedKeys,
161 access_rights: ContextAccessRights,
162 runtime_args: RuntimeArgs,
163 ) -> Self {
164 let runtime_footprint = self.runtime_footprint.clone();
165 let authorization_keys = self.authorization_keys.clone();
166 let account_hash = self.account_hash;
167
168 let address_generator = self.address_generator.clone();
169 let tracking_copy = self.state();
170 let engine_config = self.engine_config.clone();
171
172 let block_info = self.block_info;
173 let transaction_hash = self.transaction_hash;
174 let phase = self.phase;
175
176 let gas_limit = self.gas_limit;
177 let gas_counter = self.gas_counter;
178 let remaining_spending_limit = self.remaining_spending_limit();
179
180 let transfers = self.transfers.clone();
181 let payment_purse = self.payment_purse;
182
183 RuntimeContext {
184 tracking_copy,
185 entry_point_type,
186 named_keys,
187 access_rights,
188 args: runtime_args,
189 runtime_footprint,
190 context_key,
191 authorization_keys,
192 account_hash,
193 block_info,
194 transaction_hash,
195 gas_limit,
196 gas_counter,
197 address_generator,
198 phase,
199 engine_config,
200 transfers,
201 remaining_spending_limit,
202 emit_message_cost: self.emit_message_cost,
203 allow_install_upgrade: self.allow_install_upgrade,
204 payment_purse,
205 }
206 }
207
208 pub fn authorization_keys(&self) -> &BTreeSet<AccountHash> {
210 &self.authorization_keys
211 }
212
213 pub fn named_keys_get(&self, name: &str) -> Option<&Key> {
215 self.named_keys.get(name)
216 }
217
218 pub fn named_keys(&self) -> &NamedKeys {
220 self.named_keys
221 }
222
223 pub fn named_keys_mut(&mut self) -> &mut NamedKeys {
225 self.named_keys
226 }
227
228 pub fn named_keys_contains_key(&self, name: &str) -> bool {
230 self.named_keys.contains(name)
231 }
232
233 pub fn maybe_payment_purse(&self) -> Option<URef> {
235 self.payment_purse
236 }
237
238 pub fn set_payment_purse(&mut self, uref: URef) {
240 self.payment_purse = Some(uref);
241 }
242
243 pub fn engine_config(&self) -> &EngineConfig {
245 &self.engine_config
246 }
247
248 fn remove_key_from_contract(
250 &mut self,
251 key: Key,
252 mut contract: Contract,
253 name: &str,
254 ) -> Result<(), ExecError> {
255 if contract.remove_named_key(name).is_none() {
256 return Ok(());
257 }
258 self.metered_write_gs_unsafe(key, contract)?;
259 Ok(())
260 }
261
262 fn remove_key_from_entity(&mut self, name: &str) -> Result<(), ExecError> {
264 let key = self.context_key;
265 match key {
266 Key::AddressableEntity(entity_addr) => {
267 let named_key =
268 NamedKeyAddr::new_from_string(entity_addr, name.to_string())?.into();
269 if let Some(StoredValue::NamedKey(_)) = self.read_gs(&named_key)? {
270 self.prune_gs_unsafe(named_key);
271 }
272 }
273 account_hash @ Key::Account(_) => {
274 let account: Account = {
275 let mut account: Account = self.read_gs_typed(&account_hash)?;
276 account.named_keys_mut().remove(name);
277 account
278 };
279 self.named_keys.remove(name);
280 let account_value = self.account_to_validated_value(account)?;
281 self.metered_write_gs_unsafe(account_hash, account_value)?;
282 }
283 contract_uref @ Key::URef(_) => {
284 let contract: Contract = {
285 let value: StoredValue = self
286 .tracking_copy
287 .borrow_mut()
288 .read(&contract_uref)?
289 .ok_or(ExecError::KeyNotFound(contract_uref))?;
290
291 value.try_into().map_err(ExecError::TypeMismatch)?
292 };
293
294 self.named_keys.remove(name);
295 self.remove_key_from_contract(contract_uref, contract, name)?
296 }
297 contract_hash @ Key::Hash(_) => {
298 let contract: Contract = self.read_gs_typed(&contract_hash)?;
299 self.named_keys.remove(name);
300 self.remove_key_from_contract(contract_hash, contract, name)?
301 }
302 _ => return Err(ExecError::UnexpectedKeyVariant(key)),
303 }
304 Ok(())
305 }
306
307 pub fn remove_key(&mut self, name: &str) -> Result<(), ExecError> {
311 self.named_keys.remove(name);
312 self.remove_key_from_entity(name)
313 }
314
315 pub fn get_block_info(&self) -> BlockInfo {
317 self.block_info
318 }
319
320 pub fn get_transaction_hash(&self) -> TransactionHash {
322 self.transaction_hash
323 }
324
325 pub fn access_rights_extend(&mut self, urefs: &[URef]) {
327 self.access_rights.extend(urefs);
328 }
329
330 pub fn access_rights(&self) -> &ContextAccessRights {
332 &self.access_rights
333 }
334
335 pub fn runtime_footprint(&self) -> Rc<RefCell<RuntimeFootprint>> {
337 Rc::clone(&self.runtime_footprint)
338 }
339
340 pub fn args(&self) -> &RuntimeArgs {
342 &self.args
343 }
344
345 pub(crate) fn set_args(&mut self, args: RuntimeArgs) {
346 self.args = args
347 }
348
349 pub fn address_generator(&self) -> Rc<RefCell<AddressGenerator>> {
351 Rc::clone(&self.address_generator)
352 }
353
354 pub(super) fn state(&self) -> Rc<RefCell<TrackingCopy<R>>> {
356 Rc::clone(&self.tracking_copy)
357 }
358
359 pub fn gas_limit(&self) -> Gas {
361 self.gas_limit
362 }
363
364 pub fn gas_counter(&self) -> Gas {
366 self.gas_counter
367 }
368
369 pub fn set_gas_counter(&mut self, new_gas_counter: Gas) {
371 self.gas_counter = new_gas_counter;
372 }
373
374 pub fn get_context_key(&self) -> Key {
376 self.context_key
377 }
378
379 pub fn get_initiator(&self) -> AccountHash {
381 self.account_hash
382 }
383
384 pub fn protocol_version(&self) -> ProtocolVersion {
386 self.block_info.protocol_version()
387 }
388
389 pub fn phase(&self) -> Phase {
391 self.phase
392 }
393
394 pub fn install_upgrade_allowed(&self) -> bool {
396 self.allow_install_upgrade == AllowInstallUpgrade::Allowed
397 }
398
399 pub fn new_hash_address(&mut self) -> Result<[u8; KEY_HASH_LENGTH], ExecError> {
401 Ok(self.address_generator.borrow_mut().new_hash_address())
402 }
403
404 pub fn random_bytes(&mut self) -> Result<[u8; RANDOM_BYTES_COUNT], ExecError> {
406 Ok(self.address_generator.borrow_mut().create_address())
407 }
408
409 pub fn new_uref(&mut self, value: StoredValue) -> Result<URef, ExecError> {
411 let uref = self
412 .address_generator
413 .borrow_mut()
414 .new_uref(AccessRights::READ_ADD_WRITE);
415 self.insert_uref(uref);
416 self.metered_write_gs(Key::URef(uref), value)?;
417 Ok(uref)
418 }
419
420 pub(crate) fn new_unit_uref(&mut self) -> Result<URef, ExecError> {
422 self.new_uref(StoredValue::CLValue(CLValue::unit()))
423 }
424
425 pub fn put_key(&mut self, name: String, key: Key) -> Result<(), ExecError> {
427 match self.get_context_key() {
430 Key::Account(_) | Key::Hash(_) => {
431 let named_key_value = StoredValue::CLValue(CLValue::from_t((name.clone(), key))?);
432 self.validate_value(&named_key_value)?;
433 self.metered_add_gs_unsafe(self.get_context_key(), named_key_value)?;
434 self.insert_named_key(name, key);
435 }
436 Key::AddressableEntity(entity_addr) => {
437 let named_key_value =
438 StoredValue::NamedKey(NamedKeyValue::from_concrete_values(key, name.clone())?);
439 self.validate_value(&named_key_value)?;
440 let named_key_addr = NamedKeyAddr::new_from_string(entity_addr, name.clone())?;
441 self.metered_write_gs_unsafe(Key::NamedKey(named_key_addr), named_key_value)?;
442 self.insert_named_key(name, key);
443 }
444 _ => return Err(ExecError::InvalidContext),
445 }
446
447 Ok(())
448 }
449
450 pub(crate) fn get_message_topics(
451 &mut self,
452 hash_addr: EntityAddr,
453 ) -> Result<MessageTopics, ExecError> {
454 self.tracking_copy
455 .borrow_mut()
456 .get_message_topics(hash_addr)
457 .map_err(Into::into)
458 }
459
460 pub(crate) fn get_named_keys(&mut self, entity_key: Key) -> Result<NamedKeys, ExecError> {
461 let entity_addr = if let Key::AddressableEntity(entity_addr) = entity_key {
462 entity_addr
463 } else {
464 return Err(ExecError::UnexpectedKeyVariant(entity_key));
465 };
466 self.tracking_copy
467 .borrow_mut()
468 .get_named_keys(entity_addr)
469 .map_err(Into::into)
470 }
471
472 pub(crate) fn write_entry_points(
473 &mut self,
474 entity_addr: EntityAddr,
475 entry_points: EntryPoints,
476 ) -> Result<(), ExecError> {
477 if entry_points.is_empty() {
478 return Ok(());
479 }
480
481 for entry_point in entry_points.take_entry_points() {
482 let entry_point_addr =
483 EntryPointAddr::new_v1_entry_point_addr(entity_addr, entry_point.name())?;
484 let entry_point_value =
485 StoredValue::EntryPoint(EntryPointValue::V1CasperVm(entry_point));
486 self.metered_write_gs_unsafe(Key::EntryPoint(entry_point_addr), entry_point_value)?;
487 }
488
489 Ok(())
490 }
491
492 pub(crate) fn get_casper_vm_v1_entry_point(
493 &mut self,
494 entity_key: Key,
495 ) -> Result<EntryPoints, ExecError> {
496 let entity_addr = if let Key::AddressableEntity(entity_addr) = entity_key {
497 entity_addr
498 } else {
499 return Err(ExecError::UnexpectedKeyVariant(entity_key));
500 };
501
502 self.tracking_copy
503 .borrow_mut()
504 .get_v1_entry_points(entity_addr)
505 .map_err(Into::into)
506 }
507
508 pub(crate) fn total_balance(&mut self, purse_uref: &URef) -> Result<Motes, ExecError> {
512 let key = Key::URef(*purse_uref);
513 let total = self
514 .tracking_copy
515 .borrow_mut()
516 .get_total_balance(key)
517 .map_err(ExecError::TrackingCopy)?;
518 Ok(total)
519 }
520
521 pub(crate) fn available_balance(&mut self, purse_uref: &URef) -> Result<Motes, ExecError> {
525 let key = Key::URef(*purse_uref);
526 self.tracking_copy
527 .borrow_mut()
528 .get_available_balance(key)
529 .map_err(ExecError::TrackingCopy)
530 }
531
532 pub fn read_gs(&mut self, key: &Key) -> Result<Option<StoredValue>, ExecError> {
534 self.validate_readable(key)?;
535 self.validate_key(key)?;
536
537 let maybe_stored_value = self.tracking_copy.borrow_mut().read(key)?;
538
539 let stored_value = match maybe_stored_value {
540 Some(stored_value) => handle_stored_dictionary_value(*key, stored_value)?,
541 None => return Ok(None),
542 };
543
544 Ok(Some(stored_value))
545 }
546
547 pub fn read_gs_unsafe(&mut self, key: &Key) -> Result<Option<StoredValue>, ExecError> {
554 self.tracking_copy
555 .borrow_mut()
556 .read(key)
557 .map_err(Into::into)
558 }
559
560 pub fn read_gs_typed<T>(&mut self, key: &Key) -> Result<T, ExecError>
565 where
566 T: TryFrom<StoredValue, Error = StoredValueTypeMismatch>,
567 T::Error: Debug,
568 {
569 let value = match self.read_gs(key)? {
570 None => return Err(ExecError::KeyNotFound(*key)),
571 Some(value) => value,
572 };
573
574 value
575 .try_into()
576 .map_err(|error| ExecError::TrackingCopy(TrackingCopyError::TypeMismatch(error)))
577 }
578
579 pub fn get_keys(&mut self, key_tag: &KeyTag) -> Result<BTreeSet<Key>, ExecError> {
581 self.tracking_copy
582 .borrow_mut()
583 .get_keys(key_tag)
584 .map_err(Into::into)
585 }
586
587 pub fn get_keys_with_prefix(&mut self, prefix: &[u8]) -> Result<Vec<Key>, ExecError> {
589 self.tracking_copy
590 .borrow_mut()
591 .reader()
592 .keys_with_prefix(prefix)
593 .map_err(Into::into)
594 }
595
596 pub fn write_era_info(&mut self, key: Key, value: EraInfo) {
598 if let Key::EraSummary = key {
599 self.tracking_copy
601 .borrow_mut()
602 .write(key, StoredValue::EraInfo(value));
603 } else {
604 panic!("Do not use this function for writing non-era-info keys")
605 }
606 }
607
608 fn account_to_validated_value(&self, account: Account) -> Result<StoredValue, ExecError> {
610 let value = StoredValue::Account(account);
611 self.validate_value(&value)?;
612 Ok(value)
613 }
614
615 pub fn write_account(&mut self, key: Key, account: Account) -> Result<(), ExecError> {
617 if let Key::Account(_) = key {
618 self.validate_key(&key)?;
619 let account_value = self.account_to_validated_value(account)?;
620 self.metered_write_gs_unsafe(key, account_value)?;
621 Ok(())
622 } else {
623 panic!("Do not use this function for writing non-account keys")
624 }
625 }
626
627 pub fn read_account(&mut self, key: &Key) -> Result<Option<StoredValue>, ExecError> {
629 if let Key::Account(_) = key {
630 self.validate_key(key)?;
631 self.tracking_copy
632 .borrow_mut()
633 .read(key)
634 .map_err(Into::into)
635 } else {
636 panic!("Do not use this function for reading from non-account keys")
637 }
638 }
639
640 fn insert_named_key(&mut self, name: String, key: Key) {
645 if let Key::URef(uref) = key {
646 self.insert_uref(uref);
647 }
648 self.named_keys.insert(name, key);
649 }
650
651 fn insert_uref(&mut self, uref: URef) {
655 self.access_rights.extend(&[uref])
656 }
657
658 pub fn grant_access(&mut self, uref: URef) -> GrantedAccess {
660 self.access_rights.grant_access(uref)
661 }
662
663 pub fn remove_access(&mut self, uref_addr: URefAddr, access_rights: AccessRights) {
665 self.access_rights.remove_access(uref_addr, access_rights)
666 }
667
668 pub fn effects(&self) -> Effects {
670 self.tracking_copy.borrow().effects()
671 }
672
673 pub fn messages(&self) -> Messages {
675 self.tracking_copy.borrow().messages()
676 }
677
678 pub fn cache(&self) -> TrackingCopyCache {
680 self.tracking_copy.borrow().cache()
681 }
682
683 pub fn emit_message_cost(&self) -> U512 {
685 self.emit_message_cost
686 }
687
688 pub fn set_emit_message_cost(&mut self, cost: U512) {
690 self.emit_message_cost = cost
691 }
692
693 pub fn transfers(&self) -> &Vec<Transfer> {
695 &self.transfers
696 }
697
698 pub fn transfers_mut(&mut self) -> &mut Vec<Transfer> {
700 &mut self.transfers
701 }
702
703 fn validate_cl_value(&self, cl_value: &CLValue) -> Result<(), ExecError> {
704 match cl_value.cl_type() {
705 CLType::Bool
706 | CLType::I32
707 | CLType::I64
708 | CLType::U8
709 | CLType::U32
710 | CLType::U64
711 | CLType::U128
712 | CLType::U256
713 | CLType::U512
714 | CLType::Unit
715 | CLType::String
716 | CLType::Option(_)
717 | CLType::List(_)
718 | CLType::ByteArray(..)
719 | CLType::Result { .. }
720 | CLType::Map { .. }
721 | CLType::Tuple1(_)
722 | CLType::Tuple3(_)
723 | CLType::Any
724 | CLType::PublicKey => Ok(()),
725 CLType::Key => {
726 let key: Key = cl_value.to_t()?;
727 self.validate_key(&key)
728 }
729 CLType::URef => {
730 let uref: URef = cl_value.to_t()?;
731 self.validate_uref(&uref)
732 }
733 tuple @ CLType::Tuple2(_) if *tuple == casper_types::named_key_type() => {
734 let (_name, key): (String, Key) = cl_value.to_t()?;
735 self.validate_key(&key)
736 }
737 CLType::Tuple2(_) => Ok(()),
738 }
739 }
740
741 pub(crate) fn validate_value(&self, value: &StoredValue) -> Result<(), ExecError> {
743 match value {
744 StoredValue::CLValue(cl_value) => self.validate_cl_value(cl_value),
745 StoredValue::NamedKey(named_key_value) => {
746 self.validate_cl_value(named_key_value.get_key_as_cl_value())?;
747 self.validate_cl_value(named_key_value.get_name_as_cl_value())
748 }
749 StoredValue::Account(_)
750 | StoredValue::ByteCode(_)
751 | StoredValue::Contract(_)
752 | StoredValue::AddressableEntity(_)
753 | StoredValue::SmartContract(_)
754 | StoredValue::Transfer(_)
755 | StoredValue::DeployInfo(_)
756 | StoredValue::EraInfo(_)
757 | StoredValue::Bid(_)
758 | StoredValue::BidKind(_)
759 | StoredValue::Withdraw(_)
760 | StoredValue::Unbonding(_)
761 | StoredValue::ContractPackage(_)
762 | StoredValue::ContractWasm(_)
763 | StoredValue::MessageTopic(_)
764 | StoredValue::Message(_)
765 | StoredValue::Prepayment(_)
766 | StoredValue::EntryPoint(_)
767 | StoredValue::RawBytes(_) => Ok(()),
768 }
769 }
770
771 pub(crate) fn context_key_to_entity_addr(&self) -> Result<EntityAddr, ExecError> {
772 match self.context_key {
773 Key::Account(account_hash) => Ok(EntityAddr::Account(account_hash.value())),
774 Key::Hash(hash) => {
775 if self.is_system_addressable_entity(&hash)? {
776 Ok(EntityAddr::System(hash))
777 } else {
778 Ok(EntityAddr::SmartContract(hash))
779 }
780 }
781 Key::AddressableEntity(addr) => Ok(addr),
782 _ => Err(ExecError::UnexpectedKeyVariant(self.context_key)),
783 }
784 }
785
786 pub(crate) fn validate_key(&self, key: &Key) -> Result<(), ExecError> {
791 let uref = match key {
792 Key::URef(uref) => uref,
793 _ => return Ok(()),
794 };
795 self.validate_uref(uref)
796 }
797
798 pub(crate) fn validate_uref(&self, uref: &URef) -> Result<(), ExecError> {
803 if self.access_rights.has_access_rights_to_uref(uref) {
804 Ok(())
805 } else {
806 Err(ExecError::ForgedReference(*uref))
807 }
808 }
809
810 fn validate_readable(&self, key: &Key) -> Result<(), ExecError> {
812 if self.is_readable(key) {
813 Ok(())
814 } else {
815 Err(ExecError::InvalidAccess {
816 required: AccessRights::READ,
817 })
818 }
819 }
820
821 fn validate_addable(&self, key: &Key) -> Result<(), ExecError> {
823 if self.is_addable(key) {
824 Ok(())
825 } else {
826 Err(ExecError::InvalidAccess {
827 required: AccessRights::ADD,
828 })
829 }
830 }
831
832 pub(crate) fn validate_writeable(&self, key: &Key) -> Result<(), ExecError> {
834 if self.is_writeable(key) {
835 Ok(())
836 } else {
837 Err(ExecError::InvalidAccess {
838 required: AccessRights::WRITE,
839 })
840 }
841 }
842
843 pub fn is_readable(&self, key: &Key) -> bool {
845 match self.context_key_to_entity_addr() {
846 Ok(entity_addr) => key.is_readable(&entity_addr),
847 Err(error) => {
848 error!(?error, "entity_key is unexpected key variant");
849 panic!("is_readable: entity_key is unexpected key variant");
850 }
851 }
852 }
853
854 pub fn is_addable(&self, key: &Key) -> bool {
856 match self.context_key_to_entity_addr() {
857 Ok(entity_addr) => key.is_addable(&entity_addr),
858 Err(error) => {
859 error!(?error, "entity_key is unexpected key variant");
860 panic!("is_addable: entity_key is unexpected key variant");
861 }
862 }
863 }
864
865 pub fn is_writeable(&self, key: &Key) -> bool {
867 match self.context_key_to_entity_addr() {
868 Ok(entity_addr) => key.is_writeable(&entity_addr),
869 Err(error) => {
870 error!(?error, "entity_key is unexpected key variant");
871 panic!("is_writeable: entity_key is unexpected key variant");
872 }
873 }
874 }
875
876 pub(crate) fn charge_gas(&mut self, gas: Gas) -> Result<(), ExecError> {
882 let prev = self.gas_counter();
883 let gas_limit = self.gas_limit();
884 match prev.checked_add(gas) {
886 None => {
887 self.set_gas_counter(gas_limit);
888 Err(ExecError::GasLimit)
889 }
890 Some(val) if val > gas_limit => {
891 self.set_gas_counter(gas_limit);
892 Err(ExecError::GasLimit)
893 }
894 Some(val) => {
895 self.set_gas_counter(val);
896 Ok(())
897 }
898 }
899 }
900
901 pub(crate) fn is_system_addressable_entity(
903 &self,
904 hash_addr: &HashAddr,
905 ) -> Result<bool, ExecError> {
906 Ok(self.system_entity_registry()?.exists(hash_addr))
907 }
908
909 fn charge_gas_storage(&mut self, bytes_count: usize) -> Result<(), ExecError> {
911 if let Some(hash_addr) = self.get_context_key().into_entity_hash_addr() {
912 if self.is_system_addressable_entity(&hash_addr)? {
913 return Ok(());
915 }
916 }
917
918 let storage_costs = self.engine_config.storage_costs();
919
920 let gas_cost = storage_costs.calculate_gas_cost(bytes_count);
921
922 self.charge_gas(gas_cost)
923 }
924
925 pub(crate) fn charge_system_contract_call<T>(&mut self, call_cost: T) -> Result<(), ExecError>
927 where
928 T: Into<Gas>,
929 {
930 let amount: Gas = call_cost.into();
931 self.charge_gas(amount)
932 }
933
934 pub(crate) fn prune_gs_unsafe<K>(&mut self, key: K)
939 where
940 K: Into<Key>,
941 {
942 self.tracking_copy.borrow_mut().prune(key.into());
943 }
944
945 pub(crate) fn migrate_package(
946 &mut self,
947 contract_package_hash: ContractPackageHash,
948 protocol_version: ProtocolVersion,
949 ) -> Result<(), ExecError> {
950 self.tracking_copy
951 .borrow_mut()
952 .migrate_package(Key::Hash(contract_package_hash.value()), protocol_version)
953 .map_err(ExecError::TrackingCopy)
954 }
955
956 pub(crate) fn metered_write_gs_unsafe<K, V>(
961 &mut self,
962 key: K,
963 value: V,
964 ) -> Result<(), ExecError>
965 where
966 K: Into<Key>,
967 V: Into<StoredValue>,
968 {
969 let stored_value = value.into();
970
971 let bytes_count = stored_value.serialized_length();
973 self.charge_gas_storage(bytes_count)?;
974
975 self.tracking_copy
976 .borrow_mut()
977 .write(key.into(), stored_value);
978 Ok(())
979 }
980
981 pub(crate) fn metered_emit_message(
983 &mut self,
984 topic_key: Key,
985 block_time: BlockTime,
986 block_message_count: u64,
987 topic_message_count: u32,
988 message: Message,
989 ) -> Result<(), ExecError> {
990 let topic_value = StoredValue::MessageTopic(MessageTopicSummary::new(
991 topic_message_count,
992 block_time,
993 message.topic_name().to_owned(),
994 ));
995 let message_key = message.message_key();
996 let message_value = StoredValue::Message(message.checksum().map_err(ExecError::BytesRepr)?);
997
998 let block_message_count_value =
999 StoredValue::CLValue(CLValue::from_t((block_time, block_message_count))?);
1000
1001 let bytes_count = topic_value.serialized_length()
1003 + message_value.serialized_length()
1004 + block_message_count_value.serialized_length();
1005 self.charge_gas_storage(bytes_count)?;
1006
1007 self.tracking_copy.borrow_mut().emit_message(
1008 topic_key,
1009 topic_value,
1010 message_key,
1011 message_value,
1012 block_message_count_value,
1013 message,
1014 );
1015 Ok(())
1016 }
1017
1018 pub(crate) fn metered_write_gs<T>(&mut self, key: Key, value: T) -> Result<(), ExecError>
1022 where
1023 T: Into<StoredValue>,
1024 {
1025 let stored_value = value.into();
1026 self.validate_writeable(&key)?;
1027 self.validate_key(&key)?;
1028 self.validate_value(&stored_value)?;
1029 self.metered_write_gs_unsafe(key, stored_value)
1030 }
1031
1032 pub(crate) fn metered_add_gs_unsafe(
1034 &mut self,
1035 key: Key,
1036 value: StoredValue,
1037 ) -> Result<(), ExecError> {
1038 let value_bytes_count = value.serialized_length();
1039 self.charge_gas_storage(value_bytes_count)?;
1040
1041 match self.tracking_copy.borrow_mut().add(key, value) {
1042 Err(storage_error) => Err(storage_error.into()),
1043 Ok(AddResult::Success) => Ok(()),
1044 Ok(AddResult::KeyNotFound(key)) => Err(ExecError::KeyNotFound(key)),
1045 Ok(AddResult::TypeMismatch(type_mismatch)) => {
1046 Err(ExecError::TypeMismatch(type_mismatch))
1047 }
1048 Ok(AddResult::Serialization(error)) => Err(ExecError::BytesRepr(error)),
1049 Ok(AddResult::Transform(error)) => Err(ExecError::Transform(error)),
1050 }
1051 }
1052
1053 pub(crate) fn metered_add_gs<K, V>(&mut self, key: K, value: V) -> Result<(), ExecError>
1059 where
1060 K: Into<Key>,
1061 V: Into<StoredValue>,
1062 {
1063 let key = key.into();
1064 let value = value.into();
1065 self.validate_addable(&key)?;
1066 self.validate_key(&key)?;
1067 self.validate_value(&value)?;
1068 self.metered_add_gs_unsafe(key, value)
1069 }
1070
1071 pub(crate) fn add_associated_key(
1073 &mut self,
1074 account_hash: AccountHash,
1075 weight: Weight,
1076 ) -> Result<(), ExecError> {
1077 let context_key = self.context_key;
1078 let entity_addr = self.context_key_to_entity_addr()?;
1079
1080 if EntryPointType::Caller == self.entry_point_type
1081 && entity_addr.tag() != EntityKindTag::Account
1082 {
1083 return Err(AddKeyFailure::PermissionDenied.into());
1085 }
1086
1087 if self.engine_config.enable_entity {
1088 let entity = {
1090 let mut entity: AddressableEntity = self.read_gs_typed(&context_key)?;
1091 if entity.associated_keys().len()
1093 >= (self.engine_config.max_associated_keys() as usize)
1094 {
1095 return Err(ExecError::AddKeyFailure(AddKeyFailure::MaxKeysLimit));
1096 }
1097
1098 entity
1100 .add_associated_key(account_hash, weight)
1101 .map_err(ExecError::from)?;
1102 entity
1103 };
1104
1105 self.metered_write_gs_unsafe(
1106 context_key,
1107 self.addressable_entity_to_validated_value(entity)?,
1108 )?;
1109 } else {
1110 let account = {
1112 let mut account: Account = self.read_gs_typed(&context_key)?;
1113
1114 if account.associated_keys().len() as u32
1115 >= (self.engine_config.max_associated_keys())
1116 {
1117 return Err(ExecError::AddKeyFailure(AddKeyFailure::MaxKeysLimit));
1118 }
1119
1120 let result = account.add_associated_key(
1122 account_hash,
1123 casper_types::account::Weight::new(weight.value()),
1124 );
1125
1126 result.map_err(ExecError::from)?;
1127 account
1128 };
1129
1130 let account_value = self.account_to_validated_value(account)?;
1131
1132 self.metered_write_gs_unsafe(context_key, account_value)?;
1133 }
1134
1135 Ok(())
1136 }
1137
1138 pub(crate) fn remove_associated_key(
1140 &mut self,
1141 account_hash: AccountHash,
1142 ) -> Result<(), ExecError> {
1143 let context_key = self.context_key;
1144 let entity_addr = self.context_key_to_entity_addr()?;
1145
1146 if EntryPointType::Caller == self.entry_point_type
1147 && entity_addr.tag() != EntityKindTag::Account
1148 {
1149 return Err(RemoveKeyFailure::PermissionDenied.into());
1151 }
1152
1153 if !self
1154 .runtime_footprint()
1155 .borrow()
1156 .can_manage_keys_with(&self.authorization_keys)
1157 {
1158 return Err(RemoveKeyFailure::PermissionDenied.into());
1161 }
1162
1163 if self.engine_config.enable_entity {
1164 let entity = {
1166 let mut entity: AddressableEntity = self.read_gs_typed(&context_key)?;
1167
1168 entity
1170 .remove_associated_key(account_hash)
1171 .map_err(ExecError::from)?;
1172 entity
1173 };
1174
1175 self.metered_write_gs_unsafe(
1176 context_key,
1177 self.addressable_entity_to_validated_value(entity)?,
1178 )?;
1179 } else {
1180 let account = {
1182 let mut account: Account = self.read_gs_typed(&context_key)?;
1183
1184 account
1186 .remove_associated_key(account_hash)
1187 .map_err(ExecError::from)?;
1188 account
1189 };
1190
1191 let account_value = self.account_to_validated_value(account)?;
1192
1193 self.metered_write_gs_unsafe(context_key, account_value)?;
1194 }
1195
1196 Ok(())
1197 }
1198
1199 pub(crate) fn update_associated_key(
1201 &mut self,
1202 account_hash: AccountHash,
1203 weight: Weight,
1204 ) -> Result<(), ExecError> {
1205 let context_key = self.context_key;
1206 let entity_addr = self.context_key_to_entity_addr()?;
1207
1208 if EntryPointType::Caller == self.entry_point_type
1209 && entity_addr.tag() != EntityKindTag::Account
1210 {
1211 return Err(UpdateKeyFailure::PermissionDenied.into());
1213 }
1214
1215 if !self
1216 .runtime_footprint()
1217 .borrow()
1218 .can_manage_keys_with(&self.authorization_keys)
1219 {
1220 return Err(UpdateKeyFailure::PermissionDenied.into());
1223 }
1224
1225 if self.engine_config.enable_entity {
1226 let entity = {
1228 let mut entity: AddressableEntity = self.read_gs_typed(&context_key)?;
1229
1230 entity
1232 .update_associated_key(account_hash, weight)
1233 .map_err(ExecError::from)?;
1234 entity
1235 };
1236
1237 self.metered_write_gs_unsafe(
1238 context_key,
1239 self.addressable_entity_to_validated_value(entity)?,
1240 )?;
1241 } else {
1242 let account = {
1244 let mut account: Account = self.read_gs_typed(&context_key)?;
1245
1246 account
1248 .update_associated_key(
1249 account_hash,
1250 casper_types::account::Weight::new(weight.value()),
1251 )
1252 .map_err(ExecError::from)?;
1253 account
1254 };
1255
1256 let account_value = self.account_to_validated_value(account)?;
1257
1258 self.metered_write_gs_unsafe(context_key, account_value)?;
1259 }
1260
1261 Ok(())
1262 }
1263
1264 pub(crate) fn is_authorized_by_admin(&self) -> bool {
1265 self.engine_config
1266 .administrative_accounts()
1267 .intersection(&self.authorization_keys)
1268 .next()
1269 .is_some()
1270 }
1271 pub(crate) fn get_validated_contract_package(
1273 &mut self,
1274 package_hash: HashAddr,
1275 ) -> Result<ContractPackage, ExecError> {
1276 let package_hash_key = Key::Hash(package_hash);
1277 self.validate_key(&package_hash_key)?;
1278 let contract_package: ContractPackage = self.read_gs_typed(&package_hash_key)?;
1279
1280 if !self.is_authorized_by_admin() {
1281 self.validate_uref(&contract_package.access_key())?;
1282 }
1283
1284 Ok(contract_package)
1285 }
1286
1287 pub(crate) fn set_action_threshold(
1289 &mut self,
1290 action_type: ActionType,
1291 threshold: Weight,
1292 ) -> Result<(), ExecError> {
1293 let context_key = self.context_key;
1294 let entity_addr = self.context_key_to_entity_addr()?;
1295
1296 if EntryPointType::Caller == self.entry_point_type
1297 && entity_addr.tag() != EntityKindTag::Account
1298 {
1299 return Err(SetThresholdFailure::PermissionDeniedError.into());
1301 }
1302
1303 if self.engine_config.enable_entity {
1304 let mut entity: AddressableEntity = self.read_gs_typed(&context_key)?;
1306
1307 if self.is_authorized_by_admin() {
1309 entity.set_action_threshold_unchecked(action_type, threshold)
1310 } else {
1311 entity.set_action_threshold(action_type, threshold)
1312 }
1313 .map_err(ExecError::from)?;
1314
1315 let entity_value = self.addressable_entity_to_validated_value(entity)?;
1316
1317 self.metered_write_gs_unsafe(context_key, entity_value)?;
1318 } else {
1319 let key = Key::Account(AccountHash::new(entity_addr.value()));
1321
1322 let mut account: Account = self.read_gs_typed(&key)?;
1324
1325 let action_type = match action_type {
1327 ActionType::Deployment => casper_types::account::ActionType::Deployment,
1328 ActionType::KeyManagement => casper_types::account::ActionType::KeyManagement,
1329 ActionType::UpgradeManagement => return Err(ExecError::InvalidContext),
1330 };
1331
1332 let threshold = casper_types::account::Weight::new(threshold.value());
1333
1334 if self.is_authorized_by_admin() {
1335 account.set_action_threshold_unchecked(action_type, threshold)
1336 } else {
1337 account.set_action_threshold(action_type, threshold)
1338 }
1339 .map_err(ExecError::from)?;
1340
1341 let account_value = self.account_to_validated_value(account)?;
1342
1343 self.metered_write_gs_unsafe(key, account_value)?;
1344 }
1345
1346 Ok(())
1347 }
1348
1349 fn addressable_entity_to_validated_value(
1350 &self,
1351 entity: AddressableEntity,
1352 ) -> Result<StoredValue, ExecError> {
1353 let value = StoredValue::AddressableEntity(entity);
1354 self.validate_value(&value)?;
1355 Ok(value)
1356 }
1357
1358 pub(crate) fn runtime_footprint_by_account_hash(
1359 &mut self,
1360 account_hash: AccountHash,
1361 ) -> Result<Option<RuntimeFootprint>, ExecError> {
1362 if self.engine_config.enable_entity {
1363 match self.read_gs(&Key::Account(account_hash))? {
1364 Some(StoredValue::CLValue(cl_value)) => {
1365 let key: Key = cl_value.into_t().map_err(ExecError::CLValue)?;
1366 match self.read_gs(&key)? {
1367 Some(StoredValue::AddressableEntity(addressable_entity)) => {
1368 let entity_addr = EntityAddr::Account(account_hash.value());
1369 let named_keys = self.get_named_keys(key)?;
1370 let entry_points = self.get_casper_vm_v1_entry_point(key)?;
1371 let footprint = RuntimeFootprint::new_entity_footprint(
1372 entity_addr,
1373 addressable_entity,
1374 named_keys,
1375 entry_points,
1376 );
1377 Ok(Some(footprint))
1378 }
1379 Some(_other_variant_2) => Err(ExecError::UnexpectedStoredValueVariant),
1380 None => Ok(None),
1381 }
1382 }
1383 Some(_other_variant_1) => Err(ExecError::UnexpectedStoredValueVariant),
1384 None => Ok(None),
1385 }
1386 } else {
1387 match self.read_gs(&Key::Account(account_hash))? {
1388 Some(StoredValue::Account(account)) => {
1389 Ok(Some(RuntimeFootprint::new_account_footprint(account)))
1390 }
1391 Some(_other_variant_1) => Err(ExecError::UnexpectedStoredValueVariant),
1392 None => Ok(None),
1393 }
1394 }
1395 }
1396
1397 pub fn get_main_purse(&mut self) -> Result<URef, ExecError> {
1399 let main_purse = self
1400 .runtime_footprint()
1401 .borrow()
1402 .main_purse()
1403 .ok_or(ExecError::InvalidContext)?;
1404 Ok(main_purse)
1405 }
1406
1407 pub fn entry_point_type(&self) -> EntryPointType {
1409 self.entry_point_type
1410 }
1411
1412 pub(crate) fn get_validated_package(
1414 &mut self,
1415 package_hash: PackageHash,
1416 ) -> Result<Package, ExecError> {
1417 let package_hash_key = Key::from(package_hash);
1418 self.validate_key(&package_hash_key)?;
1419 let contract_package = if self.engine_config.enable_entity {
1420 self.read_gs_typed::<Package>(&Key::SmartContract(package_hash.value()))?
1421 } else {
1422 let cp = self.read_gs_typed::<ContractPackage>(&Key::Hash(package_hash.value()))?;
1423 cp.into()
1424 };
1425 Ok(contract_package)
1426 }
1427
1428 pub(crate) fn get_package(&mut self, package_hash: HashAddr) -> Result<Package, ExecError> {
1429 self.tracking_copy
1430 .borrow_mut()
1431 .get_package(package_hash)
1432 .map_err(Into::into)
1433 }
1434
1435 pub(crate) fn get_contract(
1436 &mut self,
1437 contract_hash: ContractHash,
1438 ) -> Result<Contract, ExecError> {
1439 self.tracking_copy
1440 .borrow_mut()
1441 .get_contract(contract_hash)
1442 .map_err(Into::into)
1443 }
1444
1445 pub(crate) fn get_contract_entity(
1446 &mut self,
1447 entity_key: Key,
1448 ) -> Result<(AddressableEntity, bool), ExecError> {
1449 let entity_hash = if let Some(entity_hash) = entity_key.into_entity_hash() {
1450 entity_hash
1451 } else {
1452 return Err(ExecError::UnexpectedKeyVariant(entity_key));
1453 };
1454
1455 let mut tc = self.tracking_copy.borrow_mut();
1456
1457 let key = Key::contract_entity_key(entity_hash);
1458 match tc.read(&key)? {
1459 Some(StoredValue::AddressableEntity(entity)) => Ok((entity, false)),
1460 Some(other) => Err(ExecError::TypeMismatch(StoredValueTypeMismatch::new(
1461 "AddressableEntity".to_string(),
1462 other.type_name(),
1463 ))),
1464 None => match tc.read(&Key::Hash(entity_hash.value()))? {
1465 Some(StoredValue::Contract(contract)) => Ok((contract.into(), true)),
1466 Some(other) => Err(ExecError::TypeMismatch(StoredValueTypeMismatch::new(
1467 "Contract".to_string(),
1468 other.type_name(),
1469 ))),
1470 None => Err(TrackingCopyError::KeyNotFound(key).into()),
1471 },
1472 }
1473 }
1474
1475 pub(crate) fn dictionary_get(
1477 &mut self,
1478 uref: URef,
1479 dictionary_item_key: &str,
1480 ) -> Result<Option<CLValue>, ExecError> {
1481 self.validate_readable(&uref.into())?;
1482 self.validate_key(&uref.into())?;
1483 let dictionary_item_key_bytes = dictionary_item_key.as_bytes();
1484
1485 if dictionary_item_key_bytes.len() > DICTIONARY_ITEM_KEY_MAX_LENGTH {
1486 return Err(ExecError::DictionaryItemKeyExceedsLength);
1487 }
1488
1489 let dictionary_key = Key::dictionary(uref, dictionary_item_key_bytes);
1490 self.dictionary_read(dictionary_key)
1491 }
1492
1493 pub(crate) fn dictionary_read(
1495 &mut self,
1496 dictionary_key: Key,
1497 ) -> Result<Option<CLValue>, ExecError> {
1498 let maybe_stored_value = self
1499 .tracking_copy
1500 .borrow_mut()
1501 .read(&dictionary_key)
1502 .map_err(Into::<ExecError>::into)?;
1503
1504 if let Some(stored_value) = maybe_stored_value {
1505 let stored_value = handle_stored_dictionary_value(dictionary_key, stored_value)?;
1506 let cl_value = CLValue::try_from(stored_value).map_err(ExecError::TypeMismatch)?;
1507 Ok(Some(cl_value))
1508 } else {
1509 Ok(None)
1510 }
1511 }
1512
1513 pub fn dictionary_put(
1515 &mut self,
1516 seed_uref: URef,
1517 dictionary_item_key: &str,
1518 cl_value: CLValue,
1519 ) -> Result<(), ExecError> {
1520 let dictionary_item_key_bytes = dictionary_item_key.as_bytes();
1521
1522 if dictionary_item_key_bytes.len() > DICTIONARY_ITEM_KEY_MAX_LENGTH {
1523 return Err(ExecError::DictionaryItemKeyExceedsLength);
1524 }
1525
1526 self.validate_writeable(&seed_uref.into())?;
1527 self.validate_uref(&seed_uref)?;
1528
1529 self.validate_cl_value(&cl_value)?;
1530
1531 let wrapped_cl_value = {
1532 let dictionary_value = CLValueDictionary::new(
1533 cl_value,
1534 seed_uref.addr().to_vec(),
1535 dictionary_item_key_bytes.to_vec(),
1536 );
1537 CLValue::from_t(dictionary_value).map_err(ExecError::from)?
1538 };
1539
1540 let dictionary_key = Key::dictionary(seed_uref, dictionary_item_key_bytes);
1541 self.metered_write_gs_unsafe(dictionary_key, wrapped_cl_value)?;
1542 Ok(())
1543 }
1544
1545 pub(crate) fn get_system_contract(
1547 &self,
1548 name: &str,
1549 ) -> Result<AddressableEntityHash, ExecError> {
1550 let registry = self.system_entity_registry()?;
1551 let hash = registry.get(name).ok_or_else(|| {
1552 error!("Missing system contract hash: {}", name);
1553 ExecError::MissingSystemContractHash(name.to_string())
1554 })?;
1555 Ok(AddressableEntityHash::new(*hash))
1556 }
1557
1558 pub(crate) fn get_system_entity_key(&self, name: &str) -> Result<Key, ExecError> {
1559 let system_entity_hash = self.get_system_contract(name)?;
1560 if self.engine_config.enable_entity {
1561 Ok(Key::addressable_entity_key(
1562 EntityKindTag::System,
1563 system_entity_hash,
1564 ))
1565 } else {
1566 Ok(Key::Hash(system_entity_hash.value()))
1567 }
1568 }
1569
1570 pub fn system_entity_registry(&self) -> Result<SystemHashRegistry, ExecError> {
1572 self.tracking_copy
1573 .borrow_mut()
1574 .get_system_entity_registry()
1575 .map_err(|err| {
1576 error!("Missing system entity registry");
1577 ExecError::TrackingCopy(err)
1578 })
1579 }
1580
1581 pub(super) fn remaining_spending_limit(&self) -> U512 {
1582 self.remaining_spending_limit
1583 }
1584
1585 pub(crate) fn subtract_amount_spent(&mut self, amount: U512) -> Option<U512> {
1587 if let Some(res) = self.remaining_spending_limit.checked_sub(amount) {
1588 self.remaining_spending_limit = res;
1589 Some(self.remaining_spending_limit)
1590 } else {
1591 error!(
1592 limit = %self.remaining_spending_limit,
1593 spent = %amount,
1594 "exceeded main purse spending limit"
1595 );
1596 self.remaining_spending_limit = U512::zero();
1597 None
1598 }
1599 }
1600
1601 pub(crate) fn set_remaining_spending_limit(&mut self, amount: U512) {
1605 self.remaining_spending_limit = amount;
1606 }
1607
1608 pub(crate) fn add_message_topic(
1610 &mut self,
1611 topic_name: &str,
1612 topic_name_hash: TopicNameHash,
1613 ) -> Result<Result<(), MessageTopicError>, ExecError> {
1614 let entity_addr = self.context_key_to_entity_addr()?;
1615
1616 {
1618 let mut message_topics = self
1619 .tracking_copy
1620 .borrow_mut()
1621 .get_message_topics(entity_addr)?;
1622
1623 let max_topics_per_contract = self
1624 .engine_config
1625 .wasm_config()
1626 .messages_limits()
1627 .max_topics_per_contract();
1628
1629 if message_topics.len() >= max_topics_per_contract as usize {
1630 return Ok(Err(MessageTopicError::MaxTopicsExceeded));
1631 }
1632
1633 if let Err(e) = message_topics.add_topic(topic_name, topic_name_hash) {
1634 return Ok(Err(e));
1635 }
1636 }
1637
1638 let topic_key = Key::Message(MessageAddr::new_topic_addr(entity_addr, topic_name_hash));
1639 let block_time = self.block_info.block_time();
1640 let summary = StoredValue::MessageTopic(MessageTopicSummary::new(
1641 0,
1642 block_time,
1643 topic_name.to_string(),
1644 ));
1645
1646 self.metered_write_gs_unsafe(topic_key, summary)?;
1647
1648 Ok(Ok(()))
1649 }
1650}