Skip to content
This repository has been archived by the owner on Nov 15, 2023. It is now read-only.

The Ambassador Program #2002

Open
wants to merge 53 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 13 commits
Commits
Show all changes
53 commits
Select commit Hold shift + click to select a range
f885e71
Ambassador Program minimum setup
muharem Dec 19, 2022
8e76281
head ambassador rank
muharem Jan 9, 2023
0541b4b
docs
muharem Jan 9, 2023
5cf1abf
pallet_collective_content, tests, benches
muharem Jan 11, 2023
07075dd
clean dev code
muharem Jan 11, 2023
80df39c
docs, worst case fot bench
muharem Jan 12, 2023
8c288e3
docs
muharem Jan 12, 2023
5bd566d
collective content pallet generic over instance (I)
muharem Jan 12, 2023
5356d11
fix docs
muharem Jan 12, 2023
8112e48
ranks public
muharem Jan 12, 2023
0ffbaaf
rustfmt
muharem Jan 12, 2023
b81ba28
fix
muharem Jan 12, 2023
9b89c1d
add try runtime feature to collective content pallet
muharem Jan 12, 2023
bbe116c
Merge remote-tracking branch 'origin/master' into muharem-ambassador-…
muharem Jan 14, 2023
6104edb
typo fixes, announcement origin, ambassador proxy
muharem Jan 25, 2023
f0c3a60
announcements with an expiration
muharem Jan 25, 2023
514fce9
cleaup announcements on idle
muharem Jan 27, 2023
1323be3
docs and proxy definition changes
joepetrowski Jan 31, 2023
f200aef
merge master
joepetrowski Jan 31, 2023
1b867de
remove unused import
joepetrowski Jan 31, 2023
174a9a8
review fixes
muharem Feb 6, 2023
9017a8b
storage map for the announcements
muharem Feb 6, 2023
d602443
max scheduler per block for benches
muharem Feb 7, 2023
07c7d86
rename weights files
muharem Feb 7, 2023
fe57ff2
remove todo, update comment
muharem Feb 14, 2023
5f111a2
ToParentTreasury impl
muharem Feb 16, 2023
2ef13d0
Merge remote-tracking branch 'origin/master' into muharem-ambassador-…
muharem Aug 1, 2023
48363a7
fixes after mater merge
muharem Aug 1, 2023
a9926fb
more ranks, renames, salary and core pallets
muharem Aug 9, 2023
5313c68
ensure origin types, reuse common types
muharem Aug 10, 2023
cb79c45
fixes
muharem Aug 11, 2023
f867832
Merge remote-tracking branch 'origin/master' into muharem-ambassador-…
muharem Aug 11, 2023
35e0417
benchmark script void output file name
muharem Aug 11, 2023
d515363
weights
muharem Aug 11, 2023
c238fb2
docs fixes
muharem Aug 14, 2023
9ab6aa4
promote origin for rank 0
muharem Aug 14, 2023
67902de
Apply suggestions from code review
muharem Aug 18, 2023
54bd222
renames
muharem Aug 18, 2023
d5118b0
benchmarks v2
muharem Aug 18, 2023
15ad2f5
defensive count inc/dec
muharem Aug 18, 2023
9a562c5
default announcement lifetime, fee free expired announcement removal
muharem Aug 18, 2023
08153e7
salary in dot
muharem Aug 18, 2023
b7d8da7
Merge remote-tracking branch 'origin/master' into muharem-ambassador-…
muharem Aug 18, 2023
273e9af
benchmark fix
muharem Aug 18, 2023
9ae1f68
paymaster test
muharem Aug 18, 2023
fd88108
".git/.scripts/commands/fmt/fmt.sh"
Aug 18, 2023
56baa6a
Merge remote-tracking branch 'origin/master' into muharem-ambassador-…
Aug 21, 2023
8efb683
Merge remote-tracking branch 'origin/master' into muharem-ambassador-…
muharem Aug 22, 2023
f9c1c06
rename and tracks settings
muharem Aug 22, 2023
40bf76e
Merge remote-tracking branch 'origin/master' into muharem-ambassador-…
muharem Aug 22, 2023
69036ba
ignore test
muharem Aug 22, 2023
421d3cf
comment test
muharem Aug 22, 2023
1d625c0
Merge remote-tracking branch 'origin/master' into muharem-ambassador-…
Aug 24, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 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 @@ -30,6 +30,7 @@ members = [
"primitives/utility",
"polkadot-parachain",
"parachains/common",
"parachains/pallets/collective-content",
"parachains/pallets/parachain-info",
"parachains/pallets/ping",
"parachains/runtimes/testing/rococo-parachain",
Expand Down
45 changes: 45 additions & 0 deletions parachains/pallets/collective-content/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
[package]
name = "pallet-collective-content"
version = "0.1.0"
authors = ["Parity Technologies <admin@parity.io>"]
edition = "2021"
description = "Managed content"

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

frame-benchmarking = { git = "https://github.com/paritytech/substrate", optional = true, default-features = false, branch = "master" }
frame-support = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" }
frame-system = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" }

sp-core = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" }
sp-runtime = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" }
sp-std = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" }

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

[features]
default = [ "std" ]
runtime-benchmarks = [
"frame-benchmarking/runtime-benchmarks",
"frame-support/runtime-benchmarks",
"frame-system/runtime-benchmarks",
"sp-runtime/runtime-benchmarks",
]

std = [
"codec/std",
"scale-info/std",
"frame-support/std",
"frame-system/std",
"sp-core/std",
"sp-runtime/std",
"sp-std/std",
]

try-runtime = [
"frame-support/try-runtime",
"frame-system/try-runtime",
]
68 changes: 68 additions & 0 deletions parachains/pallets/collective-content/src/benchmarking.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
// Copyright (C) 2023 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.

//! The pallet benchmarks.

use super::{Pallet as CollectiveContent, *};
use frame_benchmarking::benchmarks_instance_pallet;
use frame_support::traits::{EnsureOrigin, UnfilteredDispatchable};
use sp_core::Get;
use sp_std::vec;

fn assert_last_event<T: Config<I>, I: 'static>(generic_event: <T as Config<I>>::RuntimeEvent) {
frame_system::Pallet::<T>::assert_last_event(generic_event.into());
}

