Skip to content

Commit

Permalink
fix unicode panic (ordinals#88)
Browse files Browse the repository at this point in the history
  • Loading branch information
wanyvic authored Aug 14, 2023
1 parent b767369 commit 663df86
Show file tree
Hide file tree
Showing 11 changed files with 260 additions and 182 deletions.
3 changes: 1 addition & 2 deletions src/brc20/ledger.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use std::fmt::{Debug, Display};
pub trait LedgerRead {
type Error: Debug + Display;

fn get_balances(&self, script_key: &ScriptKey) -> Result<Vec<(Tick, Balance)>, Self::Error>;
fn get_balances(&self, script_key: &ScriptKey) -> Result<Vec<Balance>, Self::Error>;
fn get_balance(
&self,
script_key: &ScriptKey,
Expand Down Expand Up @@ -35,7 +35,6 @@ pub trait LedgerReadWrite: LedgerRead {
fn update_token_balance(
&self,
script_key: &ScriptKey,
tick: &Tick,
new_balance: Balance,
) -> Result<(), Self::Error>;

Expand Down
13 changes: 9 additions & 4 deletions src/brc20/types/balance.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,20 @@
use serde::{Deserialize, Serialize};
use {
super::*,
serde::{Deserialize, Serialize},
};
#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, PartialOrd, Ord, Eq)]
pub struct Balance {
pub tick: Tick,
pub overall_balance: u128,
pub transferable_balance: u128,
}

impl Balance {
pub fn new() -> Self {
pub fn new(tick: &Tick) -> Self {
Self {
overall_balance: 0 as u128,
transferable_balance: 0 as u128,
tick: tick.clone(),
overall_balance: 0u128,
transferable_balance: 0u128,
}
}
}
134 changes: 103 additions & 31 deletions src/brc20/types/tick.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
use super::super::error::BRC20Error;
use crate::brc20::params::TICK_BYTE_COUNT;
use serde::{de, Deserialize, Deserializer, Serialize, Serializer};
use std::str::FromStr;
use std::{
fmt::{Display, Formatter},
str::FromStr,
};

#[derive(Debug, Clone)]
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub struct Tick([u8; TICK_BYTE_COUNT]);

impl FromStr for Tick {
Expand All @@ -15,17 +18,8 @@ impl FromStr for Tick {
if bytes.len() != TICK_BYTE_COUNT {
return Err(BRC20Error::InvalidTickLen(s.to_string()));
}
Ok(Self(bytes.try_into().unwrap()))
}
}

impl PartialEq for Tick {
fn eq(&self, other: &Self) -> bool {
self.to_lowercase().0 == other.to_lowercase().0
}

fn ne(&self, other: &Self) -> bool {
!self.eq(other)
Ok(Self(bytes.try_into().unwrap()))
}
}

Expand All @@ -36,24 +30,8 @@ impl Tick {
std::str::from_utf8(self.0.as_slice()).unwrap()
}

pub fn to_lowercase(&self) -> Tick {
Self::from_str(self.as_str().to_lowercase().as_str()).unwrap()
}

pub fn as_bytes(&self) -> &[u8] {
self.0.as_slice()
}

pub fn hex(&self) -> String {
hex::encode(&self.0)
}

pub fn min_hex() -> String {
Self([0u8; TICK_BYTE_COUNT]).hex()
}

pub fn max_hex() -> String {
Self([0xffu8; TICK_BYTE_COUNT]).hex()
pub fn to_lowercase(&self) -> LowerTick {
LowerTick::new(&self.as_str().to_lowercase())
}
}

Expand All @@ -76,15 +54,109 @@ impl<'de> Deserialize<'de> for Tick {
}
}

impl Display for Tick {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.as_str())
}
}

#[derive(Debug, Clone, PartialEq)]
pub struct LowerTick(Box<[u8]>);

impl LowerTick {
fn new(str: &str) -> Self {
LowerTick(str.as_bytes().to_vec().into_boxed_slice())
}

pub fn as_str(&self) -> &str {
std::str::from_utf8(&self.0).unwrap()
}

pub fn hex(&self) -> String {
let mut data = [0u8; TICK_BYTE_COUNT * 4];
data[..self.0.len()].copy_from_slice(&self.0);
hex::encode(data)
}

pub fn min_hex() -> String {
hex::encode([0u8; TICK_BYTE_COUNT * 4])
}

pub fn max_hex() -> String {
hex::encode([0xffu8; TICK_BYTE_COUNT * 4])
}
}

impl Display for LowerTick {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.as_str())
}
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn test_tick_length_case() {
assert!(Tick::from_str("XAİ").is_ok());
assert!(Tick::from_str("XAİİ").is_err());
assert!("XAİ".parse::<Tick>().is_ok());
assert!("XAİİ".parse::<Tick>().is_err());
assert!(Tick::from_str("X。").is_ok());
assert!("X。".parse::<Tick>().is_ok());
assert!(Tick::from_str("aBc1").is_ok());
assert!("aBc1".parse::<Tick>().is_ok());
assert!("ατ".parse::<Tick>().is_ok());
assert!("∑ii".parse::<Tick>().is_err());
assert!("∑i".parse::<Tick>().is_ok());
assert!("⊢i".parse::<Tick>().is_ok());
assert!("⊢ii".parse::<Tick>().is_err());
assert!("≯a".parse::<Tick>().is_ok());
assert!("a≯a".parse::<Tick>().is_err());
}
#[test]
fn test_tick_hex() {
assert_eq!(
Tick::from_str("XAİ").unwrap().to_lowercase().hex(),
"786169cc870000000000000000000000"
);
assert_eq!(
Tick::from_str("aBc1").unwrap().to_lowercase().hex(),
"61626331000000000000000000000000"
);
}

#[test]
fn test_tick_unicode_lowercase() {
assert_eq!(
Tick::from_str("XAİ").unwrap().to_lowercase().as_str(),
"xai\u{307}"
);
assert_eq!(
Tick::from_str("aBc1").unwrap().to_lowercase().as_str(),
"abc1",
);
assert_eq!("ατ".parse::<Tick>().unwrap().to_lowercase().as_str(), "ατ");
assert_eq!("∑H".parse::<Tick>().unwrap().to_lowercase().as_str(), "∑h");
assert_eq!("⊢I".parse::<Tick>().unwrap().to_lowercase().as_str(), "⊢i");
assert_eq!("≯A".parse::<Tick>().unwrap().to_lowercase().as_str(), "≯a");
}

#[test]
fn test_tick_compare_ignore_case() {
assert_eq!(Tick::from_str("aBc1"), Tick::from_str("AbC1"));
assert_ne!(Tick::from_str("aBc1"), Tick::from_str("AbC1"));

assert_ne!(Tick::from_str("aBc1"), Tick::from_str("aBc2"));

assert_eq!(
Tick::from_str("aBc1").unwrap().to_lowercase(),
Tick::from_str("AbC1").unwrap().to_lowercase(),
);
assert_ne!(
Tick::from_str("aBc1").unwrap().to_lowercase(),
Tick::from_str("AbC2").unwrap().to_lowercase(),
);
}

#[test]
Expand Down
2 changes: 1 addition & 1 deletion src/brc20/types/token_info.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use super::*;
use crate::InscriptionId;
use serde::{Deserialize, Serialize};
#[derive(Debug, PartialEq, Deserialize, Serialize)]
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
pub struct TokenInfo {
pub tick: Tick,
pub inscription_id: InscriptionId,
Expand Down
Loading

0 comments on commit 663df86

Please sign in to comment.