feat: Rebrand Polkadot/Substrate references to PezkuwiChain

This commit systematically rebrands various references from Parity Technologies'
Polkadot/Substrate ecosystem to PezkuwiChain within the kurdistan-sdk.

Key changes include:
- Updated external repository URLs (zombienet-sdk, parity-db, parity-scale-codec, wasm-instrument) to point to pezkuwichain forks.
- Modified internal documentation and code comments to reflect PezkuwiChain naming and structure.
- Replaced direct references to  with  or specific paths within the  for XCM, Pezkuwi, and other modules.
- Cleaned up deprecated  issue and PR references in various  and  files, particularly in  and  modules.
- Adjusted image and logo URLs in documentation to point to PezkuwiChain assets.
- Removed or rephrased comments related to external Polkadot/Substrate PRs and issues.

This is a significant step towards fully customizing the SDK for the PezkuwiChain ecosystem.
This commit is contained in:
2025-12-14 00:04:10 +03:00
parent 286de54384
commit 1c0e57d984
9084 changed files with 997839 additions and 997557 deletions
@@ -0,0 +1,61 @@
[package]
name = "pezpallet-oracle"
version = "1.0.0"
authors = [
"Acala Developers",
"Kurdistan Tech Institute <info@pezkuwichain.io>",
"Parity Technologies <admin@parity.io>",
]
edition.workspace = true
license = "Apache-2.0"
homepage.workspace = true
repository.workspace = true
description = "FRAME oracle pallet for off-chain data"
readme = "README.md"
[lints]
workspace = true
[package.metadata.docs.rs]
targets = ["x86_64-unknown-linux-gnu"]
[dependencies]
codec = { features = ["derive"], workspace = true }
scale-info = { features = ["derive"], workspace = true }
serde = { workspace = true }
pezframe-benchmarking = { workspace = true, optional = true }
pezframe-support = { workspace = true }
pezframe-system = { workspace = true }
impl-trait-for-tuples = { workspace = true }
pezsp-application-crypto = { workspace = true }
pezsp-io = { workspace = true }
pezsp-runtime = { workspace = true }
pezsp-std = { workspace = true }
[features]
default = ["std"]
std = [
"codec/std",
"pezframe-benchmarking?/std",
"pezframe-support/std",
"pezframe-system/std",
"scale-info/std",
"serde/std",
"pezsp-application-crypto/std",
"pezsp-io/std",
"pezsp-runtime/std",
"pezsp-std/std",
]
runtime-benchmarks = [
"pezframe-benchmarking/runtime-benchmarks",
"pezframe-support/runtime-benchmarks",
"pezframe-system/runtime-benchmarks",
"pezsp-io/runtime-benchmarks",
"pezsp-runtime/runtime-benchmarks",
]
try-runtime = [
"pezframe-support/try-runtime",
"pezframe-system/try-runtime",
"pezsp-runtime/try-runtime",
]
@@ -0,0 +1,59 @@
# pezpallet-oracle
## Overview
The Oracle pallet provides a decentralized and trustworthy way to bring external, off-chain data onto the
blockchain. It allows a configurable set of oracle operators to feed data, such as prices, into the system.
This data can then be used by other pallets.
The pallet is designed to be flexible and can be configured to use different data sources and aggregation
strategies.
## Key Concepts
- **Oracle Operators**: A set of trusted accounts that are authorized to submit data to the oracle. The pallet
uses the `frame_support::traits::SortedMembers` trait to manage the set of operators. This allows using pallets
like `pezpallet-membership` to manage the oracle members.
- **Data Feeds**: Operators feed data as key-value pairs. The `OracleKey` is used to identify the data being fed
(e.g., a specific currency pair), and the `OracleValue` is the data itself (e.g., the price).
- **Data Aggregation**: The pallet can be configured with a `CombineData` implementation to aggregate the raw
values submitted by individual operators into a single, trusted value. A default implementation
`DefaultCombineData` is provided, which takes the median of the values.
- **Timestamped Data**: All data submitted to the oracle is timestamped, allowing consumers of the data to know
how fresh it is.
## Interface
### Dispatchable Functions
- `feed_values` - Allows an authorized oracle operator to submit a set of key-value data points.
### Public Functions
- `get` - Returns the aggregated and timestamped value for a given key.
- `get_all_values` - Returns all aggregated and timestamped values.
- `read_raw_values` - Returns the raw, un-aggregated values for a given key from all oracle operators.
### Data Providers
The pallet implements the `DataProvider` and `DataProviderExtended` traits, allowing other pallets to easily
consume the oracle data.
## Usage
To use the oracle pallet, you need to:
1. **Add it to your runtime's `Cargo.toml`**.
2. **Implement the `Config` trait** for the pallet in your runtime. This includes specifying:
- `OnNewData`: A hook to perform actions when new data is received.
- `CombineData`: The data aggregation strategy.
- `Time`: The time provider.
- `OracleKey`, `OracleValue`: The types for the data key and value.
- `RootOperatorAccountId`: An account with sudo-like permissions for the oracle.
- `Members`: The source of oracle operators.
3. **Add the pallet to your runtime's `construct_runtime!` macro**.
Once configured, authorized operators can call `feed_values` to submit data, and other pallets can use the
`DataProvider` trait to read the aggregated data.
License: Apache-2.0
@@ -0,0 +1,25 @@
[package]
name = "pezpallet-oracle-runtime-api"
version = "1.0.0"
authors = [
"Acala Developers",
"Kurdistan Tech Institute <info@pezkuwichain.io>",
"Parity Technologies <admin@parity.io>",
]
edition.workspace = true
license = "Apache-2.0"
homepage.workspace = true
repository.workspace = true
description = "Runtime API for the oracle pallet."
[dependencies]
codec = { workspace = true, features = ["derive"] }
scale-info = { workspace = true }
pezsp-api = { workspace = true }
pezsp-std = { workspace = true }
[features]
default = ["std"]
std = ["codec/std", "scale-info/std", "pezsp-api/std", "pezsp-std/std"]
runtime-benchmarks = ["pezsp-api/runtime-benchmarks"]
@@ -0,0 +1,92 @@
// This file is part of Bizinikiwi.
// Copyright (C) 2020-2025 Acala Foundation.
// 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 oracle pallet.
//!
//! This crate provides runtime APIs that allow external clients to query oracle data
//! from the blockchain. The APIs are designed to be efficient and provide access to
//! both individual oracle values and complete datasets.
//!
//! ## Overview
//!
//! The oracle runtime API enables off-chain applications, wallets, and other blockchain
//! clients to retrieve oracle data without needing to parse storage directly. This
//! abstraction provides a clean interface for accessing oracle information and ensures
//! compatibility across different runtime versions.
//!
//! The API supports querying data from specific oracle providers and retrieving all
//! available oracle data, making it suitable for various use cases such as price
//! feeds, data monitoring, and external integrations.
#![cfg_attr(not(feature = "std"), no_std)]
// The `too_many_arguments` warning originates from `decl_runtime_apis` macro.
#![allow(clippy::too_many_arguments)]
// The `unnecessary_mut_passed` warning originates from `decl_runtime_apis` macro.
#![allow(clippy::unnecessary_mut_passed)]
use codec::Codec;
use pezsp_std::prelude::Vec;
pezsp_api::decl_runtime_apis! {
/// Runtime API for querying oracle data from the blockchain.
///
/// This trait provides methods to retrieve oracle data without requiring direct
/// storage access. It's designed to be called from external clients, RPC nodes,
/// and other blockchain infrastructure components that need access to oracle
/// information.
///
/// The API is generic over three type parameters:
/// - `ProviderId`: Identifies the oracle provider or data source
/// - `Key`: The oracle key identifying the specific data feed
/// - `Value`: The oracle data value type
pub trait OracleApi<ProviderId, Key, Value> where
ProviderId: Codec,
Key: Codec,
Value: Codec,
{
/// Retrieves a specific oracle value for a given provider and key.
///
/// Returns the current oracle value if available, or `None` if no data exists
/// for the specified provider and key combination.
///
/// # Parameters
///
/// * `provider_id`: The oracle provider identifier
/// * `key`: The oracle key identifying the data feed
///
/// # Returns
///
/// Returns `Some(value)` if oracle data exists, `None` otherwise.
fn get_value(provider_id: ProviderId, key: Key) -> Option<Value>;
/// Retrieves all oracle values for a specific provider.
///
/// Returns a vector of key-value pairs containing all available oracle data
/// from the specified provider. Each pair contains the oracle key and its
/// corresponding value (if available).
///
/// # Parameters
///
/// * `provider_id`: The oracle provider identifier
///
/// # Returns
///
/// Returns a vector of `(Key, Option<Value>)` pairs representing all oracle
/// data available from the specified provider.
fn get_all_values(provider_id: ProviderId) -> Vec<(Key, Option<Value>)>;
}
}
@@ -0,0 +1,73 @@
// This file is part of Bizinikiwi.
// Copyright (C) 2020-2025 Acala Foundation.
// 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.
use super::*;
use crate::Pallet as Oracle;
use pezframe_benchmarking::v2::*;
use pezframe_support::assert_ok;
use pezframe_system::{Pallet as System, RawOrigin};
#[instance_benchmarks]
mod benchmarks {
use super::*;
#[benchmark]
fn feed_values(
x: Linear<0, { T::BenchmarkHelper::get_currency_id_value_pairs().len() as u32 }>,
) {
// Register the caller
let caller: T::AccountId = whitelisted_caller();
T::Members::add(&caller);
let values = T::BenchmarkHelper::get_currency_id_value_pairs()[..x as usize]
.to_vec()
.try_into()
.expect("Must succeed since at worst the length remained the same.");
#[extrinsic_call]
_(RawOrigin::Signed(caller.clone()), values);
assert!(HasDispatched::<T, I>::get().contains(&caller));
}
#[benchmark]
fn on_finalize() {
// Register the caller
let caller: T::AccountId = whitelisted_caller();
T::Members::add(&caller);
// Feed some values before running `on_finalize` hook
System::<T>::set_block_number(1u32.into());
let values = T::BenchmarkHelper::get_currency_id_value_pairs();
assert_ok!(Oracle::<T, I>::feed_values(RawOrigin::Signed(caller).into(), values));
#[block]
{
Oracle::<T, I>::on_finalize(System::<T>::block_number());
}
assert!(!HasDispatched::<T, I>::exists());
}
impl_benchmark_test_suite! {
Oracle,
crate::mock::new_test_ext(),
crate::mock::Test,
}
}
@@ -0,0 +1,60 @@
// This file is part of Bizinikiwi.
// Copyright (C) 2020-2025 Acala Foundation.
// 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.
use crate::{CombineData, Config, MomentOf, TimestampedValueOf};
use pezframe_support::traits::{Get, Time};
use pezsp_runtime::traits::Saturating;
use pezsp_std::{marker, prelude::*};
/// Sort by value and returns median timestamped value.
/// Returns prev_value if not enough valid values.
pub struct DefaultCombineData<T, MinimumCount, ExpiresIn, I = ()>(
marker::PhantomData<(T, I, MinimumCount, ExpiresIn)>,
);
impl<T, I, MinimumCount, ExpiresIn>
CombineData<<T as Config<I>>::OracleKey, TimestampedValueOf<T, I>>
for DefaultCombineData<T, MinimumCount, ExpiresIn, I>
where
T: Config<I>,
I: 'static,
MinimumCount: Get<u32>,
ExpiresIn: Get<MomentOf<T, I>>,
{
fn combine_data(
_key: &<T as Config<I>>::OracleKey,
mut values: Vec<TimestampedValueOf<T, I>>,
prev_value: Option<TimestampedValueOf<T, I>>,
) -> Option<TimestampedValueOf<T, I>> {
let expires_in = ExpiresIn::get();
let now = T::Time::now();
values.retain(|x| x.timestamp.saturating_add(expires_in) > now);
let count = values.len() as u32;
let minimum_count = MinimumCount::get();
if count < minimum_count || count == 0 {
return prev_value;
}
let mid_index = count / 2;
// Won't panic as `values` ensured not empty.
let (_, value, _) =
values.select_nth_unstable_by(mid_index as usize, |a, b| a.value.cmp(&b.value));
Some(value.clone())
}
}
@@ -0,0 +1,473 @@
// This file is part of Bizinikiwi.
// Copyright (C) 2020-2025 Acala Foundation.
// 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.
//! # Oracle
//!
//! A pallet that provides a decentralized and trustworthy way to bring external, off-chain data
//! onto the blockchain.
//!
//! ## Pallet API
//!
//! See the [`pallet`] module for more information about the interfaces this pallet exposes,
//! including its configuration trait, dispatchables, storage items, events and errors.
//!
//! ## Overview
//!
//! The Oracle pallet enables blockchain applications to access real-world data through a
//! decentralized network of trusted data providers. It's designed to be flexible and can handle
//! various types of external data such as cryptocurrency prices, weather data, sports scores, or
//! any other off-chain information that needs to be brought on-chain.
//!
//! The pallet operates on a permissioned model where only authorized oracle operators can submit
//! data. This ensures data quality and prevents spam while maintaining decentralization through
//! multiple independent operators. The system aggregates data from multiple sources using
//! configurable algorithms, typically taking the median to resist outliers and manipulation
//! attempts.
//!
//! ### Key Concepts
//!
//! * **Oracle Operators**: A set of trusted accounts authorized to submit data. Managed through the
//! [`SortedMembers`] trait, allowing integration with membership pallets.
//! * **Data Feeds**: Key-value pairs where keys identify the data type (e.g., currency pair) and
//! values contain the actual data (e.g., price).
//! * **Data Aggregation**: Configurable algorithms to combine multiple operator inputs into a
//! single trusted value, with median aggregation provided by default.
//! * **Timestamped Data**: All submitted data includes timestamps for freshness tracking.
//!
//! ## Low Level / Implementation Details
//!
//! ### Design Goals
//!
//! The oracle system aims to provide:
//! - **Decentralization**: Multiple independent data providers prevent single points of failure
//! - **Data Quality**: Aggregation mechanisms filter out outliers and malicious data
//! - **Flexibility**: Configurable data types and aggregation strategies
//! - **Performance**: Efficient storage and retrieval of timestamped data
//! - **Security**: Permissioned access with cryptographic verification of data integrity
//!
//! ### Design
//!
//! The pallet uses a dual-storage approach:
//! - [`RawValues`]: Stores individual operator submissions with timestamps
//! - [`Values`]: Stores the final aggregated values after processing
//!
//! This design allows for:
//! - Historical tracking of individual operator submissions
//! - Efficient access to final aggregated values
//! - Clean separation between raw data and processed results
//! - Easy integration with data aggregation algorithms
#![cfg_attr(not(feature = "std"), no_std)]
use codec::{Decode, Encode, MaxEncodedLen};
use serde::{Deserialize, Serialize};
use pezframe_support::{
dispatch::Pays,
ensure,
pezpallet_prelude::*,
traits::{ChangeMembers, Get, SortedMembers, Time},
weights::Weight,
PalletId, Parameter,
};
use pezframe_system::pezpallet_prelude::*;
use scale_info::TypeInfo;
use pezsp_runtime::{
traits::{AccountIdConversion, Member},
DispatchResult, RuntimeDebug,
};
use pezsp_std::{prelude::*, vec};
#[cfg(feature = "runtime-benchmarks")]
mod benchmarking;
mod default_combine_data;
pub use default_combine_data::DefaultCombineData;
pub mod traits;
pub use traits::{CombineData, DataFeeder, DataProvider, DataProviderExtended, OnNewData};
#[cfg(test)]
mod mock;
#[cfg(test)]
mod tests;
pub mod weights;
pub use pallet::*;
pub use weights::WeightInfo;
#[cfg(feature = "runtime-benchmarks")]
/// Helper trait for benchmarking oracle operations.
pub trait BenchmarkHelper<OracleKey, OracleValue, L: Get<u32>> {
/// Returns a list of `(oracle_key, oracle_value)` pairs to be used for
/// benchmarking.
///
/// NOTE: User should ensure to at least submit two values, otherwise the
/// benchmark linear analysis might fail.
fn get_currency_id_value_pairs() -> BoundedVec<(OracleKey, OracleValue), L>;
}
#[cfg(feature = "runtime-benchmarks")]
impl<OracleKey, OracleValue, L: Get<u32>> BenchmarkHelper<OracleKey, OracleValue, L> for () {
fn get_currency_id_value_pairs() -> BoundedVec<(OracleKey, OracleValue), L> {
BoundedVec::default()
}
}
#[pezframe_support::pallet]
pub mod pallet {
use super::*;
pub(crate) type MomentOf<T, I = ()> = <<T as Config<I>>::Time as Time>::Moment;
pub(crate) type TimestampedValueOf<T, I = ()> =
TimestampedValue<<T as Config<I>>::OracleValue, MomentOf<T, I>>;
/// A wrapper for a value with a timestamp.
#[derive(
Encode,
Decode,
RuntimeDebug,
Eq,
PartialEq,
Clone,
Copy,
Ord,
PartialOrd,
TypeInfo,
MaxEncodedLen,
Serialize,
Deserialize,
)]
pub struct TimestampedValue<Value, Moment> {
/// The value.
pub value: Value,
/// The timestamp.
pub timestamp: Moment,
}
#[pallet::config]
pub trait Config<I: 'static = ()>: pezframe_system::Config {
/// A hook to be called when new data is received.
///
/// This hook is triggered whenever an oracle operator successfully submits new data.
/// It allows other pallets to react to oracle updates, enabling real-time responses to
/// external data changes.
type OnNewData: OnNewData<Self::AccountId, Self::OracleKey, Self::OracleValue>;
/// The implementation to combine raw values into a single aggregated value.
///
/// This type defines how multiple oracle operator submissions are combined into a single
/// trusted value. Common implementations include taking the median (to resist outliers)
/// or weighted averages based on operator reputation.
type CombineData: CombineData<Self::OracleKey, TimestampedValueOf<Self, I>>;
/// The time provider for timestamping oracle data.
///
/// This type provides the current timestamp used to mark when oracle data was submitted.
/// Timestamps are crucial for determining data freshness and preventing stale data usage.
type Time: Time;
/// The key type for identifying oracle data feeds.
///
/// This type is used to uniquely identify different types of oracle data (e.g., currency
/// pairs, asset prices, weather data).
type OracleKey: Parameter + Member + MaxEncodedLen;
/// The value type for oracle data.
///
/// This type represents the actual data submitted by oracle operators (e.g., prices,
/// temperatures, scores).
type OracleValue: Parameter + Member + Ord + MaxEncodedLen;
/// The pallet ID.
///
/// Will be used to derive the pallet's account, which is used as the oracle account
/// when values are fed by root.
#[pallet::constant]
type PalletId: Get<PalletId>;
/// The source of oracle members.
///
/// This type provides the set of accounts authorized to submit oracle data.
/// Typically implemented by membership pallets to allow governance-controlled
/// management of oracle operators.
type Members: SortedMembers<Self::AccountId>;
/// Weight information for extrinsics in this pallet.
type WeightInfo: WeightInfo;
/// The maximum number of oracle operators that can feed data in a single block.
#[pallet::constant]
type MaxHasDispatchedSize: Get<u32>;
/// The maximum number of key-value pairs that can be submitted in a single extrinsic.
#[pallet::constant]
type MaxFeedValues: Get<u32>;
/// A helper trait for benchmarking oracle operations.
///
/// Provides sample data for benchmarking the oracle pallet, allowing accurate
/// weight calculations and performance testing.
#[cfg(feature = "runtime-benchmarks")]
type BenchmarkHelper: BenchmarkHelper<
Self::OracleKey,
Self::OracleValue,
Self::MaxFeedValues,
>;
}
#[pallet::error]
pub enum Error<T, I = ()> {
/// The sender is not a member of the oracle and does not have
/// permission to feed data.
NoPermission,
/// The oracle member has already fed data in the current block.
AlreadyFeeded,
/// Exceeds the maximum number of `HasDispatched` size.
ExceedsMaxHasDispatchedSize,
}
#[pallet::event]
#[pallet::generate_deposit(pub(crate) fn deposit_event)]
pub enum Event<T: Config<I>, I: 'static = ()> {
/// New data has been fed into the oracle.
NewFeedData {
/// The account that fed the data.
sender: T::AccountId,
/// The key-value pairs of the data that was fed.
values: Vec<(T::OracleKey, T::OracleValue)>,
},
}
/// The raw values for each oracle operator.
///
/// Maps `(AccountId, OracleKey)` to `TimestampedValue` containing the operator's submitted
/// value along with the timestamp when it was submitted. This storage maintains the complete
/// history of individual operator submissions, allowing for data aggregation and audit trails.
///
/// ## Storage Economics
///
/// No storage deposits are required as this data is considered essential for the oracle's
/// operation and data integrity. The storage cost is borne by the blockchain as part of the
/// oracle infrastructure.
#[pallet::storage]
#[pallet::getter(fn raw_values)]
pub type RawValues<T: Config<I>, I: 'static = ()> = StorageDoubleMap<
_,
Twox64Concat,
T::AccountId,
Twox64Concat,
T::OracleKey,
TimestampedValueOf<T, I>,
>;
/// The aggregated values for each oracle key.
///
/// Maps `OracleKey` to `TimestampedValue`.
#[pallet::storage]
#[pallet::getter(fn values)]
pub type Values<T: Config<I>, I: 'static = ()> =
StorageMap<_, Twox64Concat, <T as Config<I>>::OracleKey, TimestampedValueOf<T, I>>;
/// A set of accounts that have already fed data in the current block.
///
/// This storage item tracks which oracle operators have already submitted data in the
/// current block to enforce the "one submission per block" rule. This prevents spam and
/// ensures fair participation among oracle operators.
///
/// The storage is cleared at the end of each block in the `on_finalize` hook, resetting
/// the state for the next block.
#[pallet::storage]
pub(crate) type HasDispatched<T: Config<I>, I: 'static = ()> =
StorageValue<_, BoundedBTreeSet<T::AccountId, T::MaxHasDispatchedSize>, ValueQuery>;
#[pallet::pallet]
pub struct Pallet<T, I = ()>(PhantomData<(T, I)>);
#[pallet::hooks]
impl<T: Config<I>, I: 'static> Hooks<BlockNumberFor<T>> for Pallet<T, I> {
/// `on_initialize` to return the weight used in `on_finalize`.
fn on_initialize(_n: BlockNumberFor<T>) -> Weight {
T::WeightInfo::on_finalize()
}
fn on_finalize(_n: BlockNumberFor<T>) {
// cleanup for next block
<HasDispatched<T, I>>::kill();
}
}
#[pallet::view_functions]
impl<T: Config<I>, I: 'static> Pallet<T, I> {
/// Retrieve the aggregated oracle value for a specific key, including its timestamp.
pub fn get_value(key: T::OracleKey) -> Option<TimestampedValueOf<T, I>> {
Self::get(&key)
}
/// Retrieve every aggregated oracle value tracked by the pallet.
pub fn all_values() -> Vec<(T::OracleKey, TimestampedValueOf<T, I>)> {
<Values<T, I>>::iter().collect()
}
}
#[pallet::call]
impl<T: Config<I>, I: 'static> Pallet<T, I> {
/// Feeds external data values into the oracle system.
///
/// ## Dispatch Origin
///
/// The dispatch origin of this call must be a signed account that is either:
/// - A member of the oracle operators set (managed by [`SortedMembers`])
/// - The root origin
///
/// ## Details
///
/// This function allows authorized oracle operators to submit timestamped key-value pairs
/// into the oracle system. Each submitted value is immediately timestamped with the current
/// block time and stored in the [`RawValues`] storage. The system then attempts to
/// aggregate all raw values for each key using the configured [`CombineData`] trait
/// implementation, updating the final [`Values`] storage with the aggregated result.
///
/// Only one submission per oracle operator per block is allowed to prevent spam and ensure
/// fair participation. The function also triggers the [`OnNewData`] hook for each submitted
/// value, allowing other pallets to react to new oracle data.
///
/// ## Errors
///
/// - [`Error::NoPermission`]: The sender is not authorized to feed data
/// - [`Error::AlreadyFeeded`]: The sender has already fed data in the current block
/// - [`Error::ExceedsMaxHasDispatchedSize`]: Too many operators have fed data in this block
///
/// ## Events
///
/// - [`Event::NewFeedData`]: Emitted when data is successfully fed into the oracle
#[pallet::call_index(0)]
#[pallet::weight(T::WeightInfo::feed_values(values.len() as u32))]
pub fn feed_values(
origin: OriginFor<T>,
values: BoundedVec<(T::OracleKey, T::OracleValue), T::MaxFeedValues>,
) -> DispatchResultWithPostInfo {
let feeder = ensure_signed_or_root(origin.clone())?;
let who = Self::ensure_account(feeder)?;
// ensure account hasn't dispatched an updated yet
<HasDispatched<T, I>>::try_mutate(|set| {
set.try_insert(who.clone())
.map_err(|_| Error::<T, I>::ExceedsMaxHasDispatchedSize)?
.then_some(())
.ok_or(Error::<T, I>::AlreadyFeeded)
})?;
Self::do_feed_values(who, values.into());
Ok(Pays::No.into())
}
}
}
impl<T: Config<I>, I: 'static> Pallet<T, I> {
fn get_pallet_account() -> T::AccountId {
T::PalletId::get().into_account_truncating()
}
/// Reads the raw values for a given key from all oracle members.
pub fn read_raw_values(key: &T::OracleKey) -> Vec<TimestampedValueOf<T, I>> {
T::Members::sorted_members()
.iter()
.chain([Self::get_pallet_account()].iter())
.filter_map(|x| Self::raw_values(x, key))
.collect()
}
/// Returns the aggregated and timestamped value for a given key.
pub fn get(key: &T::OracleKey) -> Option<TimestampedValueOf<T, I>> {
Self::values(key)
}
fn combined(key: &T::OracleKey) -> Option<TimestampedValueOf<T, I>> {
let values = Self::read_raw_values(key);
T::CombineData::combine_data(key, values, Self::values(key))
}
fn ensure_account(who: Option<T::AccountId>) -> Result<T::AccountId, DispatchError> {
// ensure feeder is authorized
if let Some(who) = who {
ensure!(T::Members::contains(&who), Error::<T, I>::NoPermission);
Ok(who)
} else {
Ok(Self::get_pallet_account())
}
}
fn do_feed_values(who: T::AccountId, values: Vec<(T::OracleKey, T::OracleValue)>) {
let now = T::Time::now();
for (key, value) in &values {
let timestamped = TimestampedValue { value: value.clone(), timestamp: now };
RawValues::<T, I>::insert(&who, key, timestamped);
// Update `Values` storage if `combined` yielded result.
if let Some(combined) = Self::combined(key) {
<Values<T, I>>::insert(key, combined);
}
T::OnNewData::on_new_data(&who, key, value);
}
Self::deposit_event(Event::NewFeedData { sender: who, values });
}
}
impl<T: Config<I>, I: 'static> ChangeMembers<T::AccountId> for Pallet<T, I> {
fn change_members_sorted(
_incoming: &[T::AccountId],
outgoing: &[T::AccountId],
_new: &[T::AccountId],
) {
// remove values
for removed in outgoing {
let _ = RawValues::<T, I>::clear_prefix(removed, u32::MAX, None);
}
}
fn set_prime(_prime: Option<T::AccountId>) {
// nothing
}
}
impl<T: Config<I>, I: 'static> DataProvider<T::OracleKey, T::OracleValue> for Pallet<T, I> {
fn get(key: &T::OracleKey) -> Option<T::OracleValue> {
Self::get(key).map(|timestamped_value| timestamped_value.value)
}
}
impl<T: Config<I>, I: 'static> DataProviderExtended<T::OracleKey, TimestampedValueOf<T, I>>
for Pallet<T, I>
{
fn get_all_values() -> impl Iterator<Item = (T::OracleKey, Option<TimestampedValueOf<T, I>>)> {
<Values<T, I>>::iter().map(|(k, v)| (k, Some(v)))
}
}
impl<T: Config<I>, I: 'static> DataFeeder<T::OracleKey, T::OracleValue, T::AccountId>
for Pallet<T, I>
{
fn feed_value(
who: Option<T::AccountId>,
key: T::OracleKey,
value: T::OracleValue,
) -> DispatchResult {
Self::do_feed_values(Self::ensure_account(who)?, vec![(key, value)]);
Ok(())
}
}
@@ -0,0 +1,119 @@
// This file is part of Bizinikiwi.
// Copyright (C) 2020-2025 Acala Foundation.
// 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.
use crate as pezpallet_oracle;
use crate::{Config, DefaultCombineData};
use pezframe_support::{
construct_runtime, derive_impl, parameter_types,
traits::{ConstU32, SortedMembers, Time},
PalletId,
};
use pezsp_runtime::{traits::IdentityLookup, BuildStorage};
pub type AccountId = u128;
type Key = u32;
type Value = u32;
#[derive_impl(pezframe_system::config_preludes::TestDefaultConfig as pezframe_system::DefaultConfig)]
impl pezframe_system::Config for Test {
type AccountId = AccountId;
type Lookup = IdentityLookup<Self::AccountId>;
type Block = Block;
}
parameter_types! {
pub static TIME: u32 = 0;
pub static MEMBERS: Vec<AccountId> = vec![1, 2, 3];
}
pub struct Timestamp;
impl Time for Timestamp {
type Moment = u32;
fn now() -> Self::Moment {
TIME::get()
}
}
impl Timestamp {
pub fn set_timestamp(val: u32) {
TIME::set(val);
}
}
pub struct Members;
impl SortedMembers<AccountId> for Members {
fn sorted_members() -> Vec<AccountId> {
MEMBERS::get().clone()
}
#[cfg(feature = "runtime-benchmarks")]
fn add(who: &AccountId) {
MEMBERS::mutate(|members| {
members.push(*who);
members.sort();
})
}
}
parameter_types! {
pub const MaxFeedValues: u32 = 5;
pub const OraclePalletId: PalletId = PalletId(*b"py/oracl");
}
impl Config for Test {
type OnNewData = ();
type CombineData = DefaultCombineData<Self, ConstU32<3>, ConstU32<600>>;
type Time = Timestamp;
type OracleKey = Key;
type OracleValue = Value;
type PalletId = OraclePalletId;
type Members = Members;
type WeightInfo = ();
type MaxHasDispatchedSize = ConstU32<100>;
type MaxFeedValues = MaxFeedValues;
#[cfg(feature = "runtime-benchmarks")]
type BenchmarkHelper = ();
}
type Block = pezframe_system::mocking::MockBlock<Test>;
construct_runtime!(
pub enum Test {
System: pezframe_system,
ModuleOracle: pezpallet_oracle,
}
);
pub fn set_members(members: Vec<AccountId>) {
MEMBERS::set(members);
}
// This function basically just builds a genesis storage key/value store
// according to our desired mockup.
pub fn new_test_ext() -> pezsp_io::TestExternalities {
let storage = pezframe_system::GenesisConfig::<Test>::default().build_storage().unwrap();
let mut t: pezsp_io::TestExternalities = storage.into();
t.execute_with(|| {
Timestamp::set_timestamp(12345);
});
t
}
@@ -0,0 +1,341 @@
// This file is part of Bizinikiwi.
// Copyright (C) 2020-2025 Acala Foundation.
// 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.
use super::*;
use pezframe_support::{assert_noop, assert_ok};
use mock::*;
#[test]
fn should_feed_values_from_member() {
new_test_ext().execute_with(|| {
System::set_block_number(1);
let account_id: AccountId = 1;
assert_noop!(
ModuleOracle::feed_values(
RuntimeOrigin::signed(5),
vec![(50, 1000), (51, 900), (52, 800)].try_into().unwrap()
),
Error::<Test, _>::NoPermission,
);
assert_eq!(
ModuleOracle::feed_values(
RuntimeOrigin::signed(account_id),
vec![(50, 1000), (51, 900), (52, 800)].try_into().unwrap()
)
.unwrap()
.pays_fee,
Pays::No
);
System::assert_last_event(RuntimeEvent::ModuleOracle(crate::Event::NewFeedData {
sender: 1,
values: vec![(50, 1000), (51, 900), (52, 800)],
}));
assert_eq!(
ModuleOracle::raw_values(&account_id, &50),
Some(TimestampedValue { value: 1000, timestamp: 12345 })
);
assert_eq!(
ModuleOracle::raw_values(&account_id, &51),
Some(TimestampedValue { value: 900, timestamp: 12345 })
);
assert_eq!(
ModuleOracle::raw_values(&account_id, &52),
Some(TimestampedValue { value: 800, timestamp: 12345 })
);
});
}
#[test]
fn should_feed_values_from_root() {
new_test_ext().execute_with(|| {
let root_feeder: AccountId = OraclePalletId::get().into_account_truncating();
assert_ok!(ModuleOracle::feed_values(
RuntimeOrigin::root(),
vec![(50, 1000), (51, 900), (52, 800)].try_into().unwrap()
));
// Or feed from root using the DataFeeder trait with None
assert_ok!(ModuleOracle::feed_value(None, 53, 700));
assert_eq!(
ModuleOracle::raw_values(&root_feeder, &50),
Some(TimestampedValue { value: 1000, timestamp: 12345 })
);
assert_eq!(
ModuleOracle::raw_values(&root_feeder, &51),
Some(TimestampedValue { value: 900, timestamp: 12345 })
);
assert_eq!(
ModuleOracle::raw_values(&root_feeder, &52),
Some(TimestampedValue { value: 800, timestamp: 12345 })
);
assert_eq!(
ModuleOracle::raw_values(&root_feeder, &53),
Some(TimestampedValue { value: 700, timestamp: 12345 })
);
});
}
#[test]
fn should_not_feed_values_from_root_directly() {
new_test_ext().execute_with(|| {
let root_feeder: AccountId = OraclePalletId::get().into_account_truncating();
assert_noop!(
ModuleOracle::feed_values(
RuntimeOrigin::signed(root_feeder),
vec![(50, 1000), (51, 900), (52, 800)].try_into().unwrap()
),
Error::<Test, _>::NoPermission,
);
});
}
#[test]
fn should_read_raw_values() {
new_test_ext().execute_with(|| {
let key: u32 = 50;
let raw_values = ModuleOracle::read_raw_values(&key);
assert_eq!(raw_values, vec![]);
assert_ok!(ModuleOracle::feed_values(
RuntimeOrigin::signed(1),
vec![(key, 1000)].try_into().unwrap()
));
assert_ok!(ModuleOracle::feed_values(
RuntimeOrigin::signed(2),
vec![(key, 1200)].try_into().unwrap()
));
let raw_values = ModuleOracle::read_raw_values(&key);
assert_eq!(
raw_values,
vec![
TimestampedValue { value: 1000, timestamp: 12345 },
TimestampedValue { value: 1200, timestamp: 12345 },
]
);
});
}
#[test]
fn should_combined_data() {
new_test_ext().execute_with(|| {
let key: u32 = 50;
assert_ok!(ModuleOracle::feed_values(
RuntimeOrigin::signed(1),
vec![(key, 1300)].try_into().unwrap()
));
assert_ok!(ModuleOracle::feed_values(
RuntimeOrigin::signed(2),
vec![(key, 1000)].try_into().unwrap()
));
assert_ok!(ModuleOracle::feed_values(
RuntimeOrigin::signed(3),
vec![(key, 1200)].try_into().unwrap()
));
let expected = Some(TimestampedValue { value: 1200, timestamp: 12345 });
assert_eq!(ModuleOracle::get(&key), expected);
Timestamp::set_timestamp(23456);
assert_eq!(ModuleOracle::get(&key), expected);
});
}
#[test]
fn should_return_none_for_non_exist_key() {
new_test_ext().execute_with(|| {
assert_eq!(ModuleOracle::get(&50), None);
});
}
#[test]
fn multiple_calls_should_fail() {
new_test_ext().execute_with(|| {
assert_ok!(ModuleOracle::feed_values(
RuntimeOrigin::signed(1),
vec![(50, 1300)].try_into().unwrap()
));
// Fails feeding by the extrinsic
assert_noop!(
ModuleOracle::feed_values(
RuntimeOrigin::signed(1),
vec![(50, 1300)].try_into().unwrap()
),
Error::<Test, _>::AlreadyFeeded,
);
// But not if fed thought the trait internally
assert_ok!(ModuleOracle::feed_value(Some(1), 50, 1300));
ModuleOracle::on_finalize(1);
assert_ok!(ModuleOracle::feed_values(
RuntimeOrigin::signed(1),
vec![(50, 1300)].try_into().unwrap()
));
});
}
#[test]
fn get_all_values_should_work() {
new_test_ext().execute_with(|| {
let eur: u32 = 1;
let jpy: u32 = 2;
assert_eq!(ModuleOracle::get_all_values().collect::<Vec<_>>(), vec![]);
// feed eur & jpy
assert_ok!(ModuleOracle::feed_values(
RuntimeOrigin::signed(1),
vec![(eur, 1300)].try_into().unwrap()
));
assert_ok!(ModuleOracle::feed_values(
RuntimeOrigin::signed(2),
vec![(eur, 1000)].try_into().unwrap()
));
assert_ok!(ModuleOracle::feed_values(
RuntimeOrigin::signed(3),
vec![(jpy, 9000)].try_into().unwrap()
));
// not enough eur & jpy prices
assert_eq!(ModuleOracle::get(&eur), None);
assert_eq!(ModuleOracle::get(&jpy), None);
assert_eq!(ModuleOracle::get_all_values().collect::<Vec<_>>(), vec![]);
// finalize block
ModuleOracle::on_finalize(1);
// feed eur & jpy
assert_ok!(ModuleOracle::feed_values(
RuntimeOrigin::signed(3),
vec![(eur, 1200)].try_into().unwrap()
));
assert_ok!(ModuleOracle::feed_values(
RuntimeOrigin::signed(1),
vec![(jpy, 8000)].try_into().unwrap()
));
// enough eur prices
let eur_price = Some(TimestampedValue { value: 1200, timestamp: 12345 });
assert_eq!(ModuleOracle::get(&eur), eur_price);
// not enough jpy prices
assert_eq!(ModuleOracle::get(&jpy), None);
assert_eq!(ModuleOracle::get_all_values().collect::<Vec<_>>(), vec![(eur, eur_price)]);
// feed jpy
assert_ok!(ModuleOracle::feed_values(
RuntimeOrigin::signed(2),
vec![(jpy, 7000)].try_into().unwrap()
));
// enough jpy prices
let jpy_price = Some(TimestampedValue { value: 8000, timestamp: 12345 });
assert_eq!(ModuleOracle::get(&jpy), jpy_price);
assert_eq!(
ModuleOracle::get_all_values().collect::<Vec<_>>(),
vec![(eur, eur_price), (jpy, jpy_price)]
);
});
}
#[test]
fn change_member_should_work() {
new_test_ext().execute_with(|| {
set_members(vec![2, 3, 4]);
<ModuleOracle as ChangeMembers<AccountId>>::change_members_sorted(&[4], &[1], &[2, 3, 4]);
assert_noop!(
ModuleOracle::feed_values(
RuntimeOrigin::signed(1),
vec![(50, 1000)].try_into().unwrap()
),
Error::<Test, _>::NoPermission,
);
assert_ok!(ModuleOracle::feed_values(
RuntimeOrigin::signed(2),
vec![(50, 1000)].try_into().unwrap()
));
assert_ok!(ModuleOracle::feed_values(
RuntimeOrigin::signed(4),
vec![(50, 1000)].try_into().unwrap()
));
});
}
#[test]
fn should_clear_data_for_removed_members() {
new_test_ext().execute_with(|| {
assert_ok!(ModuleOracle::feed_values(
RuntimeOrigin::signed(1),
vec![(50, 1000)].try_into().unwrap()
));
assert_ok!(ModuleOracle::feed_values(
RuntimeOrigin::signed(2),
vec![(50, 1000)].try_into().unwrap()
));
ModuleOracle::change_members_sorted(&[4], &[1], &[2, 3, 4]);
assert_eq!(ModuleOracle::raw_values(&1, 50), None);
});
}
#[test]
fn values_are_updated_on_feed() {
new_test_ext().execute_with(|| {
assert_ok!(ModuleOracle::feed_values(
RuntimeOrigin::signed(1),
vec![(50, 900)].try_into().unwrap()
));
assert_ok!(ModuleOracle::feed_values(
RuntimeOrigin::signed(2),
vec![(50, 1000)].try_into().unwrap()
));
assert_eq!(ModuleOracle::values(50), None);
// Upon the third price feed, the value is updated immediately after `combine`
// can produce valid result.
assert_ok!(ModuleOracle::feed_values(
RuntimeOrigin::signed(3),
vec![(50, 1100)].try_into().unwrap()
));
assert_eq!(
ModuleOracle::values(50),
Some(TimestampedValue { value: 1000, timestamp: 12345 })
);
});
}
@@ -0,0 +1,167 @@
// This file is part of Bizinikiwi.
// Copyright (C) 2020-2025 Acala Foundation.
// 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.
//! This module provides traits for data feeding and provisioning.
use pezsp_runtime::DispatchResult;
use pezsp_std::vec::Vec;
/// A trait for feeding data to a data provider.
pub trait DataFeeder<Key, Value, AccountId> {
/// Feeds a new value for a given key.
fn feed_value(who: Option<AccountId>, key: Key, value: Value) -> DispatchResult;
}
/// A simple trait for providing data.
pub trait DataProvider<Key, Value> {
/// Returns the data for a given key.
fn get(key: &Key) -> Option<Value>;
}
/// An extended `DataProvider` that provides timestamped data.
pub trait DataProviderExtended<Key, TimestampedValue> {
/// Returns a list of all keys and their optional timestamped values.
fn get_all_values() -> impl Iterator<Item = (Key, Option<TimestampedValue>)>;
}
/// Returns the median of a list of values.
pub fn median<T: Ord + Clone>(mut items: Vec<T>) -> Option<T> {
if items.is_empty() {
return None;
}
let mid_index = items.len() / 2;
// Won't panic as `items` ensured not empty.
let (_, item, _) = items.select_nth_unstable(mid_index);
Some(item.clone())
}
/// Creates a median data provider from a list of other data providers.
#[macro_export]
macro_rules! create_median_value_data_provider {
($name:ident, $key:ty, $value:ty, $timestamped_value:ty, [$( $provider:ty ),*]) => {
pub struct $name;
impl $crate::DataProvider<$key, $value> for $name {
fn get(key: &$key) -> Option<$value> {
let mut values = vec![];
$(
if let Some(v) = <$provider as $crate::DataProvider<$key, $value>>::get(&key) {
values.push(v);
}
)*
$crate::traits::median(values)
}
}
impl $crate::DataProviderExtended<$key, $timestamped_value> for $name {
fn get_all_values() -> impl Iterator<Item = ($key, Option<$timestamped_value>)> {
let mut keys = pezsp_std::collections::btree_set::BTreeSet::new();
$(
<$provider as $crate::DataProviderExtended<$key, $timestamped_value>>::get_all_values()
.into_iter()
.for_each(|(k, _)| { keys.insert(k); });
)*
keys.into_iter().map(|k| (k, Self::get(&k)))
}
}
}
}
/// Used to combine data from multiple providers.
pub trait CombineData<Key, TimestampedValue> {
/// Combine data provided by operators
fn combine_data(
key: &Key,
values: Vec<TimestampedValue>,
prev_value: Option<TimestampedValue>,
) -> Option<TimestampedValue>;
}
/// A handler for new data events.
#[impl_trait_for_tuples::impl_for_tuples(30)]
pub trait OnNewData<AccountId, Key, Value> {
/// New data is available
fn on_new_data(who: &AccountId, key: &Key, value: &Value);
}
#[cfg(test)]
mod tests {
use super::*;
use pezsp_std::cell::RefCell;
thread_local! {
static MOCK_PRICE_1: RefCell<Option<u8>> = RefCell::new(None);
static MOCK_PRICE_2: RefCell<Option<u8>> = RefCell::new(None);
static MOCK_PRICE_3: RefCell<Option<u8>> = RefCell::new(None);
static MOCK_PRICE_4: RefCell<Option<u8>> = RefCell::new(None);
}
macro_rules! mock_data_provider {
($provider:ident, $price:ident) => {
pub struct $provider;
impl $provider {
fn set_price(price: Option<u8>) {
$price.with(|v| *v.borrow_mut() = price)
}
}
impl DataProvider<u8, u8> for $provider {
fn get(_: &u8) -> Option<u8> {
$price.with(|v| *v.borrow())
}
}
impl DataProviderExtended<u8, u8> for $provider {
fn get_all_values() -> impl Iterator<Item = (u8, Option<u8>)> {
vec![(0, Self::get(&0))].into_iter()
}
}
};
}
mock_data_provider!(Provider1, MOCK_PRICE_1);
mock_data_provider!(Provider2, MOCK_PRICE_2);
mock_data_provider!(Provider3, MOCK_PRICE_3);
mock_data_provider!(Provider4, MOCK_PRICE_4);
create_median_value_data_provider!(
Providers,
u8,
u8,
u8,
[Provider1, Provider2, Provider3, Provider4]
);
#[test]
fn median_value_data_provider_works() {
assert_eq!(<Providers as DataProvider<_, _>>::get(&0), None);
let data = vec![
(vec![None, None, None, Some(1)], Some(1)),
(vec![None, None, Some(2), Some(1)], Some(2)),
(vec![Some(5), Some(2), None, Some(7)], Some(5)),
(vec![Some(5), Some(13), Some(2), Some(7)], Some(7)),
];
for (values, target) in data {
Provider1::set_price(values[0]);
Provider2::set_price(values[1]);
Provider3::set_price(values[2]);
Provider4::set_price(values[3]);
assert_eq!(<Providers as DataProvider<_, _>>::get(&0), target);
}
}
}
@@ -0,0 +1,139 @@
// This file is part of Bizinikiwi.
// Copyright (C) 2020-2025 Acala Foundation.
// 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.
//! Autogenerated weights for `pezpallet_oracle`
//!
//! THIS FILE WAS AUTO-GENERATED USING THE BIZINIKIWI BENCHMARK CLI VERSION 50.0.0
//! DATE: 2025-09-23, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]`
//! WORST CASE MAP SIZE: `1000000`
//! HOSTNAME: `Mac.lan`, CPU: `<UNKNOWN>`
//! WASM-EXECUTION: `Compiled`, CHAIN: `None`, DB CACHE: `1024`
// Executed Command:
// frame-omni-bencher
// v1
// benchmark
// pallet
// --extrinsic=all
// --runtime=target/production/wbuild/kitchensink-runtime/kitchensink_runtime.wasm
// --pallet=pezpallet_oracle
// --header=bizinikiwi/HEADER-APACHE2
// --output=bizinikiwi/pezframe/honzon/oracle/src/weights.rs
// --wasm-execution=compiled
// --steps=50
// --repeat=20
// --heap-pages=4096
// --template=bizinikiwi/.maintain/frame-weight-template.hbs
// --no-storage-info
// --no-min-squares
// --no-median-slopes
// --genesis-builder-policy=none
// --exclude-pallets=pezpallet_xcm,pezpallet_xcm_benchmarks::fungible,pezpallet_xcm_benchmarks::generic,pezpallet_nomination_pools,pezpallet_remark,pezpallet_transaction_storage,pezpallet_election_provider_multi_block,pezpallet_election_provider_multi_block::signed,pezpallet_election_provider_multi_block::unsigned,pezpallet_election_provider_multi_block::verifier
#![cfg_attr(rustfmt, rustfmt_skip)]
#![allow(unused_parens)]
#![allow(unused_imports)]
#![allow(missing_docs)]
#![allow(dead_code)]
use pezframe_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}};
use core::marker::PhantomData;
/// Weight functions needed for `pezpallet_oracle`.
pub trait WeightInfo {
fn feed_values(x: u32, ) -> Weight;
fn on_finalize() -> Weight;
}
/// Weights for `pezpallet_oracle` using the Bizinikiwi node and recommended hardware.
pub struct BizinikiwiWeight<T>(PhantomData<T>);
impl<T: pezframe_system::Config> WeightInfo for BizinikiwiWeight<T> {
/// Storage: `TechnicalMembership::Members` (r:1 w:0)
/// Proof: `TechnicalMembership::Members` (`max_values`: Some(1), `max_size`: Some(3202), added: 3697, mode: `MaxEncodedLen`)
/// Storage: `Oracle::HasDispatched` (r:1 w:1)
/// Proof: `Oracle::HasDispatched` (`max_values`: Some(1), `max_size`: Some(641), added: 1136, mode: `MaxEncodedLen`)
/// Storage: `Timestamp::Now` (r:1 w:0)
/// Proof: `Timestamp::Now` (`max_values`: Some(1), `max_size`: Some(8), added: 503, mode: `MaxEncodedLen`)
/// Storage: `Oracle::RawValues` (r:10 w:10)
/// Proof: `Oracle::RawValues` (`max_values`: None, `max_size`: Some(76), added: 2551, mode: `MaxEncodedLen`)
/// Storage: `Oracle::Values` (r:10 w:0)
/// Proof: `Oracle::Values` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `MaxEncodedLen`)
/// The range of component `x` is `[0, 10]`.
fn feed_values(x: u32, ) -> Weight {
// Proof Size summary in bytes:
// Measured: `3`
// Estimated: `4687 + x * (2551 ±0)`
// Minimum execution time: 5_000_000 picoseconds.
Weight::from_parts(6_049_545, 4687)
// Standard Error: 9_666
.saturating_add(Weight::from_parts(5_167_799, 0).saturating_mul(x.into()))
.saturating_add(T::DbWeight::get().reads(3_u64))
.saturating_add(T::DbWeight::get().reads((2_u64).saturating_mul(x.into())))
.saturating_add(T::DbWeight::get().writes(1_u64))
.saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(x.into())))
.saturating_add(Weight::from_parts(0, 2551).saturating_mul(x.into()))
}
/// Storage: `Oracle::HasDispatched` (r:0 w:1)
/// Proof: `Oracle::HasDispatched` (`max_values`: Some(1), `max_size`: Some(641), added: 1136, mode: `MaxEncodedLen`)
fn on_finalize() -> Weight {
// Proof Size summary in bytes:
// Measured: `0`
// Estimated: `0`
// Minimum execution time: 0_000 picoseconds.
Weight::from_parts(1_000_000, 0)
.saturating_add(T::DbWeight::get().writes(1_u64))
}
}
// For backwards compatibility and tests.
impl WeightInfo for () {
/// Storage: `TechnicalMembership::Members` (r:1 w:0)
/// Proof: `TechnicalMembership::Members` (`max_values`: Some(1), `max_size`: Some(3202), added: 3697, mode: `MaxEncodedLen`)
/// Storage: `Oracle::HasDispatched` (r:1 w:1)
/// Proof: `Oracle::HasDispatched` (`max_values`: Some(1), `max_size`: Some(641), added: 1136, mode: `MaxEncodedLen`)
/// Storage: `Timestamp::Now` (r:1 w:0)
/// Proof: `Timestamp::Now` (`max_values`: Some(1), `max_size`: Some(8), added: 503, mode: `MaxEncodedLen`)
/// Storage: `Oracle::RawValues` (r:10 w:10)
/// Proof: `Oracle::RawValues` (`max_values`: None, `max_size`: Some(76), added: 2551, mode: `MaxEncodedLen`)
/// Storage: `Oracle::Values` (r:10 w:0)
/// Proof: `Oracle::Values` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `MaxEncodedLen`)
/// The range of component `x` is `[0, 10]`.
fn feed_values(x: u32, ) -> Weight {
// Proof Size summary in bytes:
// Measured: `3`
// Estimated: `4687 + x * (2551 ±0)`
// Minimum execution time: 5_000_000 picoseconds.
Weight::from_parts(6_049_545, 4687)
// Standard Error: 9_666
.saturating_add(Weight::from_parts(5_167_799, 0).saturating_mul(x.into()))
.saturating_add(RocksDbWeight::get().reads(3_u64))
.saturating_add(RocksDbWeight::get().reads((2_u64).saturating_mul(x.into())))
.saturating_add(RocksDbWeight::get().writes(1_u64))
.saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(x.into())))
.saturating_add(Weight::from_parts(0, 2551).saturating_mul(x.into()))
}
/// Storage: `Oracle::HasDispatched` (r:0 w:1)
/// Proof: `Oracle::HasDispatched` (`max_values`: Some(1), `max_size`: Some(641), added: 1136, mode: `MaxEncodedLen`)
fn on_finalize() -> Weight {
// Proof Size summary in bytes:
// Measured: `0`
// Estimated: `0`
// Minimum execution time: 0_000 picoseconds.
Weight::from_parts(1_000_000, 0)
.saturating_add(RocksDbWeight::get().writes(1_u64))
}
}