Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • nodes/rust/duniter-v2s
  • llaq/lc-core-substrate
  • pini-gh/duniter-v2s
  • vincentux/duniter-v2s
  • mildred/duniter-v2s
  • d0p1/duniter-v2s
  • bgallois/duniter-v2s
  • Nicolas80/duniter-v2s
8 results
Show changes
Commits on Source (6)
Showing
with 95827 additions and 402 deletions
......@@ -22,6 +22,7 @@
- [manual](./docs/api/manual.md)
- [runtime-calls](./docs/api/runtime-calls.md) the calls you can submit through the RPC API
- [dev](./docs/dev/)
- [beginner-walkthrough](./docs/dev/beginner-walkthrough.md)
- [git-conventions](./docs/dev/git-conventions.md)
- [launch-a-live-network](./docs/dev/launch-a-live-network.md)
- [setup](./docs/dev/setup.md)
......@@ -102,6 +103,8 @@ docker run -it -p9944:9944 --name duniter-v2s \
## Contribute
If you are beginner in Rust and need a well guided tutorial, follow the [beginner walkthrough](./docs/dev/beginner-walkthrough.md).
Before any contribution, please read carefully the [CONTRIBUTING](./CONTRIBUTING.md) file and our [git conventions](./docs/dev/git-conventions.md).
### Setup your dev environment
......
# Beginner walkthrough
This is a beginner tutorial for those who do not have a previous experience with Rust ecosystem or need guidance to get familiar with Duniter v2s project. You'll need a development machine with an internet connection, at least **20 GB of free storage**, and **an hour or two** depending on your computing power.
This walkthrough is based on the following video (french), don't hesitate to record an english voicecover if you feel so.
[![preview](https://tube.p2p.legal/lazy-static/previews/654006dc-66c0-4e37-a32f-b7b5a1c13213.jpg)](https://tube.p2p.legal/w/n4TXxQ4SqxzpHPY4TNMXFu)
> video walkthrough on peertube https://tube.p2p.legal/w/n4TXxQ4SqxzpHPY4TNMXFu
## Requirements
If you are on a debian based system, you can install the required packages with:
```bash
sudo apt install cmake pkg-config libssl-dev git build-essential clang libclang-dev curl
```
Else, look at the corresponding section in the [system setup documentation](./setup.md).
Rust recommended installation method is through the rustup script that you can run with:
```bash
curl https://sh.rustup.rs -sSf | sh
```
If you reopen your terminal, it will give you access to the `rustup`, `rustc` and `cargo` commands. You can then install the required Rust toolchains with:
```bash
rustup default stable
rustup update nightly
rustup update stable
rustup target add wasm32-unknown-unknown --toolchain nightly
```
This can take about **2 minutes**.
## Build project
After cloning wherever you want the `duniter-v2s` repo with:
```bash
git clone https://git.duniter.org/nodes/rust/duniter-v2s.git
```
you can go to the root folder and build the substrate client and default runtime with:
```bash
cargo build
```
This will take about **2 minutes** to download dependencies plus between 5 and **15 minutes** to build in debug mode depending on the power of your processor. At this point, you built the *substrate client* (a kind of "shell" in which lies the runtime) and the default *runtime* itself. You can run a local blockchain with:
```bash
cargo run -- --dev --tmp # here, --dev means --chain=dev which selects the gdev runtime
```
When you see the logs, the blockchain is running and you can connect to it with polkadotjs app: [https://polkadot.js.org/apps/?rpc=ws://127.0.0.1:9944](https://polkadot.js.org/apps/?rpc=ws%3A%2F%2F127.0.0.1%3A9944). You should see blocks being added every 6 seconds. You can use Alice, Bob, etc test accounts to submit extrinsics.
## Autocompletion
When using Duniter commands, you will benefit a lot from commands autocompletion. This can be achieved by following [autocompletion documentation](../user/autocompletion.md) for you shell. If you use bash the commands are:
```bash
# create local dir to store completion script
mkdir -p ~/.local/share/duniter
# export the bash completion file
cargo run -- completion --generator bash > ~/.local/share/duniter/completion.bash
# add the following line to your ~/.bashrc to automatically load completion on startup
[[ -f $HOME/.local/share/duniter/completion.bash ]] && source $HOME/.local/share/duniter/completion.bash
```
You will then benefit from completion using `<Tab>` key and `*`.
## End-to-end tests using cucumber
Cucumber end2end tests are a good way to dive in Duniter's business procedure. They work by spawning a local blockchain and submitting extrinsics to it. You can build and run the cucumber tests by running:
```bash
cargo cucumber
```
which should take about **4 minutes** to build and run the tests. A highly detailed documentation about the end2end tests is available [in the dedicated folder](../../end2end-tests/README.md), you will learn how to read and modify the tests.
## Get in touch with us
Wether you are stuck and need help or have sucessfully completed this tutorial, don't hesitate to get in touch with us on the Duniter forum! If you found this walkthrough useful, please 🙏 let us know on the [walkthrough topic](https://forum.duniter.org/t/contribuer-a-duniter-tutoriel-video/9770) on the forum 😊.
\ No newline at end of file
......@@ -45,6 +45,10 @@ An example of genesis configuration file: `resources/gdev.json`
## 5. Generate raw spec
```docker
docker run -v $HOME/dev/duniter-v2s/resources:/var/lib/duniter/resources -e DUNITER_GENESIS_CONFIG=/var/lib/duniter/resources/gdev.json --rm -it --entrypoint duniter duniter/duniter-v2s:TAG build-spec -lerror --chain=gdev-gl --raw > name-raw.json
```
```bash
./scripts/gen-live-network-raw-spec.sh CURRENCY "<path/to/your/genesis/config/file>"
```
......
......@@ -3,7 +3,7 @@
One can generate autocompletion for its favorite shell using the following option:
```sh
cargo run --release -- completion --generator <GENERATOR>
cargo run -- completion --generator <GENERATOR>
```
Where `GENERATOR` can be any of `bash`, `elvish`, `fish`, `powershell` and `zsh`.
......@@ -14,7 +14,7 @@ First, get the completion file in a known place:
```sh
mkdir -p ~/.local/share/duniter
cargo run --release -- completion --generator bash > ~/.local/share/duniter/completion.bash
cargo run -- completion --generator bash > ~/.local/share/duniter/completion.bash
```
You can now manually source the file when needed:
......@@ -30,3 +30,17 @@ Or you can automatically source it at `bash` startup by adding this to your `~/.
```
You can now enjoy semantic completion of the `./target/release/duniter` command using `<Tab>` key.
## Zsh
Zsh equivalent
```sh
# make directory to store completion
mkdir -p ~/.zsh/completion
# write the completion script
cargo run -- completion --generator zsh > ~/.zsh/completion/_duniter.zsh
# add the following lines to your ~/.zshrc
fpath+=(~/.zsh/completion)
compinit # might slow down terminal startup
```
......@@ -9,7 +9,7 @@
- Create a `.env` file that define environment variables `SERVER_DOMAIN`, `PEER_ID` and `VALIDATOR_PEER_ID`:
- `SERVER_DOMAIN`: a domain name that point on your server
- `PEER_ID`: Your rpc node peer id, shoud be generated with this command: `docker run --rm -it --entrypoint -v $PWD:/var/lib/duniter/ duniter duniter/duniter-v2s:v0.3.0 key generate-node-key --file /var/lib/duniter/rpc-node.key`
- `VALIDATOR_PEER_ID`: Your validator node peer id, shoud be generated with this command: `docker run --rm -it --entrypoint -v $PWD:/var/lib/duniter/ duniter duniter/duniter-v2s:v0.3.0 key generate-node-key --file /var/lib/duniter/validator-node.key`
- `VALIDATOR_PEER_ID`: Your validator node peer id, shoud be generated with this command: `docker run --rm -it --entrypoint duniter -v $PWD:/var/lib/duniter/ duniter/duniter-v2s:v0.3.0 key generate-node-key --file /var/lib/duniter/validator-node.key`
Note: duniter-rpc PEER_ID and duniter-validator PEER_ID isn't the same.
- If you have write access errors run in docker-compose.yml folder : `chmod o+rwX -R .`
- `docker compose up -d` to start your node
......
This diff is collapsed.
......@@ -71,7 +71,7 @@ pub mod pallet {
/// Something that give the owner key of an identity
type OwnerKeyOf: Convert<Self::IdtyIndex, Option<Self::AccountId>>;
///
type IsCertAllowed: IsCertAllowed<Self::IdtyIndex>;
type CheckCertAllowed: CheckCertAllowed<Self::IdtyIndex>;
#[pallet::constant]
/// Maximum number of active certifications by issuer
type MaxByIssuer: Get<u32>;
......@@ -127,8 +127,9 @@ pub mod pallet {
.or_insert(IdtyCertMeta {
issued_count: 0,
next_issuable_on: sp_runtime::traits::Zero::zero(),
received_count: issuers.len() as u32,
});
received_count: 0,
})
.received_count = issuers.len() as u32;
let mut issuers_: Vec<_> = Vec::with_capacity(issuers.len());
for (issuer, maybe_removable_on) in issuers {
......@@ -138,7 +139,7 @@ pub mod pallet {
.or_insert(IdtyCertMeta {
issued_count: 0,
next_issuable_on: sp_runtime::traits::Zero::zero(),
received_count: issuers.len() as u32,
received_count: 0,
})
.issued_count += 1;
......@@ -242,8 +243,6 @@ pub mod pallet {
pub enum Error<T, I = ()> {
/// An identity cannot certify itself
CannotCertifySelf,
/// Certification non autorisée
CertNotAllowed,
/// This identity has already issued the maximum number of certifications
IssuedTooManyCert,
/// Issuer not found
......@@ -325,10 +324,7 @@ pub mod pallet {
ensure!(issuer_owner_key == who, DispatchError::BadOrigin);
// Verify compatibility with other pallets state
ensure!(
T::IsCertAllowed::is_cert_allowed(issuer, receiver),
Error::<T, I>::CertNotAllowed
);
T::CheckCertAllowed::check_cert_allowed(issuer, receiver)?;
// Verify rule MinReceivedCertToBeAbleToIssueCert
let issuer_idty_cert_meta = <StorageIdtyCertMeta<T, I>>::get(issuer);
......
......@@ -103,7 +103,7 @@ impl pallet_certification::Config for Test {
type Event = Event;
type IdtyIndex = IdtyIndex;
type OwnerKeyOf = sp_runtime::traits::ConvertInto;
type IsCertAllowed = ();
type CheckCertAllowed = ();
type MaxByIssuer = MaxByIssuer;
type MinReceivedCertToBeAbleToIssueCert = MinReceivedCertToBeAbleToIssueCert;
type OnNewcert = ();
......
......@@ -14,13 +14,15 @@
// You should have received a copy of the GNU Affero General Public License
// along with Duniter-v2S. If not, see <https://www.gnu.org/licenses/>.
pub trait IsCertAllowed<IdtyIndex> {
fn is_cert_allowed(issuer: IdtyIndex, receiver: IdtyIndex) -> bool;
use frame_support::pallet_prelude::*;
pub trait CheckCertAllowed<IdtyIndex> {
fn check_cert_allowed(issuer: IdtyIndex, receiver: IdtyIndex) -> Result<(), DispatchError>;
}
impl<IdtyIndex> IsCertAllowed<IdtyIndex> for () {
fn is_cert_allowed(_issuer: IdtyIndex, _receiver: IdtyIndex) -> bool {
true
impl<IdtyIndex> CheckCertAllowed<IdtyIndex> for () {
fn check_cert_allowed(_issuer: IdtyIndex, _receiver: IdtyIndex) -> Result<(), DispatchError> {
Ok(())
}
}
......
......@@ -92,36 +92,72 @@ pub mod pallet {
true
}
}
// ERRORS //
#[pallet::error]
pub enum Error<T, I = ()> {
/// Identity not allowed to claim membership
IdtyNotAllowedToClaimMembership,
/// Identity not allowed to request membership
IdtyNotAllowedToRequestMembership,
/// Identity not allowed to renew membership
IdtyNotAllowedToRenewMembership,
/// Identity creation period not respected
IdtyCreationPeriodNotRespected,
/// Not enough received certifications to create identity
NotEnoughReceivedCertsToCreateIdty,
/// Max number of emitted certs reached
MaxEmittedCertsReached,
/// Not allowed to change identity address
NotAllowedToChangeIdtyAddress,
/// Not allowed to remove identity
NotAllowedToRemoveIdty,
/// Issuer can not emit cert because it is not validated
IssuerCanNotEmitCert,
/// Can not issue cert to unconfirmed identity
CertToUnconfirmedIdty,
/// Issuer or receiver not found
IdtyNotFound,
}
}
impl<AccountId, T: Config<I>, I: 'static> pallet_identity::traits::EnsureIdtyCallAllowed<T>
impl<AccountId, T: Config<I>, I: 'static> pallet_identity::traits::CheckIdtyCallAllowed<T>
for Pallet<T, I>
where
T: frame_system::Config<AccountId = AccountId> + pallet_membership::Config<I>,
{
fn can_create_identity(creator: IdtyIndex) -> bool {
fn check_create_identity(creator: IdtyIndex) -> Result<(), DispatchError> {
if !T::IsSubWot::get() {
let cert_meta = pallet_certification::Pallet::<T, I>::idty_cert_meta(creator);
cert_meta.received_count >= T::MinCertForCreateIdtyRight::get()
&& cert_meta.next_issuable_on <= frame_system::pallet::Pallet::<T>::block_number()
&& cert_meta.issued_count < T::MaxByIssuer::get()
} else {
true
// perform all checks
ensure!(
cert_meta.received_count >= T::MinCertForCreateIdtyRight::get(),
Error::<T, I>::NotEnoughReceivedCertsToCreateIdty
);
ensure!(
cert_meta.issued_count < T::MaxByIssuer::get(),
Error::<T, I>::MaxEmittedCertsReached
);
ensure!(
cert_meta.next_issuable_on <= frame_system::pallet::Pallet::<T>::block_number(),
Error::<T, I>::IdtyCreationPeriodNotRespected
);
}
Ok(())
}
fn can_confirm_identity(idty_index: IdtyIndex) -> bool {
fn check_confirm_identity(idty_index: IdtyIndex) -> Result<(), DispatchError> {
if !T::IsSubWot::get() {
pallet_membership::Pallet::<T, I>::force_request_membership(
RawOrigin::Root.into(),
idty_index,
Default::default(),
)
.is_ok()
} else {
true
.map_err(|e| e.error)?;
}
Ok(())
}
fn can_validate_identity(idty_index: IdtyIndex) -> bool {
fn check_validate_identity(idty_index: IdtyIndex) -> Result<(), DispatchError> {
if !T::IsSubWot::get() {
// TODO replace this code by the commented one for distance feature
/*let idty_cert_meta = pallet_certification::Pallet::<T, I>::idty_cert_meta(idty_index);
......@@ -130,81 +166,88 @@ where
RawOrigin::Root.into(),
Some(idty_index),
)
.is_ok()
} else {
true
.map_err(|e| e.error)?;
}
Ok(())
}
fn can_change_identity_address(idty_index: IdtyIndex) -> bool {
fn check_change_identity_address(idty_index: IdtyIndex) -> Result<(), DispatchError> {
if T::IsSubWot::get() {
!pallet_membership::Pallet::<T, I>::is_member(&idty_index)
} else {
true
ensure!(
!pallet_membership::Pallet::<T, I>::is_member(&idty_index),
Error::<T, I>::NotAllowedToChangeIdtyAddress
);
}
Ok(())
}
fn can_remove_identity(idty_index: IdtyIndex) -> bool {
fn check_remove_identity(idty_index: IdtyIndex) -> Result<(), DispatchError> {
if T::IsSubWot::get() {
!pallet_membership::Pallet::<T, I>::is_member(&idty_index)
} else {
true
ensure!(
!pallet_membership::Pallet::<T, I>::is_member(&idty_index),
Error::<T, I>::NotAllowedToRemoveIdty
);
}
Ok(())
}
}
impl<T: Config<I>, I: 'static> pallet_certification::traits::IsCertAllowed<IdtyIndex>
impl<T: Config<I>, I: 'static> pallet_certification::traits::CheckCertAllowed<IdtyIndex>
for Pallet<T, I>
{
fn is_cert_allowed(issuer: IdtyIndex, receiver: IdtyIndex) -> bool {
fn check_cert_allowed(issuer: IdtyIndex, receiver: IdtyIndex) -> Result<(), DispatchError> {
if let Some(issuer_data) = pallet_identity::Pallet::<T>::identity(issuer) {
if issuer_data.status != IdtyStatus::Validated {
return false;
}
if let Some(receiver_data) = pallet_identity::Pallet::<T>::identity(receiver) {
match receiver_data.status {
IdtyStatus::ConfirmedByOwner | IdtyStatus::Validated => true,
IdtyStatus::Created => false,
}
} else {
// Receiver not found
false
}
ensure!(
issuer_data.status == IdtyStatus::Validated,
Error::<T, I>::IssuerCanNotEmitCert
);
} else {
// Issuer not found
false
return Err(Error::<T, I>::IdtyNotFound.into());
}
if let Some(receiver_data) = pallet_identity::Pallet::<T>::identity(receiver) {
match receiver_data.status {
IdtyStatus::ConfirmedByOwner | IdtyStatus::Validated => {} // able to receive cert
IdtyStatus::Created => return Err(Error::<T, I>::CertToUnconfirmedIdty.into()),
};
} else {
return Err(Error::<T, I>::IdtyNotFound.into());
}
Ok(())
}
}
impl<T: Config<I>, I: 'static> sp_membership::traits::IsIdtyAllowedToClaimMembership<IdtyIndex>
for Pallet<T, I>
{
fn is_idty_allowed_to_claim_membership(idty_index: &IdtyIndex) -> bool {
impl<T: Config<I>, I: 'static> sp_membership::traits::CheckCallAllowed<IdtyIndex> for Pallet<T, I> {
fn check_idty_allowed_to_claim_membership(idty_index: &IdtyIndex) -> Result<(), DispatchError> {
let idty_cert_meta = pallet_certification::Pallet::<T, I>::idty_cert_meta(idty_index);
idty_cert_meta.received_count >= T::MinCertForMembership::get() as u32
ensure!(
idty_cert_meta.received_count >= T::MinCertForMembership::get() as u32,
Error::<T, I>::IdtyNotAllowedToClaimMembership
);
Ok(())
}
}
impl<T: Config<I>, I: 'static> sp_membership::traits::IsIdtyAllowedToRenewMembership<IdtyIndex>
for Pallet<T, I>
{
fn is_idty_allowed_to_renew_membership(idty_index: &IdtyIndex) -> bool {
fn check_idty_allowed_to_renew_membership(idty_index: &IdtyIndex) -> Result<(), DispatchError> {
if let Some(idty_value) = pallet_identity::Pallet::<T>::identity(idty_index) {
idty_value.status == IdtyStatus::Validated
ensure!(
idty_value.status == IdtyStatus::Validated,
Error::<T, I>::IdtyNotAllowedToRenewMembership
);
} else {
false
return Err(Error::<T, I>::IdtyNotFound.into());
}
Ok(())
}
}
impl<T: Config<I>, I: 'static> sp_membership::traits::IsIdtyAllowedToRequestMembership<IdtyIndex>
for Pallet<T, I>
{
fn is_idty_allowed_to_request_membership(idty_index: &IdtyIndex) -> bool {
fn check_idty_allowed_to_request_membership(
idty_index: &IdtyIndex,
) -> Result<(), DispatchError> {
if let Some(idty_value) = pallet_identity::Pallet::<T>::identity(idty_index) {
T::IsSubWot::get() && idty_value.status == IdtyStatus::Validated
ensure!(
T::IsSubWot::get() && idty_value.status == IdtyStatus::Validated,
Error::<T, I>::IdtyNotAllowedToRequestMembership
);
} else {
false
return Err(Error::<T, I>::IdtyNotFound.into());
}
Ok(())
}
}
......
......@@ -122,7 +122,7 @@ impl pallet_identity::Config for Test {
type ChangeOwnerKeyPeriod = ChangeOwnerKeyPeriod;
type ConfirmPeriod = ConfirmPeriod;
type Event = Event;
type EnsureIdtyCallAllowed = (DuniterWot, SmithsSubWot);
type CheckIdtyCallAllowed = (DuniterWot, SmithsSubWot);
type IdtyCreationPeriod = IdtyCreationPeriod;
type IdtyData = ();
type IdtyNameValidator = IdtyNameValidatorTestImpl;
......@@ -142,9 +142,7 @@ parameter_types! {
}
impl pallet_membership::Config<Instance1> for Test {
type IsIdtyAllowedToClaimMembership = DuniterWot;
type IsIdtyAllowedToRenewMembership = DuniterWot;
type IsIdtyAllowedToRequestMembership = DuniterWot;
type CheckCallAllowed = DuniterWot;
type Event = Event;
type IdtyId = IdtyIndex;
type IdtyIdOf = IdentityIndexOf<Self>;
......@@ -167,7 +165,7 @@ impl pallet_certification::Config<Instance1> for Test {
type Event = Event;
type IdtyIndex = IdtyIndex;
type OwnerKeyOf = Identity;
type IsCertAllowed = DuniterWot;
type CheckCertAllowed = DuniterWot;
type MaxByIssuer = MaxByIssuer;
type MinReceivedCertToBeAbleToIssueCert = MinReceivedCertToBeAbleToIssueCert;
type OnNewcert = DuniterWot;
......@@ -196,9 +194,7 @@ parameter_types! {
}
impl pallet_membership::Config<Instance2> for Test {
type IsIdtyAllowedToClaimMembership = SmithsSubWot;
type IsIdtyAllowedToRenewMembership = SmithsSubWot;
type IsIdtyAllowedToRequestMembership = SmithsSubWot;
type CheckCallAllowed = SmithsSubWot;
type Event = Event;
type IdtyId = IdtyIndex;
type IdtyIdOf = IdentityIndexOf<Self>;
......@@ -221,7 +217,7 @@ impl pallet_certification::Config<Instance2> for Test {
type Event = Event;
type IdtyIndex = IdtyIndex;
type OwnerKeyOf = Identity;
type IsCertAllowed = SmithsSubWot;
type CheckCertAllowed = SmithsSubWot;
type MaxByIssuer = SmithsMaxByIssuer;
type MinReceivedCertToBeAbleToIssueCert = SmithsMinReceivedCertToBeAbleToIssueCert;
type OnNewcert = SmithsSubWot;
......
......@@ -16,8 +16,9 @@
use crate::mock::*;
use crate::mock::{Identity, System};
use crate::pallet as pallet_duniter_wot;
use codec::Encode;
use frame_support::instances::Instance1;
use frame_support::instances::{Instance1, Instance2};
use frame_support::{assert_noop, assert_ok};
use pallet_identity::{
IdtyName, IdtyStatus, NewOwnerKeyPayload, RevocationPayload, NEW_OWNER_KEY_PAYLOAD_PREFIX,
......@@ -46,9 +47,10 @@ fn test_creator_not_allowed_to_create_idty() {
// Alice should not be able to create an identity before block #2
// because Alice.next_issuable_on = 2
// but the true reason is that alice did not receive enough certs
assert_noop!(
Identity::create_identity(Origin::signed(1), 4),
pallet_identity::Error::<Test>::CreatorNotAllowedToCreateIdty
pallet_duniter_wot::Error::<Test, Instance1>::NotEnoughReceivedCertsToCreateIdty
);
});
}
......@@ -114,7 +116,7 @@ fn test_smith_member_cant_change_its_idty_address() {
13,
TestSignature(13, (NEW_OWNER_KEY_PAYLOAD_PREFIX, new_key_payload).encode())
),
pallet_identity::Error::<Test>::NotAllowedToChangeIdtyAddress
pallet_duniter_wot::Error::<Test, Instance2>::NotAllowedToChangeIdtyAddress
);
});
}
......@@ -137,7 +139,7 @@ fn test_smith_member_cant_revoke_its_idty() {
3,
TestSignature(3, (REVOCATION_PAYLOAD_PREFIX, revocation_payload).encode())
),
pallet_identity::Error::<Test>::NotAllowedToRemoveIdty
pallet_duniter_wot::Error::<Test, Instance2>::NotAllowedToRemoveIdty
);
});
}
......@@ -269,7 +271,7 @@ fn test_idty_membership_expire_them_requested() {
// Alice can't renew her cert to Charlie
assert_noop!(
Cert::add_cert(Origin::signed(1), 1, 3),
pallet_certification::Error::<Test, Instance1>::CertNotAllowed
pallet_duniter_wot::Error::<Test, Instance1>::IdtyNotFound
);
});
}
......
......@@ -72,7 +72,7 @@ pub mod pallet {
type Event: From<Event<Self>> + IsType<<Self as frame_system::Config>::Event>;
/// Management of the authorizations of the different calls.
/// The default implementation allows everything.
type EnsureIdtyCallAllowed: EnsureIdtyCallAllowed<Self>;
type CheckIdtyCallAllowed: CheckIdtyCallAllowed<Self>;
#[pallet::constant]
/// Minimum duration between the creation of 2 identities by the same creator
type IdtyCreationPeriod: Get<Self::BlockNumber>;
......@@ -271,9 +271,8 @@ pub mod pallet {
return Err(Error::<T>::IdtyAlreadyCreated.into());
}
if !T::EnsureIdtyCallAllowed::can_create_identity(creator) {
return Err(Error::<T>::CreatorNotAllowedToCreateIdty.into());
}
// run checks for identity creation
T::CheckIdtyCallAllowed::check_create_identity(creator)?;
let block_number = frame_system::pallet::Pallet::<T>::block_number();
......@@ -341,9 +340,7 @@ pub mod pallet {
if <IdentitiesNames<T>>::contains_key(&idty_name) {
return Err(Error::<T>::IdtyNameAlreadyExist.into());
}
if !T::EnsureIdtyCallAllowed::can_confirm_identity(idty_index) {
return Err(Error::<T>::NotAllowedToConfirmIdty.into());
}
T::CheckIdtyCallAllowed::check_confirm_identity(idty_index)?;
// Apply phase //
idty_value.status = IdtyStatus::ConfirmedByOwner;
......@@ -372,9 +369,7 @@ pub mod pallet {
match idty_value.status {
IdtyStatus::Created => return Err(Error::<T>::IdtyNotConfirmedByOwner.into()),
IdtyStatus::ConfirmedByOwner => {
if !T::EnsureIdtyCallAllowed::can_validate_identity(idty_index) {
return Err(Error::<T>::NotAllowedToValidateIdty.into());
}
T::CheckIdtyCallAllowed::check_validate_identity(idty_index)?;
}
IdtyStatus::Validated => return Err(Error::<T>::IdtyAlreadyValidated.into()),
}
......@@ -416,10 +411,7 @@ pub mod pallet {
Error::<T>::OwnerKeyAlreadyUsed
);
ensure!(
T::EnsureIdtyCallAllowed::can_change_identity_address(idty_index),
Error::<T>::NotAllowedToChangeIdtyAddress
);
T::CheckIdtyCallAllowed::check_change_identity_address(idty_index)?;
let block_number = frame_system::Pallet::<T>::block_number();
let maybe_old_old_owner_key =
......@@ -506,10 +498,7 @@ pub mod pallet {
Error::<T>::InvalidRevocationKey
);
ensure!(
T::EnsureIdtyCallAllowed::can_remove_identity(idty_index),
Error::<T>::NotAllowedToRemoveIdty
);
T::CheckIdtyCallAllowed::check_remove_identity(idty_index)?;
let genesis_hash = frame_system::Pallet::<T>::block_hash(T::BlockNumber::zero());
let revocation_payload = RevocationPayload {
......@@ -579,8 +568,6 @@ pub mod pallet {
#[pallet::error]
pub enum Error<T> {
/// Creator not allowed to create identities
CreatorNotAllowedToCreateIdty,
/// Identity already confirmed
IdtyAlreadyConfirmed,
/// Identity already created
......@@ -611,14 +598,6 @@ pub mod pallet {
InvalidRevocationKey,
/// Revocation payload signature is invalid
InvalidRevocationSig,
/// Identity not allowed to change address
NotAllowedToChangeIdtyAddress,
/// Not allowed to confirm identity
NotAllowedToConfirmIdty,
/// Not allowed to remove identity
NotAllowedToRemoveIdty,
/// Not allowed to validate identity
NotAllowedToValidateIdty,
/// Identity creation period is not respected
NotRespectIdtyCreationPeriod,
/// Not the same identity name
......
......@@ -94,7 +94,7 @@ impl pallet_identity::Config for Test {
type ChangeOwnerKeyPeriod = ChangeOwnerKeyPeriod;
type ConfirmPeriod = ConfirmPeriod;
type Event = Event;
type EnsureIdtyCallAllowed = ();
type CheckIdtyCallAllowed = ();
type IdtyCreationPeriod = IdtyCreationPeriod;
type IdtyData = ();
type IdtyNameValidator = IdtyNameValidatorTestImpl;
......
......@@ -19,36 +19,35 @@ use frame_support::pallet_prelude::*;
use impl_trait_for_tuples::impl_for_tuples;
use sp_runtime::traits::Saturating;
pub trait EnsureIdtyCallAllowed<T: Config> {
fn can_create_identity(creator: T::IdtyIndex) -> bool;
fn can_confirm_identity(idty_index: T::IdtyIndex) -> bool;
fn can_validate_identity(idty_index: T::IdtyIndex) -> bool;
fn can_change_identity_address(idty_index: T::IdtyIndex) -> bool;
fn can_remove_identity(idty_index: T::IdtyIndex) -> bool;
pub trait CheckIdtyCallAllowed<T: Config> {
fn check_create_identity(creator: T::IdtyIndex) -> Result<(), DispatchError>;
fn check_confirm_identity(idty_index: T::IdtyIndex) -> Result<(), DispatchError>;
fn check_validate_identity(idty_index: T::IdtyIndex) -> Result<(), DispatchError>;
fn check_change_identity_address(idty_index: T::IdtyIndex) -> Result<(), DispatchError>;
fn check_remove_identity(idty_index: T::IdtyIndex) -> Result<(), DispatchError>;
}
#[impl_for_tuples(5)]
#[allow(clippy::let_and_return)]
impl<T: Config> EnsureIdtyCallAllowed<T> for Tuple {
fn can_create_identity(creator: T::IdtyIndex) -> bool {
for_tuples!( #( if !Tuple::can_create_identity(creator) { return false; } )* );
true
impl<T: Config> CheckIdtyCallAllowed<T> for Tuple {
fn check_create_identity(creator: T::IdtyIndex) -> Result<(), DispatchError> {
for_tuples!( #( Tuple::check_create_identity(creator)?; )* );
Ok(())
}
fn can_confirm_identity(idty_index: T::IdtyIndex) -> bool {
for_tuples!( #( if !Tuple::can_confirm_identity(idty_index) { return false; } )* );
true
fn check_confirm_identity(idty_index: T::IdtyIndex) -> Result<(), DispatchError> {
for_tuples!( #( Tuple::check_confirm_identity(idty_index)?; )* );
Ok(())
}
fn can_validate_identity(idty_index: T::IdtyIndex) -> bool {
for_tuples!( #( if !Tuple::can_validate_identity(idty_index) { return false; } )* );
true
fn check_validate_identity(idty_index: T::IdtyIndex) -> Result<(), DispatchError> {
for_tuples!( #( Tuple::check_validate_identity(idty_index)?; )* );
Ok(())
}
fn can_change_identity_address(idty_index: T::IdtyIndex) -> bool {
for_tuples!( #( if !Tuple::can_change_identity_address(idty_index) { return false; } )* );
true
fn check_change_identity_address(idty_index: T::IdtyIndex) -> Result<(), DispatchError> {
for_tuples!( #( Tuple::check_change_identity_address(idty_index)?; )* );
Ok(())
}
fn can_remove_identity(idty_index: T::IdtyIndex) -> bool {
for_tuples!( #( if !Tuple::can_remove_identity(idty_index) { return false; } )* );
true
fn check_remove_identity(idty_index: T::IdtyIndex) -> Result<(), DispatchError> {
for_tuples!( #( Tuple::check_remove_identity(idty_index)?; )* );
Ok(())
}
}
......
......@@ -59,12 +59,8 @@ pub mod pallet {
#[pallet::config]
pub trait Config<I: 'static = ()>: frame_system::Config {
/// Ask the runtime if the identity can claim the membership
type IsIdtyAllowedToClaimMembership: IsIdtyAllowedToClaimMembership<Self::IdtyId>;
/// Ask the runtime if the identity can renew his membership
type IsIdtyAllowedToRenewMembership: IsIdtyAllowedToRenewMembership<Self::IdtyId>;
/// Ask the runtime if the identity can request the membership
type IsIdtyAllowedToRequestMembership: IsIdtyAllowedToRequestMembership<Self::IdtyId>;
/// Ask the runtime whether the identity can perform membership operations
type CheckCallAllowed: CheckCallAllowed<Self::IdtyId>;
/// Because this pallet emits events, it depends on the runtime's definition of an event.
type Event: From<Event<Self, I>> + IsType<<Self as frame_system::Config>::Event>;
/// Something that identifies an identity
......@@ -160,12 +156,6 @@ pub mod pallet {
#[pallet::error]
pub enum Error<T, I = ()> {
/// Identity not allowed to claim membership
IdtyNotAllowedToClaimMembership,
/// Identity not allowed to request membership
IdtyNotAllowedToRequestMembership,
/// Identity not allowed to renew membership
IdtyNotAllowedToRenewMembership,
/// Invalid meta data
InvalidMetaData,
/// Identity id not found
......@@ -221,10 +211,7 @@ pub mod pallet {
if !metadata.validate(&who) {
return Err(Error::<T, I>::InvalidMetaData.into());
}
if !T::IsIdtyAllowedToRequestMembership::is_idty_allowed_to_request_membership(&idty_id)
{
return Err(Error::<T, I>::IdtyNotAllowedToRequestMembership.into());
}
T::CheckCallAllowed::check_idty_allowed_to_request_membership(&idty_id)?;
Self::do_request_membership(idty_id, metadata)
}
......@@ -242,10 +229,7 @@ pub mod pallet {
Error::<T, I>::MembershipAlreadyAcquired
);
ensure!(
T::IsIdtyAllowedToClaimMembership::is_idty_allowed_to_claim_membership(&idty_id),
Error::<T, I>::IdtyNotAllowedToClaimMembership
);
T::CheckCallAllowed::check_idty_allowed_to_claim_membership(&idty_id)?;
let metadata = PendingMembership::<T, I>::take(&idty_id)
.ok_or(Error::<T, I>::MembershipRequestNotFound)?;
......@@ -271,10 +255,7 @@ pub mod pallet {
Error::<T, I>::MembershipNotFound
);
ensure!(
T::IsIdtyAllowedToRenewMembership::is_idty_allowed_to_renew_membership(&idty_id),
Error::<T, I>::IdtyNotAllowedToRenewMembership,
);
T::CheckCallAllowed::check_idty_allowed_to_renew_membership(&idty_id)?;
let _ = Self::do_renew_membership(idty_id);
......
......@@ -83,9 +83,7 @@ parameter_types! {
}
impl pallet_membership::Config for Test {
type IsIdtyAllowedToClaimMembership = ();
type IsIdtyAllowedToRenewMembership = ();
type IsIdtyAllowedToRequestMembership = ();
type CheckCallAllowed = ();
type Event = Event;
type IdtyId = IdtyId;
type IdtyIdOf = ConvertInto;
......
......@@ -14,35 +14,23 @@
// You should have received a copy of the GNU Affero General Public License
// along with Duniter-v2S. If not, see <https://www.gnu.org/licenses/>.
use frame_support::pallet_prelude::Weight;
use frame_support::pallet_prelude::*;
pub trait IsIdtyAllowedToClaimMembership<IdtyId> {
fn is_idty_allowed_to_claim_membership(idty_id: &IdtyId) -> bool;
pub trait CheckCallAllowed<IdtyId> {
fn check_idty_allowed_to_claim_membership(idty_id: &IdtyId) -> Result<(), DispatchError>;
fn check_idty_allowed_to_renew_membership(idty_id: &IdtyId) -> Result<(), DispatchError>;
fn check_idty_allowed_to_request_membership(idty_id: &IdtyId) -> Result<(), DispatchError>;
}
impl<IdtyId> IsIdtyAllowedToClaimMembership<IdtyId> for () {
fn is_idty_allowed_to_claim_membership(_: &IdtyId) -> bool {
true
impl<IdtyId> CheckCallAllowed<IdtyId> for () {
fn check_idty_allowed_to_claim_membership(_: &IdtyId) -> Result<(), DispatchError> {
Ok(())
}
}
pub trait IsIdtyAllowedToRenewMembership<IdtyId> {
fn is_idty_allowed_to_renew_membership(idty_id: &IdtyId) -> bool;
}
impl<IdtyId> IsIdtyAllowedToRenewMembership<IdtyId> for () {
fn is_idty_allowed_to_renew_membership(_: &IdtyId) -> bool {
true
fn check_idty_allowed_to_renew_membership(_: &IdtyId) -> Result<(), DispatchError> {
Ok(())
}
}
pub trait IsIdtyAllowedToRequestMembership<IdtyId> {
fn is_idty_allowed_to_request_membership(idty_id: &IdtyId) -> bool;
}
impl<IdtyId> IsIdtyAllowedToRequestMembership<IdtyId> for () {
fn is_idty_allowed_to_request_membership(_: &IdtyId) -> bool {
true
fn check_idty_allowed_to_request_membership(_: &IdtyId) -> Result<(), DispatchError> {
Ok(())
}
}
......
......@@ -430,7 +430,7 @@ macro_rules! pallets_config {
type ChangeOwnerKeyPeriod = ChangeOwnerKeyPeriod;
type ConfirmPeriod = ConfirmPeriod;
type Event = Event;
type EnsureIdtyCallAllowed = (Wot, SmithsSubWot);
type CheckIdtyCallAllowed = (Wot, SmithsSubWot);
type IdtyCreationPeriod = IdtyCreationPeriod;
type IdtyData = IdtyData;
type IdtyIndex = IdtyIndex;
......@@ -444,9 +444,7 @@ macro_rules! pallets_config {
}
impl pallet_membership::Config<frame_support::instances::Instance1> for Runtime {
type IsIdtyAllowedToClaimMembership = Wot;
type IsIdtyAllowedToRenewMembership = Wot;
type IsIdtyAllowedToRequestMembership = Wot;
type CheckCallAllowed = Wot;
type Event = Event;
type IdtyId = IdtyIndex;
type IdtyIdOf = common_runtime::providers::IdentityIndexOf<Self>;
......@@ -461,7 +459,7 @@ macro_rules! pallets_config {
type Event = Event;
type IdtyIndex = IdtyIndex;
type OwnerKeyOf = Identity;
type IsCertAllowed = Wot;
type CheckCertAllowed = Wot;
type MaxByIssuer = MaxByIssuer;
type MinReceivedCertToBeAbleToIssueCert = MinReceivedCertToBeAbleToIssueCert;
type OnNewcert = Wot;
......@@ -480,9 +478,7 @@ macro_rules! pallets_config {
}
impl pallet_membership::Config<Instance2> for Runtime {
type IsIdtyAllowedToClaimMembership = SmithsSubWot;
type IsIdtyAllowedToRenewMembership = SmithsSubWot;
type IsIdtyAllowedToRequestMembership = SmithsSubWot;
type CheckCallAllowed = SmithsSubWot;
type Event = Event;
type IdtyId = IdtyIndex;
type IdtyIdOf = common_runtime::providers::IdentityIndexOf<Self>;
......@@ -497,7 +493,7 @@ macro_rules! pallets_config {
type Event = Event;
type IdtyIndex = IdtyIndex;
type OwnerKeyOf = Identity;
type IsCertAllowed = SmithsSubWot;
type CheckCertAllowed = SmithsSubWot;
type MaxByIssuer = SmithMaxByIssuer;
type MinReceivedCertToBeAbleToIssueCert = SmithMinReceivedCertToBeAbleToIssueCert;
type OnNewcert = SmithsSubWot;
......
......@@ -84,7 +84,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion {
// `spec_version`, and `authoring_version` are the same between Wasm and native.
// This value is set to 100 to notify Polkadot-JS App (https://polkadot.js.org/apps) to use
// the compatible custom types.
spec_version: 300,
spec_version: 400,
impl_version: 1,
apis: RUNTIME_API_VERSIONS,
transaction_version: 1,
......