Skip to content

Commit

Permalink
Merge pull request #14 from provable-things/fix/serialization
Browse files Browse the repository at this point in the history
  • Loading branch information
oliviera9 authored Jun 1, 2023
2 parents a7d1864 + c36a55c commit a249201
Show file tree
Hide file tree
Showing 19 changed files with 6,372 additions and 55 deletions.
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "rust-algorand"
version = "1.7.0"
version = "1.8.0"
edition = "2021"

[dependencies]
Expand Down
50 changes: 41 additions & 9 deletions src/algorand_blocks/block_header.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use std::str::FromStr;
use std::{collections::HashMap, str::FromStr};

use serde::{Deserialize, Serialize};
use serde_with::skip_serializing_none;
Expand All @@ -8,6 +8,7 @@ use crate::{
algorand_blocks::{
block_header_json::AlgorandBlockHeaderJson,
rewards_state::RewardsState,
state_proof_tracking::StateProofTracking,
upgrade_state::UpgradeState,
upgrade_vote::UpgradeVote,
},
Expand All @@ -17,15 +18,9 @@ use crate::{
algorand_micro_algos::MicroAlgos,
algorand_types::{Byte, Bytes, Result},
crypto_utils::sha512_256_hash_bytes,
predicates::{is_empty_or_none, is_zero_hash, is_zero_hash_or_none},
};

fn is_zero_hash(hash: &Option<AlgorandHash>) -> bool {
match hash {
Some(hash) => hash.is_zero(),
_ => false,
}
}

#[skip_serializing_none]
#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
pub struct AlgorandBlockHeader {
Expand Down Expand Up @@ -82,6 +77,9 @@ pub struct AlgorandBlockHeader {

pub seed: Option<AlgorandHash>,

#[serde(rename = "spt", skip_serializing_if = "is_empty_or_none")]
pub state_proof_tracking: Option<HashMap<u64, StateProofTracking>>,

#[serde(rename = "t")]
pub compact_cert_voters_total: Option<MicroAlgos>,

Expand All @@ -94,7 +92,7 @@ pub struct AlgorandBlockHeader {
#[serde(rename = "txn", skip_serializing_if = "is_zero_hash")]
pub transactions_root: Option<AlgorandHash>,

#[serde(skip_serializing)]
#[serde(rename = "txn256", skip_serializing_if = "is_zero_hash_or_none")]
pub transactions_root_sha256: Option<AlgorandHash>,

#[serde(rename = "upgradedelay")]
Expand Down Expand Up @@ -280,6 +278,7 @@ impl AlgorandBlockHeader {
),
None => None,
},
state_proof_tracking: json.maybe_get_state_proof_tracking(),
})
}

Expand Down Expand Up @@ -380,6 +379,12 @@ impl AlgorandBlockHeader {
.transactions_root_sha256
.as_ref()
.map(|x| x.to_string()),
state_proof_tracking: self.state_proof_tracking.as_ref().map(|proofs| {
proofs
.iter()
.map(|(key, value)| value.to_json(*key))
.collect()
}),
})
}
}
Expand Down Expand Up @@ -451,4 +456,31 @@ mod tests {
let expected_result = "MPKXXXRFQHOF6MBYSTOFHEAS7257JDLUQD6GSR47TDPVY2JWZ6VQ".to_string();
assert_eq!(result, expected_result);
}

#[test]
fn should_calculate_block_header_hash_4() {
let header = get_sample_block_header_n(13);
let result = header.hash().unwrap().to_base_32();
// NOTE: See https://algoexplorer.io/block/29285128
let expected_result = "3N42ATIC6DDITHDV3FXEAGKVGX5CTBKEXWU2T5OVBHOLIOQA2KUQ".to_string();
assert_eq!(result, expected_result);
}

#[test]
fn should_calculate_block_header_hash_5() {
let header = get_sample_block_header_n(14);
let result = header.hash().unwrap().to_base_32();
// NOTE: See https://algoexplorer.io/block/29285129
let expected_result = "SXHKXOZTZLHKKLG7S47ZTAIVAVK5TDAWWRRLI3QAA6G7DJ5OBRNA".to_string();
assert_eq!(result, expected_result);
}

#[test]
fn should_calculate_block_header_hash_6() {
let header = get_sample_block_header_n(15);
let result = header.hash().unwrap().to_base_32();
// NOTE: See https://algoexplorer.io/block/29285130
let expected_result = "2FI2UN6DNEAOFFCKWVW673YOD57JV5ZQFQCMW7CPDEN4GFKQ5XWA".to_string();
assert_eq!(result, expected_result);
}
}
20 changes: 19 additions & 1 deletion src/algorand_blocks/block_header_json.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use std::{fmt::Display, str::FromStr};
use std::{collections::HashMap, fmt::Display, str::FromStr};

