1#![allow(rustdoc::private_intra_doc_links)]
87#![cfg_attr(not(feature = "std"), no_std)]
88#![cfg_attr(feature = "runtime-benchmarks", recursion_limit = "1024")]
89
90extern crate alloc;
91mod address;
92mod benchmarking;
93mod exec;
94mod gas;
95mod primitives;
96pub use primitives::*;
97
98mod schedule;
99mod storage;
100mod transient_storage;
101mod wasm;
102
103pub mod chain_extension;
104pub mod debug;
105pub mod migration;
106pub mod test_utils;
107pub mod weights;
108
109#[cfg(test)]
110mod tests;
111use crate::{
112 exec::{
113 AccountIdOf, ErrorOrigin, ExecError, Executable, Ext, Key, MomentOf, Stack as ExecStack,
114 },
115 gas::GasMeter,
116 storage::{meter::Meter as StorageMeter, ContractInfo, DeletionQueueManager},
117 wasm::{CodeInfo, RuntimeCosts, WasmBlob},
118};
119use codec::{Codec, Decode, DecodeWithMemTracking, Encode, HasCompact, MaxEncodedLen};
120use core::fmt::Debug;
121use environmental::*;
122use frame_support::{
123 dispatch::{GetDispatchInfo, Pays, PostDispatchInfo, RawOrigin, WithPostDispatchInfo},
124 ensure,
125 traits::{
126 fungible::{Inspect, Mutate, MutateHold},
127 ConstU32, Contains, Get, Randomness, Time,
128 },
129 weights::{Weight, WeightMeter},
130 BoundedVec, DebugNoBound, DefaultNoBound,
131};
132use frame_system::{
133 ensure_signed,
134 pallet_prelude::{BlockNumberFor, OriginFor},
135 EventRecord, Pallet as System,
136};
137use scale_info::TypeInfo;
138use smallvec::Array;
139use sp_runtime::{
140 traits::{BadOrigin, Convert, Dispatchable, Saturating, StaticLookup, Zero},
141 DispatchError,
142};
143
144pub use crate::{
145 address::{AddressGenerator, DefaultAddressGenerator},
146 debug::Tracing,
147 exec::Frame,
148 migration::{MigrateSequence, Migration, NoopMigration},
149 pallet::*,
150 schedule::{InstructionWeights, Limits, Schedule},
151 wasm::Determinism,
152};
153pub use weights::WeightInfo;
154
155#[cfg(doc)]
156pub use crate::wasm::api_doc;
157
158type CodeHash<T> = <T as frame_system::Config>::Hash;
159type TrieId = BoundedVec<u8, ConstU32<128>>;
160type BalanceOf<T> =
161 <<T as Config>::Currency as Inspect<<T as frame_system::Config>::AccountId>>::Balance;
162type CodeVec<T> = BoundedVec<u8, <T as Config>::MaxCodeLen>;
163type AccountIdLookupOf<T> = <<T as frame_system::Config>::Lookup as StaticLookup>::Source;
164type DebugBufferVec<T> = BoundedVec<u8, <T as Config>::MaxDebugBufferLen>;
165type EventRecordOf<T> =
166 EventRecord<<T as frame_system::Config>::RuntimeEvent, <T as frame_system::Config>::Hash>;
167
168type OldWeight = u64;
173
174const SENTINEL: u32 = u32::MAX;
181
182const LOG_TARGET: &str = "runtime::contracts";
188
189#[derive(Encode, Decode, DefaultNoBound, TypeInfo)]
195#[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))]
196pub struct EnvironmentType<T>(PhantomData<T>);
197
198#[derive(Encode, Decode, DefaultNoBound, TypeInfo)]
208#[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))]
209#[scale_info(skip_type_params(T))]
210pub struct Environment<T: Config> {
211 account_id: EnvironmentType<AccountIdOf<T>>,
212 balance: EnvironmentType<BalanceOf<T>>,
213 hash: EnvironmentType<<T as frame_system::Config>::Hash>,
214 hasher: EnvironmentType<<T as frame_system::Config>::Hashing>,
215 timestamp: EnvironmentType<MomentOf<T>>,
216 block_number: EnvironmentType<BlockNumberFor<T>>,
217}
218
219#[derive(Encode, Decode, TypeInfo)]
224pub struct ApiVersion(u16);
225impl Default for ApiVersion {
226 fn default() -> Self {
227 Self(4)
228 }
229}
230
231#[test]
232fn api_version_is_up_to_date() {
233 assert_eq!(
234 111,
235 crate::wasm::STABLE_API_COUNT,
236 "Stable API count has changed. Bump the returned value of ApiVersion::default() and update the test."
237 );
238}
239
240#[frame_support::pallet]
241pub mod pallet {
242 use super::*;
243 use crate::debug::Debugger;
244 use frame_support::pallet_prelude::*;
245 use frame_system::pallet_prelude::*;
246 use sp_runtime::Perbill;
247
248 pub(crate) const STORAGE_VERSION: StorageVersion = StorageVersion::new(16);
250
251 #[pallet::pallet]
252 #[pallet::storage_version(STORAGE_VERSION)]
253 pub struct Pallet<T>(_);
254
255 #[pallet::config(with_default)]
256 pub trait Config: frame_system::Config {
257 type Time: Time;
259
260 #[pallet::no_default_bounds]
269 type Randomness: Randomness<Self::Hash, BlockNumberFor<Self>>;
270
271 #[pallet::no_default]
273 type Currency: Inspect<Self::AccountId>
274 + Mutate<Self::AccountId>
275 + MutateHold<Self::AccountId, Reason = Self::RuntimeHoldReason>;
276
277 #[pallet::no_default_bounds]
279 #[allow(deprecated)]
280 type RuntimeEvent: From<Event<Self>> + IsType<<Self as frame_system::Config>::RuntimeEvent>;
281
282 #[pallet::no_default_bounds]
284 type RuntimeCall: Dispatchable<RuntimeOrigin = Self::RuntimeOrigin, PostInfo = PostDispatchInfo>
285 + GetDispatchInfo
286 + codec::Decode
287 + IsType<<Self as frame_system::Config>::RuntimeCall>;
288
289 #[pallet::no_default_bounds]
291 type RuntimeHoldReason: From<HoldReason>;
292
293 #[pallet::no_default_bounds]
316 type CallFilter: Contains<<Self as frame_system::Config>::RuntimeCall>;
317
318 #[pallet::no_default_bounds]
321 type WeightPrice: Convert<Weight, BalanceOf<Self>>;
322
323 type WeightInfo: WeightInfo;
326
327 #[pallet::no_default_bounds]
329 type ChainExtension: chain_extension::ChainExtension<Self> + Default;
330
331 #[pallet::constant]
333 #[pallet::no_default]
334 type Schedule: Get<Schedule<Self>>;
335
336 #[pallet::no_default]
345 type CallStack: Array<Item = Frame<Self>>;
346
347 #[pallet::constant]
353 #[pallet::no_default_bounds]
354 type DepositPerByte: Get<BalanceOf<Self>>;
355
356 #[pallet::constant]
358 #[pallet::no_default_bounds]
359 type DefaultDepositLimit: Get<BalanceOf<Self>>;
360
361 #[pallet::constant]
367 #[pallet::no_default_bounds]
368 type DepositPerItem: Get<BalanceOf<Self>>;
369
370 #[pallet::constant]
375 type CodeHashLockupDepositPercent: Get<Perbill>;
376
377 #[pallet::no_default_bounds]
379 type AddressGenerator: AddressGenerator<Self>;
380
381 #[pallet::constant]
387 type MaxCodeLen: Get<u32>;
388
389 #[pallet::constant]
391 type MaxStorageKeyLen: Get<u32>;
392
393 #[pallet::constant]
396 type MaxTransientStorageSize: Get<u32>;
397
398 #[pallet::constant]
401 type MaxDelegateDependencies: Get<u32>;
402
403 #[pallet::constant]
413 type UnsafeUnstableInterface: Get<bool>;
414
415 #[pallet::constant]
417 type MaxDebugBufferLen: Get<u32>;
418
419 #[pallet::no_default_bounds]
424 type UploadOrigin: EnsureOrigin<Self::RuntimeOrigin, Success = Self::AccountId>;
425
426 #[pallet::no_default_bounds]
437 type InstantiateOrigin: EnsureOrigin<Self::RuntimeOrigin, Success = Self::AccountId>;
438
439 type Migrations: MigrateSequence;
457
458 #[pallet::no_default_bounds]
463 type Debug: Debugger<Self>;
464
465 #[pallet::constant]
470 #[pallet::no_default_bounds]
471 type Environment: Get<Environment<Self>>;
472
473 #[pallet::constant]
477 #[pallet::no_default_bounds]
478 type ApiVersion: Get<ApiVersion>;
479
480 #[pallet::no_default_bounds]
483 type Xcm: xcm_builder::Controller<
484 OriginFor<Self>,
485 <Self as frame_system::Config>::RuntimeCall,
486 BlockNumberFor<Self>,
487 >;
488 }
489
490 pub mod config_preludes {
492 use super::*;
493 use frame_support::{
494 derive_impl,
495 traits::{ConstBool, ConstU32},
496 };
497 use frame_system::EnsureSigned;
498 use sp_core::parameter_types;
499
500 type AccountId = sp_runtime::AccountId32;
501 type Balance = u64;
502 const UNITS: Balance = 10_000_000_000;
503 const CENTS: Balance = UNITS / 100;
504
505 const fn deposit(items: u32, bytes: u32) -> Balance {
506 items as Balance * 1 * CENTS + (bytes as Balance) * 1 * CENTS
507 }
508
509 parameter_types! {
510 pub const DepositPerItem: Balance = deposit(1, 0);
511 pub const DepositPerByte: Balance = deposit(0, 1);
512 pub const DefaultDepositLimit: Balance = deposit(1024, 1024 * 1024);
513 pub const CodeHashLockupDepositPercent: Perbill = Perbill::from_percent(0);
514 pub const MaxDelegateDependencies: u32 = 32;
515 }
516
517 pub struct TestDefaultConfig;
519
520 impl<Output, BlockNumber> Randomness<Output, BlockNumber> for TestDefaultConfig {
521 fn random(_subject: &[u8]) -> (Output, BlockNumber) {
522 unimplemented!("No default `random` implementation in `TestDefaultConfig`, provide a custom `T::Randomness` type.")
523 }
524 }
525
526 impl Time for TestDefaultConfig {
527 type Moment = u64;
528 fn now() -> Self::Moment {
529 unimplemented!("No default `now` implementation in `TestDefaultConfig` provide a custom `T::Time` type.")
530 }
531 }
532
533 impl<T: From<u64>> Convert<Weight, T> for TestDefaultConfig {
534 fn convert(w: Weight) -> T {
535 w.ref_time().into()
536 }
537 }
538
539 #[derive_impl(frame_system::config_preludes::TestDefaultConfig, no_aggregated_types)]
540 impl frame_system::DefaultConfig for TestDefaultConfig {}
541
542 #[frame_support::register_default_impl(TestDefaultConfig)]
543 impl DefaultConfig for TestDefaultConfig {
544 #[inject_runtime_type]
545 type RuntimeEvent = ();
546
547 #[inject_runtime_type]
548 type RuntimeHoldReason = ();
549
550 #[inject_runtime_type]
551 type RuntimeCall = ();
552
553 type AddressGenerator = DefaultAddressGenerator;
554 type CallFilter = ();
555 type ChainExtension = ();
556 type CodeHashLockupDepositPercent = CodeHashLockupDepositPercent;
557 type DefaultDepositLimit = DefaultDepositLimit;
558 type DepositPerByte = DepositPerByte;
559 type DepositPerItem = DepositPerItem;
560 type MaxCodeLen = ConstU32<{ 123 * 1024 }>;
561 type MaxDebugBufferLen = ConstU32<{ 2 * 1024 * 1024 }>;
562 type MaxDelegateDependencies = MaxDelegateDependencies;
563 type MaxStorageKeyLen = ConstU32<128>;
564 type MaxTransientStorageSize = ConstU32<{ 1 * 1024 * 1024 }>;
565 type Migrations = ();
566 type Time = Self;
567 type Randomness = Self;
568 type UnsafeUnstableInterface = ConstBool<true>;
569 type UploadOrigin = EnsureSigned<AccountId>;
570 type InstantiateOrigin = EnsureSigned<AccountId>;
571 type WeightInfo = ();
572 type WeightPrice = Self;
573 type Debug = ();
574 type Environment = ();
575 type ApiVersion = ();
576 type Xcm = ();
577 }
578 }
579
580 #[pallet::hooks]
581 impl<T: Config> Hooks<BlockNumberFor<T>> for Pallet<T> {
582 fn on_idle(_block: BlockNumberFor<T>, limit: Weight) -> Weight {
583 use migration::MigrateResult::*;
584 let mut meter = WeightMeter::with_limit(limit);
585
586 loop {
587 match Migration::<T>::migrate(&mut meter) {
588 NoMigrationPerformed | InProgress { steps_done: 0 } => return meter.consumed(),
591 InProgress { .. } => continue,
593 Completed | NoMigrationInProgress => break,
596 }
597 }
598
599 ContractInfo::<T>::process_deletion_queue_batch(&mut meter);
600 meter.consumed()
601 }
602
603 fn integrity_test() {
604 Migration::<T>::integrity_test();
605
606 let max_runtime_mem: u32 = T::Schedule::get().limits.runtime_memory;
608 const MAX_STACK_SIZE: u32 = 1024 * 1024;
611 let max_heap_size = T::Schedule::get().limits.max_memory_size();
613 let max_call_depth = u32::try_from(T::CallStack::size().saturating_add(1))
615 .expect("CallStack size is too big");
616 let max_transient_storage_size = T::MaxTransientStorageSize::get()
619 .checked_mul(2)
620 .expect("MaxTransientStorageSize is too large");
621 let code_len_limit = max_runtime_mem
651 .saturating_div(2)
652 .saturating_sub(max_transient_storage_size)
653 .saturating_div(max_call_depth)
654 .saturating_sub(max_heap_size)
655 .saturating_sub(MAX_STACK_SIZE)
656 .saturating_div(17 * 4);
657
658 assert!(
659 T::MaxCodeLen::get() < code_len_limit,
660 "Given `CallStack` height {:?}, `MaxCodeLen` should be set less than {:?} \
661 (current value is {:?}), to avoid possible runtime oom issues.",
662 max_call_depth,
663 code_len_limit,
664 T::MaxCodeLen::get(),
665 );
666
667 const MIN_DEBUG_BUF_SIZE: u32 = 256;
669 assert!(
670 T::MaxDebugBufferLen::get() >= MIN_DEBUG_BUF_SIZE,
671 "Debug buffer should have minimum size of {} (current setting is {})",
672 MIN_DEBUG_BUF_SIZE,
673 T::MaxDebugBufferLen::get(),
674 );
675
676 let max_block_ref_time = T::BlockWeights::get()
682 .get(DispatchClass::Normal)
683 .max_total
684 .unwrap_or_else(|| T::BlockWeights::get().max_block)
685 .ref_time();
686 let max_payload_size = T::Schedule::get().limits.payload_len;
687 let max_key_size =
688 Key::<T>::try_from_var(alloc::vec![0u8; T::MaxStorageKeyLen::get() as usize])
689 .expect("Key of maximal size shall be created")
690 .hash()
691 .len() as u32;
692
693 let max_storage_size: u32 = ((max_block_ref_time /
696 (<RuntimeCosts as gas::Token<T>>::weight(&RuntimeCosts::SetStorage {
697 new_bytes: max_payload_size,
698 old_bytes: 0,
699 })
700 .ref_time()))
701 .saturating_mul(max_payload_size.saturating_add(max_key_size) as u64))
702 .try_into()
703 .expect("Storage size too big");
704
705 let max_validator_runtime_mem: u32 = T::Schedule::get().limits.validator_runtime_memory;
706 let storage_size_limit = max_validator_runtime_mem.saturating_sub(max_runtime_mem) / 2;
707
708 assert!(
709 max_storage_size <= storage_size_limit,
710 "Maximal storage size {} exceeds the storage limit {}",
711 max_storage_size,
712 storage_size_limit
713 );
714
715 let max_events_size: u32 = ((max_block_ref_time /
719 (<RuntimeCosts as gas::Token<T>>::weight(&RuntimeCosts::DepositEvent {
720 num_topic: 0,
721 len: max_payload_size,
722 })
723 .ref_time()))
724 .saturating_mul(max_payload_size as u64))
725 .try_into()
726 .expect("Events size too big");
727
728 assert!(
729 max_events_size <= storage_size_limit,
730 "Maximal events size {} exceeds the events limit {}",
731 max_events_size,
732 storage_size_limit
733 );
734 }
735 }
736
737 #[pallet::call]
738 impl<T: Config> Pallet<T>
739 where
740 <BalanceOf<T> as HasCompact>::Type: Clone + Eq + PartialEq + Debug + TypeInfo + Encode,
741 {
742 #[pallet::call_index(0)]
744 #[pallet::weight(T::WeightInfo::call().saturating_add(<Pallet<T>>::compat_weight_limit(*gas_limit)))]
745 #[allow(deprecated)]
746 #[deprecated(note = "1D weight is used in this extrinsic, please migrate to `call`")]
747 pub fn call_old_weight(
748 origin: OriginFor<T>,
749 dest: AccountIdLookupOf<T>,
750 #[pallet::compact] value: BalanceOf<T>,
751 #[pallet::compact] gas_limit: OldWeight,
752 storage_deposit_limit: Option<<BalanceOf<T> as codec::HasCompact>::Type>,
753 data: Vec<u8>,
754 ) -> DispatchResultWithPostInfo {
755 Self::call(
756 origin,
757 dest,
758 value,
759 <Pallet<T>>::compat_weight_limit(gas_limit),
760 storage_deposit_limit,
761 data,
762 )
763 }
764
765 #[pallet::call_index(1)]
767 #[pallet::weight(
768 T::WeightInfo::instantiate_with_code(code.len() as u32, data.len() as u32, salt.len() as u32)
769 .saturating_add(<Pallet<T>>::compat_weight_limit(*gas_limit))
770 )]
771 #[allow(deprecated)]
772 #[deprecated(
773 note = "1D weight is used in this extrinsic, please migrate to `instantiate_with_code`"
774 )]
775 pub fn instantiate_with_code_old_weight(
776 origin: OriginFor<T>,
777 #[pallet::compact] value: BalanceOf<T>,
778 #[pallet::compact] gas_limit: OldWeight,
779 storage_deposit_limit: Option<<BalanceOf<T> as codec::HasCompact>::Type>,
780 code: Vec<u8>,
781 data: Vec<u8>,
782 salt: Vec<u8>,
783 ) -> DispatchResultWithPostInfo {
784 Self::instantiate_with_code(
785 origin,
786 value,
787 <Pallet<T>>::compat_weight_limit(gas_limit),
788 storage_deposit_limit,
789 code,
790 data,
791 salt,
792 )
793 }
794
795 #[pallet::call_index(2)]
797 #[pallet::weight(
798 T::WeightInfo::instantiate(data.len() as u32, salt.len() as u32).saturating_add(<Pallet<T>>::compat_weight_limit(*gas_limit))
799 )]
800 #[allow(deprecated)]
801 #[deprecated(note = "1D weight is used in this extrinsic, please migrate to `instantiate`")]
802 pub fn instantiate_old_weight(
803 origin: OriginFor<T>,
804 #[pallet::compact] value: BalanceOf<T>,
805 #[pallet::compact] gas_limit: OldWeight,
806 storage_deposit_limit: Option<<BalanceOf<T> as codec::HasCompact>::Type>,
807 code_hash: CodeHash<T>,
808 data: Vec<u8>,
809 salt: Vec<u8>,
810 ) -> DispatchResultWithPostInfo {
811 Self::instantiate(
812 origin,
813 value,
814 <Pallet<T>>::compat_weight_limit(gas_limit),
815 storage_deposit_limit,
816 code_hash,
817 data,
818 salt,
819 )
820 }
821
822 #[pallet::call_index(3)]
847 #[pallet::weight(
848 match determinism {
849 Determinism::Enforced => T::WeightInfo::upload_code_determinism_enforced(code.len() as u32),
850 Determinism::Relaxed => T::WeightInfo::upload_code_determinism_relaxed(code.len() as u32),
851 }
852 )]
853 pub fn upload_code(
854 origin: OriginFor<T>,
855 code: Vec<u8>,
856 storage_deposit_limit: Option<<BalanceOf<T> as codec::HasCompact>::Type>,
857 determinism: Determinism,
858 ) -> DispatchResult {
859 Migration::<T>::ensure_migrated()?;
860 let origin = T::UploadOrigin::ensure_origin(origin)?;
861 Self::bare_upload_code(origin, code, storage_deposit_limit.map(Into::into), determinism)
862 .map(|_| ())
863 }
864
865 #[pallet::call_index(4)]
870 #[pallet::weight(T::WeightInfo::remove_code())]
871 pub fn remove_code(
872 origin: OriginFor<T>,
873 code_hash: CodeHash<T>,
874 ) -> DispatchResultWithPostInfo {
875 Migration::<T>::ensure_migrated()?;
876 let origin = ensure_signed(origin)?;
877 <WasmBlob<T>>::remove(&origin, code_hash)?;
878 Ok(Pays::No.into())
880 }
881
882 #[pallet::call_index(5)]
893 #[pallet::weight(T::WeightInfo::set_code())]
894 pub fn set_code(
895 origin: OriginFor<T>,
896 dest: AccountIdLookupOf<T>,
897 code_hash: CodeHash<T>,
898 ) -> DispatchResult {
899 Migration::<T>::ensure_migrated()?;
900 ensure_root(origin)?;
901 let dest = T::Lookup::lookup(dest)?;
902 <ContractInfoOf<T>>::try_mutate(&dest, |contract| {
903 let contract = if let Some(contract) = contract {
904 contract
905 } else {
906 return Err(<Error<T>>::ContractNotFound.into())
907 };
908 <ExecStack<T, WasmBlob<T>>>::increment_refcount(code_hash)?;
909 <ExecStack<T, WasmBlob<T>>>::decrement_refcount(contract.code_hash);
910 Self::deposit_event(Event::ContractCodeUpdated {
911 contract: dest.clone(),
912 new_code_hash: code_hash,
913 old_code_hash: contract.code_hash,
914 });
915 contract.code_hash = code_hash;
916 Ok(())
917 })
918 }
919
920 #[pallet::call_index(6)]
937 #[pallet::weight(T::WeightInfo::call().saturating_add(*gas_limit))]
938 pub fn call(
939 origin: OriginFor<T>,
940 dest: AccountIdLookupOf<T>,
941 #[pallet::compact] value: BalanceOf<T>,
942 gas_limit: Weight,
943 storage_deposit_limit: Option<<BalanceOf<T> as codec::HasCompact>::Type>,
944 data: Vec<u8>,
945 ) -> DispatchResultWithPostInfo {
946 Migration::<T>::ensure_migrated()?;
947 let common = CommonInput {
948 origin: Origin::from_runtime_origin(origin)?,
949 value,
950 data,
951 gas_limit: gas_limit.into(),
952 storage_deposit_limit: storage_deposit_limit.map(Into::into),
953 debug_message: None,
954 };
955 let dest = T::Lookup::lookup(dest)?;
956 let mut output =
957 CallInput::<T> { dest, determinism: Determinism::Enforced }.run_guarded(common);
958 if let Ok(retval) = &output.result {
959 if retval.did_revert() {
960 output.result = Err(<Error<T>>::ContractReverted.into());
961 }
962 }
963 output.gas_meter.into_dispatch_result(output.result, T::WeightInfo::call())
964 }
965
966 #[pallet::call_index(7)]
992 #[pallet::weight(
993 T::WeightInfo::instantiate_with_code(code.len() as u32, data.len() as u32, salt.len() as u32)
994 .saturating_add(*gas_limit)
995 )]
996 pub fn instantiate_with_code(
997 origin: OriginFor<T>,
998 #[pallet::compact] value: BalanceOf<T>,
999 gas_limit: Weight,
1000 storage_deposit_limit: Option<<BalanceOf<T> as codec::HasCompact>::Type>,
1001 code: Vec<u8>,
1002 data: Vec<u8>,
1003 salt: Vec<u8>,
1004 ) -> DispatchResultWithPostInfo {
1005 Migration::<T>::ensure_migrated()?;
1006
1007 let upload_origin = T::UploadOrigin::ensure_origin(origin.clone())?;
1011 let instantiate_origin = T::InstantiateOrigin::ensure_origin(origin)?;
1012
1013 let code_len = code.len() as u32;
1014
1015 let (module, upload_deposit) = Self::try_upload_code(
1016 upload_origin,
1017 code,
1018 storage_deposit_limit.clone().map(Into::into),
1019 Determinism::Enforced,
1020 None,
1021 )?;
1022
1023 let storage_deposit_limit =
1025 storage_deposit_limit.map(|limit| limit.into().saturating_sub(upload_deposit));
1026
1027 let data_len = data.len() as u32;
1028 let salt_len = salt.len() as u32;
1029 let common = CommonInput {
1030 origin: Origin::from_account_id(instantiate_origin),
1031 value,
1032 data,
1033 gas_limit,
1034 storage_deposit_limit,
1035 debug_message: None,
1036 };
1037
1038 let mut output =
1039 InstantiateInput::<T> { code: WasmCode::Wasm(module), salt }.run_guarded(common);
1040 if let Ok(retval) = &output.result {
1041 if retval.1.did_revert() {
1042 output.result = Err(<Error<T>>::ContractReverted.into());
1043 }
1044 }
1045
1046 output.gas_meter.into_dispatch_result(
1047 output.result.map(|(_address, output)| output),
1048 T::WeightInfo::instantiate_with_code(code_len, data_len, salt_len),
1049 )
1050 }
1051
1052 #[pallet::call_index(8)]
1058 #[pallet::weight(
1059 T::WeightInfo::instantiate(data.len() as u32, salt.len() as u32).saturating_add(*gas_limit)
1060 )]
1061 pub fn instantiate(
1062 origin: OriginFor<T>,
1063 #[pallet::compact] value: BalanceOf<T>,
1064 gas_limit: Weight,
1065 storage_deposit_limit: Option<<BalanceOf<T> as codec::HasCompact>::Type>,
1066 code_hash: CodeHash<T>,
1067 data: Vec<u8>,
1068 salt: Vec<u8>,
1069 ) -> DispatchResultWithPostInfo {
1070 Migration::<T>::ensure_migrated()?;
1071 let origin = T::InstantiateOrigin::ensure_origin(origin)?;
1072 let data_len = data.len() as u32;
1073 let salt_len = salt.len() as u32;
1074 let common = CommonInput {
1075 origin: Origin::from_account_id(origin),
1076 value,
1077 data,
1078 gas_limit,
1079 storage_deposit_limit: storage_deposit_limit.map(Into::into),
1080 debug_message: None,
1081 };
1082 let mut output = InstantiateInput::<T> { code: WasmCode::CodeHash(code_hash), salt }
1083 .run_guarded(common);
1084 if let Ok(retval) = &output.result {
1085 if retval.1.did_revert() {
1086 output.result = Err(<Error<T>>::ContractReverted.into());
1087 }
1088 }
1089 output.gas_meter.into_dispatch_result(
1090 output.result.map(|(_address, output)| output),
1091 T::WeightInfo::instantiate(data_len, salt_len),
1092 )
1093 }
1094
1095 #[pallet::call_index(9)]
1100 #[pallet::weight(T::WeightInfo::migrate().saturating_add(*weight_limit))]
1101 pub fn migrate(origin: OriginFor<T>, weight_limit: Weight) -> DispatchResultWithPostInfo {
1102 use migration::MigrateResult::*;
1103 ensure_signed(origin)?;
1104
1105 let weight_limit = weight_limit.saturating_add(T::WeightInfo::migrate());
1106 let mut meter = WeightMeter::with_limit(weight_limit);
1107 let result = Migration::<T>::migrate(&mut meter);
1108
1109 match result {
1110 Completed => Ok(PostDispatchInfo {
1111 actual_weight: Some(meter.consumed()),
1112 pays_fee: Pays::No,
1113 }),
1114 InProgress { steps_done, .. } if steps_done > 0 => Ok(PostDispatchInfo {
1115 actual_weight: Some(meter.consumed()),
1116 pays_fee: Pays::No,
1117 }),
1118 InProgress { .. } => Ok(PostDispatchInfo {
1119 actual_weight: Some(meter.consumed()),
1120 pays_fee: Pays::Yes,
1121 }),
1122 NoMigrationInProgress | NoMigrationPerformed => {
1123 let err: DispatchError = <Error<T>>::NoMigrationPerformed.into();
1124 Err(err.with_weight(meter.consumed()))
1125 },
1126 }
1127 }
1128 }
1129
1130 #[pallet::event]
1131 pub enum Event<T: Config> {
1132 Instantiated { deployer: T::AccountId, contract: T::AccountId },
1134
1135 Terminated {
1142 contract: T::AccountId,
1144 beneficiary: T::AccountId,
1146 },
1147
1148 CodeStored { code_hash: T::Hash, deposit_held: BalanceOf<T>, uploader: T::AccountId },
1150
1151 ContractEmitted {
1153 contract: T::AccountId,
1155 data: Vec<u8>,
1158 },
1159
1160 CodeRemoved { code_hash: T::Hash, deposit_released: BalanceOf<T>, remover: T::AccountId },
1162
1163 ContractCodeUpdated {
1165 contract: T::AccountId,
1167 new_code_hash: T::Hash,
1169 old_code_hash: T::Hash,
1171 },
1172
1173 Called {
1181 caller: Origin<T>,
1183 contract: T::AccountId,
1185 },
1186
1187 DelegateCalled {
1195 contract: T::AccountId,
1198 code_hash: CodeHash<T>,
1200 },
1201
1202 StorageDepositTransferredAndHeld {
1204 from: T::AccountId,
1205 to: T::AccountId,
1206 amount: BalanceOf<T>,
1207 },
1208
1209 StorageDepositTransferredAndReleased {
1211 from: T::AccountId,
1212 to: T::AccountId,
1213 amount: BalanceOf<T>,
1214 },
1215 }
1216
1217 #[pallet::error]
1218 pub enum Error<T> {
1219 InvalidSchedule,
1221 InvalidCallFlags,
1223 OutOfGas,
1225 OutputBufferTooSmall,
1227 TransferFailed,
1230 MaxCallDepthReached,
1233 ContractNotFound,
1235 CodeTooLarge,
1238 CodeNotFound,
1240 CodeInfoNotFound,
1242 OutOfBounds,
1244 DecodingFailed,
1246 ContractTrapped,
1248 ValueTooLarge,
1250 TerminatedWhileReentrant,
1253 InputForwarded,
1255 RandomSubjectTooLong,
1257 TooManyTopics,
1259 NoChainExtension,
1263 XCMDecodeFailed,
1265 DuplicateContract,
1267 TerminatedInConstructor,
1271 ReentranceDenied,
1276 StateChangeDenied,
1278 StorageDepositNotEnoughFunds,
1280 StorageDepositLimitExhausted,
1282 CodeInUse,
1284 ContractReverted,
1289 CodeRejected,
1298 Indeterministic,
1300 MigrationInProgress,
1302 NoMigrationPerformed,
1304 MaxDelegateDependenciesReached,
1306 DelegateDependencyNotFound,
1308 DelegateDependencyAlreadyExists,
1310 CannotAddSelfAsDelegateDependency,
1312 OutOfTransientStorage,
1314 }
1315
1316 #[pallet::composite_enum]
1318 pub enum HoldReason {
1319 CodeUploadDepositReserve,
1321 StorageDepositReserve,
1323 }
1324
1325 #[pallet::storage]
1327 pub(crate) type PristineCode<T: Config> = StorageMap<_, Identity, CodeHash<T>, CodeVec<T>>;
1328
1329 #[pallet::storage]
1331 pub(crate) type CodeInfoOf<T: Config> = StorageMap<_, Identity, CodeHash<T>, CodeInfo<T>>;
1332
1333 #[pallet::storage]
1356 pub(crate) type Nonce<T: Config> = StorageValue<_, u64, ValueQuery>;
1357
1358 #[pallet::storage]
1362 pub(crate) type ContractInfoOf<T: Config> =
1363 StorageMap<_, Twox64Concat, T::AccountId, ContractInfo<T>>;
1364
1365 #[pallet::storage]
1370 pub(crate) type DeletionQueue<T: Config> = StorageMap<_, Twox64Concat, u32, TrieId>;
1371
1372 #[pallet::storage]
1375 pub(crate) type DeletionQueueCounter<T: Config> =
1376 StorageValue<_, DeletionQueueManager<T>, ValueQuery>;
1377
1378 #[pallet::storage]
1381 pub(crate) type MigrationInProgress<T: Config> =
1382 StorageValue<_, migration::Cursor, OptionQuery>;
1383}
1384
1385#[derive(Clone, Encode, Decode, DecodeWithMemTracking, PartialEq, TypeInfo, DebugNoBound)]
1387pub enum Origin<T: Config> {
1388 Root,
1389 Signed(T::AccountId),
1390}
1391
1392impl<T: Config> Origin<T> {
1393 pub fn from_account_id(account_id: T::AccountId) -> Self {
1395 Origin::Signed(account_id)
1396 }
1397 pub fn from_runtime_origin(o: OriginFor<T>) -> Result<Self, DispatchError> {
1399 match o.into() {
1400 Ok(RawOrigin::Root) => Ok(Self::Root),
1401 Ok(RawOrigin::Signed(t)) => Ok(Self::Signed(t)),
1402 _ => Err(BadOrigin.into()),
1403 }
1404 }
1405 pub fn account_id(&self) -> Result<&T::AccountId, DispatchError> {
1407 match self {
1408 Origin::Signed(id) => Ok(id),
1409 Origin::Root => Err(DispatchError::RootNotAllowed),
1410 }
1411 }
1412}
1413
1414struct CommonInput<'a, T: Config> {
1416 origin: Origin<T>,
1417 value: BalanceOf<T>,
1418 data: Vec<u8>,
1419 gas_limit: Weight,
1420 storage_deposit_limit: Option<BalanceOf<T>>,
1421 debug_message: Option<&'a mut DebugBufferVec<T>>,
1422}
1423
1424struct CallInput<T: Config> {
1426 dest: T::AccountId,
1427 determinism: Determinism,
1428}
1429
1430enum WasmCode<T: Config> {
1432 Wasm(WasmBlob<T>),
1433 CodeHash(CodeHash<T>),
1434}
1435
1436struct InstantiateInput<T: Config> {
1438 code: WasmCode<T>,
1439 salt: Vec<u8>,
1440}
1441
1442#[derive(
1444 Copy, Clone, PartialEq, Eq, Debug, Decode, Encode, MaxEncodedLen, scale_info::TypeInfo,
1445)]
1446pub enum CollectEvents {
1447 UnsafeCollect,
1456 Skip,
1458}
1459
1460#[derive(
1462 Copy, Clone, PartialEq, Eq, Debug, Decode, Encode, MaxEncodedLen, scale_info::TypeInfo,
1463)]
1464pub enum DebugInfo {
1465 UnsafeDebug,
1471 Skip,
1473}
1474
1475struct InternalOutput<T: Config, O> {
1477 gas_meter: GasMeter<T>,
1479 storage_deposit: StorageDeposit<BalanceOf<T>>,
1481 result: Result<O, ExecError>,
1483}
1484
1485environmental!(executing_contract: bool);
1487
1488trait Invokable<T: Config>: Sized {
1491 type Output;
1493
1494 fn run_guarded(self, common: CommonInput<T>) -> InternalOutput<T, Self::Output> {
1503 let gas_limit = common.gas_limit;
1504
1505 if let Err(e) = self.ensure_origin(common.origin.clone()) {
1510 return InternalOutput {
1511 gas_meter: GasMeter::new(gas_limit),
1512 storage_deposit: Default::default(),
1513 result: Err(ExecError { error: e.into(), origin: ErrorOrigin::Caller }),
1514 }
1515 }
1516
1517 executing_contract::using_once(&mut false, || {
1518 executing_contract::with(|f| {
1519 if *f {
1521 return Err(())
1522 }
1523 *f = true;
1525 Ok(())
1526 })
1527 .expect("Returns `Ok` if called within `using_once`. It is syntactically obvious that this is the case; qed")
1528 .map_or_else(
1529 |_| InternalOutput {
1530 gas_meter: GasMeter::new(gas_limit),
1531 storage_deposit: Default::default(),
1532 result: Err(ExecError {
1533 error: <Error<T>>::ReentranceDenied.into(),
1534 origin: ErrorOrigin::Caller,
1535 }),
1536 },
1537 |_| self.run(common, GasMeter::new(gas_limit)),
1539 )
1540 })
1541 }
1542
1543 fn run(self, common: CommonInput<T>, gas_meter: GasMeter<T>)
1548 -> InternalOutput<T, Self::Output>;
1549
1550 fn ensure_origin(&self, origin: Origin<T>) -> Result<(), DispatchError>;
1554}
1555
1556impl<T: Config> Invokable<T> for CallInput<T> {
1557 type Output = ExecReturnValue;
1558
1559 fn run(
1560 self,
1561 common: CommonInput<T>,
1562 mut gas_meter: GasMeter<T>,
1563 ) -> InternalOutput<T, Self::Output> {
1564 let CallInput { dest, determinism } = self;
1565 let CommonInput { origin, value, data, debug_message, .. } = common;
1566 let mut storage_meter =
1567 match StorageMeter::new(&origin, common.storage_deposit_limit, common.value) {
1568 Ok(meter) => meter,
1569 Err(err) =>
1570 return InternalOutput {
1571 result: Err(err.into()),
1572 gas_meter,
1573 storage_deposit: Default::default(),
1574 },
1575 };
1576 let schedule = T::Schedule::get();
1577 let result = ExecStack::<T, WasmBlob<T>>::run_call(
1578 origin.clone(),
1579 dest.clone(),
1580 &mut gas_meter,
1581 &mut storage_meter,
1582 &schedule,
1583 value,
1584 data.clone(),
1585 debug_message,
1586 determinism,
1587 );
1588
1589 match storage_meter.try_into_deposit(&origin) {
1590 Ok(storage_deposit) => InternalOutput { gas_meter, storage_deposit, result },
1591 Err(err) => InternalOutput {
1592 gas_meter,
1593 storage_deposit: Default::default(),
1594 result: Err(err.into()),
1595 },
1596 }
1597 }
1598
1599 fn ensure_origin(&self, _origin: Origin<T>) -> Result<(), DispatchError> {
1600 Ok(())
1601 }
1602}
1603
1604impl<T: Config> Invokable<T> for InstantiateInput<T> {
1605 type Output = (AccountIdOf<T>, ExecReturnValue);
1606
1607 fn run(
1608 self,
1609 common: CommonInput<T>,
1610 mut gas_meter: GasMeter<T>,
1611 ) -> InternalOutput<T, Self::Output> {
1612 let mut storage_deposit = Default::default();
1613 let try_exec = || {
1614 let schedule = T::Schedule::get();
1615 let InstantiateInput { salt, .. } = self;
1616 let CommonInput { origin: contract_origin, .. } = common;
1617 let origin = contract_origin.account_id()?;
1618
1619 let executable = match self.code {
1620 WasmCode::Wasm(module) => module,
1621 WasmCode::CodeHash(code_hash) => WasmBlob::from_storage(code_hash, &mut gas_meter)?,
1622 };
1623
1624 let contract_origin = Origin::from_account_id(origin.clone());
1625 let mut storage_meter =
1626 StorageMeter::new(&contract_origin, common.storage_deposit_limit, common.value)?;
1627 let CommonInput { value, data, debug_message, .. } = common;
1628 let result = ExecStack::<T, WasmBlob<T>>::run_instantiate(
1629 origin.clone(),
1630 executable,
1631 &mut gas_meter,
1632 &mut storage_meter,
1633 &schedule,
1634 value,
1635 data.clone(),
1636 &salt,
1637 debug_message,
1638 );
1639
1640 storage_deposit = storage_meter.try_into_deposit(&contract_origin)?;
1641 result
1642 };
1643 InternalOutput { result: try_exec(), gas_meter, storage_deposit }
1644 }
1645
1646 fn ensure_origin(&self, origin: Origin<T>) -> Result<(), DispatchError> {
1647 match origin {
1648 Origin::Signed(_) => Ok(()),
1649 Origin::Root => Err(DispatchError::RootNotAllowed),
1650 }
1651 }
1652}
1653
1654macro_rules! ensure_no_migration_in_progress {
1655 () => {
1656 if Migration::<T>::in_progress() {
1657 return ContractResult {
1658 gas_consumed: Zero::zero(),
1659 gas_required: Zero::zero(),
1660 storage_deposit: Default::default(),
1661 debug_message: Vec::new(),
1662 result: Err(Error::<T>::MigrationInProgress.into()),
1663 events: None,
1664 }
1665 }
1666 };
1667}
1668
1669impl<T: Config> Pallet<T> {
1670 pub fn bare_call(
1683 origin: T::AccountId,
1684 dest: T::AccountId,
1685 value: BalanceOf<T>,
1686 gas_limit: Weight,
1687 storage_deposit_limit: Option<BalanceOf<T>>,
1688 data: Vec<u8>,
1689 debug: DebugInfo,
1690 collect_events: CollectEvents,
1691 determinism: Determinism,
1692 ) -> ContractExecResult<BalanceOf<T>, EventRecordOf<T>> {
1693 ensure_no_migration_in_progress!();
1694
1695 let mut debug_message = if matches!(debug, DebugInfo::UnsafeDebug) {
1696 Some(DebugBufferVec::<T>::default())
1697 } else {
1698 None
1699 };
1700 let origin = Origin::from_account_id(origin);
1701 let common = CommonInput {
1702 origin,
1703 value,
1704 data,
1705 gas_limit,
1706 storage_deposit_limit,
1707 debug_message: debug_message.as_mut(),
1708 };
1709 let output = CallInput::<T> { dest, determinism }.run_guarded(common);
1710 let events = if matches!(collect_events, CollectEvents::UnsafeCollect) {
1711 Some(System::<T>::read_events_no_consensus().map(|e| *e).collect())
1712 } else {
1713 None
1714 };
1715
1716 ContractExecResult {
1717 result: output.result.map_err(|r| r.error),
1718 gas_consumed: output.gas_meter.gas_consumed(),
1719 gas_required: output.gas_meter.gas_required(),
1720 storage_deposit: output.storage_deposit,
1721 debug_message: debug_message.unwrap_or_default().to_vec(),
1722 events,
1723 }
1724 }
1725
1726 pub fn bare_instantiate(
1741 origin: T::AccountId,
1742 value: BalanceOf<T>,
1743 gas_limit: Weight,
1744 mut storage_deposit_limit: Option<BalanceOf<T>>,
1745 code: Code<CodeHash<T>>,
1746 data: Vec<u8>,
1747 salt: Vec<u8>,
1748 debug: DebugInfo,
1749 collect_events: CollectEvents,
1750 ) -> ContractInstantiateResult<T::AccountId, BalanceOf<T>, EventRecordOf<T>> {
1751 ensure_no_migration_in_progress!();
1752
1753 let mut debug_message = if debug == DebugInfo::UnsafeDebug {
1754 Some(DebugBufferVec::<T>::default())
1755 } else {
1756 None
1757 };
1758 let events = || {
1760 if collect_events == CollectEvents::UnsafeCollect {
1761 Some(System::<T>::read_events_no_consensus().map(|e| *e).collect())
1762 } else {
1763 None
1764 }
1765 };
1766
1767 let (code, upload_deposit): (WasmCode<T>, BalanceOf<T>) = match code {
1768 Code::Upload(code) => {
1769 let result = Self::try_upload_code(
1770 origin.clone(),
1771 code,
1772 storage_deposit_limit.map(Into::into),
1773 Determinism::Enforced,
1774 debug_message.as_mut(),
1775 );
1776
1777 let (module, deposit) = match result {
1778 Ok(result) => result,
1779 Err(error) =>
1780 return ContractResult {
1781 gas_consumed: Zero::zero(),
1782 gas_required: Zero::zero(),
1783 storage_deposit: Default::default(),
1784 debug_message: debug_message.unwrap_or(Default::default()).into(),
1785 result: Err(error),
1786 events: events(),
1787 },
1788 };
1789
1790 storage_deposit_limit =
1791 storage_deposit_limit.map(|l| l.saturating_sub(deposit.into()));
1792 (WasmCode::Wasm(module), deposit)
1793 },
1794 Code::Existing(hash) => (WasmCode::CodeHash(hash), Default::default()),
1795 };
1796
1797 let common = CommonInput {
1798 origin: Origin::from_account_id(origin),
1799 value,
1800 data,
1801 gas_limit,
1802 storage_deposit_limit,
1803 debug_message: debug_message.as_mut(),
1804 };
1805
1806 let output = InstantiateInput::<T> { code, salt }.run_guarded(common);
1807 ContractInstantiateResult {
1808 result: output
1809 .result
1810 .map(|(account_id, result)| InstantiateReturnValue { result, account_id })
1811 .map_err(|e| e.error),
1812 gas_consumed: output.gas_meter.gas_consumed(),
1813 gas_required: output.gas_meter.gas_required(),
1814 storage_deposit: output
1815 .storage_deposit
1816 .saturating_add(&StorageDeposit::Charge(upload_deposit)),
1817 debug_message: debug_message.unwrap_or_default().to_vec(),
1818 events: events(),
1819 }
1820 }
1821
1822 pub fn bare_upload_code(
1827 origin: T::AccountId,
1828 code: Vec<u8>,
1829 storage_deposit_limit: Option<BalanceOf<T>>,
1830 determinism: Determinism,
1831 ) -> CodeUploadResult<CodeHash<T>, BalanceOf<T>> {
1832 Migration::<T>::ensure_migrated()?;
1833 let (module, deposit) =
1834 Self::try_upload_code(origin, code, storage_deposit_limit, determinism, None)?;
1835 Ok(CodeUploadReturnValue { code_hash: *module.code_hash(), deposit })
1836 }
1837
1838 fn try_upload_code(
1840 origin: T::AccountId,
1841 code: Vec<u8>,
1842 storage_deposit_limit: Option<BalanceOf<T>>,
1843 determinism: Determinism,
1844 mut debug_message: Option<&mut DebugBufferVec<T>>,
1845 ) -> Result<(WasmBlob<T>, BalanceOf<T>), DispatchError> {
1846 let schedule = T::Schedule::get();
1847 let mut module =
1848 WasmBlob::from_code(code, &schedule, origin, determinism).map_err(|(err, msg)| {
1849 debug_message.as_mut().map(|d| d.try_extend(msg.bytes()));
1850 err
1851 })?;
1852 let deposit = module.store_code()?;
1853 if let Some(storage_deposit_limit) = storage_deposit_limit {
1854 ensure!(storage_deposit_limit >= deposit, <Error<T>>::StorageDepositLimitExhausted);
1855 }
1856
1857 Ok((module, deposit))
1858 }
1859
1860 pub fn get_storage(address: T::AccountId, key: Vec<u8>) -> GetStorageResult {
1862 if Migration::<T>::in_progress() {
1863 return Err(ContractAccessError::MigrationInProgress)
1864 }
1865 let contract_info =
1866 ContractInfoOf::<T>::get(&address).ok_or(ContractAccessError::DoesntExist)?;
1867
1868 let maybe_value = contract_info.read(
1869 &Key::<T>::try_from_var(key)
1870 .map_err(|_| ContractAccessError::KeyDecodingFailed)?
1871 .into(),
1872 );
1873 Ok(maybe_value)
1874 }
1875
1876 pub fn contract_address(
1881 deploying_address: &T::AccountId,
1882 code_hash: &CodeHash<T>,
1883 input_data: &[u8],
1884 salt: &[u8],
1885 ) -> T::AccountId {
1886 T::AddressGenerator::contract_address(deploying_address, code_hash, input_data, salt)
1887 }
1888
1889 pub fn code_hash(account: &AccountIdOf<T>) -> Option<CodeHash<T>> {
1891 ContractInfo::<T>::load_code_hash(account)
1892 }
1893
1894 #[cfg(feature = "runtime-benchmarks")]
1896 fn store_code_raw(
1897 code: Vec<u8>,
1898 owner: T::AccountId,
1899 ) -> frame_support::dispatch::DispatchResult {
1900 let schedule = T::Schedule::get();
1901 WasmBlob::<T>::from_code_unchecked(code, &schedule, owner)?.store_code()?;
1902 Ok(())
1903 }
1904
1905 fn deposit_event(event: Event<T>) {
1907 <frame_system::Pallet<T>>::deposit_event(<T as Config>::RuntimeEvent::from(event))
1908 }
1909
1910 fn deposit_indexed_event(topics: Vec<T::Hash>, event: Event<T>) {
1912 <frame_system::Pallet<T>>::deposit_event_indexed(
1913 &topics,
1914 <T as Config>::RuntimeEvent::from(event).into(),
1915 )
1916 }
1917
1918 fn min_balance() -> BalanceOf<T> {
1920 <T::Currency as Inspect<AccountIdOf<T>>>::minimum_balance()
1921 }
1922
1923 fn compat_weight_limit(gas_limit: OldWeight) -> Weight {
1928 Weight::from_parts(gas_limit, u64::from(T::MaxCodeLen::get()) * 2)
1929 }
1930}
1931
1932sp_api::decl_runtime_apis! {
1933 #[api_version(2)]
1935 pub trait ContractsApi<AccountId, Balance, BlockNumber, Hash, EventRecord> where
1936 AccountId: Codec,
1937 Balance: Codec,
1938 BlockNumber: Codec,
1939 Hash: Codec,
1940 EventRecord: Codec,
1941 {
1942 fn call(
1946 origin: AccountId,
1947 dest: AccountId,
1948 value: Balance,
1949 gas_limit: Option<Weight>,
1950 storage_deposit_limit: Option<Balance>,
1951 input_data: Vec<u8>,
1952 ) -> ContractExecResult<Balance, EventRecord>;
1953
1954 fn instantiate(
1958 origin: AccountId,
1959 value: Balance,
1960 gas_limit: Option<Weight>,
1961 storage_deposit_limit: Option<Balance>,
1962 code: Code<Hash>,
1963 data: Vec<u8>,
1964 salt: Vec<u8>,
1965 ) -> ContractInstantiateResult<AccountId, Balance, EventRecord>;
1966
1967 fn upload_code(
1971 origin: AccountId,
1972 code: Vec<u8>,
1973 storage_deposit_limit: Option<Balance>,
1974 determinism: Determinism,
1975 ) -> CodeUploadResult<Hash, Balance>;
1976
1977 fn get_storage(
1983 address: AccountId,
1984 key: Vec<u8>,
1985 ) -> GetStorageResult;
1986 }
1987}