-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* initial commit for new pallet. not compiling yet * builds and test passes * simplify: only one quality per vouch * cleanup warnings * more cleanup * undisputed review comment fixes * enum encoding hints and more specific docs to enums * fix benchmarks * remove hard-coding of enum encoding
- Loading branch information
Showing
11 changed files
with
470 additions
and
3 deletions.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
// Copyright (c) 2023 Encointer Association | ||
// This file is part of Encointer | ||
// | ||
// Encointer is free software: you can redistribute it and/or modify | ||
// it under the terms of the GNU General Public License as published by | ||
// the Free Software Foundation, either version 3 of the License, or | ||
// (at your option) any later version. | ||
// | ||
// Encointer is distributed in the hope that it will be useful, | ||
// but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
// GNU General Public License for more details. | ||
// | ||
// You should have received a copy of the GNU General Public License | ||
// along with Encointer. If not, see <http://www.gnu.org/licenses/>. | ||
|
||
use crate::common::BoundedIpfsCid; | ||
use codec::{Decode, Encode, MaxEncodedLen}; | ||
use frame_support::RuntimeDebug; | ||
use scale_info::TypeInfo; | ||
#[cfg(feature = "serde_derive")] | ||
use serde::{Deserialize, Serialize}; | ||
|
||
/// Did the attester meet the attestee physically, virtually or through asynchronous messages? | ||
#[derive(Default, Encode, Decode, Copy, Clone, PartialEq, Eq, Debug, TypeInfo, MaxEncodedLen)] | ||
#[cfg_attr(feature = "serde_derive", derive(Serialize, Deserialize))] | ||
pub enum PresenceType { | ||
/// could be "I have exchanged messages with the person I vouch for" | ||
/// could be "I have watched the replay of the Event or talk I vouch for" | ||
#[default] | ||
Asynchronous, | ||
/// could be "I have attended that online conference remotely" | ||
/// could be "I have visited that place in the metaverse" | ||
/// could be "I have met this person on an video call and they presented this account to me" | ||
LiveVirtual, | ||
/// could be "I met the human I vouch for in-person and scanned the account they presented at the occasion of this physical encounter" | ||
/// could be "I was standing in front of this monument and scanned the QR code on its plate" | ||
/// could be "I ate at this restaurant and scanned the QR code presented at their entrance in order to submit a rating" | ||
LivePhysical, | ||
} | ||
|
||
/// The nature of a vouch | ||
/// this set is most likely incomplete. we leave gaps in the encoding to have room for more kinds | ||
/// which still results in meaningful order | ||
#[derive(Default, Encode, Decode, Copy, Clone, PartialEq, Eq, Debug, TypeInfo, MaxEncodedLen)] | ||
#[cfg_attr(feature = "serde_derive", derive(Serialize, Deserialize))] | ||
pub enum VouchKind { | ||
/// Unspecified. This should generally be handeled as an invalid vouch or an alien use case | ||
#[default] | ||
Unspecified, | ||
/// This person is know to me and I have verified their account with specified presence type | ||
KnownHuman(PresenceType), | ||
/// I do not claim to know this person, but I encountered a human being providing me with the account I vouch for | ||
EncounteredHuman(PresenceType), | ||
/// I encountered an object showing the account I vouch for | ||
EncounteredObject(PresenceType), | ||
/// I have visited a place labeled with the account I vouch for | ||
VisitedPlace(PresenceType), | ||
/// I have attended an event which identifies with the account I vouch for | ||
AttendedEvent(PresenceType), | ||
} | ||
|
||
/// a scalar expression of quality. Interpretation left to client side per use case | ||
/// could be a 0-5 star rating or a high-resolution 0..255 | ||
pub type Rating = u8; | ||
|
||
/// additional information about the attestee's qualities | ||
#[derive(Default, Encode, Decode, Clone, PartialEq, Eq, Debug, TypeInfo, MaxEncodedLen)] | ||
#[cfg_attr(feature = "serde_derive", derive(Serialize, Deserialize))] | ||
pub enum VouchQuality { | ||
/// Don't want to submit additional information | ||
#[default] | ||
Unspecified, | ||
/// a generic badge for qualitative attestation stored as a json file on IPFS (json schema TBD) | ||
Badge(BoundedIpfsCid), | ||
/// a quantitative expression of the attestee's quality (i.e. number of stars) | ||
Rating(Rating), | ||
} | ||
|
||
#[derive(Default, Encode, Decode, PartialEq, Eq, RuntimeDebug, Clone, TypeInfo, MaxEncodedLen)] | ||
#[cfg_attr(feature = "serde_derive", derive(Serialize, Deserialize))] | ||
pub struct Vouch<Moment> { | ||
/// protected vouches can't be purged. unprotected ones can be lazily purged after a time-to-live. (future feature) | ||
pub protected: bool, | ||
/// the timestamp of the block which registers this Vouch | ||
pub timestamp: Moment, | ||
/// what is the nature of this vouch? | ||
pub vouch_kind: VouchKind, | ||
/// additional information about the attestee's qualities | ||
pub quality: VouchQuality, | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
[package] | ||
name = "pallet-encointer-vouches" | ||
version = "1.2.0" | ||
authors = ["encointer.org <alain@encointer.org> and Parity Technologies <admin@parity.io>"] | ||
edition = "2021" | ||
|
||
[dependencies] | ||
approx = { version = "0.5.1", optional = true } | ||
codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } | ||
log = { version = "0.4.14", default-features = false } | ||
scale-info = { version = "2.5.0", default-features = false } | ||
|
||
# local deps | ||
encointer-primitives = { path = "../primitives", default-features = false, features = ["serde_derive"] } | ||
|
||
# substrate deps | ||
frame-benchmarking = { version = "4.0.0-dev", default-features = false, optional = true, git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v1.0.0" } | ||
frame-support = { version = "4.0.0-dev", default-features = false, git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v1.0.0" } | ||
frame-system = { version = "4.0.0-dev", default-features = false, git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v1.0.0" } | ||
pallet-timestamp = { version = "4.0.0-dev", default-features = false, git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v1.0.0" } | ||
sp-core = { version = "21.0.0", default-features = false, git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v1.0.0" } | ||
sp-runtime = { version = "24.0.0", default-features = false, git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v1.0.0" } | ||
sp-std = { version = "8.0.0", default-features = false, git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v1.0.0" } | ||
|
||
[dev-dependencies] | ||
approx = "0.5.1" | ||
sp-io = { version = "23.0.0", git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v1.0.0" } | ||
test-utils = { path = "../test-utils" } | ||
|
||
[features] | ||
default = ["std"] | ||
std = [ | ||
"codec/std", | ||
"log/std", | ||
"scale-info/std", | ||
"approx/std", | ||
# local deps | ||
"encointer-primitives/std", | ||
# substrate deps | ||
"frame-benchmarking/std", | ||
"frame-support/std", | ||
"frame-system/std", | ||
"sp-std/std", | ||
"sp-runtime/std", | ||
"sp-core/std", | ||
] | ||
|
||
runtime-benchmarks = ["frame-benchmarking", "approx"] | ||
|
||
try-runtime = [ | ||
"frame-system/try-runtime", | ||
] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
use crate::*; | ||
use encointer_primitives::vouches::{PresenceType, VouchKind, VouchQuality}; | ||
use frame_benchmarking::{account, benchmarks, impl_benchmark_test_suite}; | ||
use frame_system::RawOrigin; | ||
|
||
benchmarks! { | ||
vouch_for { | ||
let zoran = account("zoran", 1, 1); | ||
let goran = account("goran", 1, 2); | ||
let vouch_kind = VouchKind::EncounteredHuman(PresenceType::LivePhysical); | ||
let quality = VouchQuality::default(); | ||
assert!(<Vouches<T>>::iter().next().is_none()); | ||
}: _(RawOrigin::Signed(zoran), goran, vouch_kind, quality) | ||
verify { | ||
assert!(<Vouches<T>>::iter().next().is_some()); | ||
} | ||
|
||
} | ||
|
||
impl_benchmark_test_suite!(Pallet, crate::mock::new_test_ext(), crate::mock::TestRuntime); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,105 @@ | ||
// Copyright (c) 2019 Encointer Association | ||
// This file is part of Encointer | ||
// | ||
// Encointer is free software: you can redistribute it and/or modify | ||
// it under the terms of the GNU General Public License as published by | ||
// the Free Software Foundation, either version 3 of the License, or | ||
// (at your option) any later version. | ||
// | ||
// Encointer is distributed in the hope that it will be useful, | ||
// but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
// GNU General Public License for more details. | ||
// | ||
// You should have received a copy of the GNU General Public License | ||
// along with Encointer. If not, see <http://www.gnu.org/licenses/>. | ||
|
||
#![cfg_attr(not(feature = "std"), no_std)] | ||
|
||
use core::marker::PhantomData; | ||
use encointer_primitives::vouches::{Vouch, VouchKind, VouchQuality}; | ||
use frame_system::{self as frame_system, ensure_signed, pallet_prelude::OriginFor}; | ||
use log::info; | ||
pub use pallet::*; | ||
use sp_std::convert::TryInto; | ||
pub use weights::WeightInfo; | ||
// Logger target | ||
const LOG: &str = "encointer::vouches"; | ||
|
||
#[cfg(feature = "runtime-benchmarks")] | ||
mod benchmarking; | ||
#[cfg(test)] | ||
mod mock; | ||
#[cfg(test)] | ||
mod tests; | ||
|
||
mod weights; | ||
#[frame_support::pallet] | ||
pub mod pallet { | ||
use super::*; | ||
use frame_support::pallet_prelude::*; | ||
|
||
#[pallet::pallet] | ||
pub struct Pallet<T>(PhantomData<T>); | ||
|
||
#[pallet::config] | ||
pub trait Config: frame_system::Config + pallet_timestamp::Config { | ||
type RuntimeEvent: From<Event<Self>> + IsType<<Self as frame_system::Config>::RuntimeEvent>; | ||
type WeightInfo: WeightInfo; | ||
#[pallet::constant] | ||
type MaxVouchesPerAttester: Get<u32>; | ||
} | ||
|
||
#[pallet::call] | ||
impl<T: Config> Pallet<T> { | ||
#[pallet::call_index(0)] | ||
#[pallet::weight((<T as Config>::WeightInfo::vouch_for(), DispatchClass::Normal, Pays::Yes))] | ||
pub fn vouch_for( | ||
origin: OriginFor<T>, | ||
attestee: T::AccountId, | ||
vouch_kind: VouchKind, | ||
quality: VouchQuality, | ||
) -> DispatchResultWithPostInfo { | ||
let attester = ensure_signed(origin)?; | ||
let now = <pallet_timestamp::Pallet<T>>::get(); | ||
let vouch = | ||
Vouch { protected: false, timestamp: now, vouch_kind, quality: quality.clone() }; | ||
<Vouches<T>>::try_mutate( | ||
&attestee, | ||
&attester, | ||
|vouches| -> DispatchResultWithPostInfo { | ||
vouches.try_push(vouch).map_err(|_| Error::<T>::TooManyVouchesForAttestee)?; | ||
Ok(().into()) | ||
}, | ||
)?; | ||
info!(target: LOG, "vouching: {:?} for {:?}, vouch type: {:?}, quality: {:?}", attester, attestee, vouch_kind, quality); | ||
Self::deposit_event(Event::VouchedFor { attestee, attester, vouch_kind }); | ||
Ok(().into()) | ||
} | ||
} | ||
|
||
#[pallet::event] | ||
#[pallet::generate_deposit(pub(super) fn deposit_event)] | ||
pub enum Event<T: Config> { | ||
/// someone or something has vouched for someone or something | ||
VouchedFor { attestee: T::AccountId, attester: T::AccountId, vouch_kind: VouchKind }, | ||
} | ||
|
||
#[pallet::error] | ||
pub enum Error<T> { | ||
/// The calling attester has too many vouches for this attestee | ||
TooManyVouchesForAttestee, | ||
} | ||
|
||
#[pallet::storage] | ||
#[pallet::getter(fn vouches)] | ||
pub(super) type Vouches<T: Config> = StorageDoubleMap< | ||
_, | ||
Blake2_128Concat, | ||
T::AccountId, | ||
Blake2_128Concat, | ||
T::AccountId, | ||
BoundedVec<Vouch<T::Moment>, T::MaxVouchesPerAttester>, | ||
ValueQuery, | ||
>; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
// Copyright (c) 2019 Alain Brenzikofer | ||
// This file is part of Encointer | ||
// | ||
// Encointer is free software: you can redistribute it and/or modify | ||
// it under the terms of the GNU General Public License as published by | ||
// the Free Software Foundation, either version 3 of the License, or | ||
// (at your option) any later version. | ||
// | ||
// Encointer is distributed in the hope that it will be useful, | ||
// but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
// GNU General Public License for more details. | ||
// | ||
// You should have received a copy of the GNU General Public License | ||
// along with Encointer. If not, see <http://www.gnu.org/licenses/>. | ||
|
||
//! Mock runtime for the encointer_balances module | ||
|
||
use crate as dut; | ||
use frame_support::{parameter_types, traits::ConstU32}; | ||
use sp_runtime::BuildStorage; | ||
use test_utils::*; | ||
|
||
type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic<TestRuntime>; | ||
|
||
frame_support::construct_runtime!( | ||
pub enum TestRuntime | ||
{ | ||
System: frame_system::{Pallet, Call, Config<T>, Storage, Event<T>}, | ||
Timestamp: pallet_timestamp::{Pallet, Call, Storage, Inherent}, | ||
EncointerVouches: dut::{Pallet, Call, Storage, Event<T>}, | ||
} | ||
); | ||
|
||
parameter_types! {} | ||
|
||
impl dut::Config for TestRuntime { | ||
type RuntimeEvent = RuntimeEvent; | ||
type WeightInfo = (); | ||
type MaxVouchesPerAttester = ConstU32<4>; | ||
} | ||
|
||
// boilerplate | ||
impl_frame_system!(TestRuntime); | ||
impl_timestamp!(TestRuntime); | ||
|
||
// genesis values | ||
pub fn new_test_ext() -> sp_io::TestExternalities { | ||
let t = frame_system::GenesisConfig::<TestRuntime>::default().build_storage().unwrap(); | ||
t.into() | ||
} |
Oops, something went wrong.