use serde::{Deserialize, Serialize};
use serde_json::json;
Expand All @@ -7,6 +7,7 @@ use serde_with::skip_serializing_none;
use crate::{
algorand_blocks::{
rewards_state::RewardsStateJson,
state_proof_tracking::{StateProofTracking, StateProofTrackingJson},
upgrade_state::UpgradeStateJson,
upgrade_vote::UpgradeVoteJson,
},
Expand Down Expand Up @@ -55,6 +56,9 @@ pub struct AlgorandBlockHeaderJson {

#[serde(rename = "expired-participation-accounts")]
pub participation_updates: Option<Vec<String>>,

#[serde(rename = "state-proof-tracking")]
pub state_proof_tracking: Option<Vec<StateProofTrackingJson>>,
}

impl FromStr for AlgorandBlockHeaderJson {
Expand All @@ -71,6 +75,20 @@ impl Display for AlgorandBlockHeaderJson {
}
}

impl AlgorandBlockHeaderJson {
pub fn maybe_get_state_proof_tracking(&self) -> Option<HashMap<u64, StateProofTracking>> {
self.state_proof_tracking.as_ref().map(|proofs| {
let mut hash_map = HashMap::new();
proofs.iter().for_each(|proof| {
if let (Some(k), Ok(v)) = (proof.proof_type, StateProofTracking::from_json(proof)) {
hash_map.insert(k, v);
};
});
hash_map
})
}
}

// TODO Impl Display!

#[cfg(test)]
Expand Down
1 change: 1 addition & 0 deletions src/algorand_blocks/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ pub(crate) mod block_header_json;
pub(crate) mod block_json;
pub(crate) mod participation_updates;
pub(crate) mod rewards_state;
pub(crate) mod state_proof_tracking;
pub(crate) mod test_utils;
pub(crate) mod upgrade_state;
pub(crate) mod upgrade_vote;
75 changes: 75 additions & 0 deletions src/algorand_blocks/state_proof_tracking.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
use std::str::FromStr;

use serde::{Deserialize, Serialize};

use crate::{
algorand_errors::AlgorandError,
algorand_types::{Bytes, Result},
predicates::{is_empty_vec, is_zero_option},
};

#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)]
pub struct StateProofTracking {
#[serde(rename = "v", skip_serializing_if = "is_empty_vec")]
pub voters_commitment: Option<Bytes>,
#[serde(rename(serialize = "t"), skip_serializing_if = "is_zero_option")]
pub online_total_weight: Option<u64>,
#[serde(rename = "n")]
pub next_round: Option<u64>,
}

impl StateProofTracking {
pub fn from_json(json: &StateProofTrackingJson) -> Result<Self> {
Ok(Self {
voters_commitment: json
.voters_commitment
.as_ref()
.map(|commitment| commitment.to_vec()),
next_round: json.next_round,
online_total_weight: json.online_total_weight,
})
}

pub fn to_json(&self, proof_type: u64) -> StateProofTrackingJson {
StateProofTrackingJson {
next_round: self.next_round,
proof_type: Some(proof_type),
online_total_weight: self.online_total_weight,
voters_commitment: self.voters_commitment.clone(),
}
}
}

impl FromStr for StateProofTracking {
type Err = AlgorandError;

fn from_str(s: &str) -> Result<Self> {
StateProofTrackingJson::from_str(s).and_then(|json| Self::from_json(&json))
}
}

#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize, Default)]
pub struct StateProofTrackingJson {
#[serde(rename = "next-round", skip_serializing_if = "Option::is_none")]
pub next_round: Option<u64>,

#[serde(
rename = "online-total-weight",
skip_serializing_if = "Option::is_none"
)]
pub online_total_weight: Option<u64>,

#[serde(rename = "type", skip_serializing_if = "Option::is_none")]
pub proof_type: Option<u64>,

#[serde(rename = "voters-commitment", skip_serializing_if = "Option::is_none")]
pub voters_commitment: Option<Bytes>,
}

impl FromStr for StateProofTrackingJson {
type Err = AlgorandError;

fn from_str(s: &str) -> Result<Self> {
Ok(serde_json::from_str(s)?)
}
}
Loading

0 comments on commit a249201

Please sign in to comment.