diff --git a/app-libs/stf/src/getter.rs b/app-libs/stf/src/getter.rs index 48f7d588..7a4a6866 100644 --- a/app-libs/stf/src/getter.rs +++ b/app-libs/stf/src/getter.rs @@ -18,7 +18,8 @@ use crate::{AccountId, KeyPair, Signature}; use codec::{Decode, Encode}; use encointer_primitives::{ - ceremonies::ParticipantIndexType, communities::CommunityIdentifier, + ceremonies::{AttestationIndexType, ParticipantIndexType}, + communities::CommunityIdentifier, scheduler::CeremonyIndexType, }; use ita_sgx_runtime::System; @@ -66,6 +67,7 @@ impl From for Getter { pub enum PublicGetter { some_value, ceremonies_assignment_counts(CommunityIdentifier, CeremonyIndexType), + ceremonies_attestation_count(CommunityIdentifier, CeremonyIndexType), ceremonies_meetup_count(CommunityIdentifier, CeremonyIndexType), ceremonies_meetup_time_offset(), ceremonies_registered_bootstrappers_count(CommunityIdentifier, CeremonyIndexType), @@ -91,12 +93,29 @@ pub enum TrustedGetter { //encointer_balance(AccountId, CommunityIdentifier), //ceremonies_participant_index(AccountId, CommunityIdentifier), //Not public : ceremonies_meetup_index(AccountId, CommunityIdentifier), - ceremonies_aggregated_account_data(AccountId, CommunityIdentifier, CeremonyIndexType), + ceremonies_aggregated_account_data(AccountId, CommunityIdentifier, AccountId), ceremonies_assignments(AccountId, CommunityIdentifier, CeremonyIndexType), //ceremonies_meetup_locations(AccountId, CommunityIdentifier, CeremonyIndexType, MeetupIndexType), //ceremonies_reputations(AccountId, CommunityIdentifier), - //ceremonies_attestations(AccountId, CommunityIdentifier), //ceremonies_participant_reputation(AccountId, CommunityIdentifier, CeremonyIndexType), + ceremonies_meetup_participant_count_vote( + AccountId, + CommunityIdentifier, + CeremonyIndexType, + AccountId, + ), + ceremonies_participant_attestees( + AccountId, + CommunityIdentifier, + CeremonyIndexType, + AttestationIndexType, + ), + ceremonies_participant_attestation_index( + AccountId, + CommunityIdentifier, + CeremonyIndexType, + AccountId, + ), ceremonies_registered_bootstrapper( AccountId, CommunityIdentifier, @@ -152,6 +171,12 @@ impl TrustedGetter { sender_account, TrustedGetter::ceremonies_assignments(sender_account, _, _) => sender_account, //TrustedGetter::ceremonies_meetup_locations(sender_account, _, _, _) => sender_account, + TrustedGetter::ceremonies_meetup_participant_count_vote(sender_account, _, _, _) => + sender_account, + TrustedGetter::ceremonies_participant_attestees(sender_account, _, _, _) => + sender_account, + TrustedGetter::ceremonies_participant_attestation_index(sender_account, _, _, _) => + sender_account, TrustedGetter::ceremonies_registered_bootstrapper(sender_account, _, _, _) => sender_account, TrustedGetter::ceremonies_registered_bootstrappers(sender_account, _, _) => @@ -269,27 +294,92 @@ impl ExecuteGetter for TrustedGetterSigned { Some(attestations.encode()) }, */ - TrustedGetter::ceremonies_aggregated_account_data( - who, - community_id, - _ceremony_index, - ) => { - error!("TrustedGetter ceremonies_aggregated_account_data"); + TrustedGetter::ceremonies_aggregated_account_data(who, community_id, account_id) => { + debug!("TrustedGetter ceremonies_aggregated_account_data"); + //Todo Master or Me? + if !is_ceremony_master(who) { + debug!("TrustedGetter ceremonies_aggregated_account_data, return: No master"); + return None + } let aggregated_account_data = - EncointerCeremonies::get_aggregated_account_data(community_id, &who); - //aggregated_account_data.personal.map(|p| p.encode()) + EncointerCeremonies::get_aggregated_account_data(community_id, &account_id); Some(aggregated_account_data.encode()) }, TrustedGetter::ceremonies_assignments(who, community_id, ceremony_index) => { - error!("TrustedGetter ceremonies_assignments"); + debug!("TrustedGetter ceremonies_assignments"); // Block getter of confidential data if it is not the CeremonyMaster. if !is_ceremony_master(who) { - error!("TrustedGetter ceremonies_assignments, return: No master"); + debug!("TrustedGetter ceremonies_assignments, return: No master"); return None } let assignments = EncointerCeremonies::assignments((community_id, ceremony_index)); Some(assignments.encode()) }, + TrustedGetter::ceremonies_meetup_participant_count_vote( + who, + community_id, + ceremony_index, + participant_account_id, + ) => { + debug!("TrustedGetter ceremonies_meetup_participant_count_vote"); + // Todo Master or Me? + // Block getter of confidential data if it is not the CeremonyMaster + if !is_ceremony_master(who) { + return None + } + Some( + EncointerCeremonies::meetup_participant_count_vote( + (community_id, ceremony_index), + &participant_account_id, + ) + .encode(), + ) + }, + TrustedGetter::ceremonies_participant_attestees( + who, + community_id, + ceremony_index, + attestation_index, + ) => { + debug!("TrustedGetter ceremonies_participant_attestees"); + // Block getter of confidential data if it is not the CeremonyMaster + if !is_ceremony_master(who) { + return None + } + match EncointerCeremonies::attestation_registry( + (community_id, ceremony_index), + &attestation_index, + ) { + Some(b) => Some(b.encode()), + _ => { + warn!( + "no attestees for {}, {}, {}", + community_id, ceremony_index, attestation_index + ); + None + }, + } + }, + TrustedGetter::ceremonies_participant_attestation_index( + who, + community_id, + ceremony_index, + participant_account_id, + ) => { + debug!("TrustedGetter ceremonies_participant_attestation_index"); + //Todo Master or Me? + // Block getter of confidential data if it is not the CeremonyMaster + if !is_ceremony_master(who) { + return None + } + Some( + EncointerCeremonies::attestation_index( + (community_id, ceremony_index), + &participant_account_id, + ) + .encode(), + ) + }, TrustedGetter::ceremonies_registered_bootstrapper( who, community_id, @@ -576,17 +666,13 @@ impl ExecuteGetter for TrustedGetterSigned { fn get_storage_hashes_to_update(self) -> Vec> { let mut key_hashes = Vec::new(); match self.getter { - TrustedGetter::ceremonies_aggregated_account_data( - _, - _community_id, - _ceremony_index, - ) => { + TrustedGetter::ceremonies_aggregated_account_data(_, _, _) => { key_hashes.push(storage_value_key("EncointerScheduler", "CurrentCeremonyIndex")); let current_phase = pallet_encointer_scheduler::Pallet::::current_phase(); // updated im block import key_hashes.push(storage_map_key( "EncointerScheduler", - "PhaseDuration", + "PhaseDurations", ¤t_phase, &StorageHasher::Blake2_128Concat, )); @@ -608,6 +694,12 @@ impl ExecuteGetter for PublicGetter { let count = EncointerCeremonies::assignment_counts((community_id, ceremony_index)); Some(count.encode()) }, + PublicGetter::ceremonies_attestation_count(community_id, ceremony_index) => { + let count = pallet_encointer_ceremonies::Pallet::< + ita_sgx_runtime::Runtime, + >::attestation_count((community_id, ceremony_index)); + Some(count.encode()) + }, PublicGetter::ceremonies_meetup_count(community_id, ceremony_index) => { let count = EncointerCeremonies::meetup_count((community_id, ceremony_index)); Some(count.encode()) diff --git a/app-libs/stf/src/trusted_call.rs b/app-libs/stf/src/trusted_call.rs index 0d2990fd..207f2828 100644 --- a/app-libs/stf/src/trusted_call.rs +++ b/app-libs/stf/src/trusted_call.rs @@ -64,6 +64,7 @@ pub enum TrustedCall { encointer_set_fee_conversion_factor(AccountId, FeeConversionFactorType), encointer_transfer_all(AccountId, AccountId, CommunityIdentifier), */ + ceremonies_attest_attendees(AccountId, CommunityIdentifier, u32, Vec), ceremonies_register_participant( AccountId, CommunityIdentifier, @@ -76,13 +77,6 @@ pub enum TrustedCall { ProofOfAttendance, ), ceremonies_unregister_participant(AccountId, CommunityIdentifier, Option), - ceremonies_attest_attendees( - AccountId, - CommunityIdentifier, - u32, - CeremonyIndexType, - Vec, - ), ceremonies_endorse_newcomer(AccountId, CommunityIdentifier, AccountId), ceremonies_claim_rewards(AccountId, CommunityIdentifier, Option), ceremonies_set_inactivity_timeout(AccountId, InactivityTimeoutType), @@ -152,6 +146,7 @@ impl TrustedCall { //TrustedCall::encointer_balance_transfer(sender_account, ..) => sender_account, //TrustedCall::encointer_set_fee_conversion_factor(sender_account, ..) => sender_account, //TrustedCall::encointer_transfer_all(sender_account, ..) => sender_account, + TrustedCall::ceremonies_attest_attendees(sender_account, ..) => sender_account, TrustedCall::ceremonies_register_participant(sender_account, ..) => sender_account, TrustedCall::ceremonies_migrate_to_private_community(sender_account, ..) => sender_account, @@ -160,7 +155,6 @@ impl TrustedCall { TrustedCall::ceremonies_upgrade_registration(sender_account, ..) => sender_account, TrustedCall::ceremonies_unregister_participant(sender_account, ..) => sender_account, - TrustedCall::ceremonies_attest_attendees(sender_account, ..) => sender_account, TrustedCall::ceremonies_endorse_newcomer(sender_account, ..) => sender_account, TrustedCall::ceremonies_claim_rewards(sender_account, ..) => sender_account, TrustedCall::ceremonies_set_inactivity_timeout(sender_account, ..) => sender_account, @@ -384,6 +378,28 @@ impl ExecuteCall for TrustedCallSigned { }, */ + TrustedCall::ceremonies_attest_attendees( + who, + cid, + number_of_participants_vote, + attestations, + ) => { + let origin = ita_sgx_runtime::Origin::signed(who); + + ita_sgx_runtime::EncointerCeremoniesCall::::attest_attendees { + cid, + number_of_participants_vote, + attestations, + } + .dispatch_bypass_filter(origin) + .map_err(|e| { + Self::Error::Dispatch(format!( + "Ceremonies attendees attestation error: {:?}", + e.error + )) + })?; + Ok(()) + }, TrustedCall::ceremonies_register_participant(who, cid, proof) => { let origin = ita_sgx_runtime::Origin::signed(who); @@ -393,15 +409,6 @@ impl ExecuteCall for TrustedCallSigned { )) } - if pallet_encointer_scheduler::Pallet::::current_phase() - == CeremonyPhaseType::Assigning - { - return Err(Self::Error::Dispatch( - "registering a participant can only be done during registering or attesting phase" - .to_string(), - )) - } - ita_sgx_runtime::EncointerCeremoniesCall::::register_participant { cid, proof, @@ -472,14 +479,6 @@ impl ExecuteCall for TrustedCallSigned { )) } - if pallet_encointer_scheduler::Pallet::::current_phase() - != CeremonyPhaseType::Registering - { - return Err(Self::Error::Dispatch( - "adding a location can only be done during the registering phase" - .to_string(), - )) - } ita_sgx_runtime::EncointerCommunitiesCall::::add_location { cid, location, @@ -546,37 +545,6 @@ impl ExecuteCall for TrustedCallSigned { })?; Ok(()) }, - TrustedCall::ceremonies_attest_attendees( - who, - cid, - number_of_participants_vote, - _ceremony_index, - attestations, - ) => { - let origin = ita_sgx_runtime::Origin::signed(who); - - if pallet_encointer_scheduler::Pallet::::current_phase() - != CeremonyPhaseType::Attesting - { - return Err(Self::Error::Dispatch( - "attendees attestation can only be done during attesting phase".to_string(), - )) - } - - ita_sgx_runtime::EncointerCeremoniesCall::::attest_attendees { - cid, - number_of_participants_vote, - attestations, - } - .dispatch_bypass_filter(origin) - .map_err(|e| { - Self::Error::Dispatch(format!( - "Ceremonies attendees attestation error: {:?}", - e.error - )) - })?; - Ok(()) - }, TrustedCall::ceremonies_endorse_newcomer(who, cid, newbie) => { let origin = ita_sgx_runtime::Origin::signed(who); @@ -926,6 +894,10 @@ impl ExecuteCall for TrustedCallSigned { | TrustedCall::ceremonies_upgrade_registration(_, cid, _) | TrustedCall::ceremonies_unregister_participant(_, cid, _) => { */ + TrustedCall::ceremonies_attest_attendees(_, _, _, _) => { + key_hashes.push(storage_value_key("EncointerScheduler", "PhaseDurations")); + key_hashes.push(storage_value_key("EncointerScheduler", "CurrentCeremonyIndex")); + }, TrustedCall::ceremonies_register_participant(_, _, _) => { key_hashes.push(storage_value_key("EncointerScheduler", "CurrentCeremonyIndex")); }, @@ -970,20 +942,6 @@ impl ExecuteCall for TrustedCallSigned { TrustedCall::communities_add_location(_, _, _) => debug!("No storage updates needed..."), /* - //get_aggregated_account_data ? - TrustedCall::ceremonies_attest_attendees(_, cid, _, ceremony_index, _) => { - key_hashes.push(storage_value_key("EncointerScheduler", "PhaseDurations")); - key_hashes.push(storage_value_key("EncointerScheduler", "CurrentCeremonyIndex")); - key_hashes.push(storage_value_key("EncointerCommunities", "CommunityIdentifiers")); - key_hashes.push(storage_double_map_key( - "EncointerCommunities", - "Locations", - &cid, - &StorageHasher::Blake2_128Concat, - &ceremony_index, - &StorageHasher::Identity, - )); - }, TrustedCall::ceremonies_claim_rewards(_, cid, _) => { key_hashes.push(storage_value_key("EncointerCommunities", "CommunityIdentifiers")); key_hashes.push(storage_value_key("EncointerCommunities", "NominalIncome")); diff --git a/cli/demo_private_community.sh b/cli/demo_private_community.sh index e13f27c0..aff96884 100644 --- a/cli/demo_private_community.sh +++ b/cli/demo_private_community.sh @@ -74,13 +74,13 @@ echo "Reading MRENCLAVE from worker list: ${MRENCLAVE}" [[ -z $MRENCLAVE ]] && { echo "MRENCLAVE is empty. cannot continue" ; exit 1; } echo "" -echo "" -echo "* Try to register //Alice, but community is not private! " -$CLIENT trusted --mrenclave ${MRENCLAVE} register-participant //Alice ${COMMUNITY_IDENTIFIER} -echo "" -echo "* Listing participants: There is no participants! " -$CLIENT trusted --mrenclave ${MRENCLAVE} list-participants //Alice ${COMMUNITY_IDENTIFIER} -echo "" +# echo "" +# echo "* Try to register //Alice, but community is not private! " +# $CLIENT trusted --mrenclave ${MRENCLAVE} register-participant //Alice ${COMMUNITY_IDENTIFIER} +# echo "" +# echo "* Listing participants: There is no participants! " +# $CLIENT trusted --mrenclave ${MRENCLAVE} list-participants //Alice ${COMMUNITY_IDENTIFIER} +# echo "" echo "" echo "* Migrating community ${COMMUNITY_IDENTIFIER} to private" @@ -88,7 +88,7 @@ $CLIENT trusted --mrenclave ${MRENCLAVE} make-community-private //Alice ${COMMUN echo "" echo "" -echo "* Registering 3 bootstrapper : " +echo "* Registering 3 bootstrappers : " echo " //Alice," $CLIENT trusted --mrenclave ${MRENCLAVE} register-participant //Alice ${COMMUNITY_IDENTIFIER} echo " //Bob" @@ -117,3 +117,35 @@ echo "" echo "* Listing Meetups" $CLIENT trusted --mrenclave ${MRENCLAVE} list-meetups //Alice ${COMMUNITY_IDENTIFIER} echo "" + +echo "" +echo "* Performing Meetups" + +echo "" +echo "* Triggering manually next phase: Attesting" +$CLIENT next-phase //Alice +echo "" + +echo " //Alice's attest attendees claim" +$CLIENT trusted --mrenclave ${MRENCLAVE} attest-attendees //Alice ${COMMUNITY_IDENTIFIER} //Bob //Charlie //Cora +echo "" + +echo " //Bob's attest attendees claim" +$CLIENT trusted --mrenclave ${MRENCLAVE} attest-attendees //Bob ${COMMUNITY_IDENTIFIER} //Alice //Charlie //Cora +echo "" + +echo " //Charlie's attest attendees claim" +$CLIENT trusted --mrenclave ${MRENCLAVE} attest-attendees //Charlie ${COMMUNITY_IDENTIFIER} //Alice //Bob //Cora +echo "" + +echo " //Cora's attest attendees claim" +$CLIENT trusted --mrenclave ${MRENCLAVE} attest-attendees //Cora ${COMMUNITY_IDENTIFIER} //Alice //Charlie //Bob +echo "" + +echo "* Waiting enough time, such that xt's are processed... 3 blocks 30 seconds" +sleep 30 + +echo "" +echo "* Listing Attestees" +$CLIENT trusted --mrenclave ${MRENCLAVE} list-attestees //Alice ${COMMUNITY_IDENTIFIER} +echo "" diff --git a/cli/src/ceremonies/commands/attest_attendees.rs b/cli/src/ceremonies/commands/attest_attendees.rs new file mode 100644 index 00000000..5da1f040 --- /dev/null +++ b/cli/src/ceremonies/commands/attest_attendees.rs @@ -0,0 +1,81 @@ +/* + Copyright 2022 Encointer Association + + 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. + +*/ + +use crate::{ + get_layer_two_nonce, + trusted_command_utils::{get_accountid_from_str, get_identifiers, get_pair_from_str}, + trusted_commands::TrustedArgs, + trusted_operation::perform_trusted_operation, + Cli, +}; +use codec::Decode; +use encointer_primitives::communities::CommunityIdentifier; +use ita_stf::{Index, KeyPair, TrustedCall, TrustedGetter, TrustedOperation}; +use log::*; +use sp_core::Pair; +use std::str::FromStr; + +/// Attest Encointer ceremony attendees claim for the supplied community +#[derive(Debug, Clone, Parser)] +pub struct AttestAttendeesCommand { + /// Participant : sender's on-chain AccountId in ss58check format. + who: String, + + /// Community Id. + community_id: String, + + /// Participants who attested: list of AccountIds in ss58check format. + #[structopt(min_values = 2)] + attestations: Vec, +} + +impl AttestAttendeesCommand { + pub fn run(&self, cli: &Cli, trusted_args: &TrustedArgs) { + let who = get_pair_from_str(trusted_args, &self.who); + let (mrenclave, shard) = get_identifiers(trusted_args); + + info!( + "Attest attendees claim for community {} and participant {}", + self.community_id, + who.public() + ); + + let community_identifier = CommunityIdentifier::from_str(&self.community_id).unwrap(); + + let mut attestations = Vec::new(); + + for a in &self.attestations { + attestations.push(get_accountid_from_str(a)); + } + + let number_of_participants_vote = attestations.len() as u32 + 1u32; + info!("Number of vote {}", number_of_participants_vote); + + let nonce = get_layer_two_nonce!(who, cli, trusted_args); + let top = TrustedCall::ceremonies_attest_attendees( + who.public().into(), + community_identifier, + number_of_participants_vote, + attestations, + ) + .sign(&KeyPair::Sr25519(who), nonce, &mrenclave, &shard) + .into_trusted_operation(trusted_args.direct); + + let _ = perform_trusted_operation(cli, trusted_args, &top); + debug!("trusted call ceremonies_attest_attendees executed"); + } +} diff --git a/cli/src/ceremonies/commands/ceremonies_command_utils.rs b/cli/src/ceremonies/commands/ceremonies_command_utils.rs index c30a7728..ae60f95e 100644 --- a/cli/src/ceremonies/commands/ceremonies_command_utils.rs +++ b/cli/src/ceremonies/commands/ceremonies_command_utils.rs @@ -23,8 +23,9 @@ use codec::{Decode, Encode, Error as CodecError}; use encointer_ceremonies_assignment::assignment_fn_inverse; use encointer_primitives::{ ceremonies::{ - Assignment, AssignmentCount, CommunityCeremony, MeetupIndexType, ParticipantIndexType, - ParticipantType, ProofOfAttendance, + AggregatedAccountData, Assignment, AssignmentCount, AttestationIndexType, + CommunityCeremony, MeetupIndexType, ParticipantIndexType, ParticipantType, + ProofOfAttendance, }, communities::{CommunityIdentifier, Location}, scheduler::CeremonyIndexType, @@ -37,6 +38,7 @@ use log::*; use serde::{Deserialize, Serialize}; use sp_application_crypto::Ss58Codec; use sp_core::{sr25519 as sr25519_core, Pair}; +use std::collections::HashMap; pub const ONE_DAY: Moment = 86_400_000; @@ -90,6 +92,29 @@ impl CommunityCeremonyStats { } } +#[derive(Debug, Serialize, Deserialize)] +pub struct AttestationState { + pub community_ceremony: CommunityCeremony, + pub meetup_index: MeetupIndexType, + pub vote: u32, + pub attestation_index: u64, + pub attestor: AccountId, + pub attestees: Vec, +} + +impl AttestationState { + pub fn new( + community_ceremony: CommunityCeremony, + meetup_index: MeetupIndexType, + vote: u32, + attestation_index: u64, + attestor: AccountId, + attestees: Vec, + ) -> Self { + Self { community_ceremony, meetup_index, vote, attestation_index, attestor, attestees } + } +} + pub fn get_ceremony_stats( cli: &Cli, trusted_args: &TrustedArgs, @@ -161,57 +186,42 @@ pub fn get_ceremony_stats( )) } -/* fn get_aggregated_account_data( cli: &Cli, trusted_args: &TrustedArgs, arg_who: &str, community_identifier: CommunityIdentifier, - ceremony_index: CeremonyIndexType, account_id: AccountId, -) -> Option> { - //signer: Master or Me (account_id) +) -> Result, Error> { let who = get_pair_from_str(trusted_args, arg_who); - //TODO account sign and param? let top: TrustedOperation = TrustedGetter::ceremonies_aggregated_account_data( - account_id, + who.public().into(), community_identifier, - ceremony_index, + account_id, ) - .sign(&KeyPair::Sr25519(who.clone())) + .sign(&KeyPair::Sr25519(who)) .into(); - let encoded_data = perform_trusted_operation(cli, trusted_args, &top); - decode_aggregated_account_data(encoded_data) + let encoded_data = perform_trusted_operation(cli, trusted_args, &top) + .ok_or_else(|| Error::Other("AggregatedAccountData doesn't exist".into()))?; + Ok(Decode::decode(&mut encoded_data.as_slice())?) } -fn get_meetup_index( +pub fn get_meetup_index( cli: &Cli, trusted_args: &TrustedArgs, arg_who: &str, community_identifier: CommunityIdentifier, - ceremony_index: CeremonyIndexType, account_id: AccountId, -) -> Option { - if let Some(account_data) = get_aggregated_account_data( - cli, - trusted_args, - arg_who, - community_identifier, - ceremony_index, - account_id, - ) { - match account_data.personal { - Some(personal) => return personal.meetup_index, - None => return None, - } - } else { - println!("aggregated account data: unknown"); +) -> Result, Error> { + let account_data = + get_aggregated_account_data(cli, trusted_args, arg_who, community_identifier, account_id)?; + match account_data.personal { + Some(personal) => Ok(personal.meetup_index), + None => Err(Error::Other("No personal data in AggregatedAccountData".into())), } - None } - */ #[allow(clippy::too_many_arguments)] fn get_meetup_participants_with_type( @@ -467,21 +477,41 @@ pub fn list_participants(encoded_participants: Option>) { }, }; } -/* -pub fn decode_aggregated_account_data( - encoded_data: Option>, -) -> Option> { - encoded_data.and_then(|data| { - if let Ok(data_decoded) = Decode::decode(&mut data.as_slice()) { - Some(data_decoded) - } else { - error!("Could not decode the aggregated account data"); - None - } - }) -} - */ +pub fn participant_attestation_index_map( + cli: &Cli, + trusted_args: &TrustedArgs, + arg_who: &str, + community_identifier: CommunityIdentifier, + ceremony_index: CeremonyIndexType, + encoded_participants: Vec, +) -> HashMap { + let mut participants_attestation_indexes = HashMap::new(); + let who = get_pair_from_str(trusted_args, arg_who); + match decode_participants(Some(encoded_participants)) { + Some(p) => + for account_id in p { + let top: TrustedOperation = + TrustedGetter::ceremonies_participant_attestation_index( + who.public().into(), + community_identifier, + ceremony_index, + account_id.clone(), + ) + .sign(&KeyPair::Sr25519(who.clone())) + .into(); + if let Some(encoded_index) = perform_trusted_operation(cli, trusted_args, &top) { + if let Ok(index) = AttestationIndexType::decode(&mut encoded_index.as_slice()) { + participants_attestation_indexes.insert(index, account_id); + } + } + }, + None => { + error!("participant_attestation_index_map: Couldn't decode participants"); + }, + }; + participants_attestation_indexes +} pub fn decode_participants(encoded_participants: Option>) -> Option> { encoded_participants.and_then(|participants| { diff --git a/cli/src/ceremonies/commands/list_attestees.rs b/cli/src/ceremonies/commands/list_attestees.rs new file mode 100644 index 00000000..da445727 --- /dev/null +++ b/cli/src/ceremonies/commands/list_attestees.rs @@ -0,0 +1,214 @@ +/* + Copyright 2022 Encointer Association + + 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. + +*/ + +use crate::{ + ceremonies::commands::ceremonies_command_utils::{ + get_meetup_index, participant_attestation_index_map, AttestationState, + }, + command_utils::get_chain_api, + trusted_command_utils::get_pair_from_str, + trusted_commands::TrustedArgs, + trusted_operation::perform_trusted_operation, + Cli, +}; +use codec::Decode; +use encointer_primitives::{ceremonies::AttestationIndexType, communities::CommunityIdentifier}; +use ita_stf::{KeyPair, PublicGetter, TrustedGetter, TrustedOperation}; +use itp_node_api::api_client::encointer::EncointerApi; +use log::*; +use sp_core::Pair; +use std::{collections::HashMap, str::FromStr}; + +/// Listing all attestees for participants for supplied community identifier and ceremony index. +#[derive(Debug, Clone, Parser)] +pub struct ListAttesteesCommand { + /// Participant : sender's on-chain AccountId in ss58check format. + who: String, + + /// Community Id. + community_id: String, +} + +impl ListAttesteesCommand { + pub fn run(&self, cli: &Cli, trusted_args: &TrustedArgs) { + let api = get_chain_api(cli); + let who = get_pair_from_str(trusted_args, &self.who); + + let community_identifier = CommunityIdentifier::from_str(&self.community_id).unwrap(); + let ceremony_index = api.get_current_ceremony_index(None).unwrap().unwrap(); + + println!( + "Listing all attestees for community {} and ceremony {}", + self.community_id, ceremony_index + ); + + let top: TrustedOperation = + PublicGetter::ceremonies_attestation_count(community_identifier, ceremony_index).into(); + let encoded_attestee = perform_trusted_operation(cli, trusted_args, &top).unwrap(); + let attestee_count = + AttestationIndexType::decode(&mut encoded_attestee.as_slice()).unwrap_or_default(); + println!("number of attestees: {}", attestee_count); + + println!( + "Get attestation index for all participants of cid {} and ceremony nr {}", + community_identifier, ceremony_index + ); + + let mut participants_attestation_indexes = HashMap::new(); + + let top: TrustedOperation = TrustedGetter::ceremonies_registered_bootstrappers( + who.public().into(), + community_identifier, + ceremony_index, + ) + .sign(&KeyPair::Sr25519(who.clone())) + .into(); + match perform_trusted_operation(cli, trusted_args, &top) { + Some(encoded_bootstrappers) => { + participants_attestation_indexes.extend(participant_attestation_index_map( + cli, + trusted_args, + &self.who, + community_identifier, + ceremony_index, + encoded_bootstrappers, + )); + }, + None => println!("No bootstrappers registered for this ceremony"), + } + + let top: TrustedOperation = TrustedGetter::ceremonies_registered_reputables( + who.public().into(), + community_identifier, + ceremony_index, + ) + .sign(&KeyPair::Sr25519(who.clone())) + .into(); + match perform_trusted_operation(cli, trusted_args, &top) { + Some(encoded_reputables) => { + participants_attestation_indexes.extend(participant_attestation_index_map( + cli, + trusted_args, + &self.who, + community_identifier, + ceremony_index, + encoded_reputables, + )); + }, + None => println!("No reputables registered for this ceremony"), + } + + let top: TrustedOperation = TrustedGetter::ceremonies_registered_endorsees( + who.public().into(), + community_identifier, + ceremony_index, + ) + .sign(&KeyPair::Sr25519(who.clone())) + .into(); + match perform_trusted_operation(cli, trusted_args, &top) { + Some(encoded_endorsees) => { + participants_attestation_indexes.extend(participant_attestation_index_map( + cli, + trusted_args, + &self.who, + community_identifier, + ceremony_index, + encoded_endorsees, + )); + }, + None => println!("No endorsees registered for this ceremony"), + } + + let top: TrustedOperation = TrustedGetter::ceremonies_registered_newbies( + who.public().into(), + community_identifier, + ceremony_index, + ) + .sign(&KeyPair::Sr25519(who.clone())) + .into(); + match perform_trusted_operation(cli, trusted_args, &top) { + Some(encoded_newbies) => { + participants_attestation_indexes.extend(participant_attestation_index_map( + cli, + trusted_args, + &self.who, + community_identifier, + ceremony_index, + encoded_newbies, + )); + }, + None => println!("No newbies registered for this ceremony"), + } + + let mut attestation_states = Vec::with_capacity(attestee_count as usize); + + for attestation_index in 1..=attestee_count { + let attestor = participants_attestation_indexes[&attestation_index].clone(); + info!("Create Attestation state for {:?}", attestor); + let meetup_index = get_meetup_index( + cli, + trusted_args, + &self.who, + community_identifier, + attestor.clone(), + ) + .unwrap() + .unwrap(); + + let top: TrustedOperation = TrustedGetter::ceremonies_participant_attestees( + who.public().into(), + community_identifier, + ceremony_index, + attestation_index, + ) + .sign(&KeyPair::Sr25519(who.clone())) + .into(); + let encoded_index = perform_trusted_operation(cli, trusted_args, &top).unwrap(); + let attestees = Decode::decode(&mut encoded_index.as_slice()).unwrap(); + + let top: TrustedOperation = TrustedGetter::ceremonies_meetup_participant_count_vote( + who.public().into(), + community_identifier, + ceremony_index, + attestor.clone(), + ) + .sign(&KeyPair::Sr25519(who.clone())) + .into(); + let encoded_count_vote = + perform_trusted_operation(cli, trusted_args, &top).unwrap_or_default(); + let vote = Decode::decode(&mut encoded_count_vote.as_slice()).unwrap_or_default(); + + let attestation_state = AttestationState::new( + (community_identifier, ceremony_index), + meetup_index, + vote, + attestation_index, + attestor, + attestees, + ); + + attestation_states.push(attestation_state); + } + + // Group attestation states by meetup index + attestation_states.sort_by(|a, b| a.meetup_index.partial_cmp(&b.meetup_index).unwrap()); + println!("Attestees :"); + for a in attestation_states.iter() { + println!("{:?}", a); + } + } +} diff --git a/cli/src/ceremonies/commands/mod.rs b/cli/src/ceremonies/commands/mod.rs index b49b9f81..0a1fb01d 100644 --- a/cli/src/ceremonies/commands/mod.rs +++ b/cli/src/ceremonies/commands/mod.rs @@ -15,7 +15,9 @@ */ +pub mod attest_attendees; pub mod ceremonies_command_utils; +pub mod list_attestees; pub mod list_meetups; pub mod list_participants; pub mod register_participant; diff --git a/cli/src/ceremonies/mod.rs b/cli/src/ceremonies/mod.rs index 90a52239..32b39869 100644 --- a/cli/src/ceremonies/mod.rs +++ b/cli/src/ceremonies/mod.rs @@ -17,6 +17,7 @@ use crate::{ ceremonies::commands::{ + attest_attendees::AttestAttendeesCommand, list_attestees::ListAttesteesCommand, list_meetups::ListMeetupsCommand, list_participants::ListParticipantsCommand, register_participant::RegisterParticipantCommand, upgrade_registration::UpgradeRegistrationCommand, @@ -29,10 +30,12 @@ mod commands; #[derive(Debug, clap::Subcommand)] pub enum CeremoniesCommands { + AttestAttendees(AttestAttendeesCommand), RegisterParticipant(RegisterParticipantCommand), UpgradeRegistration(UpgradeRegistrationCommand), - ListParticipants(ListParticipantsCommand), + ListAttestees(ListAttesteesCommand), ListMeetups(ListMeetupsCommand), + ListParticipants(ListParticipantsCommand), /* CeremoniesUnregisterParticipant(), CeremoniesAttestAttendees(), @@ -53,10 +56,12 @@ pub enum CeremoniesCommands { impl CeremoniesCommands { pub fn run(&self, cli: &Cli, trusted_args: &TrustedArgs) { match self { + CeremoniesCommands::AttestAttendees(cmd) => cmd.run(cli, trusted_args), CeremoniesCommands::RegisterParticipant(cmd) => cmd.run(cli, trusted_args), CeremoniesCommands::UpgradeRegistration(cmd) => cmd.run(cli, trusted_args), - CeremoniesCommands::ListParticipants(cmd) => cmd.run(cli, trusted_args), + CeremoniesCommands::ListAttestees(cmd) => cmd.run(cli, trusted_args), CeremoniesCommands::ListMeetups(cmd) => cmd.run(cli, trusted_args), + CeremoniesCommands::ListParticipants(cmd) => cmd.run(cli, trusted_args), } } } diff --git a/enclave-runtime/src/test/ceremonies_test.rs b/enclave-runtime/src/test/ceremonies_test.rs new file mode 100644 index 00000000..04296c67 --- /dev/null +++ b/enclave-runtime/src/test/ceremonies_test.rs @@ -0,0 +1,48 @@ +/* + Copyright 2022 Encointer Association + + 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. + +*/ + +pub fn test_register_bootstrapper() { + // given + let (_, mut state, shard, mrenclave, ..) = test_setup(); + let mut opaque_vec = Vec::new(); + + // Create the sender account. + let sender = funded_pair(); + + //Update state + //Create the community + //Create a bootstrapper + //Set phase registering + + //Call to register bootstrapper + let trusted_call = TrustedCall::ceremonies_register_participant(sender_acc, cid, None).sign( + &sender.clone().into(), + 0, + &mrenclave, + &shard, + ); + + //execute call + + //check + /* + let bootstrapper_count = state + .execute_with(|| get_evm_account_storages(&execution_address, &H256::zero())) + .unwrap(); + + */ +}