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, 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, DefaultNoBound, RuntimeDebugNoBound,
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, RuntimeDebug,
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 type RuntimeEvent: From<Event<Self>> + IsType<<Self as frame_system::Config>::RuntimeEvent>;
280
281 #[pallet::no_default_bounds]
283 type RuntimeCall: Dispatchable<RuntimeOrigin = Self::RuntimeOrigin, PostInfo = PostDispatchInfo>
284 + GetDispatchInfo
285 + codec::Decode
286 + IsType<<Self as frame_system::Config>::RuntimeCall>;
287
288 #[pallet::no_default_bounds]
290 type RuntimeHoldReason: From<HoldReason>;
291
292 #[pallet::no_default_bounds]
315 type CallFilter: Contains<<Self as frame_system::Config>::RuntimeCall>;
316
317 #[pallet::no_default_bounds]
320 type WeightPrice: Convert<Weight, BalanceOf<Self>>;
321
322 type WeightInfo: WeightInfo;
325
326 #[pallet::no_default_bounds]
328 type ChainExtension: chain_extension::ChainExtension<Self> + Default;
329
330 #[pallet::constant]
332 #[pallet::no_default]
333 type Schedule: Get<Schedule<Self>>;
334
335 #[pallet::no_default]
344 type CallStack: Array<Item = Frame<Self>>;
345
346 #[pallet::constant]
352 #[pallet::no_default_bounds]
353 type DepositPerByte: Get<BalanceOf<Self>>;
354
355 #[pallet::constant]
357 #[pallet::no_default_bounds]
358 type DefaultDepositLimit: Get<BalanceOf<Self>>;
359
360 #[pallet::constant]
366 #[pallet::no_default_bounds]
367 type DepositPerItem: Get<BalanceOf<Self>>;
368
369 #[pallet::constant]
374 type CodeHashLockupDepositPercent: Get<Perbill>;
375
376 #[pallet::no_default_bounds]
378 type AddressGenerator: AddressGenerator<Self>;
379
380 #[pallet::constant]
386 type MaxCodeLen: Get<u32>;
387
388 #[pallet::constant]
390 type MaxStorageKeyLen: Get<u32>;
391
392 #[pallet::constant]
395 type MaxTransientStorageSize: Get<u32>;
396
397 #[pallet::constant]
400 type MaxDelegateDependencies: Get<u32>;
401
402 #[pallet::constant]
412 type UnsafeUnstableInterface: Get<bool>;
413
414 #[pallet::constant]
416 type MaxDebugBufferLen: Get<u32>;
417
418 #[pallet::no_default_bounds]
423 type UploadOrigin: EnsureOrigin<Self::RuntimeOrigin, Success = Self::AccountId>;
424
425 #[pallet::no_default_bounds]
436 type InstantiateOrigin: EnsureOrigin<Self::RuntimeOrigin, Success = Self::AccountId>;
437
438 type Migrations: MigrateSequence;
456
457 #[pallet::no_default_bounds]
462 type Debug: Debugger<Self>;
463
464 #[pallet::constant]
469 #[pallet::no_default_bounds]
470 type Environment: Get<Environment<Self>>;
471
472 #[pallet::constant]
476 #[pallet::no_default_bounds]
477 type ApiVersion: Get<ApiVersion>;
478
479 #[pallet::no_default_bounds]
482 type Xcm: xcm_builder::Controller<
483 OriginFor<Self>,
484 <Self as frame_system::Config>::RuntimeCall,
485 BlockNumberFor<Self>,
486 >;
487 }
488
489 pub mod config_preludes {
491 use super::*;
492 use frame_support::{
493 derive_impl,
494 traits::{ConstBool, ConstU32},
495 };
496 use frame_system::EnsureSigned;
497 use sp_core::parameter_types;
498
499 type AccountId = sp_runtime::AccountId32;
500 type Balance = u64;
501 const UNITS: Balance = 10_000_000_000;
502 const CENTS: Balance = UNITS / 100;
503
504 const fn deposit(items: u32, bytes: u32) -> Balance {
505 items as Balance * 1 * CENTS + (bytes as Balance) * 1 * CENTS
506 }
507
508 parameter_types! {
509 pub const DepositPerItem: Balance = deposit(1, 0);
510 pub const DepositPerByte: Balance = deposit(0, 1);
511 pub const DefaultDepositLimit: Balance = deposit(1024, 1024 * 1024);
512 pub const CodeHashLockupDepositPercent: Perbill = Perbill::from_percent(0);
513 pub const MaxDelegateDependencies: u32 = 32;
514 }
515
516 pub struct TestDefaultConfig;
518
519 impl<Output, BlockNumber> Randomness<Output, BlockNumber> for TestDefaultConfig {
520 fn random(_subject: &[u8]) -> (Output, BlockNumber) {
521 unimplemented!("No default `random` implementation in `TestDefaultConfig`, provide a custom `T::Randomness` type.")
522 }
523 }
524
525 impl Time for TestDefaultConfig {
526 type Moment = u64;
527 fn now() -> Self::Moment {
528 unimplemented!("No default `now` implementation in `TestDefaultConfig` provide a custom `T::Time` type.")
529 }
530 }
531
532 impl<T: From<u64>> Convert<Weight, T> for TestDefaultConfig {
533 fn convert(w: Weight) -> T {
534 w.ref_time().into()
535 }
536 }
537
538 #[derive_impl(frame_system::config_preludes::TestDefaultConfig, no_aggregated_types)]
539 impl frame_system::DefaultConfig for TestDefaultConfig {}
540
541 #[frame_support::register_default_impl(TestDefaultConfig)]
542 impl DefaultConfig for TestDefaultConfig {
543 #[inject_runtime_type]
544 type RuntimeEvent = ();
545
546 #[inject_runtime_type]
547 type RuntimeHoldReason = ();
548
549 #[inject_runtime_type]
550 type RuntimeCall = ();
551
552 type AddressGenerator = DefaultAddressGenerator;
553 type CallFilter = ();
554 type ChainExtension = ();
555 type CodeHashLockupDepositPercent = CodeHashLockupDepositPercent;
556 type DefaultDepositLimit = DefaultDepositLimit;
557 type DepositPerByte = DepositPerByte;
558 type DepositPerItem = DepositPerItem;
559 type MaxCodeLen = ConstU32<{ 123 * 1024 }>;
560 type MaxDebugBufferLen = ConstU32<{ 2 * 1024 * 1024 }>;
561 type MaxDelegateDependencies = MaxDelegateDependencies;
562 type MaxStorageKeyLen = ConstU32<128>;
563 type MaxTransientStorageSize = ConstU32<{ 1 * 1024 * 1024 }>;
564 type Migrations = ();
565 type Time = Self;
566 type Randomness = Self;
567 type UnsafeUnstableInterface = ConstBool<true>;
568 type UploadOrigin = EnsureSigned<AccountId>;
569 type InstantiateOrigin = EnsureSigned<AccountId>;
570 type WeightInfo = ();
571 type WeightPrice = Self;
572 type Debug = ();
573 type Environment = ();
574 type ApiVersion = ();
575 type Xcm = ();
576 }
577 }
578
579 #[pallet::hooks]
580 impl<T: Config> Hooks<BlockNumberFor<T>> for Pallet<T> {
581 fn on_idle(_block: BlockNumberFor<T>, limit: Weight) -> Weight {
582 use migration::MigrateResult::*;
583 let mut meter = WeightMeter::with_limit(limit);
584
585 loop {
586 match Migration::<T>::migrate(&mut meter) {
587 NoMigrationPerformed | InProgress { steps_done: 0 } => return meter.consumed(),
590 InProgress { .. } => continue,
592 Completed | NoMigrationInProgress => break,
595 }
596 }
597
598 ContractInfo::<T>::process_deletion_queue_batch(&mut meter);
599 meter.consumed()
600 }
601
602 fn integrity_test() {
603 Migration::<T>::integrity_test();
604
605 let max_runtime_mem: u32 = T::Schedule::get().limits.runtime_memory;
607 const MAX_STACK_SIZE: u32 = 1024 * 1024;
610 let max_heap_size = T::Schedule::get().limits.max_memory_size();
612 let max_call_depth = u32::try_from(T::CallStack::size().saturating_add(1))
614 .expect("CallStack size is too big");
615 let max_transient_storage_size = T::MaxTransientStorageSize::get()
618 .checked_mul(2)
619 .expect("MaxTransientStorageSize is too large");
620 let code_len_limit = max_runtime_mem
650 .saturating_div(2)
651 .saturating_sub(max_transient_storage_size)
652 .saturating_div(max_call_depth)
653 .saturating_sub(max_heap_size)
654 .saturating_sub(MAX_STACK_SIZE)
655 .saturating_div(17 * 4);
656
657 assert!(
658 T::MaxCodeLen::get() < code_len_limit,
659 "Given `CallStack` height {:?}, `MaxCodeLen` should be set less than {:?} \
660 (current value is {:?}), to avoid possible runtime oom issues.",
661 max_call_depth,
662 code_len_limit,
663 T::MaxCodeLen::get(),
664 );
665
666 const MIN_DEBUG_BUF_SIZE: u32 = 256;
668 assert!(
669 T::MaxDebugBufferLen::get() > MIN_DEBUG_BUF_SIZE,
670 "Debug buffer should have minimum size of {} (current setting is {})",
671 MIN_DEBUG_BUF_SIZE,
672 T::MaxDebugBufferLen::get(),
673 );
674
675 let max_block_ref_time = T::BlockWeights::get()
681 .get(DispatchClass::Normal)
682 .max_total
683 .unwrap_or_else(|| T::BlockWeights::get().max_block)
684 .ref_time();
685 let max_payload_size = T::Schedule::get().limits.payload_len;
686 let max_key_size =
687 Key::<T>::try_from_var(alloc::vec![0u8; T::MaxStorageKeyLen::get() as usize])
688 .expect("Key of maximal size shall be created")
689 .hash()
690 .len() as u32;
691
692 let max_storage_size: u32 = ((max_block_ref_time /
695 (<RuntimeCosts as gas::Token<T>>::weight(&RuntimeCosts::SetStorage {
696 new_bytes: max_payload_size,
697 old_bytes: 0,
698 })
699 .ref_time()))
700 .saturating_mul(max_payload_size.saturating_add(max_key_size) as u64))
701 .try_into()
702 .expect("Storage size too big");
703
704 let max_validator_runtime_mem: u32 = T::Schedule::get().limits.validator_runtime_memory;
705 let storage_size_limit = max_validator_runtime_mem.saturating_sub(max_runtime_mem) / 2;
706
707 assert!(
708 max_storage_size < storage_size_limit,
709 "Maximal storage size {} exceeds the storage limit {}",
710 max_storage_size,
711 storage_size_limit
712 );
713
714 let max_events_size: u32 = ((max_block_ref_time /
718 (<RuntimeCosts as gas::Token<T>>::weight(&RuntimeCosts::DepositEvent {
719 num_topic: 0,
720 len: max_payload_size,
721 })
722 .ref_time()))
723 .saturating_mul(max_payload_size as u64))
724 .try_into()
725 .expect("Events size too big");
726
727 assert!(
728 max_events_size < storage_size_limit,
729 "Maximal events size {} exceeds the events limit {}",
730 max_events_size,
731 storage_size_limit
732 );
733 }
734 }
735
736 #[pallet::call]
737 impl<T: Config> Pallet<T>
738 where
739 <BalanceOf<T> as HasCompact>::Type: Clone + Eq + PartialEq + Debug + TypeInfo + Encode,
740 {
741 #[pallet::call_index(0)]
743 #[pallet::weight(T::WeightInfo::call().saturating_add(<Pallet<T>>::compat_weight_limit(*gas_limit)))]
744 #[allow(deprecated)]
745 #[deprecated(note = "1D weight is used in this extrinsic, please migrate to `call`")]
746 pub fn call_old_weight(
747 origin: OriginFor<T>,
748 dest: AccountIdLookupOf<T>,
749 #[pallet::compact] value: BalanceOf<T>,
750 #[pallet::compact] gas_limit: OldWeight,
751 storage_deposit_limit: Option<<BalanceOf<T> as codec::HasCompact>::Type>,
752 data: Vec<u8>,
753 ) -> DispatchResultWithPostInfo {
754 Self::call(
755 origin,
756 dest,
757 value,
758 <Pallet<T>>::compat_weight_limit(gas_limit),
759 storage_deposit_limit,
760 data,
761 )
762 }
763
764 #[pallet::call_index(1)]
766 #[pallet::weight(
767 T::WeightInfo::instantiate_with_code(code.len() as u32, data.len() as u32, salt.len() as u32)
768 .saturating_add(<Pallet<T>>::compat_weight_limit(*gas_limit))
769 )]
770 #[allow(deprecated)]
771 #[deprecated(
772 note = "1D weight is used in this extrinsic, please migrate to `instantiate_with_code`"
773 )]
774 pub fn instantiate_with_code_old_weight(
775 origin: OriginFor<T>,
776 #[pallet::compact] value: BalanceOf<T>,
777 #[pallet::compact] gas_limit: OldWeight,
778 storage_deposit_limit: Option<<BalanceOf<T> as codec::HasCompact>::Type>,
779 code: Vec<u8>,
780 data: Vec<u8>,
781 salt: Vec<u8>,
782 ) -> DispatchResultWithPostInfo {
783 Self::instantiate_with_code(
784 origin,
785 value,
786 <Pallet<T>>::compat_weight_limit(gas_limit),
787 storage_deposit_limit,
788 code,
789 data,
790 salt,
791 )
792 }
793
794 #[pallet::call_index(2)]
796 #[pallet::weight(
797 T::WeightInfo::instantiate(data.len() as u32, salt.len() as u32).saturating_add(<Pallet<T>>::compat_weight_limit(*gas_limit))
798 )]
799 #[allow(deprecated)]
800 #[deprecated(note = "1D weight is used in this extrinsic, please migrate to `instantiate`")]
801 pub fn instantiate_old_weight(
802 origin: OriginFor<T>,
803 #[pallet::compact] value: BalanceOf<T>,
804 #[pallet::compact] gas_limit: OldWeight,
805 storage_deposit_limit: Option<<BalanceOf<T> as codec::HasCompact>::Type>,
806 code_hash: CodeHash<T>,
807 data: Vec<u8>,
808 salt: Vec<u8>,
809 ) -> DispatchResultWithPostInfo {
810 Self::instantiate(
811 origin,
812 value,
813 <Pallet<T>>::compat_weight_limit(gas_limit),
814 storage_deposit_limit,
815 code_hash,
816 data,
817 salt,
818 )
819 }
820
821 #[pallet::call_index(3)]
846 #[pallet::weight(
847 match determinism {
848 Determinism::Enforced => T::WeightInfo::upload_code_determinism_enforced(code.len() as u32),
849 Determinism::Relaxed => T::WeightInfo::upload_code_determinism_relaxed(code.len() as u32),
850 }
851 )]
852 pub fn upload_code(
853 origin: OriginFor<T>,
854 code: Vec<u8>,
855 storage_deposit_limit: Option<<BalanceOf<T> as codec::HasCompact>::Type>,
856 determinism: Determinism,
857 ) -> DispatchResult {
858 Migration::<T>::ensure_migrated()?;
859 let origin = T::UploadOrigin::ensure_origin(origin)?;
860 Self::bare_upload_code(origin, code, storage_deposit_limit.map(Into::into), determinism)
861 .map(|_| ())
862 }
863
864 #[pallet::call_index(4)]
869 #[pallet::weight(T::WeightInfo::remove_code())]
870 pub fn remove_code(
871 origin: OriginFor<T>,
872 code_hash: CodeHash<T>,
873 ) -> DispatchResultWithPostInfo {
874 Migration::<T>::ensure_migrated()?;
875 let origin = ensure_signed(origin)?;
876 <WasmBlob<T>>::remove(&origin, code_hash)?;
877 Ok(Pays::No.into())
879 }
880
881 #[pallet::call_index(5)]
892 #[pallet::weight(T::WeightInfo::set_code())]
893 pub fn set_code(
894 origin: OriginFor<T>,
895 dest: AccountIdLookupOf<T>,
896 code_hash: CodeHash<T>,
897 ) -> DispatchResult {
898 Migration::<T>::ensure_migrated()?;
899 ensure_root(origin)?;
900 let dest = T::Lookup::lookup(dest)?;
901 <ContractInfoOf<T>>::try_mutate(&dest, |contract| {
902 let contract = if let Some(contract) = contract {
903 contract
904 } else {
905 return Err(<Error<T>>::ContractNotFound.into())
906 };
907 <ExecStack<T, WasmBlob<T>>>::increment_refcount(code_hash)?;
908 <ExecStack<T, WasmBlob<T>>>::decrement_refcount(contract.code_hash);
909 Self::deposit_event(Event::ContractCodeUpdated {
910 contract: dest.clone(),
911 new_code_hash: code_hash,
912 old_code_hash: contract.code_hash,
913 });
914 contract.code_hash = code_hash;
915 Ok(())
916 })
917 }
918
919 #[pallet::call_index(6)]
936 #[pallet::weight(T::WeightInfo::call().saturating_add(*gas_limit))]
937 pub fn call(
938 origin: OriginFor<T>,
939 dest: AccountIdLookupOf<T>,
940 #[pallet::compact] value: BalanceOf<T>,
941 gas_limit: Weight,
942 storage_deposit_limit: Option<<BalanceOf<T> as codec::HasCompact>::Type>,
943 data: Vec<u8>,
944 ) -> DispatchResultWithPostInfo {
945 Migration::<T>::ensure_migrated()?;
946 let common = CommonInput {
947 origin: Origin::from_runtime_origin(origin)?,
948 value,
949 data,
950 gas_limit: gas_limit.into(),
951 storage_deposit_limit: storage_deposit_limit.map(Into::into),
952 debug_message: None,
953 };
954 let dest = T::Lookup::lookup(dest)?;
955 let mut output =
956 CallInput::<T> { dest, determinism: Determinism::Enforced }.run_guarded(common);
957 if let Ok(retval) = &output.result {
958 if retval.did_revert() {
959 output.result = Err(<Error<T>>::ContractReverted.into());
960 }
961 }
962 output.gas_meter.into_dispatch_result(output.result, T::WeightInfo::call())
963 }
964
965 #[pallet::call_index(7)]
991 #[pallet::weight(
992 T::WeightInfo::instantiate_with_code(code.len() as u32, data.len() as u32, salt.len() as u32)
993 .saturating_add(*gas_limit)
994 )]
995 pub fn instantiate_with_code(
996 origin: OriginFor<T>,
997 #[pallet::compact] value: BalanceOf<T>,
998 gas_limit: Weight,
999 storage_deposit_limit: Option<<BalanceOf<T> as codec::HasCompact>::Type>,
1000 code: Vec<u8>,
1001 data: Vec<u8>,
1002 salt: Vec<u8>,
1003 ) -> DispatchResultWithPostInfo {
1004 Migration::<T>::ensure_migrated()?;
1005
1006 let upload_origin = T::UploadOrigin::ensure_origin(origin.clone())?;
1010 let instantiate_origin = T::InstantiateOrigin::ensure_origin(origin)?;
1011
1012 let code_len = code.len() as u32;
1013
1014 let (module, upload_deposit) = Self::try_upload_code(
1015 upload_origin,
1016 code,
1017 storage_deposit_limit.clone().map(Into::into),
1018 Determinism::Enforced,
1019 None,
1020 )?;
1021
1022 let storage_deposit_limit =
1024 storage_deposit_limit.map(|limit| limit.into().saturating_sub(upload_deposit));
1025
1026 let data_len = data.len() as u32;
1027 let salt_len = salt.len() as u32;
1028 let common = CommonInput {
1029 origin: Origin::from_account_id(instantiate_origin),
1030 value,
1031 data,
1032 gas_limit,
1033 storage_deposit_limit,
1034 debug_message: None,
1035 };
1036
1037 let mut output =
1038 InstantiateInput::<T> { code: WasmCode::Wasm(module), salt }.run_guarded(common);
1039 if let Ok(retval) = &output.result {
1040 if retval.1.did_revert() {
1041 output.result = Err(<Error<T>>::ContractReverted.into());
1042 }
1043 }
1044
1045 output.gas_meter.into_dispatch_result(
1046 output.result.map(|(_address, output)| output),
1047 T::WeightInfo::instantiate_with_code(code_len, data_len, salt_len),
1048 )
1049 }
1050
1051 #[pallet::call_index(8)]
1057 #[pallet::weight(
1058 T::WeightInfo::instantiate(data.len() as u32, salt.len() as u32).saturating_add(*gas_limit)
1059 )]
1060 pub fn instantiate(
1061 origin: OriginFor<T>,
1062 #[pallet::compact] value: BalanceOf<T>,
1063 gas_limit: Weight,
1064 storage_deposit_limit: Option<<BalanceOf<T> as codec::HasCompact>::Type>,
1065 code_hash: CodeHash<T>,
1066 data: Vec<u8>,
1067 salt: Vec<u8>,
1068 ) -> DispatchResultWithPostInfo {
1069 Migration::<T>::ensure_migrated()?;
1070 let origin = T::InstantiateOrigin::ensure_origin(origin)?;
1071 let data_len = data.len() as u32;
1072 let salt_len = salt.len() as u32;
1073 let common = CommonInput {
1074 origin: Origin::from_account_id(origin),
1075 value,
1076 data,
1077 gas_limit,
1078 storage_deposit_limit: storage_deposit_limit.map(Into::into),
1079 debug_message: None,
1080 };
1081 let mut output = InstantiateInput::<T> { code: WasmCode::CodeHash(code_hash), salt }
1082 .run_guarded(common);
1083 if let Ok(retval) = &output.result {
1084 if retval.1.did_revert() {
1085 output.result = Err(<Error<T>>::ContractReverted.into());
1086 }
1087 }
1088 output.gas_meter.into_dispatch_result(
1089 output.result.map(|(_address, output)| output),
1090 T::WeightInfo::instantiate(data_len, salt_len),
1091 )
1092 }
1093
1094 #[pallet::call_index(9)]
1099 #[pallet::weight(T::WeightInfo::migrate().saturating_add(*weight_limit))]
1100 pub fn migrate(origin: OriginFor<T>, weight_limit: Weight) -> DispatchResultWithPostInfo {
1101 use migration::MigrateResult::*;
1102 ensure_signed(origin)?;
1103
1104 let weight_limit = weight_limit.saturating_add(T::WeightInfo::migrate());
1105 let mut meter = WeightMeter::with_limit(weight_limit);
1106 let result = Migration::<T>::migrate(&mut meter);
1107
1108 match result {
1109 Completed => Ok(PostDispatchInfo {
1110 actual_weight: Some(meter.consumed()),
1111 pays_fee: Pays::No,
1112 }),
1113 InProgress { steps_done, .. } if steps_done > 0 => Ok(PostDispatchInfo {
1114 actual_weight: Some(meter.consumed()),
1115 pays_fee: Pays::No,
1116 }),
1117 InProgress { .. } => Ok(PostDispatchInfo {
1118 actual_weight: Some(meter.consumed()),
1119 pays_fee: Pays::Yes,
1120 }),
1121 NoMigrationInProgress | NoMigrationPerformed => {
1122 let err: DispatchError = <Error<T>>::NoMigrationPerformed.into();
1123 Err(err.with_weight(meter.consumed()))
1124 },
1125 }
1126 }
1127 }
1128
1129 #[pallet::event]
1130 pub enum Event<T: Config> {
1131 Instantiated { deployer: T::AccountId, contract: T::AccountId },
1133
1134 Terminated {
1141 contract: T::AccountId,
1143 beneficiary: T::AccountId,
1145 },
1146
1147 CodeStored { code_hash: T::Hash, deposit_held: BalanceOf<T>, uploader: T::AccountId },
1149
1150 ContractEmitted {
1152 contract: T::AccountId,
1154 data: Vec<u8>,
1157 },
1158
1159 CodeRemoved { code_hash: T::Hash, deposit_released: BalanceOf<T>, remover: T::AccountId },
1161
1162 ContractCodeUpdated {
1164 contract: T::AccountId,
1166 new_code_hash: T::Hash,
1168 old_code_hash: T::Hash,
1170 },
1171
1172 Called {
1180 caller: Origin<T>,
1182 contract: T::AccountId,
1184 },
1185
1186 DelegateCalled {
1194 contract: T::AccountId,
1197 code_hash: CodeHash<T>,
1199 },
1200
1201 StorageDepositTransferredAndHeld {
1203 from: T::AccountId,
1204 to: T::AccountId,
1205 amount: BalanceOf<T>,
1206 },
1207
1208 StorageDepositTransferredAndReleased {
1210 from: T::AccountId,
1211 to: T::AccountId,
1212 amount: BalanceOf<T>,
1213 },
1214 }
1215
1216 #[pallet::error]
1217 pub enum Error<T> {
1218 InvalidSchedule,
1220 InvalidCallFlags,
1222 OutOfGas,
1224 OutputBufferTooSmall,
1226 TransferFailed,
1229 MaxCallDepthReached,
1232 ContractNotFound,
1234 CodeTooLarge,
1237 CodeNotFound,
1239 CodeInfoNotFound,
1241 OutOfBounds,
1243 DecodingFailed,
1245 ContractTrapped,
1247 ValueTooLarge,
1249 TerminatedWhileReentrant,
1252 InputForwarded,
1254 RandomSubjectTooLong,
1256 TooManyTopics,
1258 NoChainExtension,
1262 XCMDecodeFailed,
1264 DuplicateContract,
1266 TerminatedInConstructor,
1270 ReentranceDenied,
1275 StateChangeDenied,
1277 StorageDepositNotEnoughFunds,
1279 StorageDepositLimitExhausted,
1281 CodeInUse,
1283 ContractReverted,
1288 CodeRejected,
1297 Indeterministic,
1299 MigrationInProgress,
1301 NoMigrationPerformed,
1303 MaxDelegateDependenciesReached,
1305 DelegateDependencyNotFound,
1307 DelegateDependencyAlreadyExists,
1309 CannotAddSelfAsDelegateDependency,
1311 OutOfTransientStorage,
1313 }
1314
1315 #[pallet::composite_enum]
1317 pub enum HoldReason {
1318 CodeUploadDepositReserve,
1320 StorageDepositReserve,
1322 }
1323
1324 #[pallet::storage]
1326 pub(crate) type PristineCode<T: Config> = StorageMap<_, Identity, CodeHash<T>, CodeVec<T>>;
1327
1328 #[pallet::storage]
1330 pub(crate) type CodeInfoOf<T: Config> = StorageMap<_, Identity, CodeHash<T>, CodeInfo<T>>;
1331
1332 #[pallet::storage]
1355 pub(crate) type Nonce<T: Config> = StorageValue<_, u64, ValueQuery>;
1356
1357 #[pallet::storage]
1361 pub(crate) type ContractInfoOf<T: Config> =
1362 StorageMap<_, Twox64Concat, T::AccountId, ContractInfo<T>>;
1363
1364 #[pallet::storage]
1369 pub(crate) type DeletionQueue<T: Config> = StorageMap<_, Twox64Concat, u32, TrieId>;
1370
1371 #[pallet::storage]
1374 pub(crate) type DeletionQueueCounter<T: Config> =
1375 StorageValue<_, DeletionQueueManager<T>, ValueQuery>;
1376
1377 #[pallet::storage]
1380 pub(crate) type MigrationInProgress<T: Config> =
1381 StorageValue<_, migration::Cursor, OptionQuery>;
1382}
1383
1384#[derive(Clone, Encode, Decode, PartialEq, TypeInfo, RuntimeDebugNoBound)]
1386pub enum Origin<T: Config> {
1387 Root,
1388 Signed(T::AccountId),
1389}
1390
1391impl<T: Config> Origin<T> {
1392 pub fn from_account_id(account_id: T::AccountId) -> Self {
1394 Origin::Signed(account_id)
1395 }
1396 pub fn from_runtime_origin(o: OriginFor<T>) -> Result<Self, DispatchError> {
1398 match o.into() {
1399 Ok(RawOrigin::Root) => Ok(Self::Root),
1400 Ok(RawOrigin::Signed(t)) => Ok(Self::Signed(t)),
1401 _ => Err(BadOrigin.into()),
1402 }
1403 }
1404 pub fn account_id(&self) -> Result<&T::AccountId, DispatchError> {
1406 match self {
1407 Origin::Signed(id) => Ok(id),
1408 Origin::Root => Err(DispatchError::RootNotAllowed),
1409 }
1410 }
1411}
1412
1413struct CommonInput<'a, T: Config> {
1415 origin: Origin<T>,
1416 value: BalanceOf<T>,
1417 data: Vec<u8>,
1418 gas_limit: Weight,
1419 storage_deposit_limit: Option<BalanceOf<T>>,
1420 debug_message: Option<&'a mut DebugBufferVec<T>>,
1421}
1422
1423struct CallInput<T: Config> {
1425 dest: T::AccountId,
1426 determinism: Determinism,
1427}
1428
1429enum WasmCode<T: Config> {
1431 Wasm(WasmBlob<T>),
1432 CodeHash(CodeHash<T>),
1433}
1434
1435struct InstantiateInput<T: Config> {
1437 code: WasmCode<T>,
1438 salt: Vec<u8>,
1439}
1440
1441#[derive(
1443 Copy, Clone, PartialEq, Eq, RuntimeDebug, Decode, Encode, MaxEncodedLen, scale_info::TypeInfo,
1444)]
1445pub enum CollectEvents {
1446 UnsafeCollect,
1455 Skip,
1457}
1458
1459#[derive(
1461 Copy, Clone, PartialEq, Eq, RuntimeDebug, Decode, Encode, MaxEncodedLen, scale_info::TypeInfo,
1462)]
1463pub enum DebugInfo {
1464 UnsafeDebug,
1470 Skip,
1472}
1473
1474struct InternalOutput<T: Config, O> {
1476 gas_meter: GasMeter<T>,
1478 storage_deposit: StorageDeposit<BalanceOf<T>>,
1480 result: Result<O, ExecError>,
1482}
1483
1484environmental!(executing_contract: bool);
1486
1487trait Invokable<T: Config>: Sized {
1490 type Output;
1492
1493 fn run_guarded(self, common: CommonInput<T>) -> InternalOutput<T, Self::Output> {
1502 let gas_limit = common.gas_limit;
1503
1504 if let Err(e) = self.ensure_origin(common.origin.clone()) {
1509 return InternalOutput {
1510 gas_meter: GasMeter::new(gas_limit),
1511 storage_deposit: Default::default(),
1512 result: Err(ExecError { error: e.into(), origin: ErrorOrigin::Caller }),
1513 }
1514 }
1515
1516 executing_contract::using_once(&mut false, || {
1517 executing_contract::with(|f| {
1518 if *f {
1520 return Err(())
1521 }
1522 *f = true;
1524 Ok(())
1525 })
1526 .expect("Returns `Ok` if called within `using_once`. It is syntactically obvious that this is the case; qed")
1527 .map_or_else(
1528 |_| InternalOutput {
1529 gas_meter: GasMeter::new(gas_limit),
1530 storage_deposit: Default::default(),
1531 result: Err(ExecError {
1532 error: <Error<T>>::ReentranceDenied.into(),
1533 origin: ErrorOrigin::Caller,
1534 }),
1535 },
1536 |_| self.run(common, GasMeter::new(gas_limit)),
1538 )
1539 })
1540 }
1541
1542 fn run(self, common: CommonInput<T>, gas_meter: GasMeter<T>)
1547 -> InternalOutput<T, Self::Output>;
1548
1549 fn ensure_origin(&self, origin: Origin<T>) -> Result<(), DispatchError>;
1553}
1554
1555impl<T: Config> Invokable<T> for CallInput<T> {
1556 type Output = ExecReturnValue;
1557
1558 fn run(
1559 self,
1560 common: CommonInput<T>,
1561 mut gas_meter: GasMeter<T>,
1562 ) -> InternalOutput<T, Self::Output> {
1563 let CallInput { dest, determinism } = self;
1564 let CommonInput { origin, value, data, debug_message, .. } = common;
1565 let mut storage_meter =
1566 match StorageMeter::new(&origin, common.storage_deposit_limit, common.value) {
1567 Ok(meter) => meter,
1568 Err(err) =>
1569 return InternalOutput {
1570 result: Err(err.into()),
1571 gas_meter,
1572 storage_deposit: Default::default(),
1573 },
1574 };
1575 let schedule = T::Schedule::get();
1576 let result = ExecStack::<T, WasmBlob<T>>::run_call(
1577 origin.clone(),
1578 dest.clone(),
1579 &mut gas_meter,
1580 &mut storage_meter,
1581 &schedule,
1582 value,
1583 data.clone(),
1584 debug_message,
1585 determinism,
1586 );
1587
1588 match storage_meter.try_into_deposit(&origin) {
1589 Ok(storage_deposit) => InternalOutput { gas_meter, storage_deposit, result },
1590 Err(err) => InternalOutput {
1591 gas_meter,
1592 storage_deposit: Default::default(),
1593 result: Err(err.into()),
1594 },
1595 }
1596 }
1597
1598 fn ensure_origin(&self, _origin: Origin<T>) -> Result<(), DispatchError> {
1599 Ok(())
1600 }
1601}
1602
1603impl<T: Config> Invokable<T> for InstantiateInput<T> {
1604 type Output = (AccountIdOf<T>, ExecReturnValue);
1605
1606 fn run(
1607 self,
1608 common: CommonInput<T>,
1609 mut gas_meter: GasMeter<T>,
1610 ) -> InternalOutput<T, Self::Output> {
1611 let mut storage_deposit = Default::default();
1612 let try_exec = || {
1613 let schedule = T::Schedule::get();
1614 let InstantiateInput { salt, .. } = self;
1615 let CommonInput { origin: contract_origin, .. } = common;
1616 let origin = contract_origin.account_id()?;
1617
1618 let executable = match self.code {
1619 WasmCode::Wasm(module) => module,
1620 WasmCode::CodeHash(code_hash) => WasmBlob::from_storage(code_hash, &mut gas_meter)?,
1621 };
1622
1623 let contract_origin = Origin::from_account_id(origin.clone());
1624 let mut storage_meter =
1625 StorageMeter::new(&contract_origin, common.storage_deposit_limit, common.value)?;
1626 let CommonInput { value, data, debug_message, .. } = common;
1627 let result = ExecStack::<T, WasmBlob<T>>::run_instantiate(
1628 origin.clone(),
1629 executable,
1630 &mut gas_meter,
1631 &mut storage_meter,
1632 &schedule,
1633 value,
1634 data.clone(),
1635 &salt,
1636 debug_message,
1637 );
1638
1639 storage_deposit = storage_meter.try_into_deposit(&contract_origin)?;
1640 result
1641 };
1642 InternalOutput { result: try_exec(), gas_meter, storage_deposit }
1643 }
1644
1645 fn ensure_origin(&self, origin: Origin<T>) -> Result<(), DispatchError> {
1646 match origin {
1647 Origin::Signed(_) => Ok(()),
1648 Origin::Root => Err(DispatchError::RootNotAllowed),
1649 }
1650 }
1651}
1652
1653macro_rules! ensure_no_migration_in_progress {
1654 () => {
1655 if Migration::<T>::in_progress() {
1656 return ContractResult {
1657 gas_consumed: Zero::zero(),
1658 gas_required: Zero::zero(),
1659 storage_deposit: Default::default(),
1660 debug_message: Vec::new(),
1661 result: Err(Error::<T>::MigrationInProgress.into()),
1662 events: None,
1663 }
1664 }
1665 };
1666}
1667
1668impl<T: Config> Pallet<T> {
1669 pub fn bare_call(
1682 origin: T::AccountId,
1683 dest: T::AccountId,
1684 value: BalanceOf<T>,
1685 gas_limit: Weight,
1686 storage_deposit_limit: Option<BalanceOf<T>>,
1687 data: Vec<u8>,
1688 debug: DebugInfo,
1689 collect_events: CollectEvents,
1690 determinism: Determinism,
1691 ) -> ContractExecResult<BalanceOf<T>, EventRecordOf<T>> {
1692 ensure_no_migration_in_progress!();
1693
1694 let mut debug_message = if matches!(debug, DebugInfo::UnsafeDebug) {
1695 Some(DebugBufferVec::<T>::default())
1696 } else {
1697 None
1698 };
1699 let origin = Origin::from_account_id(origin);
1700 let common = CommonInput {
1701 origin,
1702 value,
1703 data,
1704 gas_limit,
1705 storage_deposit_limit,
1706 debug_message: debug_message.as_mut(),
1707 };
1708 let output = CallInput::<T> { dest, determinism }.run_guarded(common);
1709 let events = if matches!(collect_events, CollectEvents::UnsafeCollect) {
1710 Some(System::<T>::read_events_no_consensus().map(|e| *e).collect())
1711 } else {
1712 None
1713 };
1714
1715 ContractExecResult {
1716 result: output.result.map_err(|r| r.error),
1717 gas_consumed: output.gas_meter.gas_consumed(),
1718 gas_required: output.gas_meter.gas_required(),
1719 storage_deposit: output.storage_deposit,
1720 debug_message: debug_message.unwrap_or_default().to_vec(),
1721 events,
1722 }
1723 }
1724
1725 pub fn bare_instantiate(
1740 origin: T::AccountId,
1741 value: BalanceOf<T>,
1742 gas_limit: Weight,
1743 mut storage_deposit_limit: Option<BalanceOf<T>>,
1744 code: Code<CodeHash<T>>,
1745 data: Vec<u8>,
1746 salt: Vec<u8>,
1747 debug: DebugInfo,
1748 collect_events: CollectEvents,
1749 ) -> ContractInstantiateResult<T::AccountId, BalanceOf<T>, EventRecordOf<T>> {
1750 ensure_no_migration_in_progress!();
1751
1752 let mut debug_message = if debug == DebugInfo::UnsafeDebug {
1753 Some(DebugBufferVec::<T>::default())
1754 } else {
1755 None
1756 };
1757 let events = || {
1759 if collect_events == CollectEvents::UnsafeCollect {
1760 Some(System::<T>::read_events_no_consensus().map(|e| *e).collect())
1761 } else {
1762 None
1763 }
1764 };
1765
1766 let (code, upload_deposit): (WasmCode<T>, BalanceOf<T>) = match code {
1767 Code::Upload(code) => {
1768 let result = Self::try_upload_code(
1769 origin.clone(),
1770 code,
1771 storage_deposit_limit.map(Into::into),
1772 Determinism::Enforced,
1773 debug_message.as_mut(),
1774 );
1775
1776 let (module, deposit) = match result {
1777 Ok(result) => result,
1778 Err(error) =>
1779 return ContractResult {
1780 gas_consumed: Zero::zero(),
1781 gas_required: Zero::zero(),
1782 storage_deposit: Default::default(),
1783 debug_message: debug_message.unwrap_or(Default::default()).into(),
1784 result: Err(error),
1785 events: events(),
1786 },
1787 };
1788
1789 storage_deposit_limit =
1790 storage_deposit_limit.map(|l| l.saturating_sub(deposit.into()));
1791 (WasmCode::Wasm(module), deposit)
1792 },
1793 Code::Existing(hash) => (WasmCode::CodeHash(hash), Default::default()),
1794 };
1795
1796 let common = CommonInput {
1797 origin: Origin::from_account_id(origin),
1798 value,
1799 data,
1800 gas_limit,
1801 storage_deposit_limit,
1802 debug_message: debug_message.as_mut(),
1803 };
1804
1805 let output = InstantiateInput::<T> { code, salt }.run_guarded(common);
1806 ContractInstantiateResult {
1807 result: output
1808 .result
1809 .map(|(account_id, result)| InstantiateReturnValue { result, account_id })
1810 .map_err(|e| e.error),
1811 gas_consumed: output.gas_meter.gas_consumed(),
1812 gas_required: output.gas_meter.gas_required(),
1813 storage_deposit: output
1814 .storage_deposit
1815 .saturating_add(&StorageDeposit::Charge(upload_deposit)),
1816 debug_message: debug_message.unwrap_or_default().to_vec(),
1817 events: events(),
1818 }
1819 }
1820
1821 pub fn bare_upload_code(
1826 origin: T::AccountId,
1827 code: Vec<u8>,
1828 storage_deposit_limit: Option<BalanceOf<T>>,
1829 determinism: Determinism,
1830 ) -> CodeUploadResult<CodeHash<T>, BalanceOf<T>> {
1831 Migration::<T>::ensure_migrated()?;
1832 let (module, deposit) =
1833 Self::try_upload_code(origin, code, storage_deposit_limit, determinism, None)?;
1834 Ok(CodeUploadReturnValue { code_hash: *module.code_hash(), deposit })
1835 }
1836
1837 fn try_upload_code(
1839 origin: T::AccountId,
1840 code: Vec<u8>,
1841 storage_deposit_limit: Option<BalanceOf<T>>,
1842 determinism: Determinism,
1843 mut debug_message: Option<&mut DebugBufferVec<T>>,
1844 ) -> Result<(WasmBlob<T>, BalanceOf<T>), DispatchError> {
1845 let schedule = T::Schedule::get();
1846 let mut module =
1847 WasmBlob::from_code(code, &schedule, origin, determinism).map_err(|(err, msg)| {
1848 debug_message.as_mut().map(|d| d.try_extend(msg.bytes()));
1849 err
1850 })?;
1851 let deposit = module.store_code()?;
1852 if let Some(storage_deposit_limit) = storage_deposit_limit {
1853 ensure!(storage_deposit_limit >= deposit, <Error<T>>::StorageDepositLimitExhausted);
1854 }
1855
1856 Ok((module, deposit))
1857 }
1858
1859 pub fn get_storage(address: T::AccountId, key: Vec<u8>) -> GetStorageResult {
1861 if Migration::<T>::in_progress() {
1862 return Err(ContractAccessError::MigrationInProgress)
1863 }
1864 let contract_info =
1865 ContractInfoOf::<T>::get(&address).ok_or(ContractAccessError::DoesntExist)?;
1866
1867 let maybe_value = contract_info.read(
1868 &Key::<T>::try_from_var(key)
1869 .map_err(|_| ContractAccessError::KeyDecodingFailed)?
1870 .into(),
1871 );
1872 Ok(maybe_value)
1873 }
1874
1875 pub fn contract_address(
1880 deploying_address: &T::AccountId,
1881 code_hash: &CodeHash<T>,
1882 input_data: &[u8],
1883 salt: &[u8],
1884 ) -> T::AccountId {
1885 T::AddressGenerator::contract_address(deploying_address, code_hash, input_data, salt)
1886 }
1887
1888 pub fn code_hash(account: &AccountIdOf<T>) -> Option<CodeHash<T>> {
1890 ContractInfo::<T>::load_code_hash(account)
1891 }
1892
1893 #[cfg(feature = "runtime-benchmarks")]
1895 fn store_code_raw(
1896 code: Vec<u8>,
1897 owner: T::AccountId,
1898 ) -> frame_support::dispatch::DispatchResult {
1899 let schedule = T::Schedule::get();
1900 WasmBlob::<T>::from_code_unchecked(code, &schedule, owner)?.store_code()?;
1901 Ok(())
1902 }
1903
1904 fn deposit_event(event: Event<T>) {
1906 <frame_system::Pallet<T>>::deposit_event(<T as Config>::RuntimeEvent::from(event))
1907 }
1908
1909 fn deposit_indexed_event(topics: Vec<T::Hash>, event: Event<T>) {
1911 <frame_system::Pallet<T>>::deposit_event_indexed(
1912 &topics,
1913 <T as Config>::RuntimeEvent::from(event).into(),
1914 )
1915 }
1916
1917 fn min_balance() -> BalanceOf<T> {
1919 <T::Currency as Inspect<AccountIdOf<T>>>::minimum_balance()
1920 }
1921
1922 fn compat_weight_limit(gas_limit: OldWeight) -> Weight {
1927 Weight::from_parts(gas_limit, u64::from(T::MaxCodeLen::get()) * 2)
1928 }
1929}
1930
1931sp_api::decl_runtime_apis! {
1932 #[api_version(2)]
1934 pub trait ContractsApi<AccountId, Balance, BlockNumber, Hash, EventRecord> where
1935 AccountId: Codec,
1936 Balance: Codec,
1937 BlockNumber: Codec,
1938 Hash: Codec,
1939 EventRecord: Codec,
1940 {
1941 fn call(
1945 origin: AccountId,
1946 dest: AccountId,
1947 value: Balance,
1948 gas_limit: Option<Weight>,
1949 storage_deposit_limit: Option<Balance>,
1950 input_data: Vec<u8>,
1951 ) -> ContractExecResult<Balance, EventRecord>;
1952
1953 fn instantiate(
1957 origin: AccountId,
1958 value: Balance,
1959 gas_limit: Option<Weight>,
1960 storage_deposit_limit: Option<Balance>,
1961 code: Code<Hash>,
1962 data: Vec<u8>,
1963 salt: Vec<u8>,
1964 ) -> ContractInstantiateResult<AccountId, Balance, EventRecord>;
1965
1966 fn upload_code(
1970 origin: AccountId,
1971 code: Vec<u8>,
1972 storage_deposit_limit: Option<Balance>,
1973 determinism: Determinism,
1974 ) -> CodeUploadResult<Hash, Balance>;
1975
1976 fn get_storage(
1982 address: AccountId,
1983 key: Vec<u8>,
1984 ) -> GetStorageResult;
1985 }
1986}