Skip to content

Commit

Permalink
define Decodable trait and implement decode
Browse files Browse the repository at this point in the history
  • Loading branch information
b00f committed Oct 7, 2024
1 parent eb1cd6f commit 2f35318
Show file tree
Hide file tree
Showing 24 changed files with 657 additions and 356 deletions.
1 change: 1 addition & 0 deletions rust/chains/tw_pactus/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ tw_keypair = { path = "../../tw_keypair" }
tw_memory = { path = "../../tw_memory" }
tw_proto = { path = "../../tw_proto" }
tw_hash = { path = "../../tw_hash" }
tw_encoding = { path = "../../tw_encoding" }

[dev-dependencies]
tw_encoding = { path = "../../tw_encoding" }
Expand Down
44 changes: 24 additions & 20 deletions rust/chains/tw_pactus/src/address.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
//
// Copyright © 2017 Trust Wallet.

use std::fmt;
use std::str::FromStr;
use std::{fmt, io};

use bech32::{FromBase32, ToBase32};
use tw_coin_entry::coin_entry::CoinAddress;
Expand Down Expand Up @@ -51,7 +51,7 @@ pub struct Address {

impl Address {
pub fn from_public_key(public_key: &PublicKey) -> Result<Self, AddressError> {
let pud_data = public_key.to_bytes();
let pud_data = public_key.to_h256();
let pub_hash =
ripemd_160(&blake2_b(pud_data.as_ref(), 32).map_err(|_| AddressError::Internal)?);

Expand Down Expand Up @@ -93,14 +93,14 @@ impl fmt::Display for Address {
}

impl encode::Encodable for Address {
fn encode(&self, stream: &mut encode::stream::Stream) {
fn encode<W: std::io::Write + ?Sized>(&self, w: &mut W) -> Result<usize, io::Error> {
if self.is_treasury() {
stream.append(&0u8);
&0u8.encode(w);

return;
return Ok(1);
}

stream.append_raw_slice(&self.data());
self.data().encode(w)
}

fn encoded_size(&self) -> usize {
Expand Down Expand Up @@ -130,7 +130,7 @@ impl FromStr for Address {
}

if b32.len() != 33 {
return Err(AddressError::InvalidInput)
return Err(AddressError::InvalidInput);
}

let addr_type = AddressType::from(b32[0].to_u8());
Expand All @@ -150,7 +150,7 @@ impl FromStr for Address {

#[cfg(test)]
mod test {
use encode::{stream::{self, Stream}, Encodable};
use encode::Encodable;
use tw_encoding::hex::DecodeHex;
use tw_keypair::ed25519::sha512::PrivateKey;

Expand All @@ -161,22 +161,26 @@ mod test {
let addr = Address::from_str(TREASURY_ADDRESS_STRING).unwrap();
assert!(addr.is_treasury());

let mut stream = Stream::new();
addr.encode(&mut stream);
assert_eq!( stream.out(), [0x00]);
assert_eq!( addr.encoded_size(), 1);
let mut w = Vec::new();
addr.encode(&mut w);
assert_eq!(w.to_vec(), [0x00]);
assert_eq!(addr.encoded_size(), 1);
}


#[test]
fn test_address_encoding() {
let addr = Address::from_str("pc1rqqqsyqcyq5rqwzqfpg9scrgwpuqqzqsr36kkra").unwrap();
assert!(!addr.is_treasury());

let mut stream = Stream::new();
addr.encode(&mut stream);
assert_eq!( stream.out(), "03000102030405060708090a0b0c0d0e0f00010203".decode_hex().unwrap());
assert_eq!( addr.encoded_size(), 21);
let mut w = Vec::new();
addr.encode(&mut w);
assert_eq!(
w.to_vec(),
"03000102030405060708090a0b0c0d0e0f00010203"
.decode_hex()
.unwrap()
);
assert_eq!(addr.encoded_size(), 21);
}

#[test]
Expand Down Expand Up @@ -238,11 +242,11 @@ mod test {
)
.unwrap();
let address = Address::from_public_key(&private_key.public()).unwrap();
let mut stream = Stream::new();
let mut w = Vec::new();

address.encode(&mut stream);
address.encode(&mut w);

assert_eq!(expected_data, stream.out(),);
assert_eq!(expected_data, w.to_vec(),);
assert_eq!(expected_data.len(), address.encoded_size());
}
}
10 changes: 6 additions & 4 deletions rust/chains/tw_pactus/src/amount.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
use crate::encode::{compact_integer::CompactInteger, stream::Stream, Encodable};
use std::io;

use crate::encode::{var_int::VarInt, Encodable};

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Amount(pub i64);

impl Encodable for Amount {
fn encode(&self, stream: &mut Stream) {
CompactInteger::from(self.0 as usize).encode(stream)
fn encode<W: std::io::Write + ?Sized>(&self, w: &mut W) -> Result<usize, io::Error> {
VarInt::from(self.0 as usize).encode(w)
}

fn encoded_size(&self) -> usize {
CompactInteger::from(self.0 as usize).encoded_size()
VarInt::from(self.0 as usize).encoded_size()
}
}
130 changes: 0 additions & 130 deletions rust/chains/tw_pactus/src/encode/compact_integer.rs

This file was deleted.

121 changes: 121 additions & 0 deletions rust/chains/tw_pactus/src/encode/decode.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
// SPDX-License-Identifier: Apache-2.0
//
// Copyright © 2017 Trust Wallet.

use std::io;

use tw_hash::Hash;
use tw_keypair::ed25519::{sha512::PublicKey, Signature};

use super::error::Error;
use crate::encode::var_int::VarInt;
use crate::encode::Decodable;

pub(crate) fn decode_var_slice(r: &mut dyn std::io::Read) -> Result<Vec<u8>, Error> {
let len = *VarInt::decode(r)?;
let mut buf = vec![0; len as usize];
r.read(&mut buf)?;

Ok(buf)
}

impl Decodable for Vec<u8> {
fn decode(r: &mut dyn std::io::Read) -> Result<Self, Error> {
decode_var_slice(r)
}
}

impl Decodable for String {
fn decode(r: &mut dyn std::io::Read) -> Result<Self, Error> {
let data = decode_var_slice(r)?;
String::from_utf8(data).map_err(|_| self::Error::ParseFailed("Invalid String"))
}
}

impl Decodable for PublicKey {
fn decode(r: &mut dyn std::io::Read) -> Result<Self, Error> {
let data = decode_var_slice(r)?;
PublicKey::try_from(data.as_slice())
.map_err(|_| self::Error::ParseFailed("Invalid Public Key"))
}
}

impl Decodable for Signature {
fn decode(r: &mut dyn std::io::Read) -> Result<Self, Error> {
let data = decode_var_slice(r)?;
Signature::try_from(data.as_slice())
.map_err(|_| self::Error::ParseFailed("Invalid Signature"))
}
}

impl<const N: usize> Decodable for Hash<N> {
fn decode(r: &mut dyn std::io::Read) -> Result<Self, Error> {
let data = decode_var_slice(r)?;
Hash::try_from(data.as_slice()).map_err(|_| self::Error::ParseFailed("Invalid Hash"))
}
}

macro_rules! impl_decodable_for_int {
($int:ty, $size:literal, $write_fn:tt) => {
impl Decodable for $int {
#[inline]
fn decode(r: &mut dyn std::io::Read) -> Result<Self, Error> {
let mut buf = [0; $size];
r.read(&mut buf[..])?;
Ok(<$int>::from_le_bytes(buf))
}
}
};
}

impl_decodable_for_int!(u8, 1, write_u8);
impl_decodable_for_int!(i32, 4, write_i32);
impl_decodable_for_int!(i64, 8, write_i64);
impl_decodable_for_int!(u16, 2, write_u16);
impl_decodable_for_int!(u32, 4, write_u32);
impl_decodable_for_int!(u64, 8, write_u64);

#[cfg(test)]
mod tests {
use io::Cursor;
use tw_encoding::hex::DecodeHex;

use super::*;
use crate::encode::{decode, deserialize, serialize};

#[test]
fn test_decode_var_slice() {
let expected = vec![1, 2, 3, 4];
let mut cursor = Cursor::new("0401020304".decode_hex().unwrap());
let slice = decode_var_slice(&mut cursor).unwrap();

assert_eq!(expected, slice);
}

#[test]
fn test_encode_numbers() {
let data = vec![1_u8, 2, 0, 3, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0];
let mut cursor = Cursor::new(data);

assert_eq!(1u8, u8::decode(&mut cursor).unwrap());
assert_eq!(2u16, u16::decode(&mut cursor).unwrap());
assert_eq!(3u32, u32::decode(&mut cursor).unwrap());
assert_eq!(4u64, u64::decode(&mut cursor).unwrap());
}

#[test]
fn test_decode_bytes() {
let expected = "0145".decode_hex().unwrap();
let bytes = "020145".decode_hex().unwrap();

assert_eq!(expected, deserialize::<Vec<u8>>(&bytes).unwrap());
}

#[test]
fn test_encode_string() {
let expected = "hello".to_string();
let bytes = "0568656c6c6f".decode_hex().unwrap();

assert_eq!(expected, deserialize::<String>(&bytes).unwrap());
}
}
Loading

0 comments on commit 2f35318

Please sign in to comment.