benchmarks_instance_pallet! {
set_charter {
let cid: Cid = b"ipfs_hash".to_vec().try_into().unwrap();
muharem marked this conversation as resolved.
Show resolved Hide resolved
let call = Call::<T, I>::set_charter { cid: cid.clone() };
let origin = T::CharterOrigin::successful_origin();
}: { call.dispatch_bypass_filter(origin)? }
verify {
assert_eq!(CollectiveContent::<T, I>::charter(), Some(cid.clone()));
assert_last_event::<T, I>(Event::NewCharterSet { cid }.into());
}

announce {
let cid: Cid = b"ipfs_hash".to_vec().try_into().unwrap();
muharem marked this conversation as resolved.
Show resolved Hide resolved
let call = Call::<T, I>::announce { cid: cid.clone() };
let origin = T::AnnouncementOrigin::successful_origin();
}: { call.dispatch_bypass_filter(origin)? }
verify {
assert_eq!(CollectiveContent::<T, I>::announcements().len(), 1);
assert_last_event::<T, I>(Event::AnnouncementAnnounced { cid }.into());
}

remove_announcement {
let cid: Cid = b"ipfs_hash".to_vec().try_into().unwrap();
let origin = T::AnnouncementOrigin::successful_origin();
let max_count = T::MaxAnnouncementsCount::get() as usize;

// fill the announcements vec for the worst case.
let announcements = vec![cid.clone(); max_count];
let announcements: BoundedVec<_, T::MaxAnnouncementsCount> = BoundedVec::try_from(announcements).unwrap();
Announcements::<T, I>::put(announcements);
assert_eq!(CollectiveContent::<T, I>::announcements().len(), max_count);

let call = Call::<T, I>::remove_announcement { cid: cid.clone() };
}: { call.dispatch_bypass_filter(origin)? }
verify {
assert_eq!(CollectiveContent::<T, I>::announcements().len(), max_count - 1);
assert_last_event::<T, I>(Event::AnnouncementRemoved { cid }.into());
}

impl_benchmark_test_suite!(CollectiveContent, super::mock::new_bench_ext(), super::mock::Test);
}
181 changes: 181 additions & 0 deletions parachains/pallets/collective-content/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,181 @@
// Copyright (C) 2023 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.

