Skip to content

Commit

Permalink
Introduce dock-agreement pallet (#187)
Browse files Browse the repository at this point in the history
* Introduce `dock-agreement` pallet

* Add URL

* Bump up versions

* Improve errors

* Add index
  • Loading branch information
olegnn authored Aug 29, 2024
1 parent d73d77a commit 80fbf9e
Show file tree
Hide file tree
Showing 9 changed files with 400 additions and 36 deletions.
22 changes: 20 additions & 2 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 @@ -3,6 +3,7 @@ resolver = "2"

members = [
"node",
"pallets/agreement",
"pallets/poa",
"pallets/poa/rpc",
"pallets/token-migration",
Expand Down
4 changes: 2 additions & 2 deletions node/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ authors = ["Dock.io"]
build = "build.rs"
edition = "2021"
name = "dock-node"
version = "0.29.0"
version = "0.30.0"

[package.metadata.docs.rs]
targets = ["x86_64-unknown-linux-gnu"]
Expand All @@ -28,7 +28,7 @@ optional = true

[dependencies.dock-runtime]
path = "../runtime"
version = "0.29.0"
version = "0.30.0"

[dependencies.beefy-primitives]
git = "https://github.com/paritytech/substrate.git"
Expand Down
92 changes: 92 additions & 0 deletions pallets/agreement/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
[package]
name = "dock-agreement"
version = "0.5.0"
authors = ["Dock.io"]
edition = "2021"
license = "Apache-2.0"

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

[dependencies.scale-info]
version = "2.1.2"
default-features = false
features = ["derive"]

[dependencies.codec]
default-features = false
features = ["derive"]
package = "parity-scale-codec"
version = "3.1.5"

[dependencies.serde]
features = ["derive"]
optional = true
version = "1.0.119"

[dependencies.frame-support]
default-features = false
# version = "3.0.0"
git = "https://github.com/paritytech/substrate.git"
branch = "polkadot-v0.9.29"

[dependencies.frame-system]
default-features = false
# version = "3.0.0"
git = "https://github.com/paritytech/substrate.git"
branch = "polkadot-v0.9.29"

[dependencies.sp-std]
default-features = false
# version = "3.0.0"
git = "https://github.com/paritytech/substrate.git"
branch = "polkadot-v0.9.29"

[dependencies.frame-benchmarking]
optional = true
default-features = false
# version = "3.0.0"
git = "https://github.com/paritytech/substrate.git"
branch = "polkadot-v0.9.29"

[dependencies.frame-system-benchmarking]
optional = true
default-features = false
git = "https://github.com/paritytech/substrate.git"
branch = "polkadot-v0.9.29"

[dev-dependencies.sp-io]
default-features = false
# version = "3.0.0"
git = "https://github.com/paritytech/substrate.git"
branch = "polkadot-v0.9.29"

[dev-dependencies.sp-core]
default-features = false
# version = "3.0.0"
git = "https://github.com/paritytech/substrate.git"
branch = "polkadot-v0.9.29"

[dev-dependencies.sp-runtime]
default-features = false
#version = "3.0.0"
git = "https://github.com/paritytech/substrate.git"
branch = "polkadot-v0.9.29"

[features]
default = ["std"]
std = [
"codec/std",
"serde",
"frame-support/std",
"frame-system/std",
"sp-std/std",
"sp-runtime/std",
]
test = ["std"]
runtime-benchmarks = [
"frame-system-benchmarking",
"frame-benchmarking",
"frame-system/runtime-benchmarks",
"frame-support/runtime-benchmarks",
]
61 changes: 61 additions & 0 deletions pallets/agreement/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
//! Provides the functionality to notify about the agreement concluded by majority of system participants.
#![cfg_attr(not(feature = "std"), no_std)]

use scale_info::prelude::string::String;

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

// Re-export pallet items so that they can be accessed from the crate namespace.
pub use pallet::*;

#[frame_support::pallet]
pub mod pallet {
use super::*;
use frame_support::pallet_prelude::*;
use frame_system::pallet_prelude::*;

#[pallet::config]
pub trait Config: frame_system::Config {
/// The overarching event type.
type Event: From<Event> + IsType<<Self as frame_system::Config>::Event>;
}

#[pallet::error]
pub enum Error<T> {
/// Attempting to emit an empty agreement.
EmptyAgreement,
/// Attempting to emit an agreement with an empty URL.
EmptyUrl,
}

#[pallet::pallet]
pub struct Pallet<T>(_);

#[pallet::call]
impl<T: Config> Pallet<T> {
/// Declares an agreement recognized by the majority of system participants.
#[pallet::weight(T::DbWeight::get().writes(1))]
pub fn agree(origin: OriginFor<T>, on: String, url: Option<String>) -> DispatchResult {
ensure_root(origin)?;
ensure!(!on.is_empty(), Error::<T>::EmptyAgreement);
ensure!(
!url.as_ref().map_or(false, String::is_empty),
Error::<T>::EmptyUrl
);

Self::deposit_event(Event::Agreed { on, url });
Ok(())
}
}

#[pallet::event]
#[pallet::generate_deposit(pub(super) fn deposit_event)]
pub enum Event {
/// Defines an agreement concluded by majority of system participants.
Agreed { on: String, url: Option<String> },
}
}
98 changes: 98 additions & 0 deletions pallets/agreement/src/mock.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
use super::*;
use crate as dock_agreement;

use codec::{Decode, Encode};
use frame_support::{
parameter_types,
sp_runtime::{
testing::Header,
traits::{BlakeTwo256, IdentityLookup},
Perbill,
},
weights::{
constants::{RocksDbWeight, WEIGHT_PER_SECOND},
Weight,
},
};
use sp_core::H256;

// Configure a mock runtime to test the pallet.
type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic<Test>;
type Block = frame_system::mocking::MockBlock<Test>;
frame_support::construct_runtime!(
pub enum Test where
Block = Block,
NodeBlock = Block,
UncheckedExtrinsic = UncheckedExtrinsic,
{
System: frame_system::{Pallet, Call, Config, Storage, Event<T>},
Agreement: dock_agreement::{Pallet, Call, Event},
}
);

parameter_types! {
pub const BlockHashCount: u64 = 250;
pub const MaximumBlockWeight: Weight = WEIGHT_PER_SECOND.saturating_mul(2);
pub const MaximumBlockLength: u32 = 2 * 1024;
pub const AvailableBlockRatio: Perbill = Perbill::one();
pub const TransactionByteFee: u64 = 1;
// Not accepting any uncles
pub const UncleGenerations: u32 = 0;
pub const MinimumPeriod: u64 = 1000;
}

#[derive(Encode, Decode, scale_info::TypeInfo, Clone, PartialEq, Debug, Eq)]
pub enum TestEvent {
Agreement(dock_agreement::Event),
}

impl From<frame_system::Event<Test>> for TestEvent {
fn from(_: frame_system::Event<Test>) -> Self {
unimplemented!()
}
}

impl From<dock_agreement::Event> for TestEvent {
fn from(event: dock_agreement::Event) -> Self {
Self::Agreement(event)
}
}

impl frame_system::Config for Test {
type OnSetCode = ();
type MaxConsumers = sp_runtime::traits::ConstU32<10>;
type BaseCallFilter = frame_support::traits::Everything;
type Origin = Origin;
type Call = Call;
type Index = u64;
type BlockNumber = u64;
type Hash = H256;
type Hashing = BlakeTwo256;
type AccountId = u64;
type Lookup = IdentityLookup<Self::AccountId>;
type Header = Header;
type Event = TestEvent;
type BlockHashCount = BlockHashCount;
type DbWeight = RocksDbWeight;
type BlockWeights = ();
type BlockLength = ();
type Version = ();
type PalletInfo = PalletInfo;
type AccountData = ();
type OnNewAccount = ();
type OnKilledAccount = ();
type SystemWeightInfo = ();
type SS58Prefix = ();
}

impl Config for Test {
type Event = TestEvent;
}

// Build genesis storage according to the mock runtime.
pub fn new_test_ext() -> sp_io::TestExternalities {
frame_system::GenesisConfig::default()
.build_storage::<Test>()
.unwrap()
.into()
}
70 changes: 70 additions & 0 deletions pallets/agreement/src/tests.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
use super::{Error, Event, Pallet as Remark};
use crate::mock::*;
use frame_support::{assert_noop, assert_ok};
use frame_system::RawOrigin;
use sp_runtime::DispatchError;

#[test]
fn generates_event() {
new_test_ext().execute_with(|| {
let text = "Hello world".to_string();
let url = Some("Test url".to_string());

System::set_block_number(System::block_number() + 1); //otherwise event won't be registered.
assert_ok!(Remark::<Test>::agree(
RawOrigin::Root.into(),
text.clone(),
url.clone()
));

let events = System::events();
// this one we create as we expect it
let system_event: <Test as frame_system::Config>::Event = Event::Agreed {
on: text.clone(),
url,
}
.into();
// this one we actually go into the system pallet and get the last event
// because we know its there from block +1
let frame_system::EventRecord { event, .. } = &events[events.len() - 1];
assert_eq!(event, &system_event);
});
}

#[test]
fn does_not_agree_on_empty() {
new_test_ext().execute_with(|| {
System::set_block_number(System::block_number() + 1); //otherwise event won't be registered.
assert_noop!(
Remark::<Test>::agree(RawOrigin::Root.into(), "".to_string(), None),
Error::<Test>::EmptyAgreement
);
assert_noop!(
Remark::<Test>::agree(
RawOrigin::Root.into(),
"abc".to_string(),
Some("".to_string())
),
Error::<Test>::EmptyUrl
);
assert!(System::events().is_empty());
});
}

#[test]
fn cant_be_called_not_by_root() {
new_test_ext().execute_with(|| {
let caller = 1;
let text = "Invalid".to_string();
System::set_block_number(System::block_number() + 1); //otherwise event won't be registered.
assert_noop!(
Remark::<Test>::agree(RawOrigin::Signed(caller).into(), text.clone(), None),
DispatchError::BadOrigin
);
assert_noop!(
Remark::<Test>::agree(RawOrigin::None.into(), text, None),
DispatchError::BadOrigin
);
assert!(System::events().is_empty());
});
}
Loading

0 comments on commit 80fbf9e

Please sign in to comment.