Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

pallet-collection-data-feed implementation #1324

Merged
merged 16 commits into from
May 2, 2023
37 changes: 37 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ members = [
"pallets/permissions",
"pallets/pool-system",
"pallets/pool-registry",
"pallets/collection-data-feed",
"pallets/restricted-tokens",
"pallets/transfer-allowlist",
"pallets/rewards",
Expand Down
104 changes: 104 additions & 0 deletions libs/mocks/src/data.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
#[frame_support::pallet]
pub mod pallet {
use cfg_traits::data::{DataCollection, DataRegistry};
use frame_support::pallet_prelude::*;
use mock_builder::{execute_call, register_call};

#[pallet::config]
pub trait Config: frame_system::Config {
type DataId;
type CollectionId;
type Collection: DataCollection<Self::DataId, Self::Data, Self::Moment>;
type Data;
type Moment;
}

#[pallet::pallet]
#[pallet::generate_store(pub(super) trait Store)]
pub struct Pallet<T>(_);

#[pallet::storage]
pub(super) type CallIds<T: Config> = StorageMap<
_,
Blake2_128Concat,
<Blake2_128 as frame_support::StorageHasher>::Output,
mock_builder::CallId,
>;

impl<T: Config> Pallet<T> {
pub fn mock_get(f: impl Fn(&T::DataId) -> Option<(T::Data, T::Moment)> + 'static) {
register_call!(f);
}

pub fn mock_cache(f: impl Fn(&T::CollectionId) -> T::Collection + 'static) {
register_call!(f);
}

pub fn mock_register_data_id(
f: impl Fn(&T::DataId, &T::CollectionId) -> DispatchResult + 'static,
) {
register_call!(move |(a, b)| f(a, b));
}

pub fn mock_unregister_data_id(
f: impl Fn(&T::DataId, &T::CollectionId) -> DispatchResult + 'static,
) {
register_call!(move |(a, b)| f(a, b));
}
}

impl<T: Config> DataRegistry for Pallet<T> {
type Collection = T::Collection;
type CollectionId = T::CollectionId;
type Data = T::Data;
type DataId = T::DataId;
type Moment = T::Moment;

fn get(a: &T::DataId) -> Option<(T::Data, T::Moment)> {
let a = unsafe { std::mem::transmute::<_, &'static T::DataId>(a) };
execute_call!(a)
}

fn collection(a: &T::CollectionId) -> T::Collection {
let a = unsafe { std::mem::transmute::<_, &'static T::CollectionId>(a) };
execute_call!(a)
}

fn register_data_id(a: &T::DataId, b: &T::CollectionId) -> DispatchResult {
let a = unsafe { std::mem::transmute::<_, &'static T::DataId>(a) };
let b = unsafe { std::mem::transmute::<_, &'static T::CollectionId>(b) };
execute_call!((a, b))
}

fn unregister_data_id(a: &T::DataId, b: &T::CollectionId) -> DispatchResult {
let a = unsafe { std::mem::transmute::<_, &'static T::DataId>(a) };
let b = unsafe { std::mem::transmute::<_, &'static T::CollectionId>(b) };
execute_call!((a, b))
}
}

#[cfg(feature = "std")]
pub mod util {
use std::collections::HashMap;

use super::*;

pub type Value<T> = (<T as Config>::Data, <T as Config>::Moment);
pub struct MockDataCollection<T: Config>(pub HashMap<T::DataId, Option<Value<T>>>);

impl<T: Config> DataCollection<T::DataId, T::Data, T::Moment> for MockDataCollection<T>
where
T::DataId: std::hash::Hash + Eq,
T::Data: Clone,
T::Moment: Clone,
{
fn get(&self, data_id: &T::DataId) -> Result<Option<Value<T>>, DispatchError> {
Ok(self
.0
.get(data_id)
.ok_or(DispatchError::CannotLookup)?
.clone())
}
}
}
}
2 changes: 2 additions & 0 deletions libs/mocks/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
mod data;
mod fees;
mod permissions;
mod pools;
mod rewards;

pub use data::pallet as pallet_mock_data;
pub use fees::pallet as pallet_mock_fees;
pub use permissions::pallet as pallet_mock_permissions;
pub use pools::pallet as pallet_mock_pools;
Expand Down
44 changes: 44 additions & 0 deletions libs/traits/src/data.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
use sp_runtime::{DispatchError, DispatchResult};

/// Abstraction that represents a storage where
/// you can subscribe to data updates and collect them
pub trait DataRegistry {
/// A data identification
type DataId;

/// A collection identification
type CollectionId;

/// A collection of datas
type Collection: DataCollection<Self::DataId, Self::Data, Self::Moment>;

/// Represents a data
type Data;

/// Represents a timestamp
type Moment;

/// Return the last data value for a data id along with the moment it was updated last time
fn get(data_id: &Self::DataId) -> Option<(Self::Data, Self::Moment)>;

/// Retrives a collection of datas with all datas associated to a collection id
fn collection(collection_id: &Self::CollectionId) -> Self::Collection;

/// Start listening data changes for a data id in a collection id
fn register_data_id(
data_id: &Self::DataId,
collection_id: &Self::CollectionId,
) -> DispatchResult;

/// Start listening data changes for a data id in a collection id
fn unregister_data_id(
data_id: &Self::DataId,
collection_id: &Self::CollectionId,
) -> DispatchResult;
}

/// Abstration to represent a collection of datas in memory
pub trait DataCollection<DataId, Data, Moment> {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We have the same for interest rate right?

Would it make sense to merge them into a common collection trait?

Copy link
Contributor Author

@lemunozm lemunozm Apr 20, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That would be great, but the parameters differ a little bit, the RateCollection uses two: interest_rate and normalized_debt, and in this case we only need a data_id. Maybe in a future refactor once #1310 is used instead.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've simplified the trait to allow in the future mixing DataCollection for this and interest accrual.

/// Return the last data value for a data id along with the moment it was updated last time
fn get(&self, data_id: &DataId) -> Result<Option<(Data, Moment)>, DispatchError>;
}
2 changes: 2 additions & 0 deletions libs/traits/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ pub mod ops;
/// Traits related to rewards.
pub mod rewards;

pub mod data;

/// A trait used for loosely coupling the claim pallet with a reward mechanism.
///
/// ## Overview
Expand Down
57 changes: 57 additions & 0 deletions pallets/collection-data-feed/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
[package]
authors = ["Centrifuge <admin@centrifuge.io>"]
description = "Pallet to collect data from a feeder entity"
edition = "2021"
license = "LGPL-3.0"
name = "pallet-collection-data-feed"
repository = "https://github.com/centrifuge/centrifuge-chain"
version = "1.0.0"

[package.metadata.docs.rs]
targets = ["x86_64-unknown-linux-gnu"]

[dependencies]
codec = { package = "parity-scale-codec", default-features = false, version = "3.0.0", features = ["derive"] }
scale-info = { version = "2.3.0", default-features = false, features = ["derive"] }

frame-support = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.37" }
frame-system = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.37" }
sp-arithmetic = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.37" }
sp-runtime = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.37" }
sp-std = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.37" }

orml-traits = { git = "https://github.com/open-web3-stack/open-runtime-module-library", default-features = true, branch = "polkadot-v0.9.37" }

cfg-traits = { path = "../../libs/traits", default-features = false }

[dev-dependencies]
sp-core = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.37" }
sp-io = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.37" }

orml-oracle = { git = "https://github.com/open-web3-stack/open-runtime-module-library", branch = "polkadot-v0.9.37" }
pallet-timestamp = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.37" }

[features]
default = ["std"]
std = [
"codec/std",
"scale-info/std",
"frame-support/std",
"frame-system/std",
"sp-arithmetic/std",
"sp-runtime/std",
"sp-std/std",
"cfg-traits/std",
"orml-traits/std",
]
runtime-benchmarks = [
"frame-support/runtime-benchmarks",
"frame-system/runtime-benchmarks",
"sp-runtime/runtime-benchmarks",
"cfg-traits/runtime-benchmarks",
]
try-runtime = [
"frame-support/try-runtime",
"frame-system/try-runtime",
"cfg-traits/try-runtime",
]
Loading