From 1c85bfe901741f9c456af1ac92008d647660a2f4 Mon Sep 17 00:00:00 2001
From: Sergej Sakac <73715684+Szegoo@users.noreply.github.com>
Date: Sat, 6 Apr 2024 01:29:35 +0200
Subject: [PATCH] Broker: sale price runtime api (#3485)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Defines a runtime api for `pallet-broker` for getting the current price
of a core if there is an ongoing sale.

Closes: #3413

---------

Co-authored-by: Bastian Köcher <git@kchr.de>
---
 Cargo.lock                                    |  1 +
 .../coretime/coretime-rococo/src/lib.rs       |  8 ++++-
 .../coretime/coretime-westend/src/lib.rs      |  8 ++++-
 prdoc/pr_3485.prdoc                           | 20 ++++++++++++
 substrate/frame/broker/Cargo.toml             |  2 ++
 .../frame/broker/src/dispatchable_impls.rs    | 28 ++++++++++++++---
 substrate/frame/broker/src/lib.rs             |  4 ++-
 substrate/frame/broker/src/runtime_api.rs     | 31 +++++++++++++++++++
 8 files changed, 95 insertions(+), 7 deletions(-)
 create mode 100644 prdoc/pr_3485.prdoc
 create mode 100644 substrate/frame/broker/src/runtime_api.rs

diff --git a/Cargo.lock b/Cargo.lock
index d6c46ad9975..307a6a52329 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -9423,6 +9423,7 @@ dependencies = [
  "frame-system",
  "parity-scale-codec",
  "scale-info",
+ "sp-api",
  "sp-arithmetic",
  "sp-core",
  "sp-io",
diff --git a/cumulus/parachains/runtimes/coretime/coretime-rococo/src/lib.rs b/cumulus/parachains/runtimes/coretime/coretime-rococo/src/lib.rs
index 1c67740ee54..9f01d397598 100644
--- a/cumulus/parachains/runtimes/coretime/coretime-rococo/src/lib.rs
+++ b/cumulus/parachains/runtimes/coretime/coretime-rococo/src/lib.rs
@@ -64,7 +64,7 @@ use sp_runtime::{
 	create_runtime_str, generic, impl_opaque_keys,
 	traits::Block as BlockT,
 	transaction_validity::{TransactionSource, TransactionValidity},
-	ApplyExtrinsicResult, MultiAddress, Perbill,
+	ApplyExtrinsicResult, DispatchError, MultiAddress, Perbill,
 };
 use sp_std::prelude::*;
 #[cfg(feature = "std")]
@@ -593,6 +593,12 @@ impl_runtime_apis! {
 		}
 	}
 
+	impl pallet_broker::runtime_api::BrokerApi<Block, Balance> for Runtime {
+		fn sale_price() -> Result<Balance, DispatchError> {
+			Broker::current_price()
+		}
+	}
+
 	impl pallet_transaction_payment_rpc_runtime_api::TransactionPaymentApi<Block, Balance> for Runtime {
 		fn query_info(
 			uxt: <Block as BlockT>::Extrinsic,
diff --git a/cumulus/parachains/runtimes/coretime/coretime-westend/src/lib.rs b/cumulus/parachains/runtimes/coretime/coretime-westend/src/lib.rs
index 696618c37a2..29d348c1cd9 100644
--- a/cumulus/parachains/runtimes/coretime/coretime-westend/src/lib.rs
+++ b/cumulus/parachains/runtimes/coretime/coretime-westend/src/lib.rs
@@ -64,7 +64,7 @@ use sp_runtime::{
 	create_runtime_str, generic, impl_opaque_keys,
 	traits::Block as BlockT,
 	transaction_validity::{TransactionSource, TransactionValidity},
-	ApplyExtrinsicResult, MultiAddress, Perbill,
+	ApplyExtrinsicResult, DispatchError, MultiAddress, Perbill,
 };
 use sp_std::prelude::*;
 #[cfg(feature = "std")]
@@ -584,6 +584,12 @@ impl_runtime_apis! {
 		}
 	}
 
+	impl pallet_broker::runtime_api::BrokerApi<Block, Balance> for Runtime {
+		fn sale_price() -> Result<Balance, DispatchError> {
+			Broker::current_price()
+		}
+	}
+
 	impl pallet_transaction_payment_rpc_runtime_api::TransactionPaymentApi<Block, Balance> for Runtime {
 		fn query_info(
 			uxt: <Block as BlockT>::Extrinsic,
diff --git a/prdoc/pr_3485.prdoc b/prdoc/pr_3485.prdoc
new file mode 100644
index 00000000000..2add8867c4c
--- /dev/null
+++ b/prdoc/pr_3485.prdoc
@@ -0,0 +1,20 @@
+# Schema: Polkadot SDK PRDoc Schema (prdoc) v1.0.0
+# See doc at https://raw.githubusercontent.com/paritytech/polkadot-sdk/master/prdoc/schema_user.json
+
+title: "Broker: sale price runtime api"
+
+doc:
+  - audience: Runtime Dev
+    description: |
+      Defines a runtime api for `pallet-broker` for getting the current price 
+      of a core in the ongoing sale.
+
+  - audience: Runtime User
+    description: |
+      Defines a runtime api for `pallet-broker` for getting the current price 
+      of a core in the ongoing sale.
+
+crates:
+  - name: pallet-broker
+  - name: coretime-rococo-runtime
+  - name: coretime-westend-runtime
diff --git a/substrate/frame/broker/Cargo.toml b/substrate/frame/broker/Cargo.toml
index 3b6bd2019cc..969f13e269d 100644
--- a/substrate/frame/broker/Cargo.toml
+++ b/substrate/frame/broker/Cargo.toml
@@ -18,6 +18,7 @@ targets = ["x86_64-unknown-linux-gnu"]
 codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] }
 scale-info = { version = "2.11.1", default-features = false, features = ["derive"] }
 bitvec = { version = "1.0.0", default-features = false }
+sp-api = { path = "../../primitives/api", default-features = false }
 sp-std = { path = "../../primitives/std", default-features = false }
 sp-arithmetic = { path = "../../primitives/arithmetic", default-features = false }
 sp-core = { path = "../../primitives/core", default-features = false }
@@ -39,6 +40,7 @@ std = [
 	"frame-support/std",
 	"frame-system/std",
 	"scale-info/std",
+	"sp-api/std",
 	"sp-arithmetic/std",
 	"sp-core/std",
 	"sp-io/std",
diff --git a/substrate/frame/broker/src/dispatchable_impls.rs b/substrate/frame/broker/src/dispatchable_impls.rs
index a87618147fe..ef20bc8fb80 100644
--- a/substrate/frame/broker/src/dispatchable_impls.rs
+++ b/substrate/frame/broker/src/dispatchable_impls.rs
@@ -105,8 +105,8 @@ impl<T: Config> Pallet<T> {
 	) -> Result<RegionId, DispatchError> {
 		let status = Status::<T>::get().ok_or(Error::<T>::Uninitialized)?;
 		let mut sale = SaleInfo::<T>::get().ok_or(Error::<T>::NoSales)?;
-		ensure!(sale.first_core < status.core_count, Error::<T>::Unavailable);
-		ensure!(sale.cores_sold < sale.cores_offered, Error::<T>::SoldOut);
+		Self::ensure_cores_for_sale(&status, &sale)?;
+
 		let now = frame_system::Pallet::<T>::block_number();
 		ensure!(now > sale.sale_start, Error::<T>::TooEarly);
 		let price = Self::sale_price(&sale, now);
@@ -131,8 +131,7 @@ impl<T: Config> Pallet<T> {
 		let config = Configuration::<T>::get().ok_or(Error::<T>::Uninitialized)?;
 		let status = Status::<T>::get().ok_or(Error::<T>::Uninitialized)?;
 		let mut sale = SaleInfo::<T>::get().ok_or(Error::<T>::NoSales)?;
-		ensure!(sale.first_core < status.core_count, Error::<T>::Unavailable);
-		ensure!(sale.cores_sold < sale.cores_offered, Error::<T>::SoldOut);
+		Self::ensure_cores_for_sale(&status, &sale)?;
 
 		let renewal_id = AllowedRenewalId { core, when: sale.region_begin };
 		let record = AllowedRenewals::<T>::get(renewal_id).ok_or(Error::<T>::NotAllowed)?;
@@ -456,4 +455,25 @@ impl<T: Config> Pallet<T> {
 
 		Ok(())
 	}
+
+	pub(crate) fn ensure_cores_for_sale(
+		status: &StatusRecord,
+		sale: &SaleInfoRecordOf<T>,
+	) -> Result<(), DispatchError> {
+		ensure!(sale.first_core < status.core_count, Error::<T>::Unavailable);
+		ensure!(sale.cores_sold < sale.cores_offered, Error::<T>::SoldOut);
+
+		Ok(())
+	}
+
+	/// If there is an ongoing sale returns the current price of a core.
+	pub fn current_price() -> Result<BalanceOf<T>, DispatchError> {
+		let status = Status::<T>::get().ok_or(Error::<T>::Uninitialized)?;
+		let sale = SaleInfo::<T>::get().ok_or(Error::<T>::NoSales)?;
+
+		Self::ensure_cores_for_sale(&status, &sale)?;
+
+		let now = frame_system::Pallet::<T>::block_number();
+		Ok(Self::sale_price(&sale, now))
+	}
 }
diff --git a/substrate/frame/broker/src/lib.rs b/substrate/frame/broker/src/lib.rs
index d059965a392..a39576b0901 100644
--- a/substrate/frame/broker/src/lib.rs
+++ b/substrate/frame/broker/src/lib.rs
@@ -36,6 +36,8 @@ mod tick_impls;
 mod types;
 mod utility_impls;
 
+pub mod runtime_api;
+
 pub mod weights;
 pub use weights::WeightInfo;
 
@@ -132,7 +134,7 @@ pub mod pallet {
 	pub type AllowedRenewals<T> =
 		StorageMap<_, Twox64Concat, AllowedRenewalId, AllowedRenewalRecordOf<T>, OptionQuery>;
 
-	/// The current (unassigned) Regions.
+	/// The current (unassigned or provisionally assigend) Regions.
 	#[pallet::storage]
 	pub type Regions<T> = StorageMap<_, Blake2_128Concat, RegionId, RegionRecordOf<T>, OptionQuery>;
 
diff --git a/substrate/frame/broker/src/runtime_api.rs b/substrate/frame/broker/src/runtime_api.rs
new file mode 100644
index 00000000000..6faab615650
--- /dev/null
+++ b/substrate/frame/broker/src/runtime_api.rs
@@ -0,0 +1,31 @@
+// This file is part of Substrate.
+
+// Copyright (C) Parity Technologies (UK) Ltd.
+// SPDX-License-Identifier: Apache-2.0
+
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// 	http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+//! Runtime API definition for the FRAME Broker pallet.
+
+use codec::Codec;
+use sp_runtime::DispatchError;
+
+sp_api::decl_runtime_apis! {
+	pub trait BrokerApi<Balance>
+	where
+		Balance: Codec
+	{
+		/// If there is an ongoing sale returns the current price of a core.
+		fn sale_price() -> Result<Balance, DispatchError>;
+	}
+}
-- 
GitLab