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