Skip to content

Commit

Permalink
Refactor pending approval calculation
Browse files Browse the repository at this point in the history
  • Loading branch information
DOBEN committed Aug 6, 2024
1 parent 9479bbb commit 902720f
Show file tree
Hide file tree
Showing 3 changed files with 72 additions and 82 deletions.
100 changes: 69 additions & 31 deletions compliant-reward-distribution/indexer/src/bin/server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -145,35 +145,56 @@ impl From<Box<bincode::ErrorKind>> for ServerError {
}
}

pub fn update_pending_approval(
old_pending_approval: bool,
other_task_valid: Option<bool>,
claimed: bool,
) -> bool {
let mut new_pending_approval = old_pending_approval;

// Check if we need to update `pending_approval` to true.
if let Some(other_task_valid) = other_task_valid {
if !claimed && other_task_valid {
// If the account already submitted the other task and can still claim,
// set the `pending_approval` to true.
new_pending_approval = true
}
}
new_pending_approval
}

/// Check that the account is eligible for claiming the reward by checking that:
/// - the account creation has not expired.
/// - the account exists in the database.
/// Returns the account data stored in the database.
pub async fn check_account_eligible(
state: &Server,
account: AccountAddress,
) -> Result<(), ServerError> {
) -> Result<StoredAccountData, ServerError> {
let db = state.db_pool.get().await?;
let database_result = db.get_account_data(account).await?;

if let Some(database_result) = database_result {
// Check if the claim for the reward for this account has already expired.
// After creating a new account, the account is eligible to claim the reward for a certain duration.
let expiry_date_time = Utc::now()
.checked_sub_days(state.claim_expiry_duration_days.0)
.ok_or(ServerError::UnderFlow)?;
if database_result.block_time < expiry_date_time {
return Err(ServerError::ClaimExpired(
state.claim_expiry_duration_days.clone(),
));
match database_result {
Some(database_result) => {
// Check if the claim for the reward for this account has already expired.
// After creating a new account, the account is eligible to claim the reward for a certain duration.
let expiry_date_time = Utc::now()
.checked_sub_days(state.claim_expiry_duration_days.0)
.ok_or(ServerError::UnderFlow)?;
if database_result.block_time < expiry_date_time {
return Err(ServerError::ClaimExpired(
state.claim_expiry_duration_days.clone(),
));
}
Ok(database_result)
}
None => {
// Return an error if the account does not exist in the database.
// The account has to be created at a time when the indexer was running.
let start_block_height = db.get_settings().await?.start_block_height;
Err(ServerError::AccountExists(start_block_height))
}
} else {
// Return an error if the account does not exist in the database.
// The account has to be created at a time when the indexer was running.
let settings = db.get_settings().await?;
let start_block = settings.start_block_height;
return Err(ServerError::AccountExists(start_block));
}
Ok(())
}

/// Correct the `zk_proof_valid`, `twitter_post_link_valid` and `pending_approval` values,
Expand Down Expand Up @@ -429,13 +450,21 @@ async fn post_twitter_post_link(
// Check that:
// - the account creation has not expired.
// - the account exists in the database.
check_account_eligible(&state, signer).await?;
let StoredAccountData {
pending_approval,
zk_proof_valid,
claimed,
..
} = check_account_eligible(&state, signer).await?;

let new_pending_approval = update_pending_approval(pending_approval, zk_proof_valid, claimed);

let db = state.db_pool.get().await?;

db.set_twitter_post_link(
param.signing_data.message.twitter_post_link,
signer,
new_pending_approval,
CURRENT_TWITTER_POST_LINK_VERIFICATION_VERSION,
)
.await?;
Expand Down Expand Up @@ -478,7 +507,7 @@ async fn check_zk_proof(

let num_credential_statements = request.credential_statements.len();

// We use regular accounts with exactly one credential at index 0.
// We support regular accounts with exactly one credential at index 0.
if num_credential_statements != 1 {
return Err(ServerError::WrongLength(
"credential_statements".to_string(),
Expand All @@ -487,7 +516,7 @@ async fn check_zk_proof(
));
}

// We use regular accounts with exactly one credential at index 0.
// We support regular accounts with exactly one credential at index 0.
let account_statement = request.credential_statements[0].clone();

// Check the ZK proof has been generated as expected.
Expand All @@ -510,11 +539,11 @@ async fn check_zk_proof(
Web3Id { .. } => return Err(ServerError::AccountStatement),
}

// We use regular accounts with exactly one credential at index 0.
// We support regular accounts with exactly one credential at index 0.
let credential_proof = &presentation.verifiable_credential[0];

// Get the revealed `national_id`, `nationality` and `account_address` from the credential proof.
let (national_id, nationality, account_address) = match credential_proof {
let (national_id, nationality, prover) = match credential_proof {
CredentialProof::Account {
proofs,
network: _,
Expand Down Expand Up @@ -551,9 +580,9 @@ async fn check_zk_proof(
.await
.map_err(ServerError::QueryError)?
.response;
let account_address = account_info.account_address;
let prover = account_info.account_address;

(national_id, nationality, account_address)
(national_id, nationality, prover)
}
_ => return Err(ServerError::AccountStatement),
};
Expand All @@ -563,7 +592,7 @@ async fn check_zk_proof(
Ok(ZKProofExtractedData {
national_id,
nationality,
account_address,
prover,
})
}

Expand All @@ -586,19 +615,28 @@ async fn post_zk_proof(
let ZKProofExtractedData {
national_id,
nationality,
account_address,
prover,
} = check_zk_proof(&mut state, presentation).await?;

// Check that:
// - the account creation has not expired.
// - the account exists in the database.
check_account_eligible(&state, account_address).await?;
let StoredAccountData {
pending_approval,
twitter_post_link_valid,
claimed,
..
} = check_account_eligible(&state, prover).await?;

let new_pending_approval =
update_pending_approval(pending_approval, twitter_post_link_valid, claimed);

let db = state.db_pool.get().await?;
db.set_zk_proof(
national_id,
nationality,
account_address,
prover,
new_pending_approval,
CURRENT_ZK_PROOF_VERIFICATION_VERSION,
)
.await?;
Expand Down Expand Up @@ -689,12 +727,12 @@ where
let message_bytes = bincode::serialize(&message)?;
let message_hash = sha2::Sha256::digest([&msg_prepend[0..40], &message_bytes].concat());

// We use regular accounts as admin accounts.
// We use/support regular accounts.
// Regular accounts have only one public-private key pair at index 0 in the credential map.
let signer_account_credential =
&signer_account_info.response.account_credentials[&CredentialIndex::from(0)].value;

// We use regular accounts as admin accounts.
// We use/support regular accounts.
// Regular accounts have only one public-private key pair at index 0 in the key map.
let signer_public_key = match signer_account_credential {
// TODO: usually not allowed
Expand Down
52 changes: 2 additions & 50 deletions compliant-reward-distribution/indexer/src/db.rs
Original file line number Diff line number Diff line change
Expand Up @@ -260,33 +260,9 @@ impl Database {
national_id: String,
nationality: String,
account_address: AccountAddress,
pending_approval: bool,
current_zk_proof_verification_version: u16,
) -> DatabaseResult<()> {
// Check if we need to update `pending_approval` to true.
let get_account_data = self
.client
.prepare_cached(
"SELECT claimed, twitter_post_link_valid, pending_approval
FROM accounts
WHERE account_address = $1",
)
.await?;

let params: [&(dyn ToSql + Sync); 1] = [&(account_address.0.as_ref())];
let row = self.client.query_one(&get_account_data, &params).await?;

let claimed: bool = row.try_get("claimed")?;
let twitter_post_link_valid: Option<bool> = row.try_get("twitter_post_link_valid")?;
let mut pending_approval: bool = row.try_get("pending_approval")?;

if let Some(twitter_post_link_valid) = twitter_post_link_valid {
if !claimed && twitter_post_link_valid {
// If the account has submitted a twitter post link already and can still claim,
// set the `pending_approval` to true.
pending_approval = true
}
}

// Create an `uniqueness_hash` to identify the identity associated with the account
// by hashing the concatenating string of `national_id` and `nationality`.
// Every identity should only be allowed to receive rewards once
Expand Down Expand Up @@ -352,33 +328,9 @@ impl Database {
&self,
tweet_post_link: String,
account_address: AccountAddress,
pending_approval: bool,
current_twitter_post_link_verification_version: u16,
) -> DatabaseResult<()> {
// Check if we need to update `pending_approval` to true.
let get_account_data = self
.client
.prepare_cached(
"SELECT claimed, zk_proof_valid, pending_approval
FROM accounts
WHERE account_address = $1",
)
.await?;

let params: [&(dyn ToSql + Sync); 1] = [&(account_address.0.as_ref())];
let row = self.client.query_one(&get_account_data, &params).await?;

let claimed: bool = row.try_get("claimed")?;
let zk_proof_valid: Option<bool> = row.try_get("zk_proof_valid")?;
let mut pending_approval: bool = row.try_get("pending_approval")?;

if let Some(zk_proof_valid) = zk_proof_valid {
if !claimed && zk_proof_valid {
// If the account has submitted a ZK proof already and can still claim,
// set the `pending_approval` to true.
pending_approval = true
}
}

let set_twitter_post_link = self
.client
.prepare_cached(
Expand Down
2 changes: 1 addition & 1 deletion compliant-reward-distribution/indexer/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ pub struct ZKProofExtractedData {
///
pub nationality: String,
///
pub account_address: AccountAddress,
pub prover: AccountAddress,
}

#[derive(serde::Deserialize, serde::Serialize)]
Expand Down

0 comments on commit 902720f

Please sign in to comment.