Skip to content

Commit

Permalink
revert type aliases for IDs to increase type safety
Browse files Browse the repository at this point in the history
  • Loading branch information
n8maninger committed Nov 7, 2024
1 parent 421f774 commit 6f9d4db
Show file tree
Hide file tree
Showing 2 changed files with 99 additions and 87 deletions.
176 changes: 94 additions & 82 deletions sia/src/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,100 @@ use core::fmt;
use serde::{Deserialize, Serialize};
use std::fmt::Debug;

pub type BlockID = Hash256;
// Macro to implement types used as identifiers which are 32 byte hashes and are
// serialized with a prefix
#[macro_export]
macro_rules! ImplHashID {
($name:ident) => {
#[derive(Debug, Clone, Copy, PartialEq, SiaEncode, SiaDecode, V1SiaEncode, V1SiaDecode)]
pub struct $name([u8; 32]);

impl serde::Serialize for $name {
fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
if serializer.is_human_readable() {
String::serialize(&self.to_string(), serializer)
} else {
<[u8; 32]>::serialize(&self.0, serializer)
}
}
}

impl<'de> serde::Deserialize<'de> for $name {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
let s = String::deserialize(deserializer)?;
$name::parse_string(&s).map_err(|e| serde::de::Error::custom(format!("{:?}", e)))
}
}

impl $name {
// Example method that might be used in serialization/deserialization
pub fn parse_string(s: &str) -> Result<Self, $crate::HexParseError> {
let s = match s.split_once(':') {
Some((_prefix, suffix)) => suffix,
None => s,
};

if s.len() != 64 {
return Err($crate::HexParseError::InvalidLength);
}

let mut data = [0u8; 32];
hex::decode_to_slice(s, &mut data).map_err($crate::HexParseError::HexError)?;
Ok($name(data))
}
}

impl core::fmt::Display for $name {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
write!(f, "{}", hex::encode(self.0))
}
}

impl From<blake2b_simd::Hash> for $name {
fn from(hash: blake2b_simd::Hash) -> Self {
let mut h = [0; 32];
h.copy_from_slice(&hash.as_bytes()[..32]);
Self(h)
}
}

impl From<[u8; 32]> for $name {
fn from(data: [u8; 32]) -> Self {
$name(data)
}
}

impl From<$name> for [u8; 32] {
fn from(hash: $name) -> [u8; 32] {
hash.0
}
}

impl AsRef<[u8; 32]> for $name {
fn as_ref(&self) -> &[u8; 32] {
&self.0
}
}

impl AsRef<[u8]> for $name {
fn as_ref(&self) -> &[u8] {
&self.0
}
}

impl Default for $name {
fn default() -> Self {
$name([0; 32])
}
}
};
}

ImplHashID!(Hash256);
ImplHashID!(BlockID);

#[derive(Debug, PartialEq, SiaEncode, SiaDecode, Serialize, Deserialize)]

Expand Down Expand Up @@ -57,87 +150,6 @@ impl<'de> Deserialize<'de> for Leaf {
}
}

#[derive(
Debug, Clone, Copy, PartialEq, Default, SiaEncode, V1SiaEncode, SiaDecode, V1SiaDecode,
)]
pub struct Hash256([u8; 32]);

impl serde::Serialize for Hash256 {
fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
if serializer.is_human_readable() {
String::serialize(&self.to_string(), serializer)
} else {
<[u8; 32]>::serialize(&self.0, serializer)
}
}
}

impl<'de> serde::Deserialize<'de> for Hash256 {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
if deserializer.is_human_readable() {
let s = String::deserialize(deserializer)?;
Hash256::parse_string(&s).map_err(|e| serde::de::Error::custom(format!("{:?}", e)))
} else {
let data = <[u8; 32]>::deserialize(deserializer)?;
Ok(Hash256(data))
}
}
}

impl Hash256 {
// Example method that might be used in serialization/deserialization
pub fn parse_string(s: &str) -> Result<Self, HexParseError> {
if s.len() != 64 {
return Err(HexParseError::InvalidLength);
}

let mut data = [0u8; 32];
hex::decode_to_slice(s, &mut data).map_err(HexParseError::HexError)?;
Ok(Hash256(data))
}
}

impl fmt::Display for Hash256 {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", hex::encode(self.0))
}
}

impl From<blake2b_simd::Hash> for Hash256 {
fn from(hash: blake2b_simd::Hash) -> Self {
let mut h = [0; 32];
h.copy_from_slice(&hash.as_bytes()[..32]);
Self(h)
}
}

impl From<[u8; 32]> for Hash256 {
fn from(data: [u8; 32]) -> Self {
Hash256(data)
}
}

impl From<Hash256> for [u8; 32] {
fn from(hash: Hash256) -> [u8; 32] {
hash.0
}
}

impl AsRef<[u8; 32]> for Hash256 {
fn as_ref(&self) -> &[u8; 32] {
&self.0
}
}

impl AsRef<[u8]> for Hash256 {
fn as_ref(&self) -> &[u8] {
&self.0
}
}

/// encapsulates the various errors that can occur when parsing a Sia object
/// from a string
#[derive(Debug, PartialEq)]
Expand Down
10 changes: 5 additions & 5 deletions sia/src/transactions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,14 @@ use crate::encoding::{
use crate::signing::{PrivateKey, SigningState};
use crate::specifier::{specifier, Specifier};
use crate::unlock_conditions::UnlockConditions;
use crate::{encoding, Address, Currency, Hash256, Leaf};
use crate::{encoding, Address, Currency, Hash256, ImplHashID, Leaf};
use blake2b_simd::Params;
use serde::{Deserialize, Serialize};

pub type SiacoinOutputID = Hash256;
pub type SiafundOutputID = Hash256;
pub type FileContractID = Hash256;
pub type TransactionID = Hash256;
ImplHashID!(SiacoinOutputID);
ImplHashID!(SiafundOutputID);
ImplHashID!(FileContractID);
ImplHashID!(TransactionID);

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, V1SiaEncode, V1SiaDecode)]
#[serde(rename_all = "camelCase")]
Expand Down

0 comments on commit 6f9d4db

Please sign in to comment.