use crate::config::*;
use anyhow::Result;
use bigdecimal::BigDecimal;
use plonky2::{
field::{extension::Extendable, types::Field},
hash::{
hash_types::{HashOut, RichField},
poseidon::PoseidonHash,
},
plonk::{
config::{GenericHashOut, Hasher},
proof::ProofWithPublicInputs,
},
};
use chrono::{DateTime, Utc};
pub fn pad_accounts(
accounts: &mut Vec<Vec<i64>>,
hashes: &mut Vec<String>,
asset_count: usize,
batch_size: usize,
) -> Result<()> {
let mut padded_accounts = Vec::new();
let mut padded_hashes = Vec::new();
let hash_nibbles = hashes[0].len();
if accounts.len() % batch_size != 0 {
let padding = batch_size - (accounts.len() % batch_size);
for _ in 0..padding {
padded_accounts.push(vec![0; asset_count]); padded_hashes.push("0".repeat(hash_nibbles)); }
}
accounts.extend(padded_accounts);
hashes.extend(padded_hashes);
Ok(())
}
pub fn pad_recursive_proofs(
proofs: &mut Vec<ProofWithPublicInputs<F, C, D>>,
empty_proof: &ProofWithPublicInputs<F, C, D>,
) {
if proofs.len() % RECURSIVE_SIZE != 0 {
let padding = RECURSIVE_SIZE - (proofs.len() % RECURSIVE_SIZE);
for _ in 0..padding {
proofs.push(empty_proof.clone());
}
}
}
pub fn hash_n_subhashes<F: RichField + Extendable<D>, const D: usize>(
hashes: &[Vec<u8>],
) -> HashOut<F> {
let hashout_inputs = hashes
.iter()
.map(|h| HashOut::<F>::from_bytes(h))
.collect::<Vec<HashOut<F>>>();
let inputs: Vec<F> = hashout_inputs
.iter()
.flat_map(|h| h.elements.to_vec())
.collect();
PoseidonHash::hash_no_pad(inputs.as_slice())
}
pub fn hash_account(balances: &Vec<i64>, userhash: String, nonce: u64) -> HashOut<F> {
let mut hash_input = Vec::new();
for balance in balances {
hash_input.push(F::from_noncanonical_i64(*balance));
}
let mut hash_input_hex = Vec::new();
for i in (0..userhash.len()).step_by(16) {
let hex = &userhash[i..i + 16];
let num = u64::from_str_radix(hex, 16).unwrap();
hash_input_hex.push(F::from_canonical_u64(num));
}
let nonce_field = F::from_canonical_u64(nonce);
hash_input.push(nonce_field);
PoseidonHash::hash_no_pad(hash_input.as_slice())
}
pub fn pis_to_hash_bytes<F: RichField + Extendable<D>, const D: usize>(pis: &[F]) -> Vec<u8> {
HashOut::from_partial(pis).to_bytes()
}
pub fn calculate_with_decimals(value: i64, decimals: i64) -> BigDecimal {
BigDecimal::new(value.into(), decimals)
}
pub fn format_timestamp(timestamp_milliseconds: u64) -> Result<String, &'static str> {
let timestamp_i64: i64 = timestamp_milliseconds
.try_into()
.map_err(|_| "Timestamp value out of range for i64")?;
let naive_datetime = DateTime::from_timestamp_millis(timestamp_i64)
.ok_or("Invalid timestamp value")?;
let datetime_utc = DateTime::<Utc>::from_naive_utc_and_offset(naive_datetime.naive_utc(), Utc);
let formatted_string = datetime_utc.format("%Y-%m-%d %H:%M:%S %Z").to_string();
Ok(formatted_string)
}