referrerpolicy=no-referrer-when-downgrade

coretime_westend_runtime/
coretime.rs

1// Copyright (C) Parity Technologies (UK) Ltd.
2// This file is part of Cumulus.
3// SPDX-License-Identifier: Apache-2.0
4
5// Licensed under the Apache License, Version 2.0 (the "License");
6// you may not use this file except in compliance with the License.
7// You may obtain a copy of the License at
8//
9// 	http://www.apache.org/licenses/LICENSE-2.0
10//
11// Unless required by applicable law or agreed to in writing, software
12// distributed under the License is distributed on an "AS IS" BASIS,
13// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14// See the License for the specific language governing permissions and
15// limitations under the License.
16
17use crate::{xcm_config::LocationToAccountId, *};
18use codec::{Decode, Encode};
19use cumulus_pallet_parachain_system::RelaychainDataProvider;
20use cumulus_primitives_core::relay_chain;
21use frame_support::parameter_types;
22use pallet_broker::{
23	CoreAssignment, CoreIndex, CoretimeInterface, PartsOf57600, RCBlockNumberOf, TaskId,
24};
25use parachains_common::{AccountId, Balance};
26use sp_runtime::traits::MaybeConvert;
27use westend_runtime_constants::system_parachain::coretime;
28use xcm::latest::prelude::*;
29use xcm_executor::traits::ConvertLocation;
30
31/// A type containing the encoding of the coretime pallet in the Relay chain runtime. Used to
32/// construct any remote calls. The codec index must correspond to the index of `Coretime` in the
33/// `construct_runtime` of the Relay chain.
34#[derive(Encode, Decode)]
35enum RelayRuntimePallets {
36	#[codec(index = 66)]
37	Coretime(CoretimeProviderCalls),
38}
39
40/// Call encoding for the calls needed from the relay coretime pallet.
41#[derive(Encode, Decode)]
42enum CoretimeProviderCalls {
43	#[codec(index = 1)]
44	RequestCoreCount(CoreIndex),
45	#[codec(index = 2)]
46	RequestRevenueInfoAt(relay_chain::BlockNumber),
47	#[codec(index = 3)]
48	CreditAccount(AccountId, Balance),
49	#[codec(index = 4)]
50	AssignCore(
51		CoreIndex,
52		relay_chain::BlockNumber,
53		Vec<(CoreAssignment, PartsOf57600)>,
54		Option<relay_chain::BlockNumber>,
55	),
56}
57
58parameter_types! {
59	pub const BrokerPalletId: PalletId = PalletId(*b"py/broke");
60	pub const MinimumCreditPurchase: Balance = UNITS / 10;
61	pub const MinimumEndPrice: Balance = UNITS;
62}
63
64/// Type that implements the `CoretimeInterface` for the allocation of Coretime. Meant to operate
65/// from the parachain context. That is, the parachain provides a market (broker) for the sale of
66/// coretime, but assumes a `CoretimeProvider` (i.e. a Relay Chain) to actually provide cores.
67pub struct CoretimeAllocator;
68impl CoretimeInterface for CoretimeAllocator {
69	type AccountId = AccountId;
70	type Balance = Balance;
71	type RelayChainBlockNumberProvider = RelaychainDataProvider<Runtime>;
72
73	fn request_core_count(count: CoreIndex) {
74		use crate::coretime::CoretimeProviderCalls::RequestCoreCount;
75		let request_core_count_call = RelayRuntimePallets::Coretime(RequestCoreCount(count));
76
77		// Weight for `request_core_count` from westend benchmarks:
78		// `ref_time` = 7889000 + (3 * 25000000) + (1 * 100000000) = 182889000
79		// `proof_size` = 1636
80		// Add 5% to each component and round to 2 significant figures.
81		let call_weight = Weight::from_parts(190_000_000, 1700);
82
83		let message = Xcm(vec![
84			Instruction::UnpaidExecution {
85				weight_limit: WeightLimit::Unlimited,
86				check_origin: None,
87			},
88			Instruction::Transact {
89				origin_kind: OriginKind::Native,
90				call: request_core_count_call.encode().into(),
91				fallback_max_weight: Some(call_weight),
92			},
93		]);
94
95		match PolkadotXcm::send_xcm(Here, Location::parent(), message.clone()) {
96			Ok(_) => tracing::debug!(
97				target: "runtime::coretime",
98				"Request to update schedulable cores sent successfully."
99			),
100			Err(e) => tracing::error!(
101				target: "runtime::coretime", error=?e,
102				"Failed to send request to update schedulable cores"
103			),
104		}
105	}
106
107	fn request_revenue_info_at(when: RCBlockNumberOf<Self>) {
108		use crate::coretime::CoretimeProviderCalls::RequestRevenueInfoAt;
109		let request_revenue_info_at_call =
110			RelayRuntimePallets::Coretime(RequestRevenueInfoAt(when));
111
112		let message = Xcm(vec![
113			Instruction::UnpaidExecution {
114				weight_limit: WeightLimit::Unlimited,
115				check_origin: None,
116			},
117			Instruction::Transact {
118				origin_kind: OriginKind::Native,
119				call: request_revenue_info_at_call.encode().into(),
120				fallback_max_weight: Some(Weight::from_parts(1_000_000_000, 200_000)),
121			},
122		]);
123
124		match PolkadotXcm::send_xcm(Here, Location::parent(), message.clone()) {
125			Ok(_) => tracing::debug!(
126				target: "runtime::coretime",
127				"Request for revenue information sent successfully."
128			),
129			Err(e) => tracing::error!(
130				target: "runtime::coretime", error=?e,
131				"Request for revenue information failed to send"
132			),
133		}
134	}
135
136	fn credit_account(who: Self::AccountId, amount: Self::Balance) {
137		use crate::coretime::CoretimeProviderCalls::CreditAccount;
138		let credit_account_call = RelayRuntimePallets::Coretime(CreditAccount(who, amount));
139
140		let message = Xcm(vec![
141			Instruction::UnpaidExecution {
142				weight_limit: WeightLimit::Unlimited,
143				check_origin: None,
144			},
145			Instruction::Transact {
146				origin_kind: OriginKind::Native,
147				call: credit_account_call.encode().into(),
148				fallback_max_weight: Some(Weight::from_parts(1_000_000_000, 200_000)),
149			},
150		]);
151
152		match PolkadotXcm::send_xcm(Here, Location::parent(), message.clone()) {
153			Ok(_) => tracing::debug!(
154				target: "runtime::coretime",
155				"Instruction to credit account sent successfully."
156			),
157			Err(e) => tracing::error!(
158				target: "runtime::coretime", error=?e,
159				"Instruction to credit account failed to send"
160			),
161		}
162	}
163
164	fn assign_core(
165		core: CoreIndex,
166		begin: RCBlockNumberOf<Self>,
167		assignment: Vec<(CoreAssignment, PartsOf57600)>,
168		end_hint: Option<RCBlockNumberOf<Self>>,
169	) {
170		use crate::coretime::CoretimeProviderCalls::AssignCore;
171
172		// Weight for `assign_core` from westend benchmarks:
173		// `ref_time` = 10177115 + (1 * 25000000) + (2 * 100000000) + (57600 * 13932) = 937660315
174		// `proof_size` = 3612
175		// Add 5% to each component and round to 2 significant figures.
176		let call_weight = Weight::from_parts(980_000_000, 3800);
177
178		// A maximum of 28 assignments fit in one message, so we split the assignments and send as
179		// multiple messages. This will get reassembled into a full list of assignments on the
180		// relay chain side.
181
182		for chunk in assignment.chunks(28) {
183			let partial_assignment = chunk.to_vec();
184
185			let assign_core_call = RelayRuntimePallets::Coretime(AssignCore(
186				core,
187				begin,
188				partial_assignment,
189				end_hint,
190			));
191
192			let message = Xcm(vec![
193				Instruction::UnpaidExecution {
194					weight_limit: WeightLimit::Unlimited,
195					check_origin: None,
196				},
197				Instruction::Transact {
198					origin_kind: OriginKind::Native,
199					call: assign_core_call.encode().into(),
200					fallback_max_weight: Some(call_weight),
201				},
202			]);
203
204			match PolkadotXcm::send_xcm(Here, Location::parent(), message) {
205				Ok(_) => tracing::debug!(
206					target: "runtime::coretime",
207					"Core assignment sent successfully."
208				),
209				Err(e) => tracing::error!(
210					target: "runtime::coretime", error=?e,
211					"Core assignment failed to send"
212				),
213			}
214		}
215	}
216}
217
218pub struct SovereignAccountOf;
219impl MaybeConvert<TaskId, AccountId> for SovereignAccountOf {
220	fn maybe_convert(id: TaskId) -> Option<AccountId> {
221		// Currently all tasks are parachains.
222		let location = Location::new(1, [Parachain(id)]);
223		LocationToAccountId::convert_location(&location)
224	}
225}
226
227impl pallet_broker::Config for Runtime {
228	type RuntimeEvent = RuntimeEvent;
229	type Currency = Balances;
230	type OnRevenue = AccumulateForward;
231	type TimeslicePeriod = ConstU32<{ coretime::TIMESLICE_PERIOD }>;
232	type MaxLeasedCores = ConstU32<50>;
233	type MaxReservedCores = ConstU32<50>;
234	type Coretime = CoretimeAllocator;
235	type ConvertBalance = sp_runtime::traits::Identity;
236	type WeightInfo = weights::pallet_broker::WeightInfo<Runtime>;
237	type PalletId = BrokerPalletId;
238	type AdminOrigin = EnsureRoot<AccountId>;
239	type SovereignAccountOf = SovereignAccountOf;
240	type MaxAutoRenewals = ConstU32<50>;
241	type PriceAdapter = pallet_broker::MinimumPrice<Balance, MinimumEndPrice>;
242	type MinimumCreditPurchase = MinimumCreditPurchase;
243}