idn_runtime/
apis.rs

1/*
2 * Copyright 2025 by Ideal Labs, LLC
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *     http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#[cfg(feature = "runtime-benchmarks")]
18use crate::benchmarks::*;
19// External crates imports
20use crate::{
21	configs::{xcm_config, RuntimeBlockWeights},
22	constants::relay::fee::WeightToFee,
23	BlockNumber, Contracts, EventRecord, Hash, OriginCaller, PolkadotXcm, RuntimeEvent,
24	CONTRACTS_DEBUG_OUTPUT, CONTRACTS_EVENTS,
25};
26use bp_idn::types::SERIALIZED_SIG_SIZE;
27use frame_support::{
28	genesis_builder_helper::{build_state, get_preset},
29	weights::{Weight, WeightToFee as _},
30};
31use pallet_aura::Authorities;
32use pallet_idn_manager::{BalanceOf, SubscriptionOf};
33use sp_api::impl_runtime_apis;
34use sp_consensus_aura::sr25519::AuthorityId as AuraId;
35use sp_core::{crypto::KeyTypeId, OpaqueMetadata};
36use sp_runtime::{
37	traits::Block as BlockT,
38	transaction_validity::{TransactionSource, TransactionValidity},
39	AccountId32, ApplyExtrinsicResult,
40};
41use sp_std::prelude::Vec;
42use sp_version::RuntimeVersion;
43use xcm::{
44	prelude::AssetId, Version as XcmVersion, VersionedAsset, VersionedAssetId, VersionedAssets,
45	VersionedLocation, VersionedXcm,
46};
47use xcm_runtime_apis::{
48	dry_run::{CallDryRunEffects, Error as XcmDryRunApiError, XcmDryRunEffects},
49	fees::Error as XcmPaymentApiError,
50	trusted_query::XcmTrustedQueryResult,
51};
52
53// Local module imports
54use super::{
55	AccountId, Balance, Block, ConsensusHook, Executive, InherentDataExt, Nonce, ParachainSystem,
56	Runtime, RuntimeCall, RuntimeGenesisConfig, SessionKeys, System, TransactionPayment,
57	SLOT_DURATION, VERSION,
58};
59
60impl_runtime_apis! {
61
62	impl sp_consensus_aura::AuraApi<Block, AuraId> for Runtime {
63		fn slot_duration() -> sp_consensus_aura::SlotDuration {
64			sp_consensus_aura::SlotDuration::from_millis(SLOT_DURATION)
65		}
66
67		fn authorities() -> Vec<AuraId> {
68			Authorities::<Runtime>::get().into_inner()
69		}
70	}
71
72	impl cumulus_primitives_aura::AuraUnincludedSegmentApi<Block> for Runtime {
73		fn can_build_upon(
74			included_hash: <Block as BlockT>::Hash,
75			slot: cumulus_primitives_aura::Slot
76		) -> bool {
77			ConsensusHook::can_build_upon(included_hash, slot)
78		}
79	}
80
81	impl sp_api::Core<Block> for Runtime {
82		fn version() -> RuntimeVersion {
83			VERSION
84		}
85
86		fn execute_block(block: Block) {
87			Executive::execute_block(block)
88		}
89
90		fn initialize_block(header: &<Block as BlockT>::Header) -> sp_runtime::ExtrinsicInclusionMode {
91			Executive::initialize_block(header)
92		}
93	}
94
95	impl sp_api::Metadata<Block> for Runtime {
96		fn metadata() -> OpaqueMetadata {
97			OpaqueMetadata::new(Runtime::metadata().into())
98		}
99
100		fn metadata_at_version(version: u32) -> Option<OpaqueMetadata> {
101			Runtime::metadata_at_version(version)
102		}
103
104		fn metadata_versions() -> Vec<u32> {
105			Runtime::metadata_versions()
106		}
107	}
108
109	impl sp_block_builder::BlockBuilder<Block> for Runtime {
110		fn apply_extrinsic(extrinsic: <Block as BlockT>::Extrinsic) -> ApplyExtrinsicResult {
111			Executive::apply_extrinsic(extrinsic)
112		}
113
114		fn finalize_block() -> <Block as BlockT>::Header {
115			Executive::finalize_block()
116		}
117
118		fn inherent_extrinsics(data: sp_inherents::InherentData) -> Vec<<Block as BlockT>::Extrinsic> {
119			data.create_extrinsics()
120		}
121
122		fn check_inherents(
123			block: Block,
124			data: sp_inherents::InherentData,
125		) -> sp_inherents::CheckInherentsResult {
126			data.check_extrinsics(&block)
127		}
128	}
129
130	impl sp_transaction_pool::runtime_api::TaggedTransactionQueue<Block> for Runtime {
131		fn validate_transaction(
132			source: TransactionSource,
133			tx: <Block as BlockT>::Extrinsic,
134			block_hash: <Block as BlockT>::Hash,
135		) -> TransactionValidity {
136			Executive::validate_transaction(source, tx, block_hash)
137		}
138	}
139
140	impl sp_offchain::OffchainWorkerApi<Block> for Runtime {
141		fn offchain_worker(header: &<Block as BlockT>::Header) {
142			Executive::offchain_worker(header)
143		}
144	}
145
146	impl sp_session::SessionKeys<Block> for Runtime {
147		fn generate_session_keys(seed: Option<Vec<u8>>) -> Vec<u8> {
148			SessionKeys::generate(seed)
149		}
150
151		fn decode_session_keys(
152			encoded: Vec<u8>,
153		) -> Option<Vec<(Vec<u8>, KeyTypeId)>> {
154			SessionKeys::decode_into_raw_public_keys(&encoded)
155		}
156	}
157
158	impl frame_system_rpc_runtime_api::AccountNonceApi<Block, AccountId, Nonce> for Runtime {
159		fn account_nonce(account: AccountId) -> Nonce {
160			System::account_nonce(account)
161		}
162	}
163
164	impl pallet_transaction_payment_rpc_runtime_api::TransactionPaymentApi<Block, Balance> for Runtime {
165		fn query_info(
166			uxt: <Block as BlockT>::Extrinsic,
167			len: u32,
168		) -> pallet_transaction_payment_rpc_runtime_api::RuntimeDispatchInfo<Balance> {
169			TransactionPayment::query_info(uxt, len)
170		}
171		fn query_fee_details(
172			uxt: <Block as BlockT>::Extrinsic,
173			len: u32,
174		) -> pallet_transaction_payment::FeeDetails<Balance> {
175			TransactionPayment::query_fee_details(uxt, len)
176		}
177		fn query_weight_to_fee(weight: Weight) -> Balance {
178			TransactionPayment::weight_to_fee(weight)
179		}
180		fn query_length_to_fee(length: u32) -> Balance {
181			TransactionPayment::length_to_fee(length)
182		}
183	}
184
185	impl pallet_transaction_payment_rpc_runtime_api::TransactionPaymentCallApi<Block, Balance, RuntimeCall>
186		for Runtime
187	{
188		fn query_call_info(
189			call: RuntimeCall,
190			len: u32,
191		) -> pallet_transaction_payment::RuntimeDispatchInfo<Balance> {
192			TransactionPayment::query_call_info(call, len)
193		}
194		fn query_call_fee_details(
195			call: RuntimeCall,
196			len: u32,
197		) -> pallet_transaction_payment::FeeDetails<Balance> {
198			TransactionPayment::query_call_fee_details(call, len)
199		}
200		fn query_weight_to_fee(weight: Weight) -> Balance {
201			TransactionPayment::weight_to_fee(weight)
202		}
203		fn query_length_to_fee(length: u32) -> Balance {
204			TransactionPayment::length_to_fee(length)
205		}
206	}
207
208	impl cumulus_primitives_core::CollectCollationInfo<Block> for Runtime {
209		fn collect_collation_info(header: &<Block as BlockT>::Header) -> cumulus_primitives_core::CollationInfo {
210			ParachainSystem::collect_collation_info(header)
211		}
212	}
213
214	#[cfg(feature = "try-runtime")]
215	impl frame_try_runtime::TryRuntime<Block> for Runtime {
216		fn on_runtime_upgrade(checks: frame_try_runtime::UpgradeCheckSelect) -> (Weight, Weight) {
217			use super::configs::RuntimeBlockWeights;
218
219			let weight = Executive::try_runtime_upgrade(checks).unwrap();
220			(weight, RuntimeBlockWeights::get().max_block)
221		}
222
223		fn execute_block(
224			block: Block,
225			state_root_check: bool,
226			signature_check: bool,
227			select: frame_try_runtime::TryStateSelect,
228		) -> Weight {
229			// NOTE: intentional unwrap: we don't want to propagate the error backwards, and want to
230			// have a backtrace here.
231			Executive::try_execute_block(block, state_root_check, signature_check, select).unwrap()
232		}
233	}
234
235	#[cfg(feature = "runtime-benchmarks")]
236	impl frame_benchmarking::Benchmark<Block> for Runtime {
237		fn benchmark_metadata(extra: bool) -> (
238			Vec<frame_benchmarking::BenchmarkList>,
239			Vec<frame_support::traits::StorageInfo>,
240		) {
241			let mut list = Vec::<BenchmarkList>::new();
242			list_benchmarks!(list, extra);
243
244			let storage_info = AllPalletsWithSystem::storage_info();
245			(list, storage_info)
246		}
247
248		fn dispatch_benchmark(
249			config: frame_benchmarking::BenchmarkConfig
250		) -> Result<Vec<frame_benchmarking::BenchmarkBatch>, alloc::string::String> {
251			let whitelist = AllPalletsWithSystem::whitelisted_storage_keys();
252			let mut batches = Vec::<BenchmarkBatch>::new();
253			let params = (&config, &whitelist);
254			add_benchmarks!(params, batches);
255
256			if batches.is_empty() { return Err("Benchmark not found for this pallet.".into()) }
257			Ok(batches)
258		}
259	}
260
261	impl sp_genesis_builder::GenesisBuilder<Block> for Runtime {
262		fn build_state(config: Vec<u8>) -> sp_genesis_builder::Result {
263			build_state::<RuntimeGenesisConfig>(config)
264		}
265
266		fn get_preset(id: &Option<sp_genesis_builder::PresetId>) -> Option<Vec<u8>> {
267			get_preset::<RuntimeGenesisConfig>(id, crate::genesis_config_presets::get_preset)
268		}
269
270		fn preset_names() -> Vec<sp_genesis_builder::PresetId> {
271			crate::genesis_config_presets::preset_names()
272		}
273	}
274
275	impl xcm_runtime_apis::fees::XcmPaymentApi<Block> for Runtime {
276		fn query_acceptable_payment_assets(xcm_version: xcm::Version) -> Result<Vec<VersionedAssetId>, XcmPaymentApiError> {
277			let native_token = xcm_config::RelayLocation::get();
278			let acceptable_assets = Vec::from([AssetId(native_token)]);
279			PolkadotXcm::query_acceptable_payment_assets(xcm_version, acceptable_assets)
280		}
281
282		fn query_weight_to_asset_fee(weight: Weight, asset: VersionedAssetId) -> Result<u128, XcmPaymentApiError> {
283			let native_asset = xcm_config::RelayLocation::get();
284			let fee_in_native = WeightToFee::weight_to_fee(&weight);
285			let latest_asset_id: Result<AssetId, ()> = asset.clone().try_into();
286			match latest_asset_id {
287				Ok(asset_id) if asset_id.0 == native_asset => {
288					// For native asset.
289					Ok(fee_in_native)
290				},
291				Ok(asset_id) => {
292					log::trace!(target: "xcm::xcm_runtime_apis", "query_weight_to_asset_fee - unhandled asset_id: {asset_id:?}!");
293					Err(XcmPaymentApiError::AssetNotFound)
294				},
295				Err(_) => {
296					log::trace!(target: "xcm::xcm_runtime_apis", "query_weight_to_asset_fee - failed to convert asset: {asset:?}!");
297					Err(XcmPaymentApiError::VersionedConversionFailed)
298				}
299			}
300		}
301
302		fn query_xcm_weight(message: VersionedXcm<()>) -> Result<Weight, XcmPaymentApiError> {
303			PolkadotXcm::query_xcm_weight(message)
304		}
305
306		fn query_delivery_fees(destination: VersionedLocation, message: VersionedXcm<()>) -> Result<VersionedAssets, XcmPaymentApiError> {
307			PolkadotXcm::query_delivery_fees(destination, message)
308		}
309	}
310
311	impl xcm_runtime_apis::dry_run::DryRunApi<Block, RuntimeCall, RuntimeEvent, OriginCaller> for Runtime {
312		fn dry_run_call(origin: OriginCaller, call: RuntimeCall, result_xcms_version: XcmVersion) -> Result<CallDryRunEffects<RuntimeEvent>, XcmDryRunApiError> {
313			PolkadotXcm::dry_run_call::<Runtime, xcm_config::XcmRouter, OriginCaller, RuntimeCall>(origin, call, result_xcms_version)
314		}
315
316		fn dry_run_xcm(origin_location: VersionedLocation, xcm: VersionedXcm<RuntimeCall>) -> Result<XcmDryRunEffects<RuntimeEvent>, XcmDryRunApiError> {
317			PolkadotXcm::dry_run_xcm::<Runtime, xcm_config::XcmRouter, RuntimeCall, xcm_config::XcmConfig>(origin_location, xcm)
318		}
319	}
320
321	impl xcm_runtime_apis::conversions::LocationToAccountApi<Block, AccountId> for Runtime {
322		fn convert_location(location: VersionedLocation) -> Result<
323			AccountId,
324			xcm_runtime_apis::conversions::Error
325		> {
326			xcm_runtime_apis::conversions::LocationToAccountHelper::<
327				AccountId,
328				xcm_config::LocationToAccountId,
329			>::convert_location(location)
330		}
331	}
332
333	impl xcm_runtime_apis::trusted_query::TrustedQueryApi<Block> for Runtime {
334		fn is_trusted_reserve(asset: VersionedAsset, location: VersionedLocation) -> XcmTrustedQueryResult {
335			PolkadotXcm::is_trusted_reserve(asset, location)
336		}
337
338		fn is_trusted_teleporter(asset: VersionedAsset, location: VersionedLocation) -> XcmTrustedQueryResult {
339			PolkadotXcm::is_trusted_teleporter(asset, location)
340		}
341	}
342
343	impl xcm_runtime_apis::authorized_aliases::AuthorizedAliasersApi<Block> for Runtime {
344		fn authorized_aliasers(target: VersionedLocation) -> Result<
345			Vec<xcm_runtime_apis::authorized_aliases::OriginAliaser>,
346			xcm_runtime_apis::authorized_aliases::Error
347		> {
348			PolkadotXcm::authorized_aliasers(target)
349		}
350		fn is_authorized_alias(origin: VersionedLocation, target: VersionedLocation) -> Result<
351			bool,
352			xcm_runtime_apis::authorized_aliases::Error
353		> {
354			PolkadotXcm::is_authorized_alias(origin, target)
355		}
356	}
357
358	impl pallet_randomness_beacon::RandomnessBeaconApi<Block> for Runtime {
359		fn build_extrinsic(
360			asig: Vec<u8>,
361			start: u64,
362			end: u64,
363			signature: Vec<u8>,
364		) -> crate::UncheckedExtrinsic {
365			// if a wrong-sized signature is injected, specify a default
366			let formatted: [u8; sp_consensus_randomness_beacon::types::SERIALIZED_SIG_SIZE] =
367			asig.try_into().unwrap_or([0u8; SERIALIZED_SIG_SIZE]);
368
369			let mut sig_array = [0u8; 64];
370			sig_array.copy_from_slice(&signature);
371			let sig = sp_runtime::MultiSignature::Sr25519(
372				sp_core::sr25519::Signature::from_raw(sig_array)
373			);
374
375			let call = crate::RuntimeCall::RandBeacon(
376				pallet_randomness_beacon::Call::try_submit_asig {
377					asig: formatted,
378					start,
379					end,
380					signature: sig,
381				}
382			);
383			crate::UncheckedExtrinsic::new_bare(call)
384		}
385
386		fn next_round() -> sp_consensus_randomness_beacon::types::RoundNumber {
387			pallet_randomness_beacon::Pallet::<Runtime>::next_round()
388		}
389
390		fn max_rounds() -> u8 {
391			pallet_randomness_beacon::Pallet::<Runtime>::max_rounds()
392		}
393	}
394
395	impl pallet_idn_manager::IdnManagerApi<
396		Block,
397		BalanceOf<Runtime>,
398		u64,
399		AccountId32,
400		SubscriptionOf<Runtime>,
401		<Runtime as pallet_idn_manager::Config>::SubscriptionId,
402	> for Runtime {
403		fn calculate_subscription_fees(
404			credits: <Runtime as pallet_idn_manager::Config>::Credits
405		) -> BalanceOf<Runtime> {
406			pallet_idn_manager::Pallet::<Runtime>::calculate_subscription_fees(&credits)
407		}
408		fn get_subscription(
409			sub_id: <Runtime as pallet_idn_manager::Config>::SubscriptionId
410		) -> Option<SubscriptionOf<Runtime>> {
411			pallet_idn_manager::Pallet::<Runtime>::get_subscription(&sub_id)
412		}
413		fn get_subscriptions_for_subscriber(
414			subscriber: AccountId32
415		) -> Vec<SubscriptionOf<Runtime>> {
416			pallet_idn_manager::Pallet::<Runtime>::get_subscriptions_for_subscriber(&subscriber)
417		}
418	}
419
420	impl pallet_contracts::ContractsApi<Block, AccountId, Balance, BlockNumber, Hash, EventRecord>
421		for Runtime
422	{
423		fn call(
424			origin: AccountId,
425			dest: AccountId,
426			value: Balance,
427			gas_limit: Option<Weight>,
428			storage_deposit_limit: Option<Balance>,
429			input_data: Vec<u8>,
430		) -> pallet_contracts::ContractExecResult<Balance, EventRecord> {
431			let gas_limit = gas_limit.unwrap_or(RuntimeBlockWeights::get().max_block);
432			Contracts::bare_call(
433				origin,
434				dest,
435				value,
436				gas_limit,
437				storage_deposit_limit,
438				input_data,
439				CONTRACTS_DEBUG_OUTPUT,
440				CONTRACTS_EVENTS,
441				pallet_contracts::Determinism::Enforced,
442			)
443		}
444
445		fn instantiate(
446			origin: AccountId,
447			value: Balance,
448			gas_limit: Option<Weight>,
449			storage_deposit_limit: Option<Balance>,
450			code: pallet_contracts::Code<Hash>,
451			data: Vec<u8>,
452			salt: Vec<u8>,
453		) -> pallet_contracts::ContractInstantiateResult<AccountId, Balance, EventRecord>
454		{
455			let gas_limit = gas_limit.unwrap_or(RuntimeBlockWeights::get().max_block);
456			Contracts::bare_instantiate(
457				origin,
458				value,
459				gas_limit,
460				storage_deposit_limit,
461				code,
462				data,
463				salt,
464				CONTRACTS_DEBUG_OUTPUT,
465				CONTRACTS_EVENTS,
466			)
467		}
468
469		fn upload_code(
470			origin: AccountId,
471			code: Vec<u8>,
472			storage_deposit_limit: Option<Balance>,
473			determinism: pallet_contracts::Determinism,
474		) -> pallet_contracts::CodeUploadResult<Hash, Balance>
475		{
476			Contracts::bare_upload_code(origin, code, storage_deposit_limit, determinism)
477		}
478
479		fn get_storage(
480			address: AccountId,
481			key: Vec<u8>,
482		) -> pallet_contracts::GetStorageResult {
483			Contracts::get_storage(address, key)
484		}
485	}
486}