use candid::{CandidType, Nat};
use ex3_canister_named_canisters::CanisterNames;
use ex3_canister_types::range::ReportRange;
use ex3_canister_types::report::ShardingReportSubmitter;
use ex3_crypto::sha256;
use ex3_node_types::settings::CandidWalletRegistrySetting;
use ex3_node_types::transaction::EncodedTransaction;
use ex3_node_types::CanisterId;
use ex3_node_types::{CandidBlockHeight, MerkleRoot};
use ex3_serde::bincode;
use ex3_timestamp::TimeInNs;
use ic_stable_structures::storable::Bound;
use ic_stable_structures::Storable;
use rs_merkle::algorithms::Sha256;
use rs_merkle::MerkleProof;
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
pub mod error;
#[derive(CandidType, Deserialize, Debug, Clone)]
pub struct WalletRegistryInitArgs {
#[cfg(feature = "dev_env")]
pub dev_named_canister_ids: HashMap<CanisterNames, CanisterId>,
pub seq_id: u64,
pub wallet_start_id: Nat,
pub max_wallet_count: Nat,
}
impl From<WalletRegistryInitArgs> for CandidWalletRegistrySetting {
fn from(args: WalletRegistryInitArgs) -> Self {
CandidWalletRegistrySetting {
wallet_start_id: args.wallet_start_id,
max_wallet_count: args.max_wallet_count,
}
}
}
#[derive(CandidType, Debug, Default, Clone, Deserialize, Serialize, PartialEq, Eq)]
pub struct WalletTxShardingSubReport {
pub merkle_proof: Vec<u8>,
pub range: ReportRange,
pub txs: Vec<EncodedTransaction>,
pub tx_indexes: Vec<u32>,
}
impl Storable for WalletTxShardingSubReport {
fn to_bytes(&self) -> std::borrow::Cow<[u8]> {
bincode::serialize(self).unwrap().into()
}
fn from_bytes(bytes: std::borrow::Cow<[u8]>) -> Self {
bincode::deserialize(bytes.as_ref()).unwrap()
}
const BOUND: Bound = Bound::Unbounded;
}
impl WalletTxShardingSubReport {
pub fn merkle_verify(&self, merkle_root: &[u8; 32]) -> bool {
let merkle_proof: MerkleProof<Sha256> = match MerkleProof::from_bytes(&self.merkle_proof) {
Ok(proof) => proof,
Err(_) => {
return false;
}
};
let leaves_to_prove: Vec<[u8; 32]> =
self.txs.iter().map(|tx| sha256(tx.as_ref())).collect();
let leaf_indexes: Vec<usize> = self
.tx_indexes
.iter()
.map(|index| *index as usize)
.collect();
merkle_proof.verify(
merkle_root.clone(),
&leaf_indexes,
&leaves_to_prove,
self.range.total_count as usize,
)
}
}
#[derive(CandidType, Debug, Default, Clone, Deserialize, Serialize, PartialEq, Eq)]
pub struct WalletRegistryDataIntegrityShardingSubReport {
pub merkle_proof: Vec<u8>,
pub data_digest: [u8; 32],
pub merkle_node_count: u32,
pub index: u32,
pub total_register_tx_count: u32,
}
impl Storable for WalletRegistryDataIntegrityShardingSubReport {
fn to_bytes(&self) -> std::borrow::Cow<[u8]> {
bincode::serialize(self).unwrap().into()
}
fn from_bytes(bytes: std::borrow::Cow<[u8]>) -> Self {
bincode::deserialize(bytes.as_ref()).unwrap()
}
const BOUND: Bound = Bound::Unbounded;
}
impl WalletRegistryDataIntegrityShardingSubReport {
pub fn merkle_verify(&self, merkle_root: &MerkleRoot) -> bool {
let merkle_proof: Option<MerkleProof<Sha256>> =
match MerkleProof::from_bytes(&self.merkle_proof) {
Ok(merkle_proof) => Some(merkle_proof),
Err(_) => None,
};
match merkle_proof {
Some(merkle_proof) => merkle_proof.verify(
merkle_root.clone(),
vec![self.index as usize].as_ref(),
vec![self.data_digest].as_ref(),
self.merkle_node_count as usize,
),
None => false,
}
}
}
#[derive(CandidType, Debug, Default, Clone, Deserialize, Eq, PartialEq)]
pub struct ReportStatus {
pub submitted_register_tx_report: bool,
pub register_tx_report_progress: Option<ReportRange>,
pub submitted_data_integrity_report: bool,
pub validated: bool,
}
#[derive(CandidType, Debug, Clone, Deserialize)]
pub struct ShardingReportProgressInfo {
pub current_block_height: CandidBlockHeight,
pub in_progress: bool,
pub report_status: ReportStatus,
pub major_submitter: Option<ShardingReportSubmitter>,
pub secondary_submitter: Option<ShardingReportSubmitter>,
pub now: TimeInNs,
}
#[derive(CandidType, Debug, Clone, Deserialize, Serialize)]
pub enum ShardingSubReport {
WalletRegister(WalletTxShardingSubReport),
DataIntegrity(WalletRegistryDataIntegrityShardingSubReport),
}