Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[cli] add list-reputables #332

Merged
merged 11 commits into from
Jun 17, 2023
20 changes: 17 additions & 3 deletions client/src/cli_args.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ const DRYRUN_FLAG: &str = "dryrun";
const TX_PAYMENT_CID_ARG: &str = "tx-payment-cid";
const MEETUP_INDEX_ARG: &str = "meetup-index";
const AT_BLOCK_ARG: &str = "at";
const VERBOSE_FLAG: &str = "verbose";
const FAUCET_BALANCE_ARG: &str = "faucet-balance";
const FAUCET_DRIP_AMOUNT_ARG: &str = "faucet-drip-amount";
const FAUCET_RESERVE_AMOUNT_ARG: &str = "faucet-reserve-amount";
Expand Down Expand Up @@ -53,6 +54,7 @@ pub trait EncointerArgs<'b> {
fn tx_payment_cid_arg(self) -> Self;
fn meetup_index_arg(self) -> Self;
fn at_block_arg(self) -> Self;
fn verbose_flag(self) -> Self;
fn faucet_balance_arg(self) -> Self;
fn faucet_drip_amount_arg(self) -> Self;
fn faucet_reserve_amount_arg(self) -> Self;
Expand Down Expand Up @@ -83,6 +85,7 @@ pub trait EncointerArgsExtractor {
fn tx_payment_cid_arg(&self) -> Option<&str>;
fn meetup_index_arg(&self) -> Option<u64>;
fn at_block_arg(&self) -> Option<Hash>;
fn verbose_flag(&self) -> bool;
fn faucet_balance_arg(&self) -> Option<u128>;
fn faucet_drip_amount_arg(&self) -> Option<u128>;
fn faucet_reserve_amount_arg(&self) -> Option<u128>;
Expand Down Expand Up @@ -318,7 +321,6 @@ impl<'a, 'b> EncointerArgs<'b> for App<'a, 'b> {
.help("the meetup index for which to claim rewards"),
)
}

fn at_block_arg(self) -> Self {
self.arg(
Arg::with_name(AT_BLOCK_ARG)
Expand All @@ -330,7 +332,17 @@ impl<'a, 'b> EncointerArgs<'b> for App<'a, 'b> {
.help("block hash at which to query"),
)
}

fn verbose_flag(self) -> Self {
self.arg(
Arg::with_name(VERBOSE_FLAG)
.short("v")
.long("verbose")
.global(true)
.takes_value(false)
.required(false)
.help("print extra information"),
)
}
fn faucet_balance_arg(self) -> Self {
self.arg(
Arg::with_name(FAUCET_BALANCE_ARG)
Expand All @@ -340,7 +352,6 @@ impl<'a, 'b> EncointerArgs<'b> for App<'a, 'b> {
.help("faucet balance"),
)
}