//! Managed collective content.
//!
//! The pallet provides the functionality to store different types of the content.
//! The content presented as a [Cid] of the IPFS document which might contain any type of data.
//! Every type of the content has its own origin to be manage. The origins are configurable by clients.
//! Storing the content does not require a deposit, the content expected to be managed by a trusted collective.
//!
//! Content types:
//! - the collective [charter](pallet::Charter). A single document managed by [CharterOrigin](pallet::Config::CharterOrigin).
//! - the collective [announcements](pallet::Announcements). A list of announcements managed by [AnnouncementOrigin](pallet::Config::AnnouncementOrigin).

#![cfg_attr(not(feature = "std"), no_std)]

#[cfg(test)]
mod mock;
#[cfg(test)]
mod tests;

#[cfg(feature = "runtime-benchmarks")]
mod benchmarking;
pub mod weights;

pub use pallet::*;
pub use weights::WeightInfo;

use frame_support::BoundedVec;
use sp_core::ConstU32;

/// IPFS compatible CID.
// worst case 2 bytes base and codec, 2 bytes hash type and size, 64 bytes hash digest.
muharem marked this conversation as resolved.
Show resolved Hide resolved
pub type Cid = BoundedVec<u8, ConstU32<68>>;
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ive seen few implementations of the CID in or repos (at least two).
Here I keep it simple instead introducing new. I believe we need to agree first on one type for it, and keep it consistent.

Copy link
Contributor

Choose a reason for hiding this comment

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

Storing CID as a bounded vec sounds good to me

Copy link
Contributor

Choose a reason for hiding this comment

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

We already have a type for cid, maybe we should push it down to a more common place:
https://github.com/paritytech/substrate/blob/8cfe326e4e33c5077fc67f197d6a13dd871881c7/frame/alliance/src/types.rs#L69
We shouldn't have multiple different types for cids.

Copy link
Contributor

Choose a reason for hiding this comment

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

The alternative is we could call this type an OpaqueCid maybe?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

renaming to OpaqueCid


#[frame_support::pallet]
pub mod pallet {
use super::{Cid, WeightInfo};
use frame_support::pallet_prelude::*;
use frame_system::pallet_prelude::*;

/// The current storage version.
const STORAGE_VERSION: StorageVersion = StorageVersion::new(0);

#[pallet::pallet]
#[pallet::generate_store(pub (super) trait Store)]
#[pallet::storage_version(STORAGE_VERSION)]
pub struct Pallet<T, I = ()>(PhantomData<(T, I)>);
Copy link
Contributor Author

Choose a reason for hiding this comment

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

if this setup works well for the Ambassador program, we might translate the Alliance into the similar setup, this is why the pallet generic over instance


/// The module configuration trait.
#[pallet::config]
pub trait Config<I: 'static = ()>: frame_system::Config {
/// The overarching event type.
type RuntimeEvent: From<Event<Self, I>>
+ IsType<<Self as frame_system::Config>::RuntimeEvent>;

/// The origin to control the collective announcements.
type AnnouncementOrigin: EnsureOrigin<Self::RuntimeOrigin>;

/// The origin to control the collective charter.
type CharterOrigin: EnsureOrigin<Self::RuntimeOrigin>;

/// The maximum number of announcements.
#[pallet::constant]
type MaxAnnouncementsCount: Get<u32>;
joepetrowski marked this conversation as resolved.
Show resolved Hide resolved

/// Weights information needed for the pallet.
type WeightInfo: WeightInfo;
}

/// Errors encountered by the pallet (not a full list).
#[pallet::error]
pub enum Error<T, I = ()> {
/// The announcement is not found.
MissingAnnouncement,
/// Number of announcements exceeds `MaxAnnouncementsCount`.
TooManyAnnouncements,
}

