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, 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 #[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(
1387 Clone, Encode, Decode, DecodeWithMemTracking, PartialEq, TypeInfo, RuntimeDebugNoBound,
1388)]
1389pub enum Origin<T: Config> {
1390 Root,
1391 Signed(T::AccountId),
1392}
1393
1394impl<T: Config> Origin<T> {
1395 pub fn from_account_id(account_id: T::AccountId) -> Self {
1397 Origin::Signed(account_id)
1398 }
1399 pub fn from_runtime_origin(o: OriginFor<T>) -> Result<Self, DispatchError> {
1401 match o.into() {
1402 Ok(RawOrigin::Root) => Ok(Self::Root),
1403 Ok(RawOrigin::Signed(t)) => Ok(Self::Signed(t)),
1404 _ => Err(BadOrigin.into()),
1405 }
1406 }
1407 pub fn account_id(&self) -> Result<&T::AccountId, DispatchError> {
1409 match self {
1410 Origin::Signed(id) => Ok(id),
1411 Origin::Root => Err(DispatchError::RootNotAllowed),
1412 }
1413 }
1414}
1415
1416struct CommonInput<'a, T: Config> {
1418 origin: Origin<T>,
1419 value: BalanceOf<T>,
1420 data: Vec<u8>,
1421 gas_limit: Weight,
1422 storage_deposit_limit: Option<BalanceOf<T>>,
1423 debug_message: Option<&'a mut DebugBufferVec<T>>,
1424}
1425
1426struct CallInput<T: Config> {
1428 dest: T::AccountId,
1429 determinism: Determinism,
1430}
1431
1432enum WasmCode<T: Config> {
1434 Wasm(WasmBlob<T>),
1435 CodeHash(CodeHash<T>),
1436}
1437
1438struct InstantiateInput<T: Config> {
1440 code: WasmCode<T>,
1441 salt: Vec<u8>,
1442}
1443
1444#[derive(
1446 Copy, Clone, PartialEq, Eq, RuntimeDebug, Decode, Encode, MaxEncodedLen, scale_info::TypeInfo,
1447)]
1448pub enum CollectEvents {
1449 UnsafeCollect,
1458 Skip,
1460}
1461
1462#[derive(
1464 Copy, Clone, PartialEq, Eq, RuntimeDebug, Decode, Encode, MaxEncodedLen, scale_info::TypeInfo,
1465)]
1466pub enum DebugInfo {
1467 UnsafeDebug,
1473 Skip,
1475}
1476
1477struct InternalOutput<T: Config, O> {
1479 gas_meter: GasMeter<T>,
1481 storage_deposit: StorageDeposit<BalanceOf<T>>,
1483 result: Result<O, ExecError>,
1485}
1486
1487environmental!(executing_contract: bool);
1489
1490trait Invokable<T: Config>: Sized {
1493 type Output;
1495
1496 fn run_guarded(self, common: CommonInput<T>) -> InternalOutput<T, Self::Output> {
1505 let gas_limit = common.gas_limit;
1506
1507 if let Err(e) = self.ensure_origin(common.origin.clone()) {
1512 return InternalOutput {
1513 gas_meter: GasMeter::new(gas_limit),
1514 storage_deposit: Default::default(),
1515 result: Err(ExecError { error: e.into(), origin: ErrorOrigin::Caller }),
1516 }
1517 }
1518
1519 executing_contract::using_once(&mut false, || {
1520 executing_contract::with(|f| {
1521 if *f {
1523 return Err(())
1524 }
1525 *f = true;
1527 Ok(())
1528 })
1529 .expect("Returns `Ok` if called within `using_once`. It is syntactically obvious that this is the case; qed")
1530 .map_or_else(
1531 |_| InternalOutput {
1532 gas_meter: GasMeter::new(gas_limit),
1533 storage_deposit: Default::default(),
1534 result: Err(ExecError {
1535 error: <Error<T>>::ReentranceDenied.into(),
1536 origin: ErrorOrigin::Caller,
1537 }),
1538 },
1539 |_| self.run(common, GasMeter::new(gas_limit)),
1541 )
1542 })
1543 }
1544
1545 fn run(self, common: CommonInput<T>, gas_meter: GasMeter<T>)
1550 -> InternalOutput<T, Self::Output>;
1551
1552 fn ensure_origin(&self, origin: Origin<T>) -> Result<(), DispatchError>;
1556}
1557
1558impl<T: Config> Invokable<T> for CallInput<T> {
1559 type Output = ExecReturnValue;
1560
1561 fn run(
1562 self,
1563 common: CommonInput<T>,
1564 mut gas_meter: GasMeter<T>,
1565 ) -> InternalOutput<T, Self::Output> {
1566 let CallInput { dest, determinism } = self;
1567 let CommonInput { origin, value, data, debug_message, .. } = common;
1568 let mut storage_meter =
1569 match StorageMeter::new(&origin, common.storage_deposit_limit, common.value) {
1570 Ok(meter) => meter,
1571 Err(err) =>
1572 return InternalOutput {
1573 result: Err(err.into()),
1574 gas_meter,
1575 storage_deposit: Default::default(),
1576 },
1577 };
1578 let schedule = T::Schedule::get();
1579 let result = ExecStack::<T, WasmBlob<T>>::run_call(
1580 origin.clone(),
1581 dest.clone(),
1582 &mut gas_meter,
1583 &mut storage_meter,
1584 &schedule,
1585 value,
1586 data.clone(),
1587 debug_message,
1588 determinism,
1589 );
1590
1591 match storage_meter.try_into_deposit(&origin) {
1592 Ok(storage_deposit) => InternalOutput { gas_meter, storage_deposit, result },
1593 Err(err) => InternalOutput {
1594 gas_meter,
1595 storage_deposit: Default::default(),
1596 result: Err(err.into()),
1597 },
1598 }
1599 }
1600
1601 fn ensure_origin(&self, _origin: Origin<T>) -> Result<(), DispatchError> {
1602 Ok(())
1603 }
1604}
1605
1606impl<T: Config> Invokable<T> for InstantiateInput<T> {
1607 type Output = (AccountIdOf<T>, ExecReturnValue);
1608
1609 fn run(
1610 self,
1611 common: CommonInput<T>,
1612 mut gas_meter: GasMeter<T>,
1613 ) -> InternalOutput<T, Self::Output> {
1614 let mut storage_deposit = Default::default();
1615 let try_exec = || {
1616 let schedule = T::Schedule::get();
1617 let InstantiateInput { salt, .. } = self;
1618 let CommonInput { origin: contract_origin, .. } = common;
1619 let origin = contract_origin.account_id()?;
1620
1621 let executable = match self.code {
1622 WasmCode::Wasm(module) => module,
1623 WasmCode::CodeHash(code_hash) => WasmBlob::from_storage(code_hash, &mut gas_meter)?,
1624 };
1625
1626 let contract_origin = Origin::from_account_id(origin.clone());
1627 let mut storage_meter =
1628 StorageMeter::new(&contract_origin, common.storage_deposit_limit, common.value)?;
1629 let CommonInput { value, data, debug_message, .. } = common;
1630 let result = ExecStack::<T, WasmBlob<T>>::run_instantiate(
1631 origin.clone(),
1632 executable,
1633 &mut gas_meter,
1634 &mut storage_meter,
1635 &schedule,
1636 value,
1637 data.clone(),
1638 &salt,
1639 debug_message,
1640 );
1641
1642 storage_deposit = storage_meter.try_into_deposit(&contract_origin)?;
1643 result
1644 };
1645 InternalOutput { result: try_exec(), gas_meter, storage_deposit }
1646 }
1647
1648 fn ensure_origin(&self, origin: Origin<T>) -> Result<(), DispatchError> {
1649 match origin {
1650 Origin::Signed(_) => Ok(()),
1651 Origin::Root => Err(DispatchError::RootNotAllowed),
1652 }
1653 }
1654}
1655
1656macro_rules! ensure_no_migration_in_progress {
1657 () => {
1658 if Migration::<T>::in_progress() {
1659 return ContractResult {
1660 gas_consumed: Zero::zero(),
1661 gas_required: Zero::zero(),
1662 storage_deposit: Default::default(),
1663 debug_message: Vec::new(),
1664 result: Err(Error::<T>::MigrationInProgress.into()),
1665 events: None,
1666 }
1667 }
1668 };
1669}
1670
1671impl<T: Config> Pallet<T> {
1672 pub fn bare_call(
1685 origin: T::AccountId,
1686 dest: T::AccountId,
1687 value: BalanceOf<T>,
1688 gas_limit: Weight,
1689 storage_deposit_limit: Option<BalanceOf<T>>,
1690 data: Vec<u8>,
1691 debug: DebugInfo,
1692 collect_events: CollectEvents,
1693 determinism: Determinism,
1694 ) -> ContractExecResult<BalanceOf<T>, EventRecordOf<T>> {
1695 ensure_no_migration_in_progress!();
1696
1697 let mut debug_message = if matches!(debug, DebugInfo::UnsafeDebug) {
1698 Some(DebugBufferVec::<T>::default())
1699 } else {
1700 None
1701 };
1702 let origin = Origin::from_account_id(origin);
1703 let common = CommonInput {
1704 origin,
1705 value,
1706 data,
1707 gas_limit,
1708 storage_deposit_limit,
1709 debug_message: debug_message.as_mut(),
1710 };
1711 let output = CallInput::<T> { dest, determinism }.run_guarded(common);
1712 let events = if matches!(collect_events, CollectEvents::UnsafeCollect) {
1713 Some(System::<T>::read_events_no_consensus().map(|e| *e).collect())
1714 } else {
1715 None
1716 };
1717
1718 ContractExecResult {
1719 result: output.result.map_err(|r| r.error),
1720 gas_consumed: output.gas_meter.gas_consumed(),
1721 gas_required: output.gas_meter.gas_required(),
1722 storage_deposit: output.storage_deposit,
1723 debug_message: debug_message.unwrap_or_default().to_vec(),
1724 events,
1725 }
1726 }
1727
1728 pub fn bare_instantiate(
1743 origin: T::AccountId,
1744 value: BalanceOf<T>,
1745 gas_limit: Weight,
1746 mut storage_deposit_limit: Option<BalanceOf<T>>,
1747 code: Code<CodeHash<T>>,
1748 data: Vec<u8>,
1749 salt: Vec<u8>,
1750 debug: DebugInfo,
1751 collect_events: CollectEvents,
1752 ) -> ContractInstantiateResult<T::AccountId, BalanceOf<T>, EventRecordOf<T>> {
1753 ensure_no_migration_in_progress!();
1754
1755 let mut debug_message = if debug == DebugInfo::UnsafeDebug {
1756 Some(DebugBufferVec::<T>::default())
1757 } else {
1758 None
1759 };
1760 let events = || {
1762 if collect_events == CollectEvents::UnsafeCollect {
1763 Some(System::<T>::read_events_no_consensus().map(|e| *e).collect())
1764 } else {
1765 None
1766 }
1767 };
1768
1769 let (code, upload_deposit): (WasmCode<T>, BalanceOf<T>) = match code {
1770 Code::Upload(code) => {
1771 let result = Self::try_upload_code(
1772 origin.clone(),
1773 code,
1774 storage_deposit_limit.map(Into::into),
1775 Determinism::Enforced,
1776 debug_message.as_mut(),
1777 );
1778
1779 let (module, deposit) = match result {
1780 Ok(result) => result,
1781 Err(error) =>
1782 return ContractResult {
1783 gas_consumed: Zero::zero(),
1784 gas_required: Zero::zero(),
1785 storage_deposit: Default::default(),
1786 debug_message: debug_message.unwrap_or(Default::default()).into(),
1787 result: Err(error),
1788 events: events(),
1789 },
1790 };
1791
1792 storage_deposit_limit =
1793 storage_deposit_limit.map(|l| l.saturating_sub(deposit.into()));
1794 (WasmCode::Wasm(module), deposit)
1795 },
1796 Code::Existing(hash) => (WasmCode::CodeHash(hash), Default::default()),
1797 };
1798
1799 let common = CommonInput {
1800 origin: Origin::from_account_id(origin),
1801 value,
1802 data,
1803 gas_limit,
1804 storage_deposit_limit,
1805 debug_message: debug_message.as_mut(),
1806 };
1807
1808 let output = InstantiateInput::<T> { code, salt }.run_guarded(common);
1809 ContractInstantiateResult {
1810 result: output
1811 .result
1812 .map(|(account_id, result)| InstantiateReturnValue { result, account_id })
1813 .map_err(|e| e.error),
1814 gas_consumed: output.gas_meter.gas_consumed(),
1815 gas_required: output.gas_meter.gas_required(),
1816 storage_deposit: output
1817 .storage_deposit
1818 .saturating_add(&StorageDeposit::Charge(upload_deposit)),
1819 debug_message: debug_message.unwrap_or_default().to_vec(),
1820 events: events(),
1821 }
1822 }
1823
1824 pub fn bare_upload_code(
1829 origin: T::AccountId,
1830 code: Vec<u8>,
1831 storage_deposit_limit: Option<BalanceOf<T>>,
1832 determinism: Determinism,
1833 ) -> CodeUploadResult<CodeHash<T>, BalanceOf<T>> {
1834 Migration::<T>::ensure_migrated()?;
1835 let (module, deposit) =
1836 Self::try_upload_code(origin, code, storage_deposit_limit, determinism, None)?;
1837 Ok(CodeUploadReturnValue { code_hash: *module.code_hash(), deposit })
1838 }
1839
1840 fn try_upload_code(
1842 origin: T::AccountId,
1843 code: Vec<u8>,
1844 storage_deposit_limit: Option<BalanceOf<T>>,
1845 determinism: Determinism,
1846 mut debug_message: Option<&mut DebugBufferVec<T>>,
1847 ) -> Result<(WasmBlob<T>, BalanceOf<T>), DispatchError> {
1848 let schedule = T::Schedule::get();
1849 let mut module =
1850 WasmBlob::from_code(code, &schedule, origin, determinism).map_err(|(err, msg)| {
1851 debug_message.as_mut().map(|d| d.try_extend(msg.bytes()));
1852 err
1853 })?;
1854 let deposit = module.store_code()?;
1855 if let Some(storage_deposit_limit) = storage_deposit_limit {
1856 ensure!(storage_deposit_limit >= deposit, <Error<T>>::StorageDepositLimitExhausted);
1857 }
1858
1859 Ok((module, deposit))
1860 }
1861
1862 pub fn get_storage(address: T::AccountId, key: Vec<u8>) -> GetStorageResult {
1864 if Migration::<T>::in_progress() {
1865 return Err(ContractAccessError::MigrationInProgress)
1866 }
1867 let contract_info =
1868 ContractInfoOf::<T>::get(&address).ok_or(ContractAccessError::DoesntExist)?;
1869
1870 let maybe_value = contract_info.read(
1871 &Key::<T>::try_from_var(key)
1872 .map_err(|_| ContractAccessError::KeyDecodingFailed)?
1873 .into(),
1874 );
1875 Ok(maybe_value)
1876 }
1877
1878 pub fn contract_address(
1883 deploying_address: &T::AccountId,
1884 code_hash: &CodeHash<T>,
1885 input_data: &[u8],
1886 salt: &[u8],
1887 ) -> T::AccountId {
1888 T::AddressGenerator::contract_address(deploying_address, code_hash, input_data, salt)
1889 }
1890
1891 pub fn code_hash(account: &AccountIdOf<T>) -> Option<CodeHash<T>> {
1893 ContractInfo::<T>::load_code_hash(account)
1894 }
1895
1896 #[cfg(feature = "runtime-benchmarks")]
1898 fn store_code_raw(
1899 code: Vec<u8>,
1900 owner: T::AccountId,
1901 ) -> frame_support::dispatch::DispatchResult {
1902 let schedule = T::Schedule::get();
1903 WasmBlob::<T>::from_code_unchecked(code, &schedule, owner)?.store_code()?;
1904 Ok(())
1905 }
1906
1907 fn deposit_event(event: Event<T>) {
1909 <frame_system::Pallet<T>>::deposit_event(<T as Config>::RuntimeEvent::from(event))
1910 }
1911
1912 fn deposit_indexed_event(topics: Vec<T::Hash>, event: Event<T>) {
1914 <frame_system::Pallet<T>>::deposit_event_indexed(
1915 &topics,
1916 <T as Config>::RuntimeEvent::from(event).into(),
1917 )
1918 }
1919
1920 fn min_balance() -> BalanceOf<T> {
1922 <T::Currency as Inspect<AccountIdOf<T>>>::minimum_balance()
1923 }
1924
1925 fn compat_weight_limit(gas_limit: OldWeight) -> Weight {
1930 Weight::from_parts(gas_limit, u64::from(T::MaxCodeLen::get()) * 2)
1931 }
1932}
1933
1934sp_api::decl_runtime_apis! {
1935 #[api_version(2)]
1937 pub trait ContractsApi<AccountId, Balance, BlockNumber, Hash, EventRecord> where
1938 AccountId: Codec,
1939 Balance: Codec,
1940 BlockNumber: Codec,
1941 Hash: Codec,
1942 EventRecord: Codec,
1943 {
1944 fn call(
1948 origin: AccountId,
1949 dest: AccountId,
1950 value: Balance,
1951 gas_limit: Option<Weight>,
1952 storage_deposit_limit: Option<Balance>,
1953 input_data: Vec<u8>,
1954 ) -> ContractExecResult<Balance, EventRecord>;
1955
1956 fn instantiate(
1960 origin: AccountId,
1961 value: Balance,
1962 gas_limit: Option<Weight>,
1963 storage_deposit_limit: Option<Balance>,
1964 code: Code<Hash>,
1965 data: Vec<u8>,
1966 salt: Vec<u8>,
1967 ) -> ContractInstantiateResult<AccountId, Balance, EventRecord>;
1968
1969 fn upload_code(
1973 origin: AccountId,
1974 code: Vec<u8>,
1975 storage_deposit_limit: Option<Balance>,
1976 determinism: Determinism,
1977 ) -> CodeUploadResult<Hash, Balance>;
1978
1979 fn get_storage(
1985 address: AccountId,
1986 key: Vec<u8>,
1987 ) -> GetStorageResult;
1988 }
1989}