1mod args;
3mod auction_internal;
4pub mod cryptography;
5mod externals;
6mod handle_payment_internal;
7mod host_function_flag;
8mod mint_internal;
9pub mod stack;
10mod utils;
11pub(crate) mod wasm_prep;
12
13use std::{
14 cmp,
15 collections::{BTreeMap, BTreeSet},
16 convert::{TryFrom, TryInto},
17 iter::FromIterator,
18};
19
20use casper_wasm::elements::Module;
21use casper_wasmi::{MemoryRef, Trap, TrapCode};
22use tracing::{debug, error, warn};
23
24#[cfg(feature = "test-support")]
25use casper_wasmi::RuntimeValue;
26use itertools::Itertools;
27use num_rational::Ratio;
28
29use casper_storage::{
30 global_state::{error::Error as GlobalStateError, state::StateReader},
31 system::{auction::Auction, handle_payment::HandlePayment, mint::Mint},
32 tracking_copy::TrackingCopyExt,
33};
34use casper_types::{
35 account::{
36 Account, AccountHash, AddKeyFailure, RemoveKeyFailure, SetThresholdFailure,
37 UpdateKeyFailure,
38 },
39 addressable_entity::{
40 self, ActionThresholds, ActionType, AddressableEntity, AddressableEntityHash,
41 AssociatedKeys, ContractRuntimeTag, EntityEntryPoint, EntryPointAccess, EntryPointType,
42 EntryPoints, MessageTopicError, MessageTopics, NamedKeyAddr, NamedKeyValue, Parameter,
43 Weight, DEFAULT_ENTRY_POINT_NAME,
44 },
45 bytesrepr::{self, Bytes, FromBytes, ToBytes},
46 contract_messages::{
47 Message, MessageAddr, MessagePayload, MessageTopicOperation, MessageTopicSummary,
48 },
49 contracts::{
50 ContractHash, ContractPackage, ContractPackageHash, ContractPackageStatus,
51 ContractVersions, DisabledVersions, NamedKeys, ProtocolVersionMajor,
52 },
53 system::{
54 self,
55 auction::{self, DelegatorKind, EraInfo},
56 handle_payment, mint, CallStackElement, Caller, CallerInfo, SystemEntityType, AUCTION,
57 HANDLE_PAYMENT, MINT, STANDARD_PAYMENT,
58 },
59 AccessRights, ApiError, BlockGlobalAddr, BlockTime, ByteCode, ByteCodeAddr, ByteCodeHash,
60 ByteCodeKind, CLTyped, CLValue, ContextAccessRights, Contract, ContractWasm, EntityAddr,
61 EntityKind, EntityVersion, EntityVersionKey, EntityVersions, Gas, GrantedAccess, Group, Groups,
62 HashAddr, HostFunction, HostFunctionCost, InitiatorAddr, Key, NamedArg, Package, PackageHash,
63 PackageStatus, Phase, PublicKey, RuntimeArgs, RuntimeFootprint, StoredValue, Transfer,
64 TransferResult, TransferV2, TransferredTo, URef, DICTIONARY_ITEM_KEY_MAX_LENGTH, U512,
65};
66
67use crate::{
68 execution::ExecError, runtime::host_function_flag::HostFunctionFlag,
69 runtime_context::RuntimeContext,
70};
71pub use stack::{RuntimeStack, RuntimeStackFrame, RuntimeStackOverflow};
72pub use wasm_prep::{
73 cycles_for_instruction, preprocess, PreprocessingError, WasmValidationError,
74 DEFAULT_BR_TABLE_MAX_SIZE, DEFAULT_MAX_GLOBALS, DEFAULT_MAX_PARAMETER_COUNT,
75 DEFAULT_MAX_TABLE_SIZE,
76};
77
78#[derive(Debug)]
79enum CallContractIdentifier {
80 Contract {
81 contract_hash: HashAddr,
82 },
83 ContractPackage {
84 contract_package_hash: HashAddr,
85 version: Option<EntityVersion>,
86 protocol_version_major: Option<ProtocolVersionMajor>,
87 },
88}
89
90#[repr(u8)]
91enum CallerInformation {
92 Initiator = 0,
93 Immediate = 1,
94 FullCallChain = 2,
95}
96
97impl TryFrom<u8> for CallerInformation {
98 type Error = ApiError;
99
100 fn try_from(value: u8) -> Result<Self, Self::Error> {
101 match value {
102 0 => Ok(CallerInformation::Initiator),
103 1 => Ok(CallerInformation::Immediate),
104 2 => Ok(CallerInformation::FullCallChain),
105 _ => Err(ApiError::InvalidCallerInfoRequest),
106 }
107 }
108}
109
110pub struct Runtime<'a, R> {
112 context: RuntimeContext<'a, R>,
113 memory: Option<MemoryRef>,
114 module: Option<Module>,
115 host_buffer: Option<CLValue>,
116 stack: Option<RuntimeStack>,
117 host_function_flag: HostFunctionFlag,
118}
119
120impl<'a, R> Runtime<'a, R>
121where
122 R: StateReader<Key, StoredValue, Error = GlobalStateError>,
123{
124 pub(crate) fn new(context: RuntimeContext<'a, R>) -> Self {
126 Runtime {
127 context,
128 memory: None,
129 module: None,
130 host_buffer: None,
131 stack: None,
132 host_function_flag: HostFunctionFlag::default(),
133 }
134 }
135
136 fn new_invocation_runtime(
138 &self,
139 context: RuntimeContext<'a, R>,
140 module: Module,
141 memory: MemoryRef,
142 stack: RuntimeStack,
143 ) -> Self {
144 Self::check_preconditions(&stack);
145 Runtime {
146 context,
147 memory: Some(memory),
148 module: Some(module),
149 host_buffer: None,
150 stack: Some(stack),
151 host_function_flag: self.host_function_flag.clone(),
152 }
153 }
154
155 pub(crate) fn new_with_stack(
157 &self,
158 context: RuntimeContext<'a, R>,
159 stack: RuntimeStack,
160 ) -> Self {
161 Self::check_preconditions(&stack);
162 Runtime {
163 context,
164 memory: None,
165 module: None,
166 host_buffer: None,
167 stack: Some(stack),
168 host_function_flag: self.host_function_flag.clone(),
169 }
170 }
171
172 fn check_preconditions(stack: &RuntimeStack) {
175 if stack.is_empty() {
176 error!("Call stack should not be empty while creating a new Runtime instance");
177 debug_assert!(false);
178 }
179
180 if stack.first_frame().unwrap().contract_hash().is_some() {
181 error!("First element of the call stack should always represent a Session call");
182 debug_assert!(false);
183 }
184 }
185
186 pub(crate) fn context(&self) -> &RuntimeContext<'a, R> {
188 &self.context
189 }
190
191 fn gas(&mut self, amount: Gas) -> Result<(), ExecError> {
192 self.context.charge_gas(amount)
193 }
194
195 fn gas_counter(&self) -> Gas {
197 self.context.gas_counter()
198 }
199
200 fn set_gas_counter(&mut self, new_gas_counter: Gas) {
202 self.context.set_gas_counter(new_gas_counter);
203 }
204
205 pub(crate) fn charge_system_contract_call<T>(&mut self, amount: T) -> Result<(), ExecError>
212 where
213 T: Into<Gas>,
214 {
215 if self.is_system_immediate_caller()? || self.host_function_flag.is_in_host_function_scope()
216 {
217 return Ok(());
218 }
219
220 self.context.charge_system_contract_call(amount)
221 }
222
223 fn checked_memory_slice<Ret>(
224 &self,
225 offset: usize,
226 size: usize,
227 func: impl FnOnce(&[u8]) -> Ret,
228 ) -> Result<Ret, ExecError> {
229 self.try_get_memory()?
236 .with_direct_access(|buffer| {
237 let end = offset.checked_add(size).ok_or_else(|| {
238 casper_wasmi::Error::Memory(format!(
239 "trying to access memory block of size {} from offset {}",
240 size, offset
241 ))
242 })?;
243
244 if end > buffer.len() {
245 return Err(casper_wasmi::Error::Memory(format!(
246 "trying to access region [{}..{}] in memory [0..{}]",
247 offset,
248 end,
249 buffer.len(),
250 )));
251 }
252
253 Ok(func(&buffer[offset..end]))
254 })
255 .map_err(Into::into)
256 }
257
258 #[inline]
260 fn bytes_from_mem(&self, ptr: u32, size: usize) -> Result<Vec<u8>, ExecError> {
261 self.checked_memory_slice(ptr as usize, size, |data| data.to_vec())
262 }
263
264 #[inline]
266 fn t_from_mem<T: FromBytes>(&self, ptr: u32, size: u32) -> Result<T, ExecError> {
267 let result = self.checked_memory_slice(ptr as usize, size as usize, |data| {
268 bytesrepr::deserialize_from_slice(data)
269 })?;
270 Ok(result?)
271 }
272
273 #[inline]
275 fn key_from_mem(&mut self, key_ptr: u32, key_size: u32) -> Result<Key, ExecError> {
276 self.t_from_mem(key_ptr, key_size)
277 }
278
279 #[inline]
281 fn cl_value_from_mem(
282 &mut self,
283 cl_value_ptr: u32,
284 cl_value_size: u32,
285 ) -> Result<CLValue, ExecError> {
286 self.t_from_mem(cl_value_ptr, cl_value_size)
287 }
288
289 #[inline]
291 fn string_from_mem(&self, ptr: u32, size: u32) -> Result<String, Trap> {
292 self.t_from_mem(ptr, size).map_err(Trap::from)
293 }
294
295 fn get_module_from_entry_points(
296 &mut self,
297 entry_points: &EntryPoints,
298 ) -> Result<Vec<u8>, ExecError> {
299 let module = self.try_get_module()?.clone();
300 let entry_point_names: Vec<&str> = entry_points.keys().map(|s| s.as_str()).collect();
301 let module_bytes = wasm_prep::get_module_from_entry_points(entry_point_names, module)?;
302 Ok(module_bytes)
303 }
304
305 #[allow(clippy::wrong_self_convention)]
306 fn is_valid_uref(&self, uref_ptr: u32, uref_size: u32) -> Result<bool, Trap> {
307 let uref: URef = self.t_from_mem(uref_ptr, uref_size)?;
308 Ok(self.context.validate_uref(&uref).is_ok())
309 }
310
311 fn load_key(
313 &mut self,
314 name_ptr: u32,
315 name_size: u32,
316 output_ptr: u32,
317 output_size: usize,
318 bytes_written_ptr: u32,
319 ) -> Result<Result<(), ApiError>, Trap> {
320 let name = self.string_from_mem(name_ptr, name_size)?;
321
322 let key = match self.context.named_keys_get(&name) {
324 Some(key) => key,
325 None => {
326 return Ok(Err(ApiError::MissingKey));
327 }
328 };
329
330 let key_bytes = match key.to_bytes() {
331 Ok(bytes) => bytes,
332 Err(error) => return Ok(Err(error.into())),
333 };
334
335 if output_size < key_bytes.len() {
337 return Ok(Err(ApiError::BufferTooSmall));
338 }
339
340 if let Err(error) = self.try_get_memory()?.set(output_ptr, &key_bytes) {
342 return Err(ExecError::Interpreter(error.into()).into());
343 }
344
345 let bytes_size: u32 = key_bytes
347 .len()
348 .try_into()
349 .expect("Keys should not serialize to many bytes");
350 let size_bytes = bytes_size.to_le_bytes(); if let Err(error) = self.try_get_memory()?.set(bytes_written_ptr, &size_bytes) {
352 return Err(ExecError::Interpreter(error.into()).into());
353 }
354
355 Ok(Ok(()))
356 }
357
358 fn has_key(&mut self, name_ptr: u32, name_size: u32) -> Result<i32, Trap> {
359 let name = self.string_from_mem(name_ptr, name_size)?;
360 if self.context.named_keys_contains_key(&name) {
361 Ok(0)
362 } else {
363 Ok(1)
364 }
365 }
366
367 fn put_key(
368 &mut self,
369 name_ptr: u32,
370 name_size: u32,
371 key_ptr: u32,
372 key_size: u32,
373 ) -> Result<(), Trap> {
374 let name = self.string_from_mem(name_ptr, name_size)?;
375 let key = self.key_from_mem(key_ptr, key_size)?;
376
377 if let Some(payment_purse) = self.context.maybe_payment_purse() {
378 if Key::URef(payment_purse).normalize() == key.normalize() {
379 warn!("attempt to put_key payment purse");
380 return Err(Into::into(ExecError::Revert(ApiError::HandlePayment(
381 handle_payment::Error::AttemptToPersistPaymentPurse as u8,
382 ))));
383 }
384 }
385 self.context.put_key(name, key).map_err(Into::into)
386 }
387
388 fn remove_key(&mut self, name_ptr: u32, name_size: u32) -> Result<(), Trap> {
389 let name = self.string_from_mem(name_ptr, name_size)?;
390 self.context.remove_key(&name)?;
391 Ok(())
392 }
393
394 fn get_main_purse(&mut self, dest_ptr: u32) -> Result<(), Trap> {
396 let purse = self.context.get_main_purse()?;
397 let purse_bytes = purse.into_bytes().map_err(ExecError::BytesRepr)?;
398 self.try_get_memory()?
399 .set(dest_ptr, &purse_bytes)
400 .map_err(|e| ExecError::Interpreter(e.into()).into())
401 }
402
403 fn get_caller(&mut self, output_size_ptr: u32) -> Result<Result<(), ApiError>, Trap> {
406 if !self.can_write_to_host_buffer() {
407 return Ok(Err(ApiError::HostBufferFull));
409 }
410 let value = CLValue::from_t(self.context.get_initiator()).map_err(ExecError::CLValue)?;
411 let value_size = value.inner_bytes().len();
412
413 if let Err(error) = self.write_host_buffer(value) {
415 return Ok(Err(error));
416 }
417
418 let output_size_bytes = value_size.to_le_bytes(); if let Err(error) = self
421 .try_get_memory()?
422 .set(output_size_ptr, &output_size_bytes)
423 {
424 return Err(ExecError::Interpreter(error.into()).into());
425 }
426 Ok(Ok(()))
427 }
428
429 fn get_immediate_caller(&self) -> Option<&RuntimeStackFrame> {
431 self.stack.as_ref().and_then(|stack| stack.previous_frame())
432 }
433
434 fn is_allowed_session_caller(&self, provided_account_hash: &AccountHash) -> bool {
437 if self.context.get_initiator() == PublicKey::System.to_account_hash() {
438 return true;
439 }
440
441 if let Some(Caller::Initiator { account_hash }) = self.get_immediate_caller() {
442 return account_hash == provided_account_hash;
443 }
444 false
445 }
446
447 fn get_phase(&mut self, dest_ptr: u32) -> Result<(), Trap> {
449 let phase = self.context.phase();
450 let bytes = phase.into_bytes().map_err(ExecError::BytesRepr)?;
451 self.try_get_memory()?
452 .set(dest_ptr, &bytes)
453 .map_err(|e| ExecError::Interpreter(e.into()).into())
454 }
455
456 fn get_block_info(&self, field_idx: u8, dest_ptr: u32) -> Result<(), Trap> {
458 if field_idx == 0 {
459 return self.get_blocktime(dest_ptr);
461 }
462 let block_info = self.context.get_block_info();
463
464 let mut data: Vec<u8> = vec![];
465 if field_idx == 1 {
466 data = block_info
467 .block_height()
468 .into_bytes()
469 .map_err(ExecError::BytesRepr)?;
470 }
471 if field_idx == 2 {
472 data = block_info
473 .parent_block_hash()
474 .into_bytes()
475 .map_err(ExecError::BytesRepr)?;
476 }
477 if field_idx == 3 {
478 data = block_info
479 .state_hash()
480 .into_bytes()
481 .map_err(ExecError::BytesRepr)?;
482 }
483 if field_idx == 4 {
484 data = self
485 .context
486 .protocol_version()
487 .into_bytes()
488 .map_err(ExecError::BytesRepr)?;
489 }
490 if field_idx == 5 {
491 data = self
492 .context
493 .engine_config()
494 .enable_entity
495 .into_bytes()
496 .map_err(ExecError::BytesRepr)?;
497 }
498 if data.is_empty() {
499 Err(ExecError::InvalidImputedOperation.into())
500 } else {
501 Ok(self
502 .try_get_memory()?
503 .set(dest_ptr, &data)
504 .map_err(|e| ExecError::Interpreter(e.into()))?)
505 }
506 }
507
508 fn get_blocktime(&self, dest_ptr: u32) -> Result<(), Trap> {
510 let block_info = self.context.get_block_info();
511 let blocktime = block_info
512 .block_time()
513 .into_bytes()
514 .map_err(ExecError::BytesRepr)?;
515 self.try_get_memory()?
516 .set(dest_ptr, &blocktime)
517 .map_err(|e| ExecError::Interpreter(e.into()).into())
518 }
519
520 fn load_call_stack(
522 &mut self,
523 call_stack_len_ptr: u32,
525 result_size_ptr: u32,
527 ) -> Result<Result<(), ApiError>, Trap> {
528 if !self.can_write_to_host_buffer() {
529 return Ok(Err(ApiError::HostBufferFull));
531 }
532 let call_stack: Vec<CallStackElement> = match self.try_get_stack() {
533 Ok(stack) => {
534 let caller = stack.call_stack_elements();
535 caller.iter().map_into().collect_vec()
536 }
537 Err(_error) => return Ok(Err(ApiError::Unhandled)),
538 };
539 let call_stack_len: u32 = match call_stack.len().try_into() {
540 Ok(value) => value,
541 Err(_) => return Ok(Err(ApiError::OutOfMemory)),
542 };
543 let call_stack_len_bytes = call_stack_len.to_le_bytes();
544
545 if let Err(error) = self
546 .try_get_memory()?
547 .set(call_stack_len_ptr, &call_stack_len_bytes)
548 {
549 return Err(ExecError::Interpreter(error.into()).into());
550 }
551
552 if call_stack_len == 0 {
553 return Ok(Ok(()));
554 }
555
556 let call_stack_cl_value = CLValue::from_t(call_stack).map_err(ExecError::CLValue)?;
557
558 let call_stack_cl_value_bytes_len: u32 =
559 match call_stack_cl_value.inner_bytes().len().try_into() {
560 Ok(value) => value,
561 Err(_) => return Ok(Err(ApiError::OutOfMemory)),
562 };
563
564 if let Err(error) = self.write_host_buffer(call_stack_cl_value) {
565 return Ok(Err(error));
566 }
567
568 let call_stack_cl_value_bytes_len_bytes = call_stack_cl_value_bytes_len.to_le_bytes();
569
570 if let Err(error) = self
571 .try_get_memory()?
572 .set(result_size_ptr, &call_stack_cl_value_bytes_len_bytes)
573 {
574 return Err(ExecError::Interpreter(error.into()).into());
575 }
576
577 Ok(Ok(()))
578 }
579
580 fn load_caller_information(
582 &mut self,
583 information: u8,
584 call_stack_len_ptr: u32,
586 result_size_ptr: u32,
588 ) -> Result<Result<(), ApiError>, Trap> {
589 if !self.can_write_to_host_buffer() {
590 return Ok(Err(ApiError::HostBufferFull));
592 }
593
594 let caller_info = match CallerInformation::try_from(information) {
595 Ok(info) => info,
596 Err(error) => return Ok(Err(error)),
597 };
598
599 let caller = match caller_info {
600 CallerInformation::Initiator => {
601 let initiator_account_hash = self.context.get_initiator();
602 let caller = Caller::initiator(initiator_account_hash);
603 match CallerInfo::try_from(caller) {
604 Ok(caller_info) => {
605 vec![caller_info]
606 }
607 Err(_) => return Ok(Err(ApiError::CLTypeMismatch)),
608 }
609 }
610 CallerInformation::Immediate => match self.get_immediate_caller() {
611 Some(frame) => match CallerInfo::try_from(*frame) {
612 Ok(immediate_info) => {
613 vec![immediate_info]
614 }
615 Err(_) => return Ok(Err(ApiError::CLTypeMismatch)),
616 },
617 None => return Ok(Err(ApiError::Unhandled)),
618 },
619 CallerInformation::FullCallChain => match self.try_get_stack() {
620 Ok(call_stack) => {
621 let call_stack = call_stack.call_stack_elements().clone();
622
623 let mut ret = vec![];
624 for caller in call_stack {
625 match CallerInfo::try_from(caller) {
626 Ok(info) => ret.push(info),
627 Err(_) => return Ok(Err(ApiError::CLTypeMismatch)),
628 }
629 }
630 ret
631 }
632 Err(_) => return Ok(Err(ApiError::Unhandled)),
633 },
634 };
635
636 let call_stack_len: u32 = match caller.len().try_into() {
637 Ok(value) => value,
638 Err(_) => return Ok(Err(ApiError::OutOfMemory)),
639 };
640 let call_stack_len_bytes = call_stack_len.to_le_bytes();
641
642 if let Err(error) = self
643 .try_get_memory()?
644 .set(call_stack_len_ptr, &call_stack_len_bytes)
645 {
646 return Err(ExecError::Interpreter(error.into()).into());
647 }
648
649 if call_stack_len == 0 {
650 return Ok(Ok(()));
651 }
652
653 let call_stack_cl_value = CLValue::from_t(caller).map_err(ExecError::CLValue)?;
654
655 let call_stack_cl_value_bytes_len: u32 =
656 match call_stack_cl_value.inner_bytes().len().try_into() {
657 Ok(value) => value,
658 Err(_) => return Ok(Err(ApiError::OutOfMemory)),
659 };
660
661 if let Err(error) = self.write_host_buffer(call_stack_cl_value) {
662 return Ok(Err(error));
663 }
664
665 let call_stack_cl_value_bytes_len_bytes = call_stack_cl_value_bytes_len.to_le_bytes();
666
667 if let Err(error) = self
668 .try_get_memory()?
669 .set(result_size_ptr, &call_stack_cl_value_bytes_len_bytes)
670 {
671 return Err(ExecError::Interpreter(error.into()).into());
672 }
673
674 Ok(Ok(()))
675 }
676
677 fn ret(&mut self, value_ptr: u32, value_size: usize) -> Trap {
680 self.host_buffer = None;
681
682 let mem_get =
683 self.checked_memory_slice(value_ptr as usize, value_size, |data| data.to_vec());
684
685 match mem_get {
686 Ok(buf) => {
687 self.host_buffer = bytesrepr::deserialize_from_slice(buf).ok();
690
691 let urefs = match &self.host_buffer {
692 Some(buf) => utils::extract_urefs(buf),
693 None => Ok(vec![]),
694 };
695 match urefs {
696 Ok(urefs) => {
697 for uref in &urefs {
698 if let Err(error) = self.context.validate_uref(uref) {
699 return Trap::from(error);
700 }
701 }
702 ExecError::Ret(urefs).into()
703 }
704 Err(e) => e.into(),
705 }
706 }
707 Err(e) => e.into(),
708 }
709 }
710
711 fn is_system_contract(&self, hash_addr: HashAddr) -> Result<bool, ExecError> {
713 self.context.is_system_addressable_entity(&hash_addr)
714 }
715
716 fn get_named_argument<T: FromBytes + CLTyped>(
717 args: &RuntimeArgs,
718 name: &str,
719 ) -> Result<T, ExecError> {
720 let arg: CLValue = args
721 .get(name)
722 .cloned()
723 .ok_or(ExecError::Revert(ApiError::MissingArgument))?;
724 arg.into_t()
725 .map_err(|_| ExecError::Revert(ApiError::InvalidArgument))
726 }
727
728 fn try_get_named_argument<T: FromBytes + CLTyped>(
729 args: &RuntimeArgs,
730 name: &str,
731 ) -> Result<Option<T>, ExecError> {
732 match args.get(name) {
733 Some(arg) => {
734 let arg = arg
735 .clone()
736 .into_t()
737 .map_err(|_| ExecError::Revert(ApiError::InvalidArgument))?;
738 Ok(Some(arg))
739 }
740 None => Ok(None),
741 }
742 }
743
744 fn reverter<T: Into<ApiError>>(error: T) -> ExecError {
745 let api_error: ApiError = error.into();
746 match api_error {
750 ApiError::Mint(mint_error) if mint_error == mint::Error::GasLimit as u8 => {
751 ExecError::GasLimit
752 }
753 ApiError::AuctionError(auction_error)
754 if auction_error == auction::Error::GasLimit as u8 =>
755 {
756 ExecError::GasLimit
757 }
758 ApiError::HandlePayment(handle_payment_error)
759 if handle_payment_error == handle_payment::Error::GasLimit as u8 =>
760 {
761 ExecError::GasLimit
762 }
763 api_error => ExecError::Revert(api_error),
764 }
765 }
766
767 fn call_host_mint(
769 &mut self,
770 entry_point_name: &str,
771 runtime_args: &RuntimeArgs,
772 access_rights: ContextAccessRights,
773 stack: RuntimeStack,
774 ) -> Result<CLValue, ExecError> {
775 let gas_counter = self.gas_counter();
776
777 let mint_hash = self.context.get_system_contract(MINT)?;
778 let mint_addr = EntityAddr::new_system(mint_hash.value());
779 let mint_key = if self.context.engine_config().enable_entity {
780 Key::AddressableEntity(EntityAddr::System(mint_hash.value()))
781 } else {
782 Key::Hash(mint_hash.value())
783 };
784
785 let mint_named_keys = self
786 .context
787 .state()
788 .borrow_mut()
789 .get_named_keys(mint_addr)?;
790
791 let mut named_keys = mint_named_keys;
792
793 let runtime_context = self.context.new_from_self(
794 mint_key,
795 EntryPointType::Called,
796 &mut named_keys,
797 access_rights,
798 runtime_args.to_owned(),
799 );
800
801 let mut mint_runtime = self.new_with_stack(runtime_context, stack);
802
803 let engine_config = self.context.engine_config();
804 let system_config = engine_config.system_config();
805 let mint_costs = system_config.mint_costs();
806
807 let result = match entry_point_name {
808 mint::METHOD_MINT => (|| {
810 mint_runtime.charge_system_contract_call(mint_costs.mint)?;
811
812 let amount: U512 = Self::get_named_argument(runtime_args, mint::ARG_AMOUNT)?;
813 let result: Result<URef, mint::Error> = mint_runtime.mint(amount);
814 if let Err(mint::Error::GasLimit) = result {
815 return Err(ExecError::GasLimit);
816 }
817 CLValue::from_t(result).map_err(Self::reverter)
818 })(),
819 mint::METHOD_REDUCE_TOTAL_SUPPLY => (|| {
820 mint_runtime.charge_system_contract_call(mint_costs.reduce_total_supply)?;
821
822 let amount: U512 = Self::get_named_argument(runtime_args, mint::ARG_AMOUNT)?;
823 let result: Result<(), mint::Error> = mint_runtime.reduce_total_supply(amount);
824 CLValue::from_t(result).map_err(Self::reverter)
825 })(),
826 mint::METHOD_BURN => (|| {
827 mint_runtime.charge_system_contract_call(mint_costs.burn)?;
828
829 let purse: URef = Self::get_named_argument(runtime_args, mint::ARG_PURSE)?;
830 let amount: U512 = Self::get_named_argument(runtime_args, mint::ARG_AMOUNT)?;
831 let result: Result<(), mint::Error> = mint_runtime.burn(purse, amount);
832 CLValue::from_t(result).map_err(Self::reverter)
833 })(),
834 mint::METHOD_CREATE => (|| {
836 mint_runtime.charge_system_contract_call(mint_costs.create)?;
837
838 let uref = mint_runtime.mint(U512::zero()).map_err(Self::reverter)?;
839 CLValue::from_t(uref).map_err(Self::reverter)
840 })(),
841 mint::METHOD_BALANCE => (|| {
843 mint_runtime.charge_system_contract_call(mint_costs.balance)?;
844
845 let uref: URef = Self::get_named_argument(runtime_args, mint::ARG_PURSE)?;
846
847 let maybe_balance: Option<U512> =
848 mint_runtime.balance(uref).map_err(Self::reverter)?;
849 CLValue::from_t(maybe_balance).map_err(Self::reverter)
850 })(),
851 mint::METHOD_TRANSFER => (|| {
854 mint_runtime.charge_system_contract_call(mint_costs.transfer)?;
855
856 let maybe_to: Option<AccountHash> =
857 Self::get_named_argument(runtime_args, mint::ARG_TO)?;
858 let source: URef = Self::get_named_argument(runtime_args, mint::ARG_SOURCE)?;
859 let target: URef = Self::get_named_argument(runtime_args, mint::ARG_TARGET)?;
860 let amount: U512 = Self::get_named_argument(runtime_args, mint::ARG_AMOUNT)?;
861 let id: Option<u64> = Self::get_named_argument(runtime_args, mint::ARG_ID)?;
862 let result: Result<(), mint::Error> =
863 mint_runtime.transfer(maybe_to, source, target, amount, id);
864
865 CLValue::from_t(result).map_err(Self::reverter)
866 })(),
867 mint::METHOD_READ_BASE_ROUND_REWARD => (|| {
869 mint_runtime.charge_system_contract_call(mint_costs.read_base_round_reward)?;
870
871 let result: U512 = mint_runtime
872 .read_base_round_reward()
873 .map_err(Self::reverter)?;
874 CLValue::from_t(result).map_err(Self::reverter)
875 })(),
876 mint::METHOD_MINT_INTO_EXISTING_PURSE => (|| {
877 mint_runtime.charge_system_contract_call(mint_costs.mint_into_existing_purse)?;
878
879 let amount: U512 = Self::get_named_argument(runtime_args, mint::ARG_AMOUNT)?;
880 let existing_purse: URef = Self::get_named_argument(runtime_args, mint::ARG_PURSE)?;
881
882 let result: Result<(), mint::Error> =
883 mint_runtime.mint_into_existing_purse(existing_purse, amount);
884 CLValue::from_t(result).map_err(Self::reverter)
885 })(),
886 _ => {
887 Ok(CLValue::unit())
890 }
891 };
892
893 self.gas(
897 mint_runtime
898 .gas_counter()
899 .checked_sub(gas_counter)
900 .unwrap_or(gas_counter),
901 )?;
902
903 let ret = result?;
905
906 self.context
908 .set_remaining_spending_limit(mint_runtime.context.remaining_spending_limit());
909
910 let urefs = utils::extract_urefs(&ret)?;
911 self.context.access_rights_extend(&urefs);
912 {
913 let transfers = self.context.transfers_mut();
914 mint_runtime.context.transfers().clone_into(transfers);
915 }
916 Ok(ret)
917 }
918
919 fn call_host_handle_payment(
921 &mut self,
922 entry_point_name: &str,
923 runtime_args: &RuntimeArgs,
924 access_rights: ContextAccessRights,
925 stack: RuntimeStack,
926 ) -> Result<CLValue, ExecError> {
927 let gas_counter = self.gas_counter();
928
929 let handle_payment_hash = self.context.get_system_contract(HANDLE_PAYMENT)?;
930 let handle_payment_key = if self.context.engine_config().enable_entity {
931 Key::AddressableEntity(EntityAddr::System(handle_payment_hash.value()))
932 } else {
933 Key::Hash(handle_payment_hash.value())
934 };
935
936 let handle_payment_named_keys = self
937 .context
938 .state()
939 .borrow_mut()
940 .get_named_keys(EntityAddr::System(handle_payment_hash.value()))?;
941
942 let mut named_keys = handle_payment_named_keys;
943
944 let runtime_context = self.context.new_from_self(
945 handle_payment_key,
946 EntryPointType::Called,
947 &mut named_keys,
948 access_rights,
949 runtime_args.to_owned(),
950 );
951
952 let mut runtime = self.new_with_stack(runtime_context, stack);
953
954 let engine_config = self.context.engine_config();
955 let system_config = engine_config.system_config();
956 let handle_payment_costs = system_config.handle_payment_costs();
957
958 let result = match entry_point_name {
959 handle_payment::METHOD_GET_PAYMENT_PURSE => {
960 runtime.charge_system_contract_call(handle_payment_costs.get_payment_purse)?;
961 match self.context.maybe_payment_purse() {
962 Some(payment_purse) => CLValue::from_t(payment_purse).map_err(Self::reverter),
963 None => {
964 let payment_purse = runtime.get_payment_purse().map_err(Self::reverter)?;
965 self.context.set_payment_purse(payment_purse);
966 CLValue::from_t(payment_purse).map_err(Self::reverter)
967 }
968 }
969 }
970 handle_payment::METHOD_SET_REFUND_PURSE => (|| {
971 runtime.charge_system_contract_call(handle_payment_costs.set_refund_purse)?;
972
973 let purse: URef =
974 Self::get_named_argument(runtime_args, handle_payment::ARG_PURSE)?;
975 runtime.set_refund_purse(purse).map_err(Self::reverter)?;
976 CLValue::from_t(()).map_err(Self::reverter)
977 })(),
978 handle_payment::METHOD_GET_REFUND_PURSE => (|| {
979 runtime.charge_system_contract_call(handle_payment_costs.get_refund_purse)?;
980
981 let maybe_purse = runtime.get_refund_purse().map_err(Self::reverter)?;
982 CLValue::from_t(maybe_purse).map_err(Self::reverter)
983 })(),
984 _ => {
985 Ok(CLValue::unit())
988 }
989 };
990
991 self.gas(
992 runtime
993 .gas_counter()
994 .checked_sub(gas_counter)
995 .unwrap_or(gas_counter),
996 )?;
997
998 let ret = result?;
999
1000 let urefs = utils::extract_urefs(&ret)?;
1001 self.context.access_rights_extend(&urefs);
1002 {
1003 let transfers = self.context.transfers_mut();
1004 runtime.context.transfers().clone_into(transfers);
1005 }
1006 Ok(ret)
1007 }
1008
1009 fn call_host_auction(
1011 &mut self,
1012 entry_point_name: &str,
1013 runtime_args: &RuntimeArgs,
1014 access_rights: ContextAccessRights,
1015 stack: RuntimeStack,
1016 ) -> Result<CLValue, ExecError> {
1017 let gas_counter = self.gas_counter();
1018
1019 let auction_hash = self.context.get_system_contract(AUCTION)?;
1020 let auction_key = if self.context.engine_config().enable_entity {
1021 Key::AddressableEntity(EntityAddr::System(auction_hash.value()))
1022 } else {
1023 Key::Hash(auction_hash.value())
1024 };
1025
1026 let auction_named_keys = self
1027 .context
1028 .state()
1029 .borrow_mut()
1030 .get_named_keys(EntityAddr::System(auction_hash.value()))?;
1031
1032 let mut named_keys = auction_named_keys;
1033
1034 let runtime_context = self.context.new_from_self(
1035 auction_key,
1036 EntryPointType::Called,
1037 &mut named_keys,
1038 access_rights,
1039 runtime_args.to_owned(),
1040 );
1041
1042 let mut runtime = self.new_with_stack(runtime_context, stack);
1043
1044 let engine_config = self.context.engine_config();
1045 let system_config = engine_config.system_config();
1046 let auction_costs = system_config.auction_costs();
1047
1048 let result = match entry_point_name {
1049 auction::METHOD_GET_ERA_VALIDATORS => (|| {
1050 runtime.charge_system_contract_call::<u64>(auction_costs.get_era_validators)?;
1051
1052 let result = runtime.get_era_validators().map_err(Self::reverter)?;
1053
1054 CLValue::from_t(result).map_err(Self::reverter)
1055 })(),
1056
1057 auction::METHOD_ADD_BID => (|| {
1058 runtime.charge_system_contract_call(auction_costs.add_bid)?;
1059 let public_key = Self::get_named_argument(runtime_args, auction::ARG_PUBLIC_KEY)?;
1060 let delegation_rate =
1061 Self::get_named_argument(runtime_args, auction::ARG_DELEGATION_RATE)?;
1062 let amount = Self::get_named_argument(runtime_args, auction::ARG_AMOUNT)?;
1063
1064 let global_minimum_delegation_amount =
1065 self.context.engine_config().minimum_delegation_amount();
1066 let minimum_delegation_amount = Self::try_get_named_argument(
1067 runtime_args,
1068 auction::ARG_MINIMUM_DELEGATION_AMOUNT,
1069 )?
1070 .unwrap_or(global_minimum_delegation_amount);
1071
1072 let global_maximum_delegation_amount =
1073 self.context.engine_config().maximum_delegation_amount();
1074 let maximum_delegation_amount = Self::try_get_named_argument(
1075 runtime_args,
1076 auction::ARG_MAXIMUM_DELEGATION_AMOUNT,
1077 )?
1078 .unwrap_or(global_maximum_delegation_amount);
1079
1080 if minimum_delegation_amount < global_minimum_delegation_amount
1081 || maximum_delegation_amount > global_maximum_delegation_amount
1082 || minimum_delegation_amount > maximum_delegation_amount
1083 {
1084 return Err(ExecError::Revert(ApiError::InvalidDelegationAmountLimits));
1085 }
1086 let reserved_slots =
1087 Self::try_get_named_argument(runtime_args, auction::ARG_RESERVED_SLOTS)?
1088 .unwrap_or(0);
1089
1090 let max_delegators_per_validator =
1091 self.context.engine_config().max_delegators_per_validator();
1092
1093 let minimum_bid_amount = self.context().engine_config().minimum_bid_amount();
1094
1095 let result = runtime
1096 .add_bid(
1097 public_key,
1098 delegation_rate,
1099 amount,
1100 minimum_delegation_amount,
1101 maximum_delegation_amount,
1102 minimum_bid_amount,
1103 max_delegators_per_validator,
1104 reserved_slots,
1105 )
1106 .map_err(Self::reverter)?;
1107
1108 CLValue::from_t(result).map_err(Self::reverter)
1109 })(),
1110
1111 auction::METHOD_WITHDRAW_BID => (|| {
1112 runtime.charge_system_contract_call(auction_costs.withdraw_bid)?;
1113
1114 let public_key = Self::get_named_argument(runtime_args, auction::ARG_PUBLIC_KEY)?;
1115 let amount = Self::get_named_argument(runtime_args, auction::ARG_AMOUNT)?;
1116 let min_bid_amount = self.context.engine_config().minimum_bid_amount();
1117
1118 let result = runtime
1119 .withdraw_bid(public_key, amount, min_bid_amount)
1120 .map_err(Self::reverter)?;
1121 CLValue::from_t(result).map_err(Self::reverter)
1122 })(),
1123
1124 auction::METHOD_DELEGATE => (|| {
1125 runtime.charge_system_contract_call(auction_costs.delegate)?;
1126
1127 let delegator = {
1128 match Self::get_named_argument(runtime_args, auction::ARG_DELEGATOR) {
1129 Ok(pk) => DelegatorKind::PublicKey(pk),
1130 Err(_) => {
1131 let uref: URef = match Self::get_named_argument(
1132 runtime_args,
1133 auction::ARG_DELEGATOR_PURSE,
1134 ) {
1135 Ok(uref) => uref,
1136 Err(err) => {
1137 debug!(%err, "failed to get delegator purse argument");
1138 return Err(err);
1139 }
1140 };
1141 DelegatorKind::Purse(uref.addr())
1142 }
1143 }
1144 };
1145 let validator = Self::get_named_argument(runtime_args, auction::ARG_VALIDATOR)?;
1146 let amount = Self::get_named_argument(runtime_args, auction::ARG_AMOUNT)?;
1147
1148 let max_delegators_per_validator =
1149 self.context.engine_config().max_delegators_per_validator();
1150
1151 let result = runtime
1152 .delegate(delegator, validator, amount, max_delegators_per_validator)
1153 .map_err(Self::reverter)?;
1154
1155 CLValue::from_t(result).map_err(Self::reverter)
1156 })(),
1157
1158 auction::METHOD_UNDELEGATE => (|| {
1159 runtime.charge_system_contract_call(auction_costs.undelegate)?;
1160
1161 let delegator = {
1162 match Self::get_named_argument(runtime_args, auction::ARG_DELEGATOR) {
1163 Ok(pk) => DelegatorKind::PublicKey(pk),
1164 Err(_) => {
1165 let uref: URef = match Self::get_named_argument(
1166 runtime_args,
1167 auction::ARG_DELEGATOR_PURSE,
1168 ) {
1169 Ok(uref) => uref,
1170 Err(err) => {
1171 debug!(%err, "failed to get delegator purse argument");
1172 return Err(err);
1173 }
1174 };
1175 DelegatorKind::Purse(uref.addr())
1176 }
1177 }
1178 };
1179 let validator = Self::get_named_argument(runtime_args, auction::ARG_VALIDATOR)?;
1180 let amount = Self::get_named_argument(runtime_args, auction::ARG_AMOUNT)?;
1181
1182 let result = runtime
1183 .undelegate(delegator, validator, amount)
1184 .map_err(Self::reverter)?;
1185
1186 CLValue::from_t(result).map_err(Self::reverter)
1187 })(),
1188
1189 auction::METHOD_REDELEGATE => (|| {
1190 runtime.charge_system_contract_call(auction_costs.redelegate)?;
1191
1192 let delegator = {
1193 match Self::get_named_argument(runtime_args, auction::ARG_DELEGATOR) {
1194 Ok(pk) => DelegatorKind::PublicKey(pk),
1195 Err(_) => {
1196 let uref: URef = match Self::get_named_argument(
1197 runtime_args,
1198 auction::ARG_DELEGATOR_PURSE,
1199 ) {
1200 Ok(uref) => uref,
1201 Err(err) => {
1202 debug!(%err, "failed to get delegator purse argument");
1203 return Err(err);
1204 }
1205 };
1206 DelegatorKind::Purse(uref.addr())
1207 }
1208 }
1209 };
1210 let validator = Self::get_named_argument(runtime_args, auction::ARG_VALIDATOR)?;
1211 let amount = Self::get_named_argument(runtime_args, auction::ARG_AMOUNT)?;
1212 let new_validator =
1213 Self::get_named_argument(runtime_args, auction::ARG_NEW_VALIDATOR)?;
1214
1215 let result = runtime
1216 .redelegate(delegator, validator, amount, new_validator)
1217 .map_err(Self::reverter)?;
1218
1219 CLValue::from_t(result).map_err(Self::reverter)
1220 })(),
1221
1222 auction::METHOD_RUN_AUCTION => (|| {
1223 runtime.charge_system_contract_call(auction_costs.run_auction)?;
1224
1225 let era_end_timestamp_millis =
1226 Self::get_named_argument(runtime_args, auction::ARG_ERA_END_TIMESTAMP_MILLIS)?;
1227 let evicted_validators =
1228 Self::get_named_argument(runtime_args, auction::ARG_EVICTED_VALIDATORS)?;
1229
1230 let max_delegators_per_validator =
1231 self.context.engine_config().max_delegators_per_validator();
1232 let minimum_bid_amount = self.context.engine_config().minimum_bid_amount();
1233 runtime
1234 .run_auction(
1235 era_end_timestamp_millis,
1236 evicted_validators,
1237 max_delegators_per_validator,
1238 true,
1239 Ratio::new_raw(U512::from(1), U512::from(5)),
1240 minimum_bid_amount,
1241 )
1242 .map_err(Self::reverter)?;
1243
1244 CLValue::from_t(()).map_err(Self::reverter)
1245 })(),
1246
1247 auction::METHOD_SLASH => (|| {
1249 runtime.charge_system_contract_call(auction_costs.slash)?;
1250
1251 let validator_public_keys =
1252 Self::get_named_argument(runtime_args, auction::ARG_VALIDATOR_PUBLIC_KEYS)?;
1253 runtime
1254 .slash(validator_public_keys)
1255 .map_err(Self::reverter)?;
1256 CLValue::from_t(()).map_err(Self::reverter)
1257 })(),
1258
1259 auction::METHOD_DISTRIBUTE => (|| {
1262 runtime.charge_system_contract_call(auction_costs.distribute)?;
1263 let rewards = Self::get_named_argument(runtime_args, auction::ARG_REWARDS_MAP)?;
1264 runtime.distribute(rewards).map_err(Self::reverter)?;
1265 CLValue::from_t(()).map_err(Self::reverter)
1266 })(),
1267
1268 auction::METHOD_READ_ERA_ID => (|| {
1270 runtime.charge_system_contract_call(auction_costs.read_era_id)?;
1271
1272 let result = runtime.read_era_id().map_err(Self::reverter)?;
1273 CLValue::from_t(result).map_err(Self::reverter)
1274 })(),
1275
1276 auction::METHOD_ACTIVATE_BID => (|| {
1277 runtime.charge_system_contract_call(auction_costs.activate_bid)?;
1278
1279 let validator = Self::get_named_argument(runtime_args, auction::ARG_VALIDATOR)?;
1280
1281 runtime
1282 .activate_bid(validator, engine_config.minimum_bid_amount())
1283 .map_err(Self::reverter)?;
1284
1285 CLValue::from_t(()).map_err(Self::reverter)
1286 })(),
1287 auction::METHOD_CHANGE_BID_PUBLIC_KEY => (|| {
1288 runtime.charge_system_contract_call(auction_costs.change_bid_public_key)?;
1289
1290 let public_key = Self::get_named_argument(runtime_args, auction::ARG_PUBLIC_KEY)?;
1291 let new_public_key =
1292 Self::get_named_argument(runtime_args, auction::ARG_NEW_PUBLIC_KEY)?;
1293
1294 runtime
1295 .change_bid_public_key(public_key, new_public_key)
1296 .map_err(Self::reverter)?;
1297
1298 CLValue::from_t(()).map_err(Self::reverter)
1299 })(),
1300 auction::METHOD_ADD_RESERVATIONS => (|| {
1301 runtime.charge_system_contract_call(auction_costs.add_reservations)?;
1302
1303 let reservations =
1304 Self::get_named_argument(runtime_args, auction::ARG_RESERVATIONS)?;
1305
1306 runtime
1307 .add_reservations(reservations)
1308 .map_err(Self::reverter)?;
1309
1310 CLValue::from_t(()).map_err(Self::reverter)
1311 })(),
1312 auction::METHOD_CANCEL_RESERVATIONS => (|| {
1313 runtime.charge_system_contract_call(auction_costs.cancel_reservations)?;
1314
1315 let validator = Self::get_named_argument(runtime_args, auction::ARG_VALIDATOR)?;
1316 let delegators = Self::get_named_argument(runtime_args, auction::ARG_DELEGATORS)?;
1317 let max_delegators_per_validator =
1318 self.context.engine_config().max_delegators_per_validator();
1319
1320 runtime
1321 .cancel_reservations(validator, delegators, max_delegators_per_validator)
1322 .map_err(Self::reverter)?;
1323
1324 CLValue::from_t(()).map_err(Self::reverter)
1325 })(),
1326 _ => {
1327 Ok(CLValue::unit())
1330 }
1331 };
1332
1333 self.gas(
1335 runtime
1336 .gas_counter()
1337 .checked_sub(gas_counter)
1338 .unwrap_or(gas_counter),
1339 )?;
1340
1341 let ret = result?;
1343
1344 let urefs = utils::extract_urefs(&ret)?;
1345 self.context.access_rights_extend(&urefs);
1346 {
1347 let transfers = self.context.transfers_mut();
1348 runtime.context.transfers().clone_into(transfers);
1349 }
1350
1351 Ok(ret)
1352 }
1353
1354 pub(crate) fn call_contract_with_stack(
1356 &mut self,
1357 contract_hash: AddressableEntityHash,
1358 entry_point_name: &str,
1359 args: RuntimeArgs,
1360 stack: RuntimeStack,
1361 ) -> Result<CLValue, ExecError> {
1362 self.stack = Some(stack);
1363
1364 self.call_contract(contract_hash, entry_point_name, args)
1365 }
1366
1367 pub fn call_package_version_with_stack(
1369 &mut self,
1370 contract_package_hash: PackageHash,
1371 protocol_version_major: Option<ProtocolVersionMajor>,
1372 version: Option<EntityVersion>,
1373 entry_point_name: String,
1374 args: RuntimeArgs,
1375 stack: RuntimeStack,
1376 ) -> Result<CLValue, ExecError> {
1377 self.stack = Some(stack);
1378
1379 self.call_package_version(
1380 contract_package_hash,
1381 protocol_version_major,
1382 version,
1383 entry_point_name,
1384 args,
1385 )
1386 }
1387
1388 pub(crate) fn execute_module_bytes(
1389 &mut self,
1390 module_bytes: &Bytes,
1391 stack: RuntimeStack,
1392 ) -> Result<CLValue, ExecError> {
1393 let protocol_version = self.context.protocol_version();
1394 let engine_config = self.context.engine_config();
1395 let wasm_config = engine_config.wasm_config();
1396 #[cfg(feature = "test-support")]
1397 let max_stack_height = wasm_config.v1().max_stack_height();
1398 let module = preprocess(*wasm_config, module_bytes)?;
1399 let (instance, memory) =
1400 utils::instance_and_memory(module.clone(), protocol_version, engine_config)?;
1401 self.memory = Some(memory);
1402 self.module = Some(module);
1403 self.stack = Some(stack);
1404 self.context.set_args(utils::attenuate_uref_in_args(
1405 self.context.args().clone(),
1406 self.context
1407 .runtime_footprint()
1408 .borrow()
1409 .main_purse()
1410 .expect("line 1183")
1411 .addr(),
1412 AccessRights::WRITE,
1413 )?);
1414
1415 let result = instance.invoke_export(DEFAULT_ENTRY_POINT_NAME, &[], self);
1416
1417 let error = match result {
1418 Err(error) => error,
1419 Ok(_) => {
1424 return Ok(self.take_host_buffer().unwrap_or(CLValue::from_t(())?));
1425 }
1426 };
1427
1428 #[cfg(feature = "test-support")]
1429 dump_runtime_stack_info(instance, max_stack_height);
1430
1431 if let Some(host_error) = error.as_host_error() {
1432 let downcasted_error = host_error.downcast_ref::<ExecError>();
1436 return match downcasted_error {
1437 Some(ExecError::Ret(ref _ret_urefs)) => self
1438 .take_host_buffer()
1439 .ok_or(ExecError::ExpectedReturnValue),
1440 Some(error) => Err(error.clone()),
1441 None => Err(ExecError::Interpreter(host_error.to_string())),
1442 };
1443 }
1444 Err(ExecError::Interpreter(error.into()))
1445 }
1446
1447 pub fn call_contract(
1449 &mut self,
1450 contract_hash: AddressableEntityHash,
1451 entry_point_name: &str,
1452 args: RuntimeArgs,
1453 ) -> Result<CLValue, ExecError> {
1454 let contract_hash = contract_hash.value();
1455 let identifier = CallContractIdentifier::Contract { contract_hash };
1456
1457 self.execute_contract(identifier, entry_point_name, args)
1458 }
1459
1460 pub fn call_versioned_contract(
1464 &mut self,
1465 contract_package_hash: PackageHash,
1466 contract_version: Option<EntityVersion>,
1467 entry_point_name: String,
1468 args: RuntimeArgs,
1469 ) -> Result<CLValue, ExecError> {
1470 self.call_package_version(
1471 contract_package_hash,
1472 None,
1473 contract_version,
1474 entry_point_name,
1475 args,
1476 )
1477 }
1478
1479 pub fn call_package_version(
1483 &mut self,
1484 contract_package_hash: PackageHash,
1485 protocol_version_major: Option<ProtocolVersionMajor>,
1486 version: Option<EntityVersion>,
1487 entry_point_name: String,
1488 args: RuntimeArgs,
1489 ) -> Result<CLValue, ExecError> {
1490 let contract_package_hash = contract_package_hash.value();
1506 let identifier = CallContractIdentifier::ContractPackage {
1507 contract_package_hash,
1508 version,
1509 protocol_version_major,
1510 };
1511
1512 self.execute_contract(identifier, &entry_point_name, args)
1513 }
1514
1515 fn get_protocol_version_for_entity_version(
1516 &self,
1517 entity_version: EntityVersion,
1518 package: &Package,
1519 ) -> Result<EntityVersionKey, ExecError> {
1520 let enabled_versions = package.enabled_versions();
1521 let current_protocol_version_major = self.context.protocol_version().value().major;
1522
1523 let mut possible_versions = vec![];
1524
1525 for protocol_version_major in (1..=current_protocol_version_major).rev() {
1526 let entity_version_key = EntityVersionKey::new(protocol_version_major, entity_version);
1527 if enabled_versions.get(&entity_version_key).is_some() {
1529 possible_versions.push(entity_version_key)
1530 }
1531 }
1532
1533 if possible_versions.is_empty() {
1534 return Err(ExecError::NoMatchingEntityVersionKey);
1535 }
1536
1537 if possible_versions.len() > 1
1538 && self
1539 .context
1540 .engine_config()
1541 .trap_on_ambiguous_entity_version
1542 {
1543 return Err(ExecError::AmbiguousEntityVersion);
1544 }
1545
1546 possible_versions.sort();
1552 let entity_version_key = possible_versions.pop().unwrap();
1554 Ok(entity_version_key)
1555 }
1556
1557 fn get_key_from_entity_addr(&self, entity_addr: EntityAddr) -> Key {
1558 if self.context().engine_config().enable_entity {
1559 Key::AddressableEntity(entity_addr)
1560 } else {
1561 match entity_addr {
1562 EntityAddr::System(system_hash_addr) => Key::Hash(system_hash_addr),
1563 EntityAddr::Account(hash_addr) => Key::Account(AccountHash::new(hash_addr)),
1564 EntityAddr::SmartContract(contract_hash_addr) => Key::Hash(contract_hash_addr),
1565 }
1566 }
1567 }
1568
1569 fn get_context_key_for_contract_call(
1570 &self,
1571 entity_addr: EntityAddr,
1572 entry_point: &EntityEntryPoint,
1573 ) -> Result<Key, ExecError> {
1574 let current = self.context.entry_point_type();
1575 let next = entry_point.entry_point_type();
1576 match (current, next) {
1577 (EntryPointType::Called, EntryPointType::Caller) => {
1578 Err(ExecError::InvalidContext)
1580 }
1581 (EntryPointType::Factory, EntryPointType::Caller) => {
1582 Err(ExecError::InvalidContext)
1584 }
1585 (EntryPointType::Caller, EntryPointType::Caller) => {
1586 Ok(self.context.get_context_key())
1588 }
1589 (EntryPointType::Caller, EntryPointType::Called)
1590 | (EntryPointType::Called, EntryPointType::Called) => {
1591 Ok(self.get_key_from_entity_addr(entity_addr))
1592 }
1593 _ => {
1594 Ok(self.get_key_from_entity_addr(entity_addr))
1596 }
1597 }
1598 }
1599
1600 fn try_get_memory(&self) -> Result<&MemoryRef, ExecError> {
1601 self.memory.as_ref().ok_or(ExecError::WasmPreprocessing(
1602 PreprocessingError::MissingMemorySection,
1603 ))
1604 }
1605
1606 fn try_get_module(&self) -> Result<&Module, ExecError> {
1607 self.module.as_ref().ok_or(ExecError::WasmPreprocessing(
1608 PreprocessingError::MissingModule,
1609 ))
1610 }
1611
1612 fn try_get_stack(&self) -> Result<&RuntimeStack, ExecError> {
1613 self.stack.as_ref().ok_or(ExecError::MissingRuntimeStack)
1614 }
1615
1616 fn maybe_system_type(&self, hash_addr: HashAddr) -> Option<SystemEntityType> {
1617 let is_mint = self.is_mint(hash_addr);
1618 if is_mint.is_some() {
1619 return is_mint;
1620 };
1621
1622 let is_auction = self.is_auction(hash_addr);
1623 if is_auction.is_some() {
1624 return is_auction;
1625 };
1626 let is_handle = self.is_handle_payment(hash_addr);
1627 if is_handle.is_some() {
1628 return is_handle;
1629 };
1630
1631 None
1632 }
1633
1634 fn is_mint(&self, hash_addr: HashAddr) -> Option<SystemEntityType> {
1635 let hash = match self.context.get_system_contract(MINT) {
1636 Ok(hash) => hash,
1637 Err(_) => {
1638 error!("Failed to get system mint contract hash");
1639 return None;
1640 }
1641 };
1642 if hash.value() == hash_addr {
1643 Some(SystemEntityType::Mint)
1644 } else {
1645 None
1646 }
1647 }
1648
1649 fn is_handle_payment(&self, hash_addr: HashAddr) -> Option<SystemEntityType> {
1651 let hash = match self.context.get_system_contract(HANDLE_PAYMENT) {
1652 Ok(hash) => hash,
1653 Err(_) => {
1654 error!("Failed to get system handle payment contract hash");
1655 return None;
1656 }
1657 };
1658 if hash.value() == hash_addr {
1659 Some(SystemEntityType::HandlePayment)
1660 } else {
1661 None
1662 }
1663 }
1664
1665 fn is_auction(&self, hash_addr: HashAddr) -> Option<SystemEntityType> {
1667 let hash = match self.context.get_system_contract(AUCTION) {
1668 Ok(hash) => hash,
1669 Err(_) => {
1670 error!("Failed to get system auction contract hash");
1671 return None;
1672 }
1673 };
1674
1675 if hash.value() == hash_addr {
1676 Some(SystemEntityType::Auction)
1677 } else {
1678 None
1679 }
1680 }
1681
1682 fn execute_contract(
1683 &mut self,
1684 identifier: CallContractIdentifier,
1685 entry_point_name: &str,
1686 args: RuntimeArgs,
1687 ) -> Result<CLValue, ExecError> {
1688 let (footprint, entity_addr, package) = match identifier {
1689 CallContractIdentifier::Contract { contract_hash } => {
1690 let entity_addr = if self.context.is_system_addressable_entity(&contract_hash)? {
1691 EntityAddr::new_system(contract_hash)
1692 } else {
1693 EntityAddr::new_smart_contract(contract_hash)
1694 };
1695 let footprint = match self.context.read_gs(&Key::Hash(contract_hash))? {
1696 Some(StoredValue::Contract(contract)) => {
1697 if self.context.engine_config().enable_entity {
1698 self.migrate_contract_and_contract_package(contract_hash)?;
1699 };
1700
1701 let maybe_system_entity_type = self.maybe_system_type(contract_hash);
1702
1703 RuntimeFootprint::new_contract_footprint(
1704 ContractHash::new(contract_hash),
1705 contract,
1706 maybe_system_entity_type,
1707 )
1708 }
1709 Some(_) | None => {
1710 if !self.context.engine_config().enable_entity {
1711 return Err(ExecError::KeyNotFound(Key::Hash(contract_hash)));
1712 }
1713 let key = Key::AddressableEntity(entity_addr);
1714 let entity = self.context.read_gs_typed::<AddressableEntity>(&key)?;
1715 let entity_named_keys = self
1716 .context
1717 .state()
1718 .borrow_mut()
1719 .get_named_keys(entity_addr)?;
1720 let entry_points = self.context.get_casper_vm_v1_entry_point(key)?;
1721 RuntimeFootprint::new_entity_footprint(
1722 entity_addr,
1723 entity,
1724 entity_named_keys,
1725 entry_points,
1726 )
1727 }
1728 };
1729
1730 let package_hash = footprint.package_hash().ok_or(ExecError::InvalidContext)?;
1731 let package: Package = self.context.get_package(package_hash)?;
1732
1733 let is_calling_system_contract = self.is_system_contract(contract_hash)?;
1735
1736 let entity_hash = AddressableEntityHash::new(contract_hash);
1737
1738 let is_contract_enabled = package.is_entity_enabled(&entity_addr);
1740
1741 if !is_calling_system_contract && !is_contract_enabled {
1742 return Err(ExecError::DisabledEntity(entity_hash));
1743 }
1744
1745 (footprint, entity_addr, package)
1746 }
1747 CallContractIdentifier::ContractPackage {
1748 contract_package_hash,
1749 version,
1750 protocol_version_major,
1751 } => {
1752 let package = self.context.get_package(contract_package_hash)?;
1753 let entity_version_key = match (version, protocol_version_major) {
1754 (Some(entity_version), Some(major)) => {
1755 EntityVersionKey::new(major, entity_version)
1756 }
1757 (None, Some(major)) => package.current_entity_version_for(major),
1758 (Some(entity_version), None) => {
1759 match self.get_protocol_version_for_entity_version(entity_version, &package)
1760 {
1761 Ok(entity_version_key) => entity_version_key,
1762 Err(err) => {
1763 return Err(err);
1764 }
1765 }
1766 }
1767 (None, None) => match package.current_entity_version() {
1768 Some(v) => v,
1769 None => {
1770 return Err(ExecError::NoActiveEntityVersions(
1771 contract_package_hash.into(),
1772 ));
1773 }
1774 },
1775 };
1776
1777 if package.is_version_missing(entity_version_key) {
1778 return Err(ExecError::MissingEntityVersion(entity_version_key));
1779 }
1780
1781 if !package.is_version_enabled(entity_version_key) {
1782 return Err(ExecError::DisabledEntityVersion(entity_version_key));
1783 }
1784
1785 let hash_addr = package
1786 .lookup_entity_hash(entity_version_key)
1787 .copied()
1788 .ok_or(ExecError::MissingEntityVersion(entity_version_key))?
1789 .value();
1790
1791 let entity_addr = if self.context.is_system_addressable_entity(&hash_addr)? {
1792 EntityAddr::new_system(hash_addr)
1793 } else {
1794 EntityAddr::new_smart_contract(hash_addr)
1795 };
1796
1797 let footprint = match self.context.read_gs(&Key::Hash(hash_addr))? {
1798 Some(StoredValue::Contract(contract)) => {
1799 if self.context.engine_config().enable_entity {
1800 self.migrate_contract_and_contract_package(hash_addr)?;
1801 };
1802 let maybe_system_entity_type = self.maybe_system_type(hash_addr);
1803 RuntimeFootprint::new_contract_footprint(
1804 ContractHash::new(hash_addr),
1805 contract,
1806 maybe_system_entity_type,
1807 )
1808 }
1809 Some(_) | None => {
1810 if !self.context.engine_config().enable_entity {
1811 return Err(ExecError::KeyNotFound(Key::Hash(hash_addr)));
1812 }
1813 let key = Key::AddressableEntity(entity_addr);
1814 let entity = self.context.read_gs_typed::<AddressableEntity>(&key)?;
1815 let entity_named_keys = self
1816 .context
1817 .state()
1818 .borrow_mut()
1819 .get_named_keys(entity_addr)?;
1820 let entry_points = self.context.get_casper_vm_v1_entry_point(key)?;
1821 RuntimeFootprint::new_entity_footprint(
1822 entity_addr,
1823 entity,
1824 entity_named_keys,
1825 entry_points,
1826 )
1827 }
1828 };
1829
1830 (footprint, entity_addr, package)
1831 }
1832 };
1833
1834 if let EntityKind::Account(_) = footprint.entity_kind() {
1835 return Err(ExecError::InvalidContext);
1836 }
1837
1838 let entry_point = match footprint.entry_points().get(entry_point_name) {
1839 Some(entry_point) => entry_point,
1840 None => {
1841 match footprint.entity_kind() {
1842 EntityKind::System(_) => {
1843 self.charge_system_contract_call(
1844 self.context()
1845 .engine_config()
1846 .system_config()
1847 .no_such_entrypoint(),
1848 )?;
1849 }
1850 EntityKind::Account(_) => {}
1851 EntityKind::SmartContract(_) => {}
1852 }
1853 return Err(ExecError::NoSuchMethod(entry_point_name.to_owned()));
1854 }
1855 };
1856
1857 let entry_point_type = entry_point.entry_point_type();
1858
1859 if self.context.engine_config().enable_entity && entry_point_type.is_invalid_context() {
1860 return Err(ExecError::InvalidContext);
1861 }
1862
1863 self.validate_entry_point_access(&package, entry_point_name, entry_point.access())?;
1868 if self.context.engine_config().strict_argument_checking() {
1869 let entry_point_args_lookup: BTreeMap<&str, &Parameter> = entry_point
1870 .args()
1871 .iter()
1872 .map(|param| (param.name(), param))
1873 .collect();
1874
1875 let args_lookup: BTreeMap<&str, &NamedArg> = args
1876 .named_args()
1877 .map(|named_arg| (named_arg.name(), named_arg))
1878 .collect();
1879
1880 for (param_name, param) in entry_point_args_lookup {
1882 if let Some(named_arg) = args_lookup.get(param_name) {
1883 if param.cl_type() != named_arg.cl_value().cl_type() {
1884 return Err(ExecError::type_mismatch(
1885 param.cl_type().clone(),
1886 named_arg.cl_value().cl_type().clone(),
1887 ));
1888 }
1889 } else if !param.cl_type().is_option() {
1890 return Err(ExecError::MissingArgument {
1891 name: param.name().to_string(),
1892 });
1893 }
1894 }
1895 }
1896
1897 let entity_hash = AddressableEntityHash::new(entity_addr.value());
1898
1899 if !self
1900 .context
1901 .engine_config()
1902 .administrative_accounts()
1903 .is_empty()
1904 && !package.is_entity_enabled(&entity_addr)
1905 && !self
1906 .context
1907 .is_system_addressable_entity(&entity_addr.value())?
1908 {
1909 return Err(ExecError::DisabledEntity(entity_hash));
1910 }
1911
1912 let context_entity_key =
1915 self.get_context_key_for_contract_call(entity_addr, entry_point)?;
1916
1917 let context_entity_hash = context_entity_key
1918 .into_entity_hash_addr()
1919 .ok_or(ExecError::UnexpectedKeyVariant(context_entity_key))?;
1920
1921 let (should_attenuate_urefs, should_validate_urefs) = {
1922 let is_system_account =
1925 self.context.get_initiator() == PublicKey::System.to_account_hash();
1926 let is_caller_system_contract =
1928 self.is_system_contract(self.context.access_rights().context_key())?;
1929 let is_calling_system_contract = self.is_system_contract(context_entity_hash)?;
1931 let should_attenuate_urefs =
1936 !is_system_account && !is_caller_system_contract && !is_calling_system_contract;
1937 let should_validate_urefs = !is_caller_system_contract || !is_calling_system_contract;
1938 (should_attenuate_urefs, should_validate_urefs)
1939 };
1940 let runtime_args = if should_attenuate_urefs {
1941 utils::attenuate_uref_in_args(
1944 args,
1945 self.context
1946 .runtime_footprint()
1947 .borrow()
1948 .main_purse()
1949 .expect("need purse for attenuation")
1950 .addr(),
1951 AccessRights::WRITE,
1952 )?
1953 } else {
1954 args
1955 };
1956
1957 let extended_access_rights = {
1958 let mut all_urefs = vec![];
1959 for arg in runtime_args.to_values() {
1960 let urefs = utils::extract_urefs(arg)?;
1961 if should_validate_urefs {
1962 for uref in &urefs {
1963 self.context.validate_uref(uref)?;
1964 }
1965 }
1966 all_urefs.extend(urefs);
1967 }
1968 all_urefs
1969 };
1970
1971 let (mut named_keys, access_rights) = match entry_point_type {
1972 EntryPointType::Caller => {
1973 let mut access_rights = self
1974 .context
1975 .runtime_footprint()
1976 .borrow()
1977 .extract_access_rights(context_entity_hash);
1978 access_rights.extend(&extended_access_rights);
1979
1980 let named_keys = self
1981 .context
1982 .runtime_footprint()
1983 .borrow()
1984 .named_keys()
1985 .clone();
1986
1987 (named_keys, access_rights)
1988 }
1989 EntryPointType::Called | EntryPointType::Factory => {
1990 let mut access_rights = footprint.extract_access_rights(entity_hash.value());
1991 access_rights.extend(&extended_access_rights);
1992 let named_keys = footprint.named_keys().clone();
1993 (named_keys, access_rights)
1994 }
1995 };
1996
1997 let stack = {
1998 let mut stack = self.try_get_stack()?.clone();
1999
2000 let package_hash = match footprint.package_hash() {
2001 Some(hash) => PackageHash::new(hash),
2002 None => {
2003 return Err(ExecError::UnexpectedStoredValueVariant);
2004 }
2005 };
2006
2007 let caller = if self.context.engine_config().enable_entity {
2008 Caller::entity(package_hash, entity_addr)
2009 } else {
2010 Caller::smart_contract(
2011 ContractPackageHash::new(package_hash.value()),
2012 ContractHash::new(entity_addr.value()),
2013 )
2014 };
2015
2016 stack.push(caller)?;
2017
2018 stack
2019 };
2020
2021 if let EntityKind::System(system_contract_type) = footprint.entity_kind() {
2022 let entry_point_name = entry_point.name();
2023
2024 match system_contract_type {
2025 SystemEntityType::Mint => {
2026 return self.call_host_mint(
2027 entry_point_name,
2028 &runtime_args,
2029 access_rights,
2030 stack,
2031 );
2032 }
2033 SystemEntityType::HandlePayment => {
2034 return self.call_host_handle_payment(
2035 entry_point_name,
2036 &runtime_args,
2037 access_rights,
2038 stack,
2039 );
2040 }
2041 SystemEntityType::Auction => {
2042 return self.call_host_auction(
2043 entry_point_name,
2044 &runtime_args,
2045 access_rights,
2046 stack,
2047 );
2048 }
2049 SystemEntityType::StandardPayment => {}
2051 }
2052 }
2053
2054 let module: Module = {
2055 let byte_code_addr = footprint.wasm_hash().ok_or(ExecError::InvalidContext)?;
2056
2057 let byte_code_key = match footprint.entity_kind() {
2058 EntityKind::System(_) | EntityKind::Account(_) => {
2059 Key::ByteCode(ByteCodeAddr::Empty)
2060 }
2061 EntityKind::SmartContract(ContractRuntimeTag::VmCasperV1) => {
2062 if self.context.engine_config().enable_entity {
2063 Key::ByteCode(ByteCodeAddr::new_wasm_addr(byte_code_addr))
2064 } else {
2065 Key::Hash(byte_code_addr)
2066 }
2067 }
2068 EntityKind::SmartContract(runtime @ ContractRuntimeTag::VmCasperV2) => {
2069 return Err(ExecError::IncompatibleRuntime(runtime));
2070 }
2071 };
2072
2073 let byte_code: ByteCode = match self.context.read_gs(&byte_code_key)? {
2074 Some(StoredValue::ContractWasm(wasm)) => {
2075 ByteCode::new(ByteCodeKind::V1CasperWasm, wasm.take_bytes())
2076 }
2077 Some(StoredValue::ByteCode(byte_code)) => byte_code,
2078 Some(_) => {
2079 return Err(ExecError::InvalidByteCode(ByteCodeHash::new(
2080 byte_code_addr,
2081 )))
2082 }
2083 None => return Err(ExecError::KeyNotFound(byte_code_key)),
2084 };
2085
2086 casper_wasm::deserialize_buffer(byte_code.bytes())?
2087 };
2088
2089 let context = self.context.new_from_self(
2090 context_entity_key,
2091 entry_point.entry_point_type(),
2092 &mut named_keys,
2093 access_rights,
2094 runtime_args,
2095 );
2096
2097 let (instance, memory) = utils::instance_and_memory(
2098 module.clone(),
2099 self.context.protocol_version(),
2100 self.context.engine_config(),
2101 )?;
2102 let runtime = &mut Runtime::new_invocation_runtime(self, context, module, memory, stack);
2103 let result = instance.invoke_export(entry_point.name(), &[], runtime);
2104 self.context.set_gas_counter(runtime.context.gas_counter());
2108 self.context
2109 .set_emit_message_cost(runtime.context.emit_message_cost());
2110 let transfers = self.context.transfers_mut();
2111 runtime.context.transfers().clone_into(transfers);
2112
2113 match result {
2114 Ok(_) => {
2115 if self.context.entry_point_type() == EntryPointType::Caller
2120 && runtime.context.entry_point_type() == EntryPointType::Caller
2121 {
2122 *self.context.named_keys_mut() = runtime.context.named_keys().clone();
2125 }
2126 self.context
2127 .set_remaining_spending_limit(runtime.context.remaining_spending_limit());
2128 Ok(runtime.take_host_buffer().unwrap_or(CLValue::from_t(())?))
2129 }
2130 Err(error) => {
2131 #[cfg(feature = "test-support")]
2132 dump_runtime_stack_info(
2133 instance,
2134 self.context
2135 .engine_config()
2136 .wasm_config()
2137 .v1()
2138 .max_stack_height(),
2139 );
2140 if let Some(host_error) = error.as_host_error() {
2141 let downcasted_error = host_error.downcast_ref::<ExecError>();
2145 return match downcasted_error {
2146 Some(ExecError::Ret(ref ret_urefs)) => {
2147 self.context.access_rights_extend(ret_urefs);
2151 if self.context.entry_point_type() == EntryPointType::Caller
2152 && runtime.context.entry_point_type() == EntryPointType::Caller
2153 {
2154 *self.context.named_keys_mut() =
2157 runtime.context.named_keys().clone();
2158 }
2159 runtime
2162 .take_host_buffer()
2163 .ok_or(ExecError::ExpectedReturnValue)
2164 }
2165 Some(error) => Err(error.clone()),
2166 None => Err(ExecError::Interpreter(host_error.to_string())),
2167 };
2168 }
2169 Err(ExecError::Interpreter(error.into()))
2170 }
2171 }
2172 }
2173
2174 fn call_contract_host_buffer(
2175 &mut self,
2176 contract_hash: AddressableEntityHash,
2177 entry_point_name: &str,
2178 args_bytes: &[u8],
2179 result_size_ptr: u32,
2180 ) -> Result<Result<(), ApiError>, ExecError> {
2181 if let Err(err) = self.check_host_buffer() {
2183 return Ok(Err(err));
2184 }
2185 let args: RuntimeArgs = bytesrepr::deserialize_from_slice(args_bytes)?;
2186
2187 if let Some(payment_purse) = self.context.maybe_payment_purse() {
2188 for named_arg in args.named_args() {
2189 if utils::extract_urefs(named_arg.cl_value())?
2190 .into_iter()
2191 .any(|uref| uref.remove_access_rights() == payment_purse.remove_access_rights())
2192 {
2193 warn!("attempt to call_contract with payment purse");
2194
2195 return Err(Into::into(ExecError::Revert(ApiError::HandlePayment(
2196 handle_payment::Error::AttemptToPersistPaymentPurse as u8,
2197 ))));
2198 }
2199 }
2200 }
2201
2202 let result = self.call_contract(contract_hash, entry_point_name, args)?;
2203 self.manage_call_contract_host_buffer(result_size_ptr, result)
2204 }
2205
2206 fn call_versioned_contract_host_buffer(
2207 &mut self,
2208 contract_package_hash: PackageHash,
2209 contract_version: Option<EntityVersion>,
2210 entry_point_name: String,
2211 args_bytes: &[u8],
2212 result_size_ptr: u32,
2213 ) -> Result<Result<(), ApiError>, ExecError> {
2214 if let Err(err) = self.check_host_buffer() {
2216 return Ok(Err(err));
2217 }
2218 let args: RuntimeArgs = bytesrepr::deserialize_from_slice(args_bytes)?;
2219
2220 if let Some(payment_purse) = self.context.maybe_payment_purse() {
2221 for named_arg in args.named_args() {
2222 if utils::extract_urefs(named_arg.cl_value())?
2223 .into_iter()
2224 .any(|uref| uref.remove_access_rights() == payment_purse.remove_access_rights())
2225 {
2226 warn!("attempt to call_versioned_contract with payment purse");
2227
2228 return Err(Into::into(ExecError::Revert(ApiError::HandlePayment(
2229 handle_payment::Error::AttemptToPersistPaymentPurse as u8,
2230 ))));
2231 }
2232 }
2233 }
2234
2235 let result = self.call_versioned_contract(
2236 contract_package_hash,
2237 contract_version,
2238 entry_point_name,
2239 args,
2240 )?;
2241 self.manage_call_contract_host_buffer(result_size_ptr, result)
2242 }
2243
2244 fn call_package_version_host_buffer(
2245 &mut self,
2246 contract_package_hash: PackageHash,
2247 protocol_version_major: Option<ProtocolVersionMajor>,
2248 contract_version: Option<EntityVersion>,
2249 entry_point_name: String,
2250 args_bytes: &[u8],
2251 result_size_ptr: u32,
2252 ) -> Result<Result<(), ApiError>, ExecError> {
2253 if let Err(err) = self.check_host_buffer() {
2255 return Ok(Err(err));
2256 }
2257 let args: RuntimeArgs = bytesrepr::deserialize_from_slice(args_bytes)?;
2258
2259 if let Some(payment_purse) = self.context.maybe_payment_purse() {
2260 for named_arg in args.named_args() {
2261 if utils::extract_urefs(named_arg.cl_value())?
2262 .into_iter()
2263 .any(|uref| uref.remove_access_rights() == payment_purse.remove_access_rights())
2264 {
2265 warn!("attempt to call_versioned_contract with payment purse");
2266
2267 return Err(Into::into(ExecError::Revert(ApiError::HandlePayment(
2268 handle_payment::Error::AttemptToPersistPaymentPurse as u8,
2269 ))));
2270 }
2271 }
2272 }
2273
2274 let result = self.call_package_version(
2275 contract_package_hash,
2276 protocol_version_major,
2277 contract_version,
2278 entry_point_name,
2279 args,
2280 )?;
2281 self.manage_call_contract_host_buffer(result_size_ptr, result)
2282 }
2283
2284 fn check_host_buffer(&mut self) -> Result<(), ApiError> {
2285 if !self.can_write_to_host_buffer() {
2286 Err(ApiError::HostBufferFull)
2287 } else {
2288 Ok(())
2289 }
2290 }
2291
2292 fn manage_call_contract_host_buffer(
2293 &mut self,
2294 result_size_ptr: u32,
2295 result: CLValue,
2296 ) -> Result<Result<(), ApiError>, ExecError> {
2297 let result_size: u32 = match result.inner_bytes().len().try_into() {
2298 Ok(value) => value,
2299 Err(_) => return Ok(Err(ApiError::OutOfMemory)),
2300 };
2301
2302 if result_size != 0 {
2304 if let Err(error) = self.write_host_buffer(result) {
2305 return Ok(Err(error));
2306 }
2307 }
2308
2309 let result_size_bytes = result_size.to_le_bytes(); if let Err(error) = self
2311 .try_get_memory()?
2312 .set(result_size_ptr, &result_size_bytes)
2313 {
2314 return Err(ExecError::Interpreter(error.into()));
2315 }
2316
2317 Ok(Ok(()))
2318 }
2319
2320 fn load_named_keys(
2321 &mut self,
2322 total_keys_ptr: u32,
2323 result_size_ptr: u32,
2324 ) -> Result<Result<(), ApiError>, Trap> {
2325 if !self.can_write_to_host_buffer() {
2326 return Ok(Err(ApiError::HostBufferFull));
2328 }
2329
2330 let total_keys: u32 = match self.context.named_keys().len().try_into() {
2331 Ok(value) => value,
2332 Err(_) => return Ok(Err(ApiError::OutOfMemory)),
2333 };
2334
2335 let total_keys_bytes = total_keys.to_le_bytes();
2336 if let Err(error) = self
2337 .try_get_memory()?
2338 .set(total_keys_ptr, &total_keys_bytes)
2339 {
2340 return Err(ExecError::Interpreter(error.into()).into());
2341 }
2342
2343 if total_keys == 0 {
2344 return Ok(Ok(()));
2346 }
2347
2348 let named_keys =
2349 CLValue::from_t(self.context.named_keys().clone()).map_err(ExecError::CLValue)?;
2350
2351 let length: u32 = match named_keys.inner_bytes().len().try_into() {
2352 Ok(value) => value,
2353 Err(_) => return Ok(Err(ApiError::BufferTooSmall)),
2354 };
2355
2356 if let Err(error) = self.write_host_buffer(named_keys) {
2357 return Ok(Err(error));
2358 }
2359
2360 let length_bytes = length.to_le_bytes();
2361 if let Err(error) = self.try_get_memory()?.set(result_size_ptr, &length_bytes) {
2362 return Err(ExecError::Interpreter(error.into()).into());
2363 }
2364
2365 Ok(Ok(()))
2366 }
2367
2368 fn create_contract_package(
2369 &mut self,
2370 is_locked: PackageStatus,
2371 ) -> Result<(ContractPackage, URef), ExecError> {
2372 let access_key = self.context.new_unit_uref()?;
2373 let package_status = match is_locked {
2374 PackageStatus::Locked => ContractPackageStatus::Locked,
2375 PackageStatus::Unlocked => ContractPackageStatus::Unlocked,
2376 };
2377
2378 let contract_package = ContractPackage::new(
2379 access_key,
2380 ContractVersions::default(),
2381 DisabledVersions::default(),
2382 Groups::default(),
2383 package_status,
2384 );
2385
2386 Ok((contract_package, access_key))
2387 }
2388
2389 fn create_package(&mut self, is_locked: PackageStatus) -> Result<(Package, URef), ExecError> {
2390 let access_key = self.context.new_unit_uref()?;
2391 let contract_package = Package::new(
2392 EntityVersions::new(),
2393 BTreeSet::new(),
2394 Groups::new(),
2395 is_locked,
2396 );
2397
2398 Ok((contract_package, access_key))
2399 }
2400
2401 fn create_contract_package_at_hash(
2402 &mut self,
2403 lock_status: PackageStatus,
2404 ) -> Result<([u8; 32], [u8; 32]), ExecError> {
2405 let addr = self.context.new_hash_address()?;
2406 let access_key = if self.context.engine_config().enable_entity {
2407 let (package, access_key) = self.create_package(lock_status)?;
2408 self.context
2409 .metered_write_gs_unsafe(Key::SmartContract(addr), package)?;
2410 access_key
2411 } else {
2412 let (package, access_key) = self.create_contract_package(lock_status)?;
2413 self.context
2414 .metered_write_gs_unsafe(Key::Hash(addr), package)?;
2415 access_key
2416 };
2417 Ok((addr, access_key.addr()))
2418 }
2419
2420 fn create_contract_user_group_by_contract_package(
2421 &mut self,
2422 contract_package_hash: PackageHash,
2423 label: String,
2424 num_new_urefs: u32,
2425 mut existing_urefs: BTreeSet<URef>,
2426 output_size_ptr: u32,
2427 ) -> Result<Result<(), ApiError>, ExecError> {
2428 let mut contract_package: ContractPackage = self
2429 .context
2430 .get_validated_contract_package(contract_package_hash.value())?;
2431
2432 let groups = contract_package.groups_mut();
2433 let new_group = Group::new(label);
2434
2435 if groups.contains(&new_group) {
2437 return Ok(Err(addressable_entity::Error::GroupAlreadyExists.into()));
2438 }
2439
2440 if groups.len() >= (addressable_entity::MAX_GROUPS as usize) {
2442 return Ok(Err(addressable_entity::Error::MaxGroupsExceeded.into()));
2443 }
2444
2445 let total_urefs: usize =
2447 groups.total_urefs() + (num_new_urefs as usize) + existing_urefs.len();
2448 if total_urefs > addressable_entity::MAX_TOTAL_UREFS {
2449 let err = addressable_entity::Error::MaxTotalURefsExceeded;
2450 return Ok(Err(ApiError::ContractHeader(err as u8)));
2451 }
2452
2453 let mut new_urefs = Vec::with_capacity(num_new_urefs as usize);
2455 for _ in 0..num_new_urefs {
2456 let u = self.context.new_unit_uref()?;
2457 new_urefs.push(u);
2458 }
2459
2460 for u in new_urefs.iter().cloned() {
2461 existing_urefs.insert(u);
2462 }
2463 groups.insert(new_group, existing_urefs);
2464
2465 if let Err(err) = self.check_host_buffer() {
2467 return Ok(Err(err));
2468 }
2469 let new_urefs_value = CLValue::from_t(new_urefs)?;
2471 let value_size = new_urefs_value.inner_bytes().len();
2472 if let Err(err) = self.write_host_buffer(new_urefs_value) {
2474 return Ok(Err(err));
2475 }
2476 let output_size_bytes = value_size.to_le_bytes(); if let Err(error) = self
2479 .try_get_memory()?
2480 .set(output_size_ptr, &output_size_bytes)
2481 {
2482 return Err(ExecError::Interpreter(error.into()));
2483 }
2484
2485 self.context.metered_write_gs_unsafe(
2487 ContractPackageHash::new(contract_package_hash.value()),
2488 contract_package,
2489 )?;
2490
2491 Ok(Ok(()))
2492 }
2493
2494 fn create_contract_user_group(
2495 &mut self,
2496 contract_package_hash: PackageHash,
2497 label: String,
2498 num_new_urefs: u32,
2499 mut existing_urefs: BTreeSet<URef>,
2500 output_size_ptr: u32,
2501 ) -> Result<Result<(), ApiError>, ExecError> {
2502 if !self.context.engine_config().enable_entity {
2503 return self.create_contract_user_group_by_contract_package(
2504 contract_package_hash,
2505 label,
2506 num_new_urefs,
2507 existing_urefs,
2508 output_size_ptr,
2509 );
2510 };
2511
2512 let mut contract_package: Package =
2513 self.context.get_validated_package(contract_package_hash)?;
2514
2515 let groups = contract_package.groups_mut();
2516 let new_group = Group::new(label);
2517
2518 if groups.contains(&new_group) {
2520 return Ok(Err(addressable_entity::Error::GroupAlreadyExists.into()));
2521 }
2522
2523 if groups.len() >= (addressable_entity::MAX_GROUPS as usize) {
2525 return Ok(Err(addressable_entity::Error::MaxGroupsExceeded.into()));
2526 }
2527
2528 let total_urefs: usize =
2530 groups.total_urefs() + (num_new_urefs as usize) + existing_urefs.len();
2531 if total_urefs > addressable_entity::MAX_TOTAL_UREFS {
2532 let err = addressable_entity::Error::MaxTotalURefsExceeded;
2533 return Ok(Err(ApiError::ContractHeader(err as u8)));
2534 }
2535
2536 let mut new_urefs = Vec::with_capacity(num_new_urefs as usize);
2538 for _ in 0..num_new_urefs {
2539 let u = self.context.new_unit_uref()?;
2540 new_urefs.push(u);
2541 }
2542
2543 for u in new_urefs.iter().cloned() {
2544 existing_urefs.insert(u);
2545 }
2546 groups.insert(new_group, existing_urefs);
2547
2548 if let Err(err) = self.check_host_buffer() {
2550 return Ok(Err(err));
2551 }
2552 let new_urefs_value = CLValue::from_t(new_urefs)?;
2554 let value_size = new_urefs_value.inner_bytes().len();
2555 if let Err(err) = self.write_host_buffer(new_urefs_value) {
2557 return Ok(Err(err));
2558 }
2559 let output_size_bytes = value_size.to_le_bytes(); if let Err(error) = self
2562 .try_get_memory()?
2563 .set(output_size_ptr, &output_size_bytes)
2564 {
2565 return Err(ExecError::Interpreter(error.into()));
2566 }
2567
2568 self.context
2570 .metered_write_gs_unsafe(contract_package_hash, contract_package)?;
2571
2572 Ok(Ok(()))
2573 }
2574
2575 #[allow(clippy::too_many_arguments)]
2576 fn add_contract_version(
2577 &mut self,
2578 package_hash: PackageHash,
2579 version_ptr: u32,
2580 entry_points: EntryPoints,
2581 named_keys: NamedKeys,
2582 message_topics: BTreeMap<String, MessageTopicOperation>,
2583 output_ptr: u32,
2584 ) -> Result<Result<(), ApiError>, ExecError> {
2585 if self.context.engine_config().enable_entity {
2586 self.add_contract_version_by_package(
2587 package_hash,
2588 version_ptr,
2589 entry_points,
2590 named_keys,
2591 message_topics,
2592 output_ptr,
2593 )
2594 } else {
2595 self.add_contract_version_by_contract_package(
2596 package_hash.value(),
2597 version_ptr,
2598 entry_points,
2599 named_keys,
2600 message_topics,
2601 output_ptr,
2602 )
2603 }
2604 }
2605
2606 #[allow(clippy::too_many_arguments)]
2607 fn add_contract_version_by_contract_package(
2608 &mut self,
2609 contract_package_hash: HashAddr,
2610 version_ptr: u32,
2611 entry_points: EntryPoints,
2612 mut named_keys: NamedKeys,
2613 message_topics: BTreeMap<String, MessageTopicOperation>,
2614 output_ptr: u32,
2615 ) -> Result<Result<(), ApiError>, ExecError> {
2616 if !self.context.install_upgrade_allowed() {
2617 return Ok(Err(ApiError::NotAllowedToAddContractVersion));
2621 }
2622
2623 self.context
2631 .validate_key(&Key::Hash(contract_package_hash))?;
2632
2633 let mut contract_package: ContractPackage = self
2634 .context
2635 .get_validated_contract_package(contract_package_hash)?;
2636
2637 let version = contract_package.current_contract_version();
2638
2639 if contract_package.is_locked() && version.is_some() {
2641 return Err(ExecError::LockedEntity(PackageHash::new(
2642 contract_package_hash,
2643 )));
2644 }
2645
2646 for (_, key) in named_keys.iter() {
2647 self.context.validate_key(key)?
2648 }
2649
2650 let contract_wasm_hash = self.context.new_hash_address()?;
2651 let contract_wasm = {
2652 let module_bytes = self.get_module_from_entry_points(&entry_points)?;
2653 ContractWasm::new(module_bytes)
2654 };
2655
2656 let contract_hash_addr: HashAddr = self.context.new_hash_address()?;
2657 let contract_entity_addr = EntityAddr::SmartContract(contract_hash_addr);
2658
2659 let protocol_version = self.context.protocol_version();
2660 let major = protocol_version.value().major;
2661
2662 let maybe_previous_hash =
2663 if let Some(previous_contract_hash) = contract_package.current_contract_hash() {
2664 let previous_contract: Contract =
2665 self.context.read_gs_typed(&previous_contract_hash.into())?;
2666
2667 let previous_named_keys = previous_contract.take_named_keys();
2668 named_keys.append(previous_named_keys);
2669 Some(EntityAddr::SmartContract(previous_contract_hash.value()))
2670 } else {
2671 None
2672 };
2673
2674 if let Err(err) = self.carry_forward_message_topics(
2675 maybe_previous_hash,
2676 contract_entity_addr,
2677 message_topics,
2678 )? {
2679 return Ok(Err(err));
2680 };
2681
2682 let contract_package_hash = ContractPackageHash::new(contract_package_hash);
2683 let contract = Contract::new(
2684 contract_package_hash,
2685 contract_wasm_hash.into(),
2686 named_keys,
2687 entry_points.into(),
2688 protocol_version,
2689 );
2690
2691 let insert_contract_result =
2692 contract_package.insert_contract_version(major, contract_hash_addr.into());
2693
2694 self.context
2695 .metered_write_gs_unsafe(Key::Hash(contract_wasm_hash), contract_wasm)?;
2696 self.context
2697 .metered_write_gs_unsafe(Key::Hash(contract_hash_addr), contract)?;
2698 self.context
2699 .metered_write_gs_unsafe(Key::Hash(contract_package_hash.value()), contract_package)?;
2700
2701 {
2703 let hash_bytes = match contract_hash_addr.to_bytes() {
2704 Ok(bytes) => bytes,
2705 Err(error) => return Ok(Err(error.into())),
2706 };
2707
2708 if let Err(error) = self.try_get_memory()?.set(output_ptr, &hash_bytes) {
2710 return Err(ExecError::Interpreter(error.into()));
2711 }
2712
2713 let version_value: u32 = insert_contract_result.contract_version();
2715 let version_bytes = version_value.to_le_bytes();
2716 if let Err(error) = self.try_get_memory()?.set(version_ptr, &version_bytes) {
2717 return Err(ExecError::Interpreter(error.into()));
2718 }
2719 }
2720
2721 Ok(Ok(()))
2722 }
2723
2724 #[allow(clippy::too_many_arguments)]
2725 fn add_contract_version_by_package(
2726 &mut self,
2727 package_hash: PackageHash,
2728 version_ptr: u32,
2729 entry_points: EntryPoints,
2730 mut named_keys: NamedKeys,
2731 message_topics: BTreeMap<String, MessageTopicOperation>,
2732 output_ptr: u32,
2733 ) -> Result<Result<(), ApiError>, ExecError> {
2734 if !self.context.install_upgrade_allowed() {
2735 return Ok(Err(ApiError::NotAllowedToAddContractVersion));
2739 }
2740
2741 if entry_points.contains_stored_session() {
2742 return Err(ExecError::InvalidEntryPointType);
2746 }
2747
2748 let mut package = self.context.get_package(package_hash.value())?;
2749
2750 if package.is_locked() {
2752 return Err(ExecError::LockedEntity(package_hash));
2753 }
2754
2755 let (
2756 main_purse,
2757 previous_named_keys,
2758 action_thresholds,
2759 associated_keys,
2760 previous_hash_addr,
2761 ) = self.new_version_entity_parts(&package)?;
2762
2763 let byte_code_hash = self.context.new_hash_address()?;
2766
2767 let hash_addr = self.context.new_hash_address()?;
2768 let entity_addr = EntityAddr::SmartContract(hash_addr);
2769
2770 if let Err(err) =
2771 self.carry_forward_message_topics(previous_hash_addr, entity_addr, message_topics)?
2772 {
2773 return Ok(Err(err));
2774 };
2775
2776 let protocol_version = self.context.protocol_version();
2777
2778 let insert_entity_version_result =
2779 package.insert_entity_version(protocol_version.value().major, entity_addr);
2780
2781 let byte_code = {
2782 let module_bytes = self.get_module_from_entry_points(&entry_points)?;
2783 ByteCode::new(ByteCodeKind::V1CasperWasm, module_bytes)
2784 };
2785
2786 self.context.metered_write_gs_unsafe(
2787 Key::ByteCode(ByteCodeAddr::new_wasm_addr(byte_code_hash)),
2788 byte_code,
2789 )?;
2790
2791 let entity_addr = EntityAddr::new_smart_contract(hash_addr);
2792
2793 {
2794 for (_, key) in named_keys.iter() {
2796 self.context.validate_key(key)?;
2799 }
2800 named_keys.append(previous_named_keys);
2803 for (name, key) in named_keys.iter() {
2804 let named_key_value =
2805 StoredValue::NamedKey(NamedKeyValue::from_concrete_values(*key, name.clone())?);
2806 let named_key_addr = NamedKeyAddr::new_from_string(entity_addr, name.clone())?;
2807 self.context
2808 .metered_write_gs_unsafe(Key::NamedKey(named_key_addr), named_key_value)?;
2809 }
2810 self.context.write_entry_points(entity_addr, entry_points)?;
2811 }
2812
2813 let entity = AddressableEntity::new(
2814 package_hash,
2815 byte_code_hash.into(),
2816 protocol_version,
2817 main_purse,
2818 associated_keys,
2819 action_thresholds,
2820 EntityKind::SmartContract(ContractRuntimeTag::VmCasperV1),
2821 );
2822 let entity_key = Key::AddressableEntity(entity_addr);
2823 self.context.metered_write_gs_unsafe(entity_key, entity)?;
2824 self.context
2825 .metered_write_gs_unsafe(package_hash, package)?;
2826
2827 {
2829 let hash_bytes = match hash_addr.to_bytes() {
2830 Ok(bytes) => bytes,
2831 Err(error) => return Ok(Err(error.into())),
2832 };
2833
2834 if let Err(error) = self.try_get_memory()?.set(output_ptr, &hash_bytes) {
2836 return Err(ExecError::Interpreter(error.into()));
2837 }
2838
2839 let version_value: u32 = insert_entity_version_result.entity_version();
2841 let version_bytes = version_value.to_le_bytes();
2842 if let Err(error) = self.try_get_memory()?.set(version_ptr, &version_bytes) {
2843 return Err(ExecError::Interpreter(error.into()));
2844 }
2845 }
2846
2847 Ok(Ok(()))
2848 }
2849
2850 fn carry_forward_message_topics(
2851 &mut self,
2852 previous_entity_addr: Option<EntityAddr>,
2853 entity_addr: EntityAddr,
2854 message_topics: BTreeMap<String, MessageTopicOperation>,
2855 ) -> Result<Result<(), ApiError>, ExecError> {
2856 let mut previous_message_topics = match previous_entity_addr {
2857 Some(previous_hash) => self.context.get_message_topics(previous_hash)?,
2858 None => MessageTopics::default(),
2859 };
2860
2861 let max_topics_per_contract = self
2862 .context
2863 .engine_config()
2864 .wasm_config()
2865 .messages_limits()
2866 .max_topics_per_contract();
2867
2868 let topics_to_add = message_topics
2869 .iter()
2870 .filter(|(_, operation)| match operation {
2871 MessageTopicOperation::Add => true,
2872 });
2873 if previous_message_topics.len() + topics_to_add.clone().count()
2875 > max_topics_per_contract as usize
2876 {
2877 return Ok(Err(ApiError::from(MessageTopicError::MaxTopicsExceeded)));
2878 }
2879
2880 for (new_topic, _) in topics_to_add {
2882 let topic_name_hash = cryptography::blake2b(new_topic.as_bytes()).into();
2883 if let Err(e) = previous_message_topics.add_topic(new_topic.as_str(), topic_name_hash) {
2884 return Ok(Err(e.into()));
2885 }
2886 }
2887
2888 for (topic_name, topic_hash) in previous_message_topics.iter() {
2889 let topic_key = Key::message_topic(entity_addr, *topic_hash);
2890 let block_time = self.context.get_block_info().block_time();
2891 let summary = StoredValue::MessageTopic(MessageTopicSummary::new(
2892 0,
2893 block_time,
2894 topic_name.clone(),
2895 ));
2896 self.context.metered_write_gs_unsafe(topic_key, summary)?;
2897 }
2898 Ok(Ok(()))
2899 }
2900
2901 fn new_version_entity_parts(
2902 &mut self,
2903 package: &Package,
2904 ) -> Result<
2905 (
2906 URef,
2907 NamedKeys,
2908 ActionThresholds,
2909 AssociatedKeys,
2910 Option<EntityAddr>,
2911 ),
2912 ExecError,
2913 > {
2914 if let Some(previous_entity_hash) = package.current_entity_hash() {
2915 let previous_entity_key = Key::AddressableEntity(previous_entity_hash);
2916 let (mut previous_entity, requires_purse_creation) =
2917 self.context.get_contract_entity(previous_entity_key)?;
2918
2919 let action_thresholds = previous_entity.action_thresholds().clone();
2920
2921 let associated_keys = previous_entity.associated_keys().clone();
2922 if !previous_entity.can_upgrade_with(self.context.authorization_keys()) {
2933 let account_hash = self.context.get_initiator();
2936
2937 let access_key = match self
2938 .context
2939 .read_gs(&Key::Hash(previous_entity.package_hash().value()))?
2940 {
2941 Some(StoredValue::ContractPackage(contract_package)) => {
2942 contract_package.access_key()
2943 }
2944 Some(StoredValue::CLValue(cl_value)) => {
2945 let (_key, uref) = cl_value
2946 .into_t::<(Key, URef)>()
2947 .map_err(ExecError::CLValue)?;
2948 uref
2949 }
2950 Some(_other) => return Err(ExecError::UnexpectedStoredValueVariant),
2951 None => {
2952 return Err(ExecError::UpgradeAuthorizationFailure);
2953 }
2954 };
2955
2956 let has_access = self.context.validate_uref(&access_key).is_ok();
2957
2958 if has_access && !associated_keys.contains_key(&account_hash) {
2959 previous_entity.add_associated_key(
2960 account_hash,
2961 *action_thresholds.upgrade_management(),
2962 )?;
2963 } else {
2964 return Err(ExecError::UpgradeAuthorizationFailure);
2965 }
2966 }
2967
2968 let main_purse = if requires_purse_creation {
2969 self.create_purse()?
2970 } else {
2971 previous_entity.main_purse()
2972 };
2973
2974 let associated_keys = previous_entity.associated_keys().clone();
2975
2976 let previous_named_keys = self.context.get_named_keys(previous_entity_key)?;
2977
2978 return Ok((
2979 main_purse,
2980 previous_named_keys,
2981 action_thresholds,
2982 associated_keys,
2983 Some(previous_entity_hash),
2984 ));
2985 }
2986
2987 Ok((
2988 self.create_purse()?,
2989 NamedKeys::new(),
2990 ActionThresholds::default(),
2991 AssociatedKeys::new(self.context.get_initiator(), Weight::new(1)),
2992 None,
2993 ))
2994 }
2995
2996 fn disable_contract_version(
2997 &mut self,
2998 contract_package_hash: PackageHash,
2999 contract_hash: AddressableEntityHash,
3000 ) -> Result<Result<(), ApiError>, ExecError> {
3001 if self.context.engine_config().enable_entity {
3002 let contract_package_key = Key::SmartContract(contract_package_hash.value());
3003 self.context.validate_key(&contract_package_key)?;
3004
3005 let mut contract_package: Package =
3006 self.context.get_validated_package(contract_package_hash)?;
3007
3008 if contract_package.is_locked() {
3009 return Err(ExecError::LockedEntity(contract_package_hash));
3010 }
3011
3012 if let Err(err) = contract_package
3013 .disable_entity_version(EntityAddr::SmartContract(contract_hash.value()))
3014 {
3015 return Ok(Err(err.into()));
3016 }
3017
3018 self.context
3019 .metered_write_gs_unsafe(contract_package_key, contract_package)?;
3020 } else {
3021 let contract_package_key = Key::Hash(contract_package_hash.value());
3022 self.context.validate_key(&contract_package_key)?;
3023
3024 let mut contract_package: ContractPackage = self
3025 .context
3026 .get_validated_contract_package(contract_package_hash.value())?;
3027
3028 if contract_package.is_locked() {
3029 return Err(ExecError::LockedEntity(PackageHash::new(
3030 contract_package_hash.value(),
3031 )));
3032 }
3033 let contract_hash = ContractHash::new(contract_hash.value());
3034
3035 if let Err(err) = contract_package.disable_contract_version(contract_hash) {
3036 return Ok(Err(err.into()));
3037 }
3038
3039 self.context
3040 .metered_write_gs_unsafe(contract_package_key, contract_package)?;
3041 }
3042
3043 Ok(Ok(()))
3044 }
3045
3046 fn enable_contract_version(
3047 &mut self,
3048 contract_package_hash: PackageHash,
3049 contract_hash: AddressableEntityHash,
3050 ) -> Result<Result<(), ApiError>, ExecError> {
3051 if self.context.engine_config().enable_entity {
3052 let contract_package_key = Key::SmartContract(contract_package_hash.value());
3053 self.context.validate_key(&contract_package_key)?;
3054
3055 let mut contract_package: Package =
3056 self.context.get_validated_package(contract_package_hash)?;
3057
3058 if contract_package.is_locked() {
3059 return Err(ExecError::LockedEntity(contract_package_hash));
3060 }
3061
3062 if let Err(err) =
3063 contract_package.enable_version(EntityAddr::SmartContract(contract_hash.value()))
3064 {
3065 return Ok(Err(err.into()));
3066 }
3067
3068 self.context
3069 .metered_write_gs_unsafe(contract_package_key, contract_package)?;
3070 } else {
3071 let contract_package_key = Key::Hash(contract_package_hash.value());
3072 self.context.validate_key(&contract_package_key)?;
3073
3074 let mut contract_package: ContractPackage = self
3075 .context
3076 .get_validated_contract_package(contract_package_hash.value())?;
3077
3078 if contract_package.is_locked() {
3079 return Err(ExecError::LockedEntity(PackageHash::new(
3080 contract_package_hash.value(),
3081 )));
3082 }
3083 let contract_hash = ContractHash::new(contract_hash.value());
3084
3085 if let Err(err) = contract_package.enable_contract_version(contract_hash) {
3086 return Ok(Err(err.into()));
3087 }
3088
3089 self.context
3090 .metered_write_gs_unsafe(contract_package_key, contract_package)?;
3091 }
3092
3093 Ok(Ok(()))
3094 }
3095
3096 fn function_address(&mut self, hash_bytes: [u8; 32], dest_ptr: u32) -> Result<(), Trap> {
3099 self.try_get_memory()?
3100 .set(dest_ptr, &hash_bytes)
3101 .map_err(|e| ExecError::Interpreter(e.into()).into())
3102 }
3103
3104 fn new_uref(&mut self, uref_ptr: u32, value_ptr: u32, value_size: u32) -> Result<(), Trap> {
3107 let cl_value = self.cl_value_from_mem(value_ptr, value_size)?; let uref = self.context.new_uref(StoredValue::CLValue(cl_value))?;
3109 self.try_get_memory()?
3110 .set(uref_ptr, &uref.into_bytes().map_err(ExecError::BytesRepr)?)
3111 .map_err(|e| ExecError::Interpreter(e.into()).into())
3112 }
3113
3114 fn write(
3116 &mut self,
3117 key_ptr: u32,
3118 key_size: u32,
3119 value_ptr: u32,
3120 value_size: u32,
3121 ) -> Result<(), Trap> {
3122 let key = self.key_from_mem(key_ptr, key_size)?;
3123 let cl_value = self.cl_value_from_mem(value_ptr, value_size)?;
3124 self.context
3125 .metered_write_gs(key, cl_value)
3126 .map_err(Into::into)
3127 }
3128
3129 fn record_transfer(
3131 &mut self,
3132 maybe_to: Option<AccountHash>,
3133 source: URef,
3134 target: URef,
3135 amount: U512,
3136 id: Option<u64>,
3137 ) -> Result<(), ExecError> {
3138 if self.context.get_context_key() != self.context.get_system_entity_key(MINT)? {
3139 return Err(ExecError::InvalidContext);
3140 }
3141
3142 if self.context.phase() != Phase::Session {
3143 return Ok(());
3144 }
3145
3146 let txn_hash = self.context.get_transaction_hash();
3147 let from = InitiatorAddr::AccountHash(self.context.get_initiator());
3148 let fee = Gas::from(
3149 self.context
3150 .engine_config()
3151 .system_config()
3152 .mint_costs()
3153 .transfer,
3154 );
3155 let transfer = Transfer::V2(TransferV2::new(
3156 txn_hash, from, maybe_to, source, target, amount, fee, id,
3157 ));
3158 self.context.transfers_mut().push(transfer);
3159 Ok(())
3160 }
3161
3162 fn record_era_info(&mut self, era_info: EraInfo) -> Result<(), ExecError> {
3164 if self.context.get_initiator() != PublicKey::System.to_account_hash() {
3165 return Err(ExecError::InvalidContext);
3166 }
3167
3168 if self.context.get_context_key() != self.context.get_system_entity_key(AUCTION)? {
3169 return Err(ExecError::InvalidContext);
3170 }
3171
3172 if self.context.phase() != Phase::Session {
3173 return Ok(());
3174 }
3175
3176 self.context.write_era_info(Key::EraSummary, era_info);
3177
3178 Ok(())
3179 }
3180
3181 fn add(
3183 &mut self,
3184 key_ptr: u32,
3185 key_size: u32,
3186 value_ptr: u32,
3187 value_size: u32,
3188 ) -> Result<(), Trap> {
3189 let key = self.key_from_mem(key_ptr, key_size)?;
3190 let cl_value = self.cl_value_from_mem(value_ptr, value_size)?;
3191 self.context
3192 .metered_add_gs(key, cl_value)
3193 .map_err(Into::into)
3194 }
3195
3196 fn read(
3202 &mut self,
3203 key_ptr: u32,
3204 key_size: u32,
3205 output_size_ptr: u32,
3206 ) -> Result<Result<(), ApiError>, Trap> {
3207 if !self.can_write_to_host_buffer() {
3208 return Ok(Err(ApiError::HostBufferFull));
3210 }
3211
3212 let key = self.key_from_mem(key_ptr, key_size)?;
3213 let cl_value = match self.context.read_gs(&key)? {
3214 Some(stored_value) => {
3215 CLValue::try_from(stored_value).map_err(ExecError::TypeMismatch)?
3216 }
3217 None => return Ok(Err(ApiError::ValueNotFound)),
3218 };
3219
3220 let value_size: u32 = match cl_value.inner_bytes().len().try_into() {
3221 Ok(value) => value,
3222 Err(_) => return Ok(Err(ApiError::BufferTooSmall)),
3223 };
3224
3225 if let Err(error) = self.write_host_buffer(cl_value) {
3226 return Ok(Err(error));
3227 }
3228
3229 let value_bytes = value_size.to_le_bytes(); if let Err(error) = self.try_get_memory()?.set(output_size_ptr, &value_bytes) {
3231 return Err(ExecError::Interpreter(error.into()).into());
3232 }
3233
3234 Ok(Ok(()))
3235 }
3236
3237 fn revert(&mut self, status: u32) -> Trap {
3239 ExecError::Revert(status.into()).into()
3240 }
3241
3242 fn can_manage_keys(&self) -> bool {
3248 if self
3249 .context
3250 .engine_config()
3251 .administrative_accounts()
3252 .is_empty()
3253 {
3254 return self
3256 .context
3257 .runtime_footprint()
3258 .borrow()
3259 .can_manage_keys_with(self.context.authorization_keys());
3260 }
3261
3262 if self
3263 .context
3264 .engine_config()
3265 .is_administrator(&self.context.get_initiator())
3266 {
3267 return true;
3268 }
3269
3270 self.context.is_authorized_by_admin()
3272 }
3273
3274 fn add_associated_key(
3275 &mut self,
3276 account_hash_ptr: u32,
3277 account_hash_size: usize,
3278 weight_value: u8,
3279 ) -> Result<i32, Trap> {
3280 let account_hash = {
3281 let source_serialized = self.bytes_from_mem(account_hash_ptr, account_hash_size)?;
3283 let source: AccountHash = bytesrepr::deserialize_from_slice(source_serialized)
3285 .map_err(ExecError::BytesRepr)?;
3286 source
3287 };
3288 let weight = Weight::new(weight_value);
3289
3290 if !self.can_manage_keys() {
3291 return Ok(AddKeyFailure::PermissionDenied as i32);
3292 }
3293
3294 match self.context.add_associated_key(account_hash, weight) {
3295 Ok(_) => Ok(0),
3296 Err(ExecError::AddKeyFailure(e)) => Ok(e as i32),
3301 Err(e) => Err(e.into()),
3303 }
3304 }
3305
3306 fn remove_associated_key(
3307 &mut self,
3308 account_hash_ptr: u32,
3309 account_hash_size: usize,
3310 ) -> Result<i32, Trap> {
3311 let account_hash = {
3312 let source_serialized = self.bytes_from_mem(account_hash_ptr, account_hash_size)?;
3314 let source: AccountHash = bytesrepr::deserialize_from_slice(source_serialized)
3316 .map_err(ExecError::BytesRepr)?;
3317 source
3318 };
3319
3320 if !self.can_manage_keys() {
3321 return Ok(RemoveKeyFailure::PermissionDenied as i32);
3322 }
3323
3324 match self.context.remove_associated_key(account_hash) {
3325 Ok(_) => Ok(0),
3326 Err(ExecError::RemoveKeyFailure(e)) => Ok(e as i32),
3327 Err(e) => Err(e.into()),
3328 }
3329 }
3330
3331 fn update_associated_key(
3332 &mut self,
3333 account_hash_ptr: u32,
3334 account_hash_size: usize,
3335 weight_value: u8,
3336 ) -> Result<i32, Trap> {
3337 let account_hash = {
3338 let source_serialized = self.bytes_from_mem(account_hash_ptr, account_hash_size)?;
3340 let source: AccountHash = bytesrepr::deserialize_from_slice(source_serialized)
3342 .map_err(ExecError::BytesRepr)?;
3343 source
3344 };
3345 let weight = Weight::new(weight_value);
3346
3347 if !self.can_manage_keys() {
3348 return Ok(UpdateKeyFailure::PermissionDenied as i32);
3349 }
3350
3351 match self.context.update_associated_key(account_hash, weight) {
3352 Ok(_) => Ok(0),
3353 Err(ExecError::UpdateKeyFailure(e)) => Ok(e as i32),
3358 Err(e) => Err(e.into()),
3360 }
3361 }
3362
3363 fn set_action_threshold(
3364 &mut self,
3365 action_type_value: u32,
3366 threshold_value: u8,
3367 ) -> Result<i32, Trap> {
3368 if !self.can_manage_keys() {
3369 return Ok(SetThresholdFailure::PermissionDeniedError as i32);
3370 }
3371
3372 match ActionType::try_from(action_type_value) {
3373 Ok(action_type) => {
3374 let threshold = Weight::new(threshold_value);
3375 match self.context.set_action_threshold(action_type, threshold) {
3376 Ok(_) => Ok(0),
3377 Err(ExecError::SetThresholdFailure(e)) => Ok(e as i32),
3378 Err(error) => Err(error.into()),
3379 }
3380 }
3381 Err(_) => Err(Trap::Code(TrapCode::Unreachable)),
3382 }
3383 }
3384
3385 fn get_mint_hash(&self) -> Result<AddressableEntityHash, ExecError> {
3389 self.context.get_system_contract(MINT)
3390 }
3391
3392 fn get_handle_payment_hash(&self) -> Result<AddressableEntityHash, ExecError> {
3396 self.context.get_system_contract(HANDLE_PAYMENT)
3397 }
3398
3399 fn get_standard_payment_hash(&self) -> Result<AddressableEntityHash, ExecError> {
3403 self.context.get_system_contract(STANDARD_PAYMENT)
3404 }
3405
3406 fn get_auction_hash(&self) -> Result<AddressableEntityHash, ExecError> {
3410 self.context.get_system_contract(AUCTION)
3411 }
3412
3413 fn mint_read_base_round_reward(
3416 &mut self,
3417 mint_contract_hash: AddressableEntityHash,
3418 ) -> Result<U512, ExecError> {
3419 let gas_counter = self.gas_counter();
3420 let call_result = self.call_contract(
3421 mint_contract_hash,
3422 mint::METHOD_READ_BASE_ROUND_REWARD,
3423 RuntimeArgs::default(),
3424 );
3425 self.set_gas_counter(gas_counter);
3426
3427 let reward = call_result?.into_t()?;
3428 Ok(reward)
3429 }
3430
3431 fn mint_mint(
3434 &mut self,
3435 mint_contract_hash: AddressableEntityHash,
3436 amount: U512,
3437 ) -> Result<URef, ExecError> {
3438 let gas_counter = self.gas_counter();
3439 let runtime_args = {
3440 let mut runtime_args = RuntimeArgs::new();
3441 runtime_args.insert(mint::ARG_AMOUNT, amount)?;
3442 runtime_args
3443 };
3444 let call_result = self.call_contract(mint_contract_hash, mint::METHOD_MINT, runtime_args);
3445 self.set_gas_counter(gas_counter);
3446
3447 let result: Result<URef, mint::Error> = call_result?.into_t()?;
3448 Ok(result.map_err(system::Error::from)?)
3449 }
3450
3451 fn mint_reduce_total_supply(
3454 &mut self,
3455 mint_contract_hash: AddressableEntityHash,
3456 amount: U512,
3457 ) -> Result<(), ExecError> {
3458 let gas_counter = self.gas_counter();
3459 let runtime_args = {
3460 let mut runtime_args = RuntimeArgs::new();
3461 runtime_args.insert(mint::ARG_AMOUNT, amount)?;
3462 runtime_args
3463 };
3464 let call_result = self.call_contract(
3465 mint_contract_hash,
3466 mint::METHOD_REDUCE_TOTAL_SUPPLY,
3467 runtime_args,
3468 );
3469 self.set_gas_counter(gas_counter);
3470
3471 let result: Result<(), mint::Error> = call_result?.into_t()?;
3472 Ok(result.map_err(system::Error::from)?)
3473 }
3474
3475 fn mint_create(
3478 &mut self,
3479 mint_contract_hash: AddressableEntityHash,
3480 ) -> Result<URef, ExecError> {
3481 let result =
3482 self.call_contract(mint_contract_hash, mint::METHOD_CREATE, RuntimeArgs::new());
3483 let purse = result?.into_t()?;
3484 Ok(purse)
3485 }
3486
3487 fn create_purse(&mut self) -> Result<URef, ExecError> {
3488 let _scoped_host_function_flag = self.host_function_flag.enter_host_function_scope();
3489 self.mint_create(self.get_mint_hash()?)
3490 }
3491
3492 fn mint_transfer(
3495 &mut self,
3496 mint_contract_hash: AddressableEntityHash,
3497 to: Option<AccountHash>,
3498 source: URef,
3499 target: URef,
3500 amount: U512,
3501 id: Option<u64>,
3502 ) -> Result<Result<(), mint::Error>, ExecError> {
3503 self.context.validate_uref(&source)?;
3504
3505 let args_values = {
3506 let mut runtime_args = RuntimeArgs::new();
3507 runtime_args.insert(mint::ARG_TO, to)?;
3508 runtime_args.insert(mint::ARG_SOURCE, source)?;
3509 runtime_args.insert(mint::ARG_TARGET, target)?;
3510 runtime_args.insert(mint::ARG_AMOUNT, amount)?;
3511 runtime_args.insert(mint::ARG_ID, id)?;
3512 runtime_args
3513 };
3514
3515 let gas_counter = self.gas_counter();
3516 let call_result =
3517 self.call_contract(mint_contract_hash, mint::METHOD_TRANSFER, args_values);
3518 self.set_gas_counter(gas_counter);
3519
3520 Ok(call_result?.into_t()?)
3521 }
3522
3523 fn transfer_to_new_account(
3526 &mut self,
3527 source: URef,
3528 target: AccountHash,
3529 amount: U512,
3530 id: Option<u64>,
3531 ) -> Result<TransferResult, ExecError> {
3532 let mint_contract_hash = self.get_mint_hash()?;
3533
3534 let allow_unrestricted_transfers =
3535 self.context.engine_config().allow_unrestricted_transfers();
3536
3537 if !allow_unrestricted_transfers
3538 && self.context.get_initiator() != PublicKey::System.to_account_hash()
3539 && !self
3540 .context
3541 .engine_config()
3542 .is_administrator(&self.context.get_initiator())
3543 && !self.context.engine_config().is_administrator(&target)
3544 {
3545 return Err(ExecError::DisabledUnrestrictedTransfers);
3546 }
3547
3548 if amount > self.available_balance(source)?.unwrap_or_default() {
3551 return Ok(Err(mint::Error::InsufficientFunds.into()));
3552 }
3553
3554 let target_purse = self.mint_create(mint_contract_hash)?;
3555
3556 if source == target_purse {
3557 return Ok(Err(mint::Error::EqualSourceAndTarget.into()));
3558 }
3559
3560 let result = self.mint_transfer(
3561 mint_contract_hash,
3562 Some(target),
3563 source,
3564 target_purse.with_access_rights(AccessRights::ADD),
3565 amount,
3566 id,
3567 );
3568
3569 self.context
3573 .remove_access(target_purse.addr(), target_purse.access_rights());
3574
3575 match result? {
3576 Ok(()) => {
3577 let main_purse = target_purse;
3578 if !self.context.engine_config().enable_entity {
3579 let account = Account::create(target, NamedKeys::new(), target_purse);
3580 self.context.metered_write_gs_unsafe(
3581 Key::Account(target),
3582 StoredValue::Account(account),
3583 )?;
3584 return Ok(Ok(TransferredTo::NewAccount));
3585 }
3586
3587 let protocol_version = self.context.protocol_version();
3588 let byte_code_hash = ByteCodeHash::default();
3589 let entity_hash = AddressableEntityHash::new(target.value());
3590 let package_hash = PackageHash::new(self.context.new_hash_address()?);
3591
3592 let associated_keys = AssociatedKeys::new(target, Weight::new(1));
3593
3594 let entity = AddressableEntity::new(
3595 package_hash,
3596 byte_code_hash,
3597 protocol_version,
3598 main_purse,
3599 associated_keys,
3600 ActionThresholds::default(),
3601 EntityKind::Account(target),
3602 );
3603
3604 let package = {
3605 let mut package = Package::new(
3606 EntityVersions::default(),
3607 BTreeSet::default(),
3608 Groups::default(),
3609 PackageStatus::Locked,
3610 );
3611 package.insert_entity_version(
3612 protocol_version.value().major,
3613 EntityAddr::Account(target.value()),
3614 );
3615 package
3616 };
3617
3618 let entity_key: Key = entity.entity_key(entity_hash);
3619
3620 self.context
3621 .metered_write_gs_unsafe(entity_key, StoredValue::AddressableEntity(entity))?;
3622
3623 let contract_package_key: Key = package_hash.into();
3624
3625 self.context.metered_write_gs_unsafe(
3626 contract_package_key,
3627 StoredValue::SmartContract(package),
3628 )?;
3629
3630 let contract_by_account = CLValue::from_t(entity_key)?;
3631
3632 let target_key = Key::Account(target);
3633
3634 self.context.metered_write_gs_unsafe(
3635 target_key,
3636 StoredValue::CLValue(contract_by_account),
3637 )?;
3638
3639 Ok(Ok(TransferredTo::NewAccount))
3640 }
3641 Err(mint_error) => Ok(Err(mint_error.into())),
3642 }
3643 }
3644
3645 fn transfer_to_existing_account(
3649 &mut self,
3650 to: Option<AccountHash>,
3651 source: URef,
3652 target: URef,
3653 amount: U512,
3654 id: Option<u64>,
3655 ) -> Result<TransferResult, ExecError> {
3656 let mint_contract_key = self.get_mint_hash()?;
3657
3658 match self.mint_transfer(mint_contract_key, to, source, target, amount, id)? {
3659 Ok(()) => Ok(Ok(TransferredTo::ExistingAccount)),
3660 Err(error) => Ok(Err(error.into())),
3661 }
3662 }
3663
3664 fn transfer_to_account(
3667 &mut self,
3668 target: AccountHash,
3669 amount: U512,
3670 id: Option<u64>,
3671 ) -> Result<TransferResult, ExecError> {
3672 let source = self.context.get_main_purse()?;
3673 self.transfer_from_purse_to_account_hash(source, target, amount, id)
3674 }
3675
3676 fn transfer_from_purse_to_account_hash(
3679 &mut self,
3680 source: URef,
3681 target: AccountHash,
3682 amount: U512,
3683 id: Option<u64>,
3684 ) -> Result<TransferResult, ExecError> {
3685 let _scoped_host_function_flag = self.host_function_flag.enter_host_function_scope();
3686 let target_key = Key::Account(target);
3687
3688 match self.context.read_gs(&target_key)? {
3690 None => {
3691 self.transfer_to_new_account(source, target, amount, id)
3695 }
3696 Some(StoredValue::CLValue(entity_key_value)) => {
3697 let entity_key = CLValue::into_t::<Key>(entity_key_value)?;
3699 let target_uref = if let Some(StoredValue::AddressableEntity(entity)) =
3700 self.context.read_gs(&entity_key)?
3701 {
3702 entity.main_purse_add_only()
3703 } else {
3704 let contract_hash = if let Some(entity_hash) = entity_key
3705 .into_entity_hash_addr()
3706 .map(AddressableEntityHash::new)
3707 {
3708 entity_hash
3709 } else {
3710 return Err(ExecError::UnexpectedKeyVariant(entity_key));
3711 };
3712 return Err(ExecError::InvalidEntity(contract_hash));
3713 };
3714
3715 if source.with_access_rights(AccessRights::ADD) == target_uref {
3716 return Ok(Ok(TransferredTo::ExistingAccount));
3717 }
3718
3719 let granted_access = self.context.grant_access(target_uref);
3722
3723 let transfer_result = self.transfer_to_existing_account(
3725 Some(target),
3726 source,
3727 target_uref,
3728 amount,
3729 id,
3730 );
3731
3732 if let GrantedAccess::Granted {
3734 uref_addr,
3735 newly_granted_access_rights,
3736 } = granted_access
3737 {
3738 self.context
3739 .remove_access(uref_addr, newly_granted_access_rights)
3740 }
3741 transfer_result
3742 }
3743 Some(StoredValue::Account(account)) => {
3744 self.transfer_from_purse_to_account(source, &account, amount, id)
3745 }
3746 Some(_) => {
3747 Err(ExecError::AccountNotFound(target_key))
3749 }
3750 }
3751 }
3752
3753 fn transfer_from_purse_to_account(
3754 &mut self,
3755 source: URef,
3756 target_account: &Account,
3757 amount: U512,
3758 id: Option<u64>,
3759 ) -> Result<TransferResult, ExecError> {
3760 let target_uref = target_account.main_purse_add_only();
3762
3763 if source.with_access_rights(AccessRights::ADD) == target_uref {
3764 return Ok(Ok(TransferredTo::ExistingAccount));
3765 }
3766
3767 let granted_access = self.context.grant_access(target_uref);
3770
3771 let transfer_result = self.transfer_to_existing_account(
3773 Some(target_account.account_hash()),
3774 source,
3775 target_uref,
3776 amount,
3777 id,
3778 );
3779
3780 if let GrantedAccess::Granted {
3782 uref_addr,
3783 newly_granted_access_rights,
3784 } = granted_access
3785 {
3786 self.context
3787 .remove_access(uref_addr, newly_granted_access_rights)
3788 }
3789 transfer_result
3790 }
3791
3792 fn transfer_from_purse_to_purse(
3794 &mut self,
3795 source: URef,
3796 target: URef,
3797 amount: U512,
3798 id: Option<u64>,
3799 ) -> Result<Result<(), mint::Error>, ExecError> {
3800 self.context.validate_uref(&source)?;
3801 let mint_contract_key = self.get_mint_hash()?;
3802 match self.mint_transfer(mint_contract_key, None, source, target, amount, id)? {
3803 Ok(()) => Ok(Ok(())),
3804 Err(mint_error) => Ok(Err(mint_error)),
3805 }
3806 }
3807
3808 fn total_balance(&mut self, purse: URef) -> Result<U512, ExecError> {
3809 match self.context.total_balance(&purse) {
3810 Ok(motes) => Ok(motes.value()),
3811 Err(err) => Err(err),
3812 }
3813 }
3814
3815 fn available_balance(&mut self, purse: URef) -> Result<Option<U512>, ExecError> {
3816 match self.context.available_balance(&purse) {
3817 Ok(motes) => Ok(Some(motes.value())),
3818 Err(err) => Err(err),
3819 }
3820 }
3821
3822 fn get_balance_host_buffer(
3823 &mut self,
3824 purse_ptr: u32,
3825 purse_size: usize,
3826 output_size_ptr: u32,
3827 ) -> Result<Result<(), ApiError>, ExecError> {
3828 if !self.can_write_to_host_buffer() {
3829 return Ok(Err(ApiError::HostBufferFull));
3831 }
3832
3833 let purse: URef = {
3834 let bytes = self.bytes_from_mem(purse_ptr, purse_size)?;
3835 match bytesrepr::deserialize_from_slice(bytes) {
3836 Ok(purse) => purse,
3837 Err(error) => return Ok(Err(error.into())),
3838 }
3839 };
3840
3841 let balance = match self.available_balance(purse)? {
3842 Some(balance) => balance,
3843 None => return Ok(Err(ApiError::InvalidPurse)),
3844 };
3845
3846 let balance_cl_value = match CLValue::from_t(balance) {
3847 Ok(cl_value) => cl_value,
3848 Err(error) => return Ok(Err(error.into())),
3849 };
3850
3851 let balance_size = balance_cl_value.inner_bytes().len() as i32;
3852 if let Err(error) = self.write_host_buffer(balance_cl_value) {
3853 return Ok(Err(error));
3854 }
3855
3856 let balance_size_bytes = balance_size.to_le_bytes(); if let Err(error) = self
3858 .try_get_memory()?
3859 .set(output_size_ptr, &balance_size_bytes)
3860 {
3861 return Err(ExecError::Interpreter(error.into()));
3862 }
3863
3864 Ok(Ok(()))
3865 }
3866
3867 fn get_system_contract(
3868 &mut self,
3869 system_contract_index: u32,
3870 dest_ptr: u32,
3871 _dest_size: u32,
3872 ) -> Result<Result<(), ApiError>, Trap> {
3873 let hash: AddressableEntityHash = match SystemEntityType::try_from(system_contract_index) {
3874 Ok(SystemEntityType::Mint) => self.get_mint_hash()?,
3875 Ok(SystemEntityType::HandlePayment) => self.get_handle_payment_hash()?,
3876 Ok(SystemEntityType::StandardPayment) => self.get_standard_payment_hash()?,
3877 Ok(SystemEntityType::Auction) => self.get_auction_hash()?,
3878 Err(error) => return Ok(Err(error)),
3879 };
3880
3881 match self.try_get_memory()?.set(dest_ptr, hash.as_ref()) {
3882 Ok(_) => Ok(Ok(())),
3883 Err(error) => Err(ExecError::Interpreter(error.into()).into()),
3884 }
3885 }
3886
3887 pub fn take_host_buffer(&mut self) -> Option<CLValue> {
3889 self.host_buffer.take()
3890 }
3891
3892 fn can_write_to_host_buffer(&self) -> bool {
3896 self.host_buffer.is_none()
3897 }
3898
3899 fn write_host_buffer(&mut self, data: CLValue) -> Result<(), ApiError> {
3901 match self.host_buffer {
3902 Some(_) => return Err(ApiError::HostBufferFull),
3903 None => self.host_buffer = Some(data),
3904 }
3905 Ok(())
3906 }
3907
3908 fn read_host_buffer(
3909 &mut self,
3910 dest_ptr: u32,
3911 dest_size: usize,
3912 bytes_written_ptr: u32,
3913 ) -> Result<Result<(), ApiError>, ExecError> {
3914 let (_cl_type, serialized_value) = match self.take_host_buffer() {
3915 None => return Ok(Err(ApiError::HostBufferEmpty)),
3916 Some(cl_value) => cl_value.destructure(),
3917 };
3918
3919 if serialized_value.len() > u32::MAX as usize {
3920 return Ok(Err(ApiError::OutOfMemory));
3921 }
3922 if serialized_value.len() > dest_size {
3923 return Ok(Err(ApiError::BufferTooSmall));
3924 }
3925
3926 let sliced_buf = &serialized_value[..cmp::min(dest_size, serialized_value.len())];
3929 if let Err(error) = self.try_get_memory()?.set(dest_ptr, sliced_buf) {
3930 return Err(ExecError::Interpreter(error.into()));
3931 }
3932
3933 let bytes_written: u32 = sliced_buf
3935 .len()
3936 .try_into()
3937 .expect("Size of buffer should fit within limit");
3938 let bytes_written_data = bytes_written.to_le_bytes();
3939
3940 if let Err(error) = self
3941 .try_get_memory()?
3942 .set(bytes_written_ptr, &bytes_written_data)
3943 {
3944 return Err(ExecError::Interpreter(error.into()));
3945 }
3946
3947 Ok(Ok(()))
3948 }
3949
3950 #[cfg(feature = "test-support")]
3951 fn print(&mut self, text_ptr: u32, text_size: u32) -> Result<(), Trap> {
3952 let text = self.string_from_mem(text_ptr, text_size)?;
3953 println!("{}", text); Ok(())
3955 }
3956
3957 fn get_named_arg_size(
3958 &mut self,
3959 name_ptr: u32,
3960 name_size: usize,
3961 size_ptr: u32,
3962 ) -> Result<Result<(), ApiError>, Trap> {
3963 let name_bytes = self.bytes_from_mem(name_ptr, name_size)?;
3964 let name = String::from_utf8_lossy(&name_bytes);
3965
3966 let arg_size: u32 = match self.context.args().get(&name) {
3967 Some(arg) if arg.inner_bytes().len() > u32::MAX as usize => {
3968 return Ok(Err(ApiError::OutOfMemory));
3969 }
3970 Some(arg) => {
3971 arg.inner_bytes()
3973 .len()
3974 .try_into()
3975 .expect("Should fit within the range")
3976 }
3977 None => return Ok(Err(ApiError::MissingArgument)),
3978 };
3979
3980 let arg_size_bytes = arg_size.to_le_bytes(); if let Err(e) = self.try_get_memory()?.set(size_ptr, &arg_size_bytes) {
3983 return Err(ExecError::Interpreter(e.into()).into());
3984 }
3985
3986 Ok(Ok(()))
3987 }
3988
3989 fn get_named_arg(
3990 &mut self,
3991 name_ptr: u32,
3992 name_size: usize,
3993 output_ptr: u32,
3994 output_size: usize,
3995 ) -> Result<Result<(), ApiError>, Trap> {
3996 let name_bytes = self.bytes_from_mem(name_ptr, name_size)?;
3997 let name = String::from_utf8_lossy(&name_bytes);
3998
3999 let arg = match self.context.args().get(&name) {
4000 Some(arg) => arg,
4001 None => return Ok(Err(ApiError::MissingArgument)),
4002 };
4003
4004 if arg.inner_bytes().len() > output_size {
4005 return Ok(Err(ApiError::OutOfMemory));
4006 }
4007
4008 if let Err(error) = self
4009 .try_get_memory()?
4010 .set(output_ptr, &arg.inner_bytes()[..output_size])
4011 {
4012 return Err(ExecError::Interpreter(error.into()).into());
4013 }
4014
4015 Ok(Ok(()))
4016 }
4017
4018 fn validate_entry_point_access(
4020 &self,
4021 package: &Package,
4022 name: &str,
4023 access: &EntryPointAccess,
4024 ) -> Result<(), ExecError> {
4025 match access {
4026 EntryPointAccess::Public => Ok(()),
4027 EntryPointAccess::Groups(group_names) => {
4028 if group_names.is_empty() {
4029 return Err(ExecError::InvalidContext);
4032 }
4033
4034 let find_result = group_names.iter().find(|&group_name| {
4035 package
4036 .groups()
4037 .get(group_name)
4038 .and_then(|urefs| {
4039 urefs
4040 .iter()
4041 .find(|&uref| self.context.validate_uref(uref).is_ok())
4042 })
4043 .is_some()
4044 });
4045
4046 if find_result.is_none() {
4047 return Err(ExecError::InvalidContext);
4048 }
4049
4050 Ok(())
4051 }
4052 EntryPointAccess::Template => Err(ExecError::TemplateMethod(name.to_string())),
4053 }
4054 }
4055
4056 fn remove_contract_user_group(
4058 &mut self,
4059 package_key: PackageHash,
4060 label: Group,
4061 ) -> Result<Result<(), ApiError>, ExecError> {
4062 if self.context.engine_config().enable_entity {
4063 let mut package: Package = self.context.get_validated_package(package_key)?;
4064 let group_to_remove = Group::new(label);
4065
4066 if !package.groups().contains(&group_to_remove) {
4068 return Ok(Err(addressable_entity::Error::GroupDoesNotExist.into()));
4069 }
4070
4071 let versions = package.versions();
4073 for entity_hash in versions.contract_hashes() {
4074 let entry_points = {
4075 self.context
4076 .get_casper_vm_v1_entry_point(Key::AddressableEntity(*entity_hash))?
4077 };
4078 for entry_point in entry_points.take_entry_points() {
4079 match entry_point.access() {
4080 EntryPointAccess::Public | EntryPointAccess::Template => {
4081 continue;
4082 }
4083 EntryPointAccess::Groups(groups) => {
4084 if groups.contains(&group_to_remove) {
4085 return Ok(Err(addressable_entity::Error::GroupInUse.into()));
4086 }
4087 }
4088 }
4089 }
4090 }
4091
4092 if !package.remove_group(&group_to_remove) {
4093 return Ok(Err(addressable_entity::Error::GroupInUse.into()));
4094 }
4095
4096 self.context.metered_write_gs_unsafe(package_key, package)?;
4098 } else {
4099 let mut contract_package = self
4100 .context
4101 .get_validated_contract_package(package_key.value())?;
4102 let group_to_remove = Group::new(label);
4103
4104 if !contract_package.groups().contains(&group_to_remove) {
4106 return Ok(Err(addressable_entity::Error::GroupDoesNotExist.into()));
4107 }
4108
4109 for (_version, contract_hash) in contract_package.versions().iter() {
4111 let entry_points = {
4112 self.context
4113 .get_casper_vm_v1_entry_point(Key::contract_entity_key(
4114 AddressableEntityHash::new(contract_hash.value()),
4115 ))?
4116 };
4117 for entry_point in entry_points.take_entry_points() {
4118 match entry_point.access() {
4119 EntryPointAccess::Public | EntryPointAccess::Template => {
4120 continue;
4121 }
4122 EntryPointAccess::Groups(groups) => {
4123 if groups.contains(&group_to_remove) {
4124 return Ok(Err(addressable_entity::Error::GroupInUse.into()));
4125 }
4126 }
4127 }
4128 }
4129 }
4130
4131 if !contract_package.remove_group(&group_to_remove) {
4132 return Ok(Err(addressable_entity::Error::GroupInUse.into()));
4133 }
4134
4135 self.context.metered_write_gs_unsafe(
4137 ContractPackageHash::new(package_key.value()),
4138 contract_package,
4139 )?;
4140 }
4141 Ok(Ok(()))
4142 }
4143
4144 #[allow(clippy::too_many_arguments)]
4145 fn provision_contract_user_group_uref(
4146 &mut self,
4147 package_ptr: u32,
4148 package_size: u32,
4149 label_ptr: u32,
4150 label_size: u32,
4151 output_size_ptr: u32,
4152 ) -> Result<Result<(), ApiError>, ExecError> {
4153 let contract_package_hash = self.t_from_mem(package_ptr, package_size)?;
4154 let label: String = self.t_from_mem(label_ptr, label_size)?;
4155 let new_uref = if self.context.engine_config().enable_entity {
4156 let mut contract_package = self.context.get_validated_package(contract_package_hash)?;
4157 let groups = contract_package.groups_mut();
4158
4159 let group_label = Group::new(label);
4160
4161 if groups.total_urefs() + 1 > addressable_entity::MAX_TOTAL_UREFS {
4163 return Ok(Err(addressable_entity::Error::MaxTotalURefsExceeded.into()));
4164 }
4165
4166 let group = match groups.get_mut(&group_label) {
4168 Some(group) if group.len() + 1 > addressable_entity::MAX_GROUPS as usize => {
4169 return Ok(Err(addressable_entity::Error::MaxTotalURefsExceeded.into()));
4171 }
4172 Some(group) => group,
4173 None => return Ok(Err(addressable_entity::Error::GroupDoesNotExist.into())),
4174 };
4175
4176 let new_uref = self.context.new_unit_uref()?;
4178 if !group.insert(new_uref) {
4179 return Ok(Err(addressable_entity::Error::URefAlreadyExists.into()));
4180 }
4181
4182 self.context
4184 .metered_write_gs_unsafe(contract_package_hash, contract_package)?;
4185 new_uref
4186 } else {
4187 let mut contract_package = self
4188 .context
4189 .get_validated_contract_package(contract_package_hash.value())?;
4190 let groups = contract_package.groups_mut();
4191
4192 let group_label = Group::new(label);
4193
4194 if groups.total_urefs() + 1 > addressable_entity::MAX_TOTAL_UREFS {
4196 return Ok(Err(addressable_entity::Error::MaxTotalURefsExceeded.into()));
4197 }
4198
4199 let group = match groups.get_mut(&group_label) {
4201 Some(group) if group.len() + 1 > addressable_entity::MAX_GROUPS as usize => {
4202 return Ok(Err(addressable_entity::Error::MaxTotalURefsExceeded.into()));
4204 }
4205 Some(group) => group,
4206 None => return Ok(Err(addressable_entity::Error::GroupDoesNotExist.into())),
4207 };
4208
4209 let new_uref = self.context.new_unit_uref()?;
4211 if !group.insert(new_uref) {
4212 return Ok(Err(addressable_entity::Error::URefAlreadyExists.into()));
4213 }
4214
4215 self.context.metered_write_gs_unsafe(
4217 ContractPackageHash::new(contract_package_hash.value()),
4218 contract_package,
4219 )?;
4220 new_uref
4221 };
4222
4223 if let Err(err) = self.check_host_buffer() {
4225 return Ok(Err(err));
4226 }
4227 let new_uref_value = CLValue::from_t(new_uref)?;
4229 let value_size = new_uref_value.inner_bytes().len();
4230 if let Err(err) = self.write_host_buffer(new_uref_value) {
4232 return Ok(Err(err));
4233 }
4234 let output_size_bytes = value_size.to_le_bytes(); if let Err(error) = self
4237 .try_get_memory()?
4238 .set(output_size_ptr, &output_size_bytes)
4239 {
4240 return Err(ExecError::Interpreter(error.into()));
4241 }
4242
4243 Ok(Ok(()))
4244 }
4245
4246 #[allow(clippy::too_many_arguments)]
4247 fn remove_contract_user_group_urefs(
4248 &mut self,
4249 package_ptr: u32,
4250 package_size: u32,
4251 label_ptr: u32,
4252 label_size: u32,
4253 urefs_ptr: u32,
4254 urefs_size: u32,
4255 ) -> Result<Result<(), ApiError>, ExecError> {
4256 let contract_package_hash: PackageHash = self.t_from_mem(package_ptr, package_size)?;
4257 let label: String = self.t_from_mem(label_ptr, label_size)?;
4258 let urefs: BTreeSet<URef> = self.t_from_mem(urefs_ptr, urefs_size)?;
4259
4260 if self.context.engine_config().enable_entity {
4261 let mut contract_package = self.context.get_validated_package(contract_package_hash)?;
4262
4263 let groups = contract_package.groups_mut();
4264 let group_label = Group::new(label);
4265
4266 let group = match groups.get_mut(&group_label) {
4267 Some(group) => group,
4268 None => return Ok(Err(addressable_entity::Error::GroupDoesNotExist.into())),
4269 };
4270
4271 if urefs.is_empty() {
4272 return Ok(Ok(()));
4273 }
4274
4275 for uref in urefs {
4276 if !group.remove(&uref) {
4277 return Ok(Err(addressable_entity::Error::UnableToRemoveURef.into()));
4278 }
4279 }
4280 self.context
4282 .metered_write_gs_unsafe(contract_package_hash, contract_package)?;
4283 } else {
4284 let contract_package_hash = ContractPackageHash::new(contract_package_hash.value());
4285 let mut contract_package = self
4286 .context
4287 .get_validated_contract_package(contract_package_hash.value())?;
4288
4289 let groups = contract_package.groups_mut();
4290 let group_label = Group::new(label);
4291
4292 let group = match groups.get_mut(&group_label) {
4293 Some(group) => group,
4294 None => return Ok(Err(addressable_entity::Error::GroupDoesNotExist.into())),
4295 };
4296
4297 if urefs.is_empty() {
4298 return Ok(Ok(()));
4299 }
4300
4301 for uref in urefs {
4302 if !group.remove(&uref) {
4303 return Ok(Err(addressable_entity::Error::UnableToRemoveURef.into()));
4304 }
4305 }
4306 self.context
4308 .metered_write_gs_unsafe(contract_package_hash, contract_package)?;
4309 }
4310
4311 Ok(Ok(()))
4312 }
4313
4314 fn charge_host_function_call<T>(
4316 &mut self,
4317 host_function: &HostFunction<T>,
4318 weights: T,
4319 ) -> Result<(), Trap>
4320 where
4321 T: AsRef<[HostFunctionCost]> + Copy,
4322 {
4323 let cost = host_function
4324 .calculate_gas_cost(weights)
4325 .ok_or(ExecError::GasLimit)?; self.gas(cost)?;
4327 Ok(())
4328 }
4329
4330 fn new_dictionary(&mut self, output_size_ptr: u32) -> Result<Result<(), ApiError>, ExecError> {
4332 if let Err(err) = self.check_host_buffer() {
4334 return Ok(Err(err));
4335 }
4336
4337 let new_uref = self.context.new_unit_uref()?;
4339
4340 let new_uref_value = CLValue::from_t(new_uref)?;
4342 let value_size = new_uref_value.inner_bytes().len();
4343 if let Err(err) = self.write_host_buffer(new_uref_value) {
4345 return Ok(Err(err));
4346 }
4347 let output_size_bytes = value_size.to_le_bytes(); if let Err(error) = self
4350 .try_get_memory()?
4351 .set(output_size_ptr, &output_size_bytes)
4352 {
4353 return Err(ExecError::Interpreter(error.into()));
4354 }
4355
4356 Ok(Ok(()))
4357 }
4358
4359 fn dictionary_get(
4361 &mut self,
4362 uref_ptr: u32,
4363 uref_size: u32,
4364 dictionary_item_key_bytes_ptr: u32,
4365 dictionary_item_key_bytes_size: u32,
4366 output_size_ptr: u32,
4367 ) -> Result<Result<(), ApiError>, Trap> {
4368 if let Err(err) = self.check_host_buffer() {
4370 return Ok(Err(err));
4371 }
4372
4373 let uref: URef = self.t_from_mem(uref_ptr, uref_size)?;
4374 let dictionary_item_key = self.checked_memory_slice(
4375 dictionary_item_key_bytes_ptr as usize,
4376 dictionary_item_key_bytes_size as usize,
4377 |utf8_bytes| std::str::from_utf8(utf8_bytes).map(ToOwned::to_owned),
4378 )?;
4379
4380 let dictionary_item_key = if let Ok(item_key) = dictionary_item_key {
4381 item_key
4382 } else {
4383 return Ok(Err(ApiError::InvalidDictionaryItemKey));
4384 };
4385
4386 let cl_value = match self.context.dictionary_get(uref, &dictionary_item_key)? {
4387 Some(cl_value) => cl_value,
4388 None => return Ok(Err(ApiError::ValueNotFound)),
4389 };
4390
4391 let value_size: u32 = match cl_value.inner_bytes().len().try_into() {
4392 Ok(value) => value,
4393 Err(_) => return Ok(Err(ApiError::BufferTooSmall)),
4394 };
4395
4396 if let Err(error) = self.write_host_buffer(cl_value) {
4397 return Ok(Err(error));
4398 }
4399
4400 let value_bytes = value_size.to_le_bytes(); if let Err(error) = self.try_get_memory()?.set(output_size_ptr, &value_bytes) {
4402 return Err(ExecError::Interpreter(error.into()).into());
4403 }
4404
4405 Ok(Ok(()))
4406 }
4407
4408 fn dictionary_read(
4410 &mut self,
4411 key_ptr: u32,
4412 key_size: u32,
4413 output_size_ptr: u32,
4414 ) -> Result<Result<(), ApiError>, Trap> {
4415 if !self.can_write_to_host_buffer() {
4416 return Ok(Err(ApiError::HostBufferFull));
4418 }
4419
4420 let dictionary_key = self.key_from_mem(key_ptr, key_size)?;
4421 let cl_value = match self.context.dictionary_read(dictionary_key)? {
4422 Some(cl_value) => cl_value,
4423 None => return Ok(Err(ApiError::ValueNotFound)),
4424 };
4425
4426 let value_size: u32 = match cl_value.inner_bytes().len().try_into() {
4427 Ok(value) => value,
4428 Err(_) => return Ok(Err(ApiError::BufferTooSmall)),
4429 };
4430
4431 if let Err(error) = self.write_host_buffer(cl_value) {
4432 return Ok(Err(error));
4433 }
4434
4435 let value_bytes = value_size.to_le_bytes(); if let Err(error) = self.try_get_memory()?.set(output_size_ptr, &value_bytes) {
4437 return Err(ExecError::Interpreter(error.into()).into());
4438 }
4439
4440 Ok(Ok(()))
4441 }
4442
4443 fn dictionary_put(
4445 &mut self,
4446 uref_ptr: u32,
4447 uref_size: u32,
4448 key_ptr: u32,
4449 key_size: u32,
4450 value_ptr: u32,
4451 value_size: u32,
4452 ) -> Result<Result<(), ApiError>, Trap> {
4453 let uref: URef = self.t_from_mem(uref_ptr, uref_size)?;
4454 let dictionary_item_key_bytes = {
4455 if (key_size as usize) > DICTIONARY_ITEM_KEY_MAX_LENGTH {
4456 return Ok(Err(ApiError::DictionaryItemKeyExceedsLength));
4457 }
4458 self.checked_memory_slice(key_ptr as usize, key_size as usize, |data| {
4459 std::str::from_utf8(data).map(ToOwned::to_owned)
4460 })?
4461 };
4462
4463 let dictionary_item_key = if let Ok(item_key) = dictionary_item_key_bytes {
4464 item_key
4465 } else {
4466 return Ok(Err(ApiError::InvalidDictionaryItemKey));
4467 };
4468 let cl_value = self.cl_value_from_mem(value_ptr, value_size)?;
4469 if let Err(e) = self
4470 .context
4471 .dictionary_put(uref, &dictionary_item_key, cl_value)
4472 {
4473 return Err(Trap::from(e));
4474 }
4475 Ok(Ok(()))
4476 }
4477
4478 fn is_system_immediate_caller(&self) -> Result<bool, ExecError> {
4483 let immediate_caller = match self.get_immediate_caller() {
4484 Some(call_stack_element) => call_stack_element,
4485 None => {
4486 return Ok(false);
4488 }
4489 };
4490
4491 match immediate_caller {
4492 Caller::Initiator { account_hash } => {
4493 Ok(account_hash == &PublicKey::System.to_account_hash())
4495 }
4496 Caller::SmartContract { contract_hash, .. } => Ok(self
4497 .context
4498 .is_system_addressable_entity(&contract_hash.value())?),
4499 Caller::Entity { entity_addr, .. } => Ok(self
4500 .context
4501 .is_system_addressable_entity(&entity_addr.value())?),
4502 }
4503 }
4504
4505 fn load_authorization_keys(
4506 &mut self,
4507 len_ptr: u32,
4508 result_size_ptr: u32,
4509 ) -> Result<Result<(), ApiError>, Trap> {
4510 if !self.can_write_to_host_buffer() {
4511 return Ok(Err(ApiError::HostBufferFull));
4513 }
4514
4515 let authorization_keys = Vec::from_iter(self.context.authorization_keys().clone());
4517
4518 let total_keys: u32 = match authorization_keys.len().try_into() {
4519 Ok(value) => value,
4520 Err(_) => return Ok(Err(ApiError::OutOfMemory)),
4521 };
4522 let total_keys_bytes = total_keys.to_le_bytes();
4523 if let Err(error) = self.try_get_memory()?.set(len_ptr, &total_keys_bytes) {
4524 return Err(ExecError::Interpreter(error.into()).into());
4525 }
4526
4527 if total_keys == 0 {
4528 return Ok(Ok(()));
4530 }
4531
4532 let authorization_keys = CLValue::from_t(authorization_keys).map_err(ExecError::CLValue)?;
4533
4534 let length: u32 = match authorization_keys.inner_bytes().len().try_into() {
4535 Ok(value) => value,
4536 Err(_) => return Ok(Err(ApiError::OutOfMemory)),
4537 };
4538 if let Err(error) = self.write_host_buffer(authorization_keys) {
4539 return Ok(Err(error));
4540 }
4541
4542 let length_bytes = length.to_le_bytes();
4543 if let Err(error) = self.try_get_memory()?.set(result_size_ptr, &length_bytes) {
4544 return Err(ExecError::Interpreter(error.into()).into());
4545 }
4546
4547 Ok(Ok(()))
4548 }
4549
4550 fn prune(&mut self, key: Key) {
4551 self.context.prune_gs_unsafe(key);
4552 }
4553
4554 pub(crate) fn migrate_contract_and_contract_package(
4555 &mut self,
4556 hash_addr: HashAddr,
4557 ) -> Result<AddressableEntity, ExecError> {
4558 let protocol_version = self.context.protocol_version();
4559 let contract = self.context.get_contract(ContractHash::new(hash_addr))?;
4560 let package_hash = contract.contract_package_hash();
4561 self.context
4562 .migrate_package(package_hash, protocol_version)?;
4563 let entity_hash = AddressableEntityHash::new(hash_addr);
4564 let key = Key::contract_entity_key(entity_hash);
4565 self.context.read_gs_typed(&key)
4566 }
4567
4568 fn add_message_topic(&mut self, topic_name: &str) -> Result<Result<(), ApiError>, ExecError> {
4569 let topic_hash = cryptography::blake2b(topic_name).into();
4570
4571 self.context
4572 .add_message_topic(topic_name, topic_hash)
4573 .map(|ret| ret.map_err(ApiError::from))
4574 }
4575
4576 fn emit_message(
4577 &mut self,
4578 topic_name: &str,
4579 message: MessagePayload,
4580 ) -> Result<Result<(), ApiError>, Trap> {
4581 let entity_addr = self.context.context_key_to_entity_addr()?;
4582
4583 let topic_name_hash = cryptography::blake2b(topic_name).into();
4584 let topic_key = Key::Message(MessageAddr::new_topic_addr(entity_addr, topic_name_hash));
4585
4586 let Some(StoredValue::MessageTopic(prev_topic_summary)) =
4588 self.context.read_gs(&topic_key)?
4589 else {
4590 return Ok(Err(ApiError::MessageTopicNotRegistered));
4591 };
4592
4593 let current_blocktime = self.context.get_block_info().block_time();
4594 let topic_message_index = if prev_topic_summary.blocktime() != current_blocktime {
4595 for index in 1..prev_topic_summary.message_count() {
4596 self.context
4597 .prune_gs_unsafe(Key::message(entity_addr, topic_name_hash, index));
4598 }
4599 0
4600 } else {
4601 prev_topic_summary.message_count()
4602 };
4603
4604 let block_message_index: u64 = match self
4605 .context
4606 .read_gs(&Key::BlockGlobal(BlockGlobalAddr::MessageCount))?
4607 {
4608 Some(stored_value) => {
4609 let (prev_block_time, prev_count): (BlockTime, u64) = CLValue::into_t(
4610 CLValue::try_from(stored_value).map_err(ExecError::TypeMismatch)?,
4611 )
4612 .map_err(ExecError::CLValue)?;
4613 if prev_block_time == current_blocktime {
4614 prev_count
4615 } else {
4616 0
4617 }
4618 }
4619 None => 0,
4620 };
4621
4622 let Some(topic_message_count) = topic_message_index.checked_add(1) else {
4623 return Ok(Err(ApiError::MessageTopicFull));
4624 };
4625
4626 let Some(block_message_count) = block_message_index.checked_add(1) else {
4627 return Ok(Err(ApiError::MaxMessagesPerBlockExceeded));
4628 };
4629
4630 self.context.metered_emit_message(
4631 topic_key,
4632 current_blocktime,
4633 block_message_count,
4634 topic_message_count,
4635 Message::new(
4636 entity_addr,
4637 message,
4638 topic_name.to_string(),
4639 topic_name_hash,
4640 topic_message_index,
4641 block_message_index,
4642 ),
4643 )?;
4644 Ok(Ok(()))
4645 }
4646}
4647
4648#[cfg(feature = "test-support")]
4649fn dump_runtime_stack_info(instance: casper_wasmi::ModuleRef, max_stack_height: u32) {
4650 let globals = instance.globals();
4651 let Some(current_runtime_call_stack_height) = globals.last() else {
4652 return;
4653 };
4654
4655 if let RuntimeValue::I32(current_runtime_call_stack_height) =
4656 current_runtime_call_stack_height.get()
4657 {
4658 if current_runtime_call_stack_height > max_stack_height as i32 {
4659 eprintln!("runtime stack overflow, current={current_runtime_call_stack_height}, max={max_stack_height}");
4660 }
4661 };
4662}