/// Events emitted by the pallet.
#[pallet::event]
#[pallet::generate_deposit(pub(super) fn deposit_event)]
pub enum Event<T: Config<I>, I: 'static = ()> {
/// A new charter has been set.
NewCharterSet { cid: Cid },
muharem marked this conversation as resolved.
Show resolved Hide resolved
/// A new announcement has been proposed.
muharem marked this conversation as resolved.
Show resolved Hide resolved
AnnouncementAnnounced { cid: Cid },
/// An on-chain announcement has been removed.
AnnouncementRemoved { cid: Cid },
Copy link
Contributor

Choose a reason for hiding this comment

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

Curiosity killed the cat, but everyone is going to want to know why an announcement has been removed. Would be cool to have an enum of Outdated, Retracted, Other as to the announcement removal reason.

}

/// The collective charter.
#[pallet::storage]
#[pallet::getter(fn charter)]
pub type Charter<T: Config<I>, I: 'static = ()> = StorageValue<_, Cid, OptionQuery>;

/// The collective announcements.
#[pallet::storage]
#[pallet::getter(fn announcements)]
pub type Announcements<T: Config<I>, I: 'static = ()> =
StorageValue<_, BoundedVec<Cid, T::MaxAnnouncementsCount>, ValueQuery>;

#[pallet::call]
impl<T: Config<I>, I: 'static> Pallet<T, I> {
/// Set the collective charter.
///
/// Parameters:
/// - `origin`: Must be the [Config::CharterOrigin].
/// - `cid`: [CID](super::Cid) of the IPFS document of the collective charter.
///
/// Weight: `O(1)`.
#[pallet::call_index(0)]
#[pallet::weight(T::WeightInfo::set_charter())]
pub fn set_charter(origin: OriginFor<T>, cid: Cid) -> DispatchResult {
T::CharterOrigin::ensure_origin(origin)?;

Charter::<T, I>::put(&cid);

Self::deposit_event(Event::<T, I>::NewCharterSet { cid });
Ok(())
}

/// Publish an announcement.
///
/// Parameters:
/// - `origin`: Must be the [Config::CharterOrigin].
/// - `cid`: [CID](super::Cid) of the IPFS document to announce.
///
/// Weight: `O(1)`.
#[pallet::call_index(1)]
#[pallet::weight(T::WeightInfo::announce())]
pub fn announce(origin: OriginFor<T>, cid: Cid) -> DispatchResult {
muharem marked this conversation as resolved.
Show resolved Hide resolved
T::AnnouncementOrigin::ensure_origin(origin)?;

let mut announcements = <Announcements<T, I>>::get();
announcements
.try_push(cid.clone())
.map_err(|_| Error::<T, I>::TooManyAnnouncements)?;
<Announcements<T, I>>::put(announcements);

Self::deposit_event(Event::<T, I>::AnnouncementAnnounced { cid });
Ok(())
}

/// Remove an announcement.
///
/// Parameters:
/// - `origin`: Must be the [Config::CharterOrigin].
/// - `cid`: [CID](super::Cid) of the IPFS document to remove.
///
/// Weight: `O(1)`, less of the [Config::MaxAnnouncementsCount] is lower.
Copy link
Contributor

Choose a reason for hiding this comment

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

worst case isn't it O(log(MaxAnnoucementsCount)) ?

Copy link
Contributor

Choose a reason for hiding this comment

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

totally, binary search is ~logN complexity.

Copy link
Contributor Author

@muharem muharem Feb 6, 2023

Choose a reason for hiding this comment

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

Not, the Weight of this call is O(1).
You are talking about its complexity

#[pallet::call_index(2)]
#[pallet::weight(T::WeightInfo::remove_announcement())]
pub fn remove_announcement(origin: OriginFor<T>, cid: Cid) -> DispatchResult {
T::AnnouncementOrigin::ensure_origin(origin)?;

let mut announcements = <Announcements<T, I>>::get();
let pos = announcements
.binary_search(&cid)
.ok()
.ok_or(Error::<T, I>::MissingAnnouncement)?;
announcements.remove(pos);
<Announcements<T, I>>::put(announcements);

Self::deposit_event(Event::<T, I>::AnnouncementRemoved { cid });
Ok(())
}
}
}
Loading