diff --git a/e2e_tests/common.ts b/e2e_tests/common.ts index b63e73e..9ca51cd 100644 --- a/e2e_tests/common.ts +++ b/e2e_tests/common.ts @@ -29,6 +29,27 @@ async function submitExtrinsic( }); } +async function submitUnsigned( + call: SubmittableExtrinsic<'promise'>, +): Promise { + return new Promise((resolve, reject) => { + const unsub = call.send(({ status, isError }) => { + console.log(`Current status is ${status}`); + if (status.isInBlock) { + console.log(`Transaction included at blockHash ${status.asInBlock}`); + } else if (status.isFinalized) { + console.log(`Transaction finalized at blockHash ${status.asFinalized}`); + unsub.then(); + return resolve(); + } else if (isError) { + console.log('Transaction error'); + unsub.then(); + return reject(); + } + }); + }); +} + async function setupRelayAsset(api: ApiPromise, signer: KeyringPair, initialBalance = 0n) { // The relay asset is registered in the genesis block. @@ -147,6 +168,7 @@ export { sleep, openHrmpChannel, submitExtrinsic, + submitUnsigned, transferRelayAssetToPara, getAddressFromModuleId, getFreeBalance, diff --git a/e2e_tests/ismp.common.ts b/e2e_tests/ismp.common.ts index 216b66d..4c96763 100644 --- a/e2e_tests/ismp.common.ts +++ b/e2e_tests/ismp.common.ts @@ -1,7 +1,6 @@ import { ApiPromise } from '@polkadot/api'; import { KeyringPair } from '@polkadot/keyring/types'; -import { ISubmittableResult } from '@polkadot/types/types'; -import { submitExtrinsic } from './common'; +import { submitExtrinsic, submitUnsigned } from './common'; import { Get, IsmpRequest } from './types'; async function ismpAddParachain(signer: KeyringPair, regionXApi: ApiPromise) { @@ -59,24 +58,7 @@ async function makeIsmpResponse( }, }, ]); - - return new Promise((resolve, reject) => { - const unsub = response.send((result: ISubmittableResult) => { - const { status, isError } = result; - console.log(`Current status is ${status}`); - if (status.isInBlock) { - console.log(`Transaction included at blockHash ${status.asInBlock}`); - } else if (status.isFinalized) { - console.log(`Transaction finalized at blockHash ${status.asFinalized}`); - unsub.then(); - return resolve(); - } else if (isError) { - console.log('Transaction error'); - unsub.then(); - return reject(); - } - }); - }); + await submitUnsigned(response); } else { new Error('Expected a Get request'); } diff --git a/e2e_tests/xc-regions.common.ts b/e2e_tests/xc-regions.common.ts index d5fa01e..fbc81d4 100644 --- a/e2e_tests/xc-regions.common.ts +++ b/e2e_tests/xc-regions.common.ts @@ -2,7 +2,7 @@ import { ApiPromise, Keyring } from '@polkadot/api'; import { KeyringPair } from '@polkadot/keyring/types'; import { getEncodedRegionId, RegionId } from 'coretime-utils'; import assert from 'node:assert'; -import { sleep, submitExtrinsic } from './common'; +import { sleep, submitExtrinsic, submitUnsigned } from './common'; import { makeIsmpResponse, queryRequest } from './ismp.common'; const REGIONX_SOVEREIGN_ACCOUNT = '5Eg2fntJ27qsari4FGrGhrMqKFDRnkNSR6UshkZYBGXmSuC8'; @@ -69,7 +69,7 @@ async function transferRegionToRegionX( await sleep(5000); const requestRecord = regionXApi.tx.regions.requestRegionRecord(regionId); - await submitExtrinsic(sender, requestRecord, {}); + await submitUnsigned(requestRecord); let regions = await regionXApi.query.regions.regions.entries(); assert.equal(regions.length, 1); diff --git a/pallets/market/src/mock.rs b/pallets/market/src/mock.rs index 2e9c359..cb9fe79 100644 --- a/pallets/market/src/mock.rs +++ b/pallets/market/src/mock.rs @@ -129,6 +129,7 @@ impl IsmpDispatcher for MockDispatcher { parameter_types! { pub const CoretimeChain: StateMachine = StateMachine::Kusama(1005); // coretime-kusama + pub const RegionsUnsignedPriority: TransactionPriority = TransactionPriority::max_value(); } impl pallet_regions::Config for Test { @@ -138,6 +139,7 @@ impl pallet_regions::Config for Test { type IsmpDispatcher = MockDispatcher; type StateMachineHeightProvider = MockStateMachineHeightProvider; type Timeout = ConstU64<1000>; + type UnsignedPriority = RegionsUnsignedPriority; type WeightInfo = (); } diff --git a/pallets/processor/src/mock.rs b/pallets/processor/src/mock.rs index 9d70207..a860e78 100644 --- a/pallets/processor/src/mock.rs +++ b/pallets/processor/src/mock.rs @@ -164,6 +164,7 @@ impl IsmpDispatcher for MockDispatcher { parameter_types! { pub const CoretimeChainStateMachine: StateMachine = StateMachine::Kusama(1005); // coretime-kusama + pub const RegionsUnsignedPriority: TransactionPriority = TransactionPriority::max_value(); } impl pallet_regions::Config for Test { @@ -173,6 +174,7 @@ impl pallet_regions::Config for Test { type IsmpDispatcher = MockDispatcher; type StateMachineHeightProvider = MockStateMachineHeightProvider; type Timeout = ConstU64<1000>; + type UnsignedPriority = RegionsUnsignedPriority; type WeightInfo = (); } diff --git a/pallets/regions/src/lib.rs b/pallets/regions/src/lib.rs index 3bf90da..201692f 100644 --- a/pallets/regions/src/lib.rs +++ b/pallets/regions/src/lib.rs @@ -63,6 +63,10 @@ const LOG_TARGET: &str = "runtime::regions"; /// Constant Pallet ID pub const PALLET_ID: ModuleId = ModuleId::Pallet(PalletId(*b"regionsp")); +// Custom transaction error codes +const REGION_NOT_FOUND: u8 = 1; +const REGION_NOT_UNAVAILABLE: u8 = 2; + #[frame_support::pallet] pub mod pallet { use super::*; @@ -93,6 +97,10 @@ pub mod pallet { /// Number of seconds before a GET request times out. type Timeout: Get; + /// The priority of unsigned transactions. + #[pallet::constant] + type UnsignedPriority: Get; + /// Weight Info type WeightInfo: WeightInfo; } @@ -281,6 +289,37 @@ pub mod pallet { Ok(key) } } + + #[pallet::validate_unsigned] + impl ValidateUnsigned for Pallet { + type Call = Call; + fn validate_unsigned(_source: TransactionSource, call: &Self::Call) -> TransactionValidity { + let region_id = match call { + Call::request_region_record { region_id } => region_id, + _ => return InvalidTransaction::Call.into(), + }; + + let Some(region) = Regions::::get(region_id) else { + return InvalidTransaction::Custom(REGION_NOT_FOUND).into() + }; + + if !region.record.is_unavailable() { + return InvalidTransaction::Custom(REGION_NOT_UNAVAILABLE).into() + } + + ValidTransaction::with_tag_prefix("RecordRequest") + .priority(T::UnsignedPriority::get()) + .and_provides(region_id) + .propagate(true) + .build() + } + + fn pre_dispatch(_call: &Self::Call) -> Result<(), TransactionValidityError> { + // Given that the `request_region_record` function contains checks there is no need to + // call `validate_unsigned` again. + Ok(()) + } + } } /// Module callback for the pallet diff --git a/pallets/regions/src/mock.rs b/pallets/regions/src/mock.rs index a0f81fc..14156d4 100644 --- a/pallets/regions/src/mock.rs +++ b/pallets/regions/src/mock.rs @@ -85,6 +85,7 @@ impl pallet_balances::Config for Test { parameter_types! { pub const CoretimeChain: StateMachine = StateMachine::Kusama(1005); // coretime-kusama + pub const RegionsUnsignedPriority: TransactionPriority = TransactionPriority::max_value(); } pub struct MockStateMachineHeightProvider; @@ -101,6 +102,7 @@ impl crate::Config for Test { type IsmpDispatcher = MockDispatcher; type StateMachineHeightProvider = MockStateMachineHeightProvider; type Timeout = ConstU64<1000>; + type UnsignedPriority = RegionsUnsignedPriority; type WeightInfo = (); } diff --git a/runtime/cocos/src/lib.rs b/runtime/cocos/src/lib.rs index ae448c1..d890f04 100644 --- a/runtime/cocos/src/lib.rs +++ b/runtime/cocos/src/lib.rs @@ -63,7 +63,7 @@ use sp_runtime::{ traits::{ AccountIdConversion, AccountIdLookup, BlakeTwo256, Block as BlockT, Convert, IdentityLookup, }, - transaction_validity::{TransactionSource, TransactionValidity}, + transaction_validity::{TransactionPriority, TransactionSource, TransactionValidity}, ApplyExtrinsicResult, }; @@ -207,7 +207,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { /// up by `pallet_aura` to implement `fn slot_duration()`. /// /// Change this to adjust the block time. -pub const MILLISECS_PER_BLOCK: u64 = 6000; +pub const MILLISECS_PER_BLOCK: u64 = 12000; // NOTE: Currently it is not possible to change the slot duration after the chain has started. // Attempting to do so will brick block production. @@ -234,7 +234,7 @@ pub const fn deposit(items: u32, bytes: u32) -> Balance { /// Maximum number of blocks simultaneously accepted by the Runtime, not yet included /// into the relay chain. -const UNINCLUDED_SEGMENT_CAPACITY: u32 = 3; +const UNINCLUDED_SEGMENT_CAPACITY: u32 = 1; /// How many parachain blocks are processed by the relay chain per parent. Limits the /// number of blocks authored per slot. const BLOCK_PROCESSING_VELOCITY: u32 = 1; @@ -254,7 +254,7 @@ const NORMAL_DISPATCH_RATIO: Perbill = Perbill::from_percent(75); /// We allow for 0.5 of a second of compute with a 12 second average block time. const MAXIMUM_BLOCK_WEIGHT: Weight = Weight::from_parts( - WEIGHT_REF_TIME_PER_SECOND.saturating_mul(2), + WEIGHT_REF_TIME_PER_SECOND.saturating_div(2), cumulus_primitives_core::relay_chain::MAX_POV_SIZE as u64, ); @@ -352,9 +352,6 @@ impl pallet_timestamp::Config for Runtime { /// A timestamp: milliseconds since the unix epoch. type Moment = u64; type OnTimestampSet = Aura; - #[cfg(feature = "experimental")] - type MinimumPeriod = ConstU64<0>; - #[cfg(not(feature = "experimental"))] type MinimumPeriod = ConstU64<{ SLOT_DURATION / 2 }>; type WeightInfo = weights::pallet_timestamp::WeightInfo; } @@ -571,7 +568,7 @@ impl pallet_aura::Config for Runtime { type AuthorityId = AuraId; type DisabledValidators = (); type MaxAuthorities = ConstU32<100_000>; - type AllowMultipleBlocksPerSlot = ConstBool; + type AllowMultipleBlocksPerSlot = ConstBool; } parameter_types! { @@ -615,6 +612,7 @@ impl StateMachineHeightProviderT for StateMachineHeightProvider { parameter_types! { pub const CoretimeChain: StateMachine = StateMachine::Kusama(CORETIME_CHAIN_PARA_ID); // coretime-kusama + pub const RegionsUnsignedPriority: TransactionPriority = TransactionPriority::max_value(); } impl pallet_regions::Config for Runtime { @@ -624,6 +622,7 @@ impl pallet_regions::Config for Runtime { type IsmpDispatcher = Ismp; type StateMachineHeightProvider = StateMachineHeightProvider; type Timeout = ConstU64<300>; // 5 minutes + type UnsignedPriority = RegionsUnsignedPriority; type WeightInfo = weights::pallet_regions::WeightInfo; }