fn faucet_drip_amount_arg(self) -> Self {
self.arg(
Arg::with_name(FAUCET_DRIP_AMOUNT_ARG)
Expand Down Expand Up @@ -452,6 +463,9 @@ impl<'a> EncointerArgsExtractor for ArgMatches<'a> {
Hash::from_slice(&vec)
})
}
fn verbose_flag(&self) -> bool {
self.is_present(VERBOSE_FLAG)
}
fn faucet_balance_arg(&self) -> Option<u128> {
self.value_of(FAUCET_BALANCE_ARG).map(|v| v.parse().unwrap())
}
Expand Down
122 changes: 108 additions & 14 deletions client/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ use encointer_primitives::{
ceremonies::{
AttestationIndexType, ClaimOfAttendance, CommunityCeremony, CommunityReputation,
MeetupIndexType, ParticipantIndexType, ProofOfAttendance, Reputation,
ReputationLifetimeType,
},
communities::{CidName, CommunityIdentifier},
faucet::{FaucetNameType, FromStr as FaucetNameFromStr, WhiteListType},
Expand Down Expand Up @@ -660,7 +661,7 @@ async fn main() {
// >>>> add some debug info as well
let bn = get_block_number(&api, None);
debug!("block number: {}", bn);
let cindex = get_ceremony_index(&api);
let cindex = get_ceremony_index(&api, None);
info!("ceremony index: {}", cindex);
let tnext: Moment = api.get_next_phase_timestamp().unwrap();
debug!("next phase timestamp: {}", tnext);
Expand Down Expand Up @@ -729,7 +730,7 @@ async fn main() {
extract_and_execute(
matches, |api, cid| -> ApiResult<()>{

let current_ceremony_index = get_ceremony_index(&api);
let current_ceremony_index = get_ceremony_index(&api, None);

let cindex = matches.ceremony_index_arg()
.map_or_else(|| current_ceremony_index , |ci| into_effective_cindex(ci, current_ceremony_index));
Expand Down Expand Up @@ -777,7 +778,7 @@ async fn main() {
extract_and_execute(
matches, |api, cid| -> ApiResult<()>{

let current_ceremony_index = get_ceremony_index(&api);
let current_ceremony_index = get_ceremony_index(&api, None);

let cindex = matches.ceremony_index_arg()
.map_or_else(|| current_ceremony_index , |ci| into_effective_cindex(ci, current_ceremony_index));
Expand Down Expand Up @@ -825,7 +826,7 @@ async fn main() {
extract_and_execute(
matches, |api, cid| -> ApiResult<()>{

let current_ceremony_index = get_ceremony_index(&api);
let current_ceremony_index = get_ceremony_index(&api, None);

let cindex = matches.ceremony_index_arg()
.map_or_else(|| current_ceremony_index , |ci| into_effective_cindex(ci, current_ceremony_index));
Expand Down Expand Up @@ -854,7 +855,7 @@ async fn main() {
extract_and_execute(
matches, |api, cid| -> ApiResult<()>{

let current_ceremony_index = get_ceremony_index(&api);
let current_ceremony_index = get_ceremony_index(&api, None);

let cindex = matches.ceremony_index_arg()
.map_or_else(|| current_ceremony_index , |ci| into_effective_cindex(ci, current_ceremony_index));
Expand Down Expand Up @@ -925,6 +926,53 @@ async fn main() {
Ok(())
}),
)
.add_cmd(
Command::new("list-reputables")
.description("list all reputables for all cycles within the current reputation-lifetime for all communities")
.options(|app| {
app.setting(AppSettings::ColoredHelp)
.at_block_arg()
.verbose_flag()
})
.runner(|_args: &str, matches: &ArgMatches<'_>| {
let api = get_chain_api(matches);

let is_verbose = matches.verbose_flag();
let at_block = matches.at_block_arg();

let lifetime = get_reputation_lifetime(&api, at_block);
let current_ceremony_index = get_ceremony_index(&api, at_block);


let first_ceremony_index_of_interest = current_ceremony_index.saturating_sub(lifetime);
let ceremony_indices: Vec<u32> = (first_ceremony_index_of_interest..current_ceremony_index).collect();

let community_ids = get_cid_names(&api).unwrap().into_iter().map(|names| names.cid);

let mut reputables_csv = Vec::new();

println!("Listing the number of attested attendees for each community and ceremony for cycles [{:}:{:}]", ceremony_indices.first().unwrap(), ceremony_indices.last().unwrap());
for community_id in community_ids {
println!("Community ID: {community_id:?}");
let mut reputables: HashMap<AccountId, usize> = HashMap::new();
for ceremony_index in &ceremony_indices {
let (attendees, noshows) = get_attendees_for_community_ceremony(&api, (community_id, *ceremony_index), at_block);
println!("Cycle ID {ceremony_index:?}: Total attested attendees: {:} (noshows: {:})", attendees.len(), noshows.len());
for attendee in attendees {
reputables_csv.push(format!("{community_id:?},{ceremony_index:?},{}", attendee.to_ss58check()));
*reputables.entry(attendee.clone()).or_insert(0) += 1;
}
}
println!("Reputables in {community_id:?} (unique accounts with at least one attendance) {:}", reputables.keys().len());
}
if is_verbose {
for reputable in reputables_csv {
println!("{reputable}");
}
}
Ok(())
}),
)
.add_cmd(
Command::new("register-participant")
.description("Register encointer ceremony participant for supplied community")
Expand All @@ -942,7 +990,7 @@ async fn main() {
};

let api = get_chain_api(matches);
let cindex = get_ceremony_index(&api);
let cindex = get_ceremony_index(&api, None);
let cid = verify_cid(&api,
matches
.cid_arg()
Expand Down Expand Up @@ -1004,7 +1052,7 @@ async fn main() {
};

let api = get_chain_api(matches);
let cindex = get_ceremony_index(&api);
let cindex = get_ceremony_index(&api, None);
let cid = verify_cid(&api,
matches
.cid_arg()
Expand Down Expand Up @@ -1080,7 +1128,7 @@ async fn main() {

let cc = match matches.ceremony_index_arg() {
Some(cindex_arg) => {
let current_ceremony_index = get_ceremony_index(&api);
let current_ceremony_index = get_ceremony_index(&api, None);
let cindex = into_effective_cindex(cindex_arg, current_ceremony_index);
Some((cid, cindex))
},
Expand Down Expand Up @@ -1165,7 +1213,7 @@ async fn main() {
let accountid = get_accountid_from_str(arg_who);
let api = get_chain_api(matches);

let current_ceremony_index = get_ceremony_index(&api);
let current_ceremony_index = get_ceremony_index(&api, None);

let cindex_arg = matches.ceremony_index_arg().unwrap_or(-1);
let cindex = into_effective_cindex(cindex_arg, current_ceremony_index);
Expand Down Expand Up @@ -1299,7 +1347,7 @@ async fn main() {
set_api_extrisic_params_builder(&mut api, tx_payment_cid_arg);

if matches.all_flag() {
let mut cindex = get_ceremony_index(&api);
let mut cindex = get_ceremony_index(&api, None);
if api.get_current_phase().unwrap() == CeremonyPhaseType::Registering {
cindex -= 1;
}
Expand Down Expand Up @@ -1463,7 +1511,7 @@ async fn main() {
let mut api = get_chain_api(matches);
api.set_signer(signer);

let current_ceremony_index = get_ceremony_index(&api);
let current_ceremony_index = get_ceremony_index(&api, None);

let from_cindex_arg = matches.from_cindex_arg().unwrap_or(0);
let to_cindex_arg = matches.to_cindex_arg().unwrap_or(0);
Expand Down Expand Up @@ -2017,8 +2065,8 @@ fn get_demurrage_per_block(api: &Api, cid: CommunityIdentifier) -> Demurrage {
}
}

fn get_ceremony_index(api: &Api) -> CeremonyIndexType {
api.get_storage("EncointerScheduler", "CurrentCeremonyIndex", None)
fn get_ceremony_index(api: &Api, at_block: Option<Hash>) -> CeremonyIndexType {
api.get_storage("EncointerScheduler", "CurrentCeremonyIndex", at_block)
.unwrap()
.unwrap()
}
Expand All @@ -2029,6 +2077,52 @@ fn get_attestee_count(api: &Api, key: CommunityCeremony) -> ParticipantIndexType
.unwrap_or(0)
}

fn get_attendees_for_community_ceremony(
api: &Api,
community_ceremony: CommunityCeremony,
at_block: Option<Hash>,
) -> (Vec<AccountId>, Vec<AccountId>) {
let key_prefix = api
.get_storage_double_map_key_prefix(
"EncointerCeremonies",
"ParticipantReputation",
community_ceremony,
)
.unwrap();
let max_keys = 1000;
let storage_keys =
api.get_storage_keys_paged(Some(key_prefix), max_keys, None, at_block).unwrap();

if storage_keys.len() == max_keys as usize {
error!("results can be wrong because max keys reached for query")
}
let mut attendees = Vec::new();
let mut noshows = Vec::new();
for storage_key in storage_keys.iter() {
match api.get_storage_by_key(storage_key.clone(), at_block).unwrap().unwrap() {
Reputation::VerifiedUnlinked | Reputation::VerifiedLinked => {
let key_postfix = storage_key.as_ref();
attendees.push(
AccountId::decode(&mut key_postfix[key_postfix.len() - 32..].as_ref()).unwrap(),
);
},
Reputation::UnverifiedReputable | Reputation::Unverified => {
let key_postfix = storage_key.as_ref();
noshows.push(
AccountId::decode(&mut key_postfix[key_postfix.len() - 32..].as_ref()).unwrap(),
);
},
}
}
(attendees, noshows)
}

fn get_reputation_lifetime(api: &Api, at_block: Option<Hash>) -> ReputationLifetimeType {
api.get_storage("EncointerCeremonies", "ReputationLifetime", at_block)
.unwrap()
.unwrap_or(5)
}

fn get_participant_attestation_index(
api: &Api,
key: CommunityCeremony,
Expand All @@ -2044,7 +2138,7 @@ fn new_claim_for(
cid: CommunityIdentifier,
n_participants: u32,
) -> Vec<u8> {
let cindex = get_ceremony_index(api);
let cindex = get_ceremony_index(api, None);
let mindex = api
.get_meetup_index(&(cid, cindex), &claimant.public().into())
.unwrap()
Expand Down