use crate::error::{Error, Result};
use crate::primitives::hash::sha256d;
pub fn to_hex(data: &[u8]) -> String {
hex::encode(data)
}
pub fn from_hex(s: &str) -> Result<Vec<u8>> {
hex::decode(s).map_err(|e| Error::InvalidHex(e.to_string()))
}
pub const BASE58_ALPHABET: &str = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
pub fn to_base58(data: &[u8]) -> String {
bs58::encode(data)
.with_alphabet(bs58::Alphabet::BITCOIN)
.into_string()
}
pub fn from_base58(s: &str) -> Result<Vec<u8>> {
if s.is_empty() {
return Err(Error::InvalidBase58("empty string".to_string()));
}
bs58::decode(s)
.with_alphabet(bs58::Alphabet::BITCOIN)
.into_vec()
.map_err(|e| Error::InvalidBase58(e.to_string()))
}
pub fn to_base58_check(payload: &[u8], version: &[u8]) -> String {
let mut data = Vec::with_capacity(version.len() + payload.len() + 4);
data.extend_from_slice(version);
data.extend_from_slice(payload);
let checksum = sha256d(&data);
data.extend_from_slice(&checksum[..4]);
to_base58(&data)
}
pub fn from_base58_check(s: &str) -> Result<(Vec<u8>, Vec<u8>)> {
from_base58_check_with_prefix_length(s, 1)
}
pub fn from_base58_check_with_prefix_length(
s: &str,
prefix_length: usize,
) -> Result<(Vec<u8>, Vec<u8>)> {
let bytes = from_base58(s)?;
if bytes.len() < prefix_length + 4 {
return Err(Error::InvalidBase58(
"data too short for Base58Check".to_string(),
));
}
let version = bytes[..prefix_length].to_vec();
let payload = bytes[prefix_length..bytes.len() - 4].to_vec();
let checksum = &bytes[bytes.len() - 4..];
let mut data = Vec::with_capacity(version.len() + payload.len());
data.extend_from_slice(&version);
data.extend_from_slice(&payload);
let expected_checksum = sha256d(&data);
if checksum != &expected_checksum[..4] {
return Err(Error::InvalidChecksum);
}
Ok((version, payload))
}
pub fn to_base64(data: &[u8]) -> String {
use base64::Engine;
base64::engine::general_purpose::STANDARD.encode(data)
}
pub fn from_base64(s: &str) -> Result<Vec<u8>> {
use base64::engine::general_purpose;
use base64::Engine;
let cleaned: String = s
.chars()
.filter(|c| !c.is_whitespace())
.map(|c| match c {
'-' => '+',
'_' => '/',
_ => c,
})
.collect();
general_purpose::STANDARD
.decode(&cleaned)
.or_else(|_| general_purpose::STANDARD_NO_PAD.decode(&cleaned))
.map_err(|e| Error::InvalidBase64(e.to_string()))
}
pub fn to_utf8_bytes(s: &str) -> Vec<u8> {
s.as_bytes().to_vec()
}
pub fn from_utf8_bytes(data: &[u8]) -> Result<String> {
String::from_utf8(data.to_vec()).map_err(|e| Error::InvalidUtf8(e.to_string()))
}
#[derive(Debug, Clone)]
pub struct Reader<'a> {
data: &'a [u8],
pos: usize,
}
impl<'a> Reader<'a> {
pub fn new(data: &'a [u8]) -> Self {
Reader { data, pos: 0 }
}
pub fn remaining(&self) -> usize {
self.data.len().saturating_sub(self.pos)
}
pub fn is_empty(&self) -> bool {
self.remaining() == 0
}
pub fn position(&self) -> usize {
self.pos
}
pub fn consumed_since(&self, from_pos: usize) -> &'a [u8] {
&self.data[from_pos..self.pos]
}
pub fn read_u8(&mut self) -> Result<u8> {
self.ensure_remaining(1)?;
let val = self.data[self.pos];
self.pos += 1;
Ok(val)
}
pub fn read_u16_le(&mut self) -> Result<u16> {
self.ensure_remaining(2)?;
let bytes = [self.data[self.pos], self.data[self.pos + 1]];
self.pos += 2;
Ok(u16::from_le_bytes(bytes))
}
pub fn read_u32_le(&mut self) -> Result<u32> {
self.ensure_remaining(4)?;
let bytes = [
self.data[self.pos],
self.data[self.pos + 1],
self.data[self.pos + 2],
self.data[self.pos + 3],
];
self.pos += 4;
Ok(u32::from_le_bytes(bytes))
}
pub fn read_u64_le(&mut self) -> Result<u64> {
self.ensure_remaining(8)?;
let bytes = [
self.data[self.pos],
self.data[self.pos + 1],
self.data[self.pos + 2],
self.data[self.pos + 3],
self.data[self.pos + 4],
self.data[self.pos + 5],
self.data[self.pos + 6],
self.data[self.pos + 7],
];
self.pos += 8;
Ok(u64::from_le_bytes(bytes))
}
pub fn read_i8(&mut self) -> Result<i8> {
self.ensure_remaining(1)?;
let val = self.data[self.pos] as i8;
self.pos += 1;
Ok(val)
}
pub fn read_i16_le(&mut self) -> Result<i16> {
self.ensure_remaining(2)?;
let bytes = [self.data[self.pos], self.data[self.pos + 1]];
self.pos += 2;
Ok(i16::from_le_bytes(bytes))
}
pub fn read_i32_le(&mut self) -> Result<i32> {
self.ensure_remaining(4)?;
let bytes = [
self.data[self.pos],
self.data[self.pos + 1],
self.data[self.pos + 2],
self.data[self.pos + 3],
];
self.pos += 4;
Ok(i32::from_le_bytes(bytes))
}
pub fn read_i64_le(&mut self) -> Result<i64> {
self.ensure_remaining(8)?;
let bytes = [
self.data[self.pos],
self.data[self.pos + 1],
self.data[self.pos + 2],
self.data[self.pos + 3],
self.data[self.pos + 4],
self.data[self.pos + 5],
self.data[self.pos + 6],
self.data[self.pos + 7],
];
self.pos += 8;
Ok(i64::from_le_bytes(bytes))
}
pub fn read_var_int(&mut self) -> Result<u64> {
let first = self.read_u8()?;
match first {
0x00..=0xFC => Ok(first as u64),
0xFD => Ok(self.read_u16_le()? as u64),
0xFE => Ok(self.read_u32_le()? as u64),
0xFF => self.read_u64_le(),
}
}
pub fn read_var_int_num(&mut self) -> Result<usize> {
let val = self.read_var_int()?;
usize::try_from(val)
.map_err(|_| Error::CryptoError(format!("varint value {} exceeds maximum usize", val)))
}
pub fn read_bytes(&mut self, len: usize) -> Result<&'a [u8]> {
self.ensure_remaining(len)?;
let bytes = &self.data[self.pos..self.pos + len];
self.pos += len;
Ok(bytes)
}
pub fn read_var_bytes(&mut self) -> Result<&'a [u8]> {
let len = self.read_var_int_num()?;
self.read_bytes(len)
}
pub fn read_remaining(&mut self) -> &'a [u8] {
let bytes = &self.data[self.pos..];
self.pos = self.data.len();
bytes
}
fn ensure_remaining(&self, needed: usize) -> Result<()> {
if self.remaining() < needed {
Err(Error::ReaderUnderflow {
needed,
available: self.remaining(),
})
} else {
Ok(())
}
}
}
#[derive(Debug, Clone, Default)]
pub struct Writer {
data: Vec<u8>,
}
impl Writer {
pub fn new() -> Self {
Writer { data: Vec::new() }
}
pub fn with_capacity(capacity: usize) -> Self {
Writer {
data: Vec::with_capacity(capacity),
}
}
pub fn len(&self) -> usize {
self.data.len()
}
pub fn is_empty(&self) -> bool {
self.data.is_empty()
}
pub fn as_bytes(&self) -> &[u8] {
&self.data
}
pub fn into_bytes(self) -> Vec<u8> {
self.data
}
pub fn write_u8(&mut self, val: u8) -> &mut Self {
self.data.push(val);
self
}
pub fn write_u16_le(&mut self, val: u16) -> &mut Self {
self.data.extend_from_slice(&val.to_le_bytes());
self
}
pub fn write_u32_le(&mut self, val: u32) -> &mut Self {
self.data.extend_from_slice(&val.to_le_bytes());
self
}
pub fn write_u64_le(&mut self, val: u64) -> &mut Self {
self.data.extend_from_slice(&val.to_le_bytes());
self
}
pub fn write_i8(&mut self, val: i8) -> &mut Self {
self.data.push(val as u8);
self
}
pub fn write_i16_le(&mut self, val: i16) -> &mut Self {
self.data.extend_from_slice(&val.to_le_bytes());
self
}
pub fn write_i32_le(&mut self, val: i32) -> &mut Self {
self.data.extend_from_slice(&val.to_le_bytes());
self
}
pub fn write_i64_le(&mut self, val: i64) -> &mut Self {
self.data.extend_from_slice(&val.to_le_bytes());
self
}
pub fn write_var_int(&mut self, val: u64) -> &mut Self {
if val < 0xFD {
self.data.push(val as u8);
} else if val <= 0xFFFF {
self.data.push(0xFD);
self.data.extend_from_slice(&(val as u16).to_le_bytes());
} else if val <= 0xFFFFFFFF {
self.data.push(0xFE);
self.data.extend_from_slice(&(val as u32).to_le_bytes());
} else {
self.data.push(0xFF);
self.data.extend_from_slice(&val.to_le_bytes());
}
self
}
pub fn write_bytes(&mut self, data: &[u8]) -> &mut Self {
self.data.extend_from_slice(data);
self
}
pub fn write_var_bytes(&mut self, data: &[u8]) -> &mut Self {
self.write_var_int(data.len() as u64);
self.data.extend_from_slice(data);
self
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_to_hex_basic() {
assert_eq!(to_hex(&[0xde, 0xad, 0xbe, 0xef]), "deadbeef");
assert_eq!(to_hex(&[0x00, 0x01, 0x02, 0x03]), "00010203");
assert_eq!(to_hex(&[]), "");
}
#[test]
fn test_from_hex_basic() {
assert_eq!(from_hex("deadbeef").unwrap(), vec![0xde, 0xad, 0xbe, 0xef]);
assert_eq!(from_hex("00010203").unwrap(), vec![0x00, 0x01, 0x02, 0x03]);
assert_eq!(from_hex("").unwrap(), Vec::<u8>::new());
}
#[test]
fn test_from_hex_case_insensitive() {
assert_eq!(from_hex("DEADBEEF").unwrap(), vec![0xde, 0xad, 0xbe, 0xef]);
assert_eq!(from_hex("DeAdBeEf").unwrap(), vec![0xde, 0xad, 0xbe, 0xef]);
}
#[test]
fn test_from_hex_invalid() {
assert!(from_hex("invalid").is_err());
assert!(from_hex("deadbee").is_err()); assert!(from_hex("gg").is_err()); }
#[test]
fn test_to_base58_leading_zeros() {
assert_eq!(to_base58(&[0x00]), "1");
assert_eq!(to_base58(&[0x00, 0x00, 0x00]), "111");
}
#[test]
fn test_to_base58_known_values() {
let bytes = from_hex("0123456789ABCDEF").unwrap();
assert_eq!(to_base58(&bytes), "C3CPq7c8PY");
let bytes = from_hex("000000287FB4CD").unwrap();
assert_eq!(to_base58(&bytes), "111233QC4");
assert_eq!(to_base58(&[]), "");
assert_eq!(to_base58(&[0, 0, 0, 0]), "1111");
assert_eq!(to_base58(&[255, 255, 255, 255]), "7YXq9G");
}
#[test]
fn test_from_base58_leading_ones() {
assert_eq!(from_base58("1").unwrap(), vec![0x00]);
assert_eq!(from_base58("111").unwrap(), vec![0x00, 0x00, 0x00]);
}
#[test]
fn test_from_base58_known_values() {
assert_eq!(
to_hex(&from_base58("C3CPq7c8PY").unwrap()),
"0123456789abcdef"
);
assert_eq!(to_hex(&from_base58("111233QC4").unwrap()), "000000287fb4cd");
}
#[test]
fn test_from_base58_invalid() {
assert!(from_base58("0").is_err());
assert!(from_base58("O").is_err());
assert!(from_base58("I").is_err());
assert!(from_base58("l").is_err());
assert!(from_base58("").is_err()); }
#[test]
fn test_base58_roundtrip() {
let original =
from_hex("02c0ded2bc1f1305fb0faac5e6c03ee3a1924234985427b6167ca569d13df435cfeb05f9d2")
.unwrap();
let encoded = to_base58(&original);
assert_eq!(
encoded,
"6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV"
);
let decoded = from_base58(&encoded).unwrap();
assert_eq!(decoded, original);
}
#[test]
fn test_from_base58_with_leading_ones() {
let decoded = from_base58("111z").unwrap();
assert_eq!(to_hex(&decoded), "00000039");
}
#[test]
fn test_base58check_address() {
let pubkey_hash = from_hex("f5f2d624cfb5c3f66d06123d0829d1c9cebf770e").unwrap();
let encoded = to_base58_check(&pubkey_hash, &[0x00]);
assert_eq!(encoded, "1PRTTaJesdNovgne6Ehcdu1fpEdX7913CK");
let (version, payload) = from_base58_check(&encoded).unwrap();
assert_eq!(version, vec![0x00]);
assert_eq!(payload, pubkey_hash);
}
#[test]
fn test_base58check_wif() {
let private_key =
from_hex("1E99423A4ED27608A15A2616A2B0E9E52CED330AC530EDCC32C8FFC6A526AEDD").unwrap();
let encoded = to_base58_check(&private_key, &[0x80]);
assert_eq!(
encoded,
"5J3mBbAH58CpQ3Y5RNJpUKPE62SQ5tfcvU2JpbnkeyhfsYB1Jcn"
);
let (version, payload) = from_base58_check(&encoded).unwrap();
assert_eq!(version, vec![0x80]);
assert_eq!(payload, private_key);
}
#[test]
fn test_base58check_wif_compressed() {
let private_key_compressed =
from_hex("1E99423A4ED27608A15A2616A2B0E9E52CED330AC530EDCC32C8FFC6A526AEDD01").unwrap();
let encoded = to_base58_check(&private_key_compressed, &[0x80]);
assert_eq!(
encoded,
"KxFC1jmwwCoACiCAWZ3eXa96mBM6tb3TYzGmf6YwgdGWZgawvrtJ"
);
let (version, payload) = from_base58_check(&encoded).unwrap();
assert_eq!(version, vec![0x80]);
assert_eq!(payload, private_key_compressed);
}
#[test]
fn test_base58check_invalid_checksum() {
let _valid = "1PRTTaJesdNovgne6Ehcdu1fpEdX7913CK";
let invalid = "1PRTTaJesdNovgne6Ehcdu1fpEdX7913CL";
let result = from_base58_check(invalid);
assert!(result.is_err());
}
#[test]
fn test_base58check_multiple_addresses() {
let data = from_hex("27b5891b01da2db74cde1689a97a2acbe23d5fb1").unwrap();
let encoded = to_base58_check(&data, &[0x00]);
assert_eq!(encoded, "14cxpo3MBCYYWCgF74SWTdcmxipnGUsPw3");
}
#[test]
fn test_to_base64_basic() {
assert_eq!(to_base64(b"f"), "Zg==");
assert_eq!(to_base64(b"fo"), "Zm8=");
assert_eq!(to_base64(b"foo"), "Zm9v");
assert_eq!(to_base64(b"Hello"), "SGVsbG8=");
}
#[test]
fn test_from_base64_basic() {
assert_eq!(from_base64("Zg==").unwrap(), b"f");
assert_eq!(from_base64("Zm8=").unwrap(), b"fo");
assert_eq!(from_base64("Zm9v").unwrap(), b"foo");
assert_eq!(from_base64("SGVsbG8=").unwrap(), b"Hello");
}
#[test]
fn test_from_base64_no_padding() {
assert_eq!(from_base64("SGVsbG8").unwrap(), b"Hello");
assert_eq!(from_base64("QQ").unwrap(), b"A");
assert_eq!(from_base64("Zm8").unwrap(), b"fo");
}
#[test]
fn test_from_base64_url_safe() {
assert_eq!(from_base64("_w==").unwrap(), vec![255]);
}
#[test]
fn test_from_base64_whitespace() {
assert_eq!(from_base64("S G V s b G 8 =\n").unwrap(), b"Hello");
}
#[test]
fn test_from_base64_invalid() {
assert!(from_base64("A?==").is_err());
}
#[test]
fn test_to_utf8_bytes_basic() {
assert_eq!(to_utf8_bytes("Hello"), vec![72, 101, 108, 108, 111]);
assert_eq!(to_utf8_bytes("€"), vec![0xE2, 0x82, 0xAC]);
assert_eq!(to_utf8_bytes("😃"), vec![0xF0, 0x9F, 0x98, 0x83]);
}
#[test]
fn test_from_utf8_bytes_basic() {
assert_eq!(from_utf8_bytes(&[72, 101, 108, 108, 111]).unwrap(), "Hello");
assert_eq!(from_utf8_bytes(&[0xE2, 0x82, 0xAC]).unwrap(), "€");
}
#[test]
fn test_from_utf8_bytes_invalid() {
assert!(from_utf8_bytes(&[0xFF, 0xFE]).is_err());
}
#[test]
fn test_reader_basic() {
let data = vec![0x01, 0x02, 0x03, 0x04];
let mut reader = Reader::new(&data);
assert_eq!(reader.position(), 0);
assert_eq!(reader.remaining(), 4);
assert!(!reader.is_empty());
assert_eq!(reader.read_u8().unwrap(), 0x01);
assert_eq!(reader.position(), 1);
assert_eq!(reader.remaining(), 3);
}
#[test]
fn test_reader_u16_le() {
let data = vec![0x01, 0x02];
let mut reader = Reader::new(&data);
assert_eq!(reader.read_u16_le().unwrap(), 0x0201);
}
#[test]
fn test_reader_u32_le() {
let data = vec![0x01, 0x02, 0x03, 0x04];
let mut reader = Reader::new(&data);
assert_eq!(reader.read_u32_le().unwrap(), 0x04030201);
}
#[test]
fn test_reader_u64_le() {
let data = vec![0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08];
let mut reader = Reader::new(&data);
assert_eq!(reader.read_u64_le().unwrap(), 0x0807060504030201);
}
#[test]
fn test_reader_signed_integers() {
let data = vec![0xFF];
let mut reader = Reader::new(&data);
assert_eq!(reader.read_i8().unwrap(), -1);
let data = vec![0xFF, 0xFF];
let mut reader = Reader::new(&data);
assert_eq!(reader.read_i16_le().unwrap(), -1);
let data = vec![0xFF, 0xFF, 0xFF, 0xFF];
let mut reader = Reader::new(&data);
assert_eq!(reader.read_i32_le().unwrap(), -1);
let data = vec![0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF];
let mut reader = Reader::new(&data);
assert_eq!(reader.read_i64_le().unwrap(), -1);
}
#[test]
fn test_reader_underflow() {
let data = vec![0x01, 0x02];
let mut reader = Reader::new(&data);
assert!(reader.read_u32_le().is_err());
}
#[test]
fn test_reader_read_bytes() {
let data = vec![0x01, 0x02, 0x03, 0x04, 0x05];
let mut reader = Reader::new(&data);
assert_eq!(reader.read_bytes(3).unwrap(), &[0x01, 0x02, 0x03]);
assert_eq!(reader.read_bytes(2).unwrap(), &[0x04, 0x05]);
assert!(reader.is_empty());
}
#[test]
fn test_reader_read_remaining() {
let data = vec![0x01, 0x02, 0x03, 0x04, 0x05];
let mut reader = Reader::new(&data);
reader.read_u8().unwrap();
reader.read_u8().unwrap();
let remaining = reader.read_remaining();
assert_eq!(remaining, &[0x03, 0x04, 0x05]);
assert!(reader.is_empty());
}
#[test]
fn test_reader_varint_single_byte() {
let data = vec![0x00];
let mut reader = Reader::new(&data);
assert_eq!(reader.read_var_int().unwrap(), 0);
let data = vec![0xFC];
let mut reader = Reader::new(&data);
assert_eq!(reader.read_var_int().unwrap(), 0xFC);
}
#[test]
fn test_reader_varint_three_bytes() {
let data = vec![0xFD, 0xFD, 0x00];
let mut reader = Reader::new(&data);
assert_eq!(reader.read_var_int().unwrap(), 0xFD);
let data = vec![0xFD, 0xFF, 0xFF];
let mut reader = Reader::new(&data);
assert_eq!(reader.read_var_int().unwrap(), 0xFFFF);
}
#[test]
fn test_reader_varint_five_bytes() {
let data = vec![0xFE, 0x00, 0x00, 0x01, 0x00];
let mut reader = Reader::new(&data);
assert_eq!(reader.read_var_int().unwrap(), 0x10000);
let data = vec![0xFE, 0xFF, 0xFF, 0xFF, 0xFF];
let mut reader = Reader::new(&data);
assert_eq!(reader.read_var_int().unwrap(), 0xFFFFFFFF);
}
#[test]
fn test_reader_varint_nine_bytes() {
let data = vec![0xFF, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00];
let mut reader = Reader::new(&data);
assert_eq!(reader.read_var_int().unwrap(), 0x100000000);
let data = vec![0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF];
let mut reader = Reader::new(&data);
assert_eq!(reader.read_var_int().unwrap(), u64::MAX);
}
#[test]
fn test_reader_varint_incomplete() {
let data = vec![0xFD, 0x01];
let mut reader = Reader::new(&data);
assert!(reader.read_var_int().is_err());
}
#[test]
fn test_reader_var_bytes() {
let data = vec![0x05, 0x68, 0x65, 0x6c, 0x6c, 0x6f]; let mut reader = Reader::new(&data);
assert_eq!(reader.read_var_bytes().unwrap(), b"hello");
assert!(reader.is_empty());
}
#[test]
fn test_writer_basic() {
let mut writer = Writer::new();
assert!(writer.is_empty());
assert_eq!(writer.len(), 0);
writer.write_u8(0x01);
assert!(!writer.is_empty());
assert_eq!(writer.len(), 1);
assert_eq!(writer.as_bytes(), &[0x01]);
}
#[test]
fn test_writer_u16_le() {
let mut writer = Writer::new();
writer.write_u16_le(0x0201);
assert_eq!(writer.into_bytes(), vec![0x01, 0x02]);
}
#[test]
fn test_writer_u32_le() {
let mut writer = Writer::new();
writer.write_u32_le(0x04030201);
assert_eq!(writer.into_bytes(), vec![0x01, 0x02, 0x03, 0x04]);
}
#[test]
fn test_writer_u64_le() {
let mut writer = Writer::new();
writer.write_u64_le(0x0807060504030201);
assert_eq!(
writer.into_bytes(),
vec![0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08]
);
}
#[test]
fn test_writer_signed_integers() {
let mut writer = Writer::new();
writer.write_i8(-1);
assert_eq!(writer.as_bytes(), &[0xFF]);
let mut writer = Writer::new();
writer.write_i16_le(-1);
assert_eq!(writer.as_bytes(), &[0xFF, 0xFF]);
let mut writer = Writer::new();
writer.write_i32_le(-1);
assert_eq!(writer.as_bytes(), &[0xFF, 0xFF, 0xFF, 0xFF]);
let mut writer = Writer::new();
writer.write_i64_le(-1);
assert_eq!(
writer.as_bytes(),
&[0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF]
);
}
#[test]
fn test_writer_varint_single_byte() {
let mut writer = Writer::new();
writer.write_var_int(0);
assert_eq!(writer.len(), 1);
assert_eq!(writer.as_bytes(), &[0x00]);
let mut writer = Writer::new();
writer.write_var_int(0xFC);
assert_eq!(writer.len(), 1);
assert_eq!(writer.as_bytes(), &[0xFC]);
}
#[test]
fn test_writer_varint_three_bytes() {
let mut writer = Writer::new();
writer.write_var_int(0xFD);
assert_eq!(writer.len(), 3);
assert_eq!(writer.as_bytes(), &[0xFD, 0xFD, 0x00]);
let mut writer = Writer::new();
writer.write_var_int(0xFFFF);
assert_eq!(writer.len(), 3);
assert_eq!(writer.as_bytes(), &[0xFD, 0xFF, 0xFF]);
}
#[test]
fn test_writer_varint_five_bytes() {
let mut writer = Writer::new();
writer.write_var_int(0x10000);
assert_eq!(writer.len(), 5);
assert_eq!(writer.as_bytes(), &[0xFE, 0x00, 0x00, 0x01, 0x00]);
let mut writer = Writer::new();
writer.write_var_int(0xFFFFFFFF);
assert_eq!(writer.len(), 5);
assert_eq!(writer.as_bytes(), &[0xFE, 0xFF, 0xFF, 0xFF, 0xFF]);
}
#[test]
fn test_writer_varint_nine_bytes() {
let mut writer = Writer::new();
writer.write_var_int(0x100000000);
assert_eq!(writer.len(), 9);
assert_eq!(
writer.as_bytes(),
&[0xFF, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00]
);
let mut writer = Writer::new();
writer.write_var_int(u64::MAX);
assert_eq!(writer.len(), 9);
assert_eq!(
writer.as_bytes(),
&[0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF]
);
}
#[test]
fn test_writer_var_bytes() {
let mut writer = Writer::new();
writer.write_var_bytes(b"hello");
assert_eq!(
writer.into_bytes(),
vec![0x05, 0x68, 0x65, 0x6c, 0x6c, 0x6f]
);
}
#[test]
fn test_writer_write_bytes() {
let mut writer = Writer::new();
writer.write_bytes(&[0x01, 0x02, 0x03]);
assert_eq!(writer.into_bytes(), vec![0x01, 0x02, 0x03]);
}
#[test]
fn test_writer_chaining() {
let mut writer = Writer::new();
writer
.write_u8(0x01)
.write_u16_le(0x0302)
.write_u32_le(0x07060504);
assert_eq!(
writer.into_bytes(),
vec![0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07]
);
}
#[test]
fn test_reader_writer_roundtrip() {
let mut writer = Writer::new();
writer.write_u8(0x01);
writer.write_u32_le(0x12345678);
writer.write_var_int(0xFFFFF);
writer.write_var_bytes(b"hello");
let data = writer.into_bytes();
let mut reader = Reader::new(&data);
assert_eq!(reader.read_u8().unwrap(), 0x01);
assert_eq!(reader.read_u32_le().unwrap(), 0x12345678);
assert_eq!(reader.read_var_int().unwrap(), 0xFFFFF);
assert_eq!(reader.read_var_bytes().unwrap(), b"hello");
assert!(reader.is_empty());
}
#[test]
fn test_varint_roundtrip() {
fn assert_varint_roundtrip(val: u64) {
let mut writer = Writer::new();
writer.write_var_int(val);
let mut reader = Reader::new(writer.as_bytes());
assert_eq!(reader.read_var_int().unwrap(), val);
}
assert_varint_roundtrip(0);
assert_varint_roundtrip(0xFC);
assert_varint_roundtrip(0xFD);
assert_varint_roundtrip(0xFFFF);
assert_varint_roundtrip(0x10000);
assert_varint_roundtrip(0xFFFFFFFF);
assert_varint_roundtrip(0x100000000);
assert_varint_roundtrip(u64::MAX);
}
#[test]
fn test_varint_encoding_size() {
let mut w = Writer::new();
w.write_var_int(0xFC);
assert_eq!(w.len(), 1);
let mut w = Writer::new();
w.write_var_int(0xFD);
assert_eq!(w.len(), 3);
let mut w = Writer::new();
w.write_var_int(0x10000);
assert_eq!(w.len(), 5);
let mut w = Writer::new();
w.write_var_int(0x100000000);
assert_eq!(w.len(), 9);
}
#[test]
fn test_ts_hex_conversion() {
assert_eq!(from_hex("1234").unwrap(), vec![0x12, 0x34]);
assert_eq!(to_hex(&[0, 1, 2, 3]), "00010203");
}
#[test]
fn test_ts_base58_conversion() {
let actual = from_base58("6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV").unwrap();
assert_eq!(
to_hex(&actual),
"02c0ded2bc1f1305fb0faac5e6c03ee3a1924234985427b6167ca569d13df435cfeb05f9d2"
);
let actual = from_base58("111z").unwrap();
assert_eq!(to_hex(&actual), "00000039");
let actual = to_base58(
&from_hex("02c0ded2bc1f1305fb0faac5e6c03ee3a1924234985427b6167ca569d13df435cfeb05f9d2")
.unwrap(),
);
assert_eq!(actual, "6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV");
assert_eq!(to_base58(&[0, 0, 0, 4]), "1115");
}
#[test]
fn test_ts_base58check() {
let data = from_hex("f5f2d624cfb5c3f66d06123d0829d1c9cebf770e").unwrap();
let encoded = to_base58_check(&data, &[0]);
assert_eq!(encoded, "1PRTTaJesdNovgne6Ehcdu1fpEdX7913CK");
let (version, decoded) = from_base58_check(&encoded).unwrap();
assert_eq!(version, vec![0]);
assert_eq!(decoded, data);
let data =
from_hex("1E99423A4ED27608A15A2616A2B0E9E52CED330AC530EDCC32C8FFC6A526AEDD").unwrap();
let encoded = to_base58_check(&data, &[0x80]);
assert_eq!(
encoded,
"5J3mBbAH58CpQ3Y5RNJpUKPE62SQ5tfcvU2JpbnkeyhfsYB1Jcn"
);
}
#[test]
fn test_ts_base64() {
assert_eq!(from_base64("Zg==").unwrap(), vec![102]);
assert_eq!(from_base64("Zm8=").unwrap(), vec![102, 111]);
assert_eq!(from_base64("Zm9v").unwrap(), vec![102, 111, 111]);
assert_eq!(
from_base64("SGVsbG8=").unwrap(),
vec![72, 101, 108, 108, 111]
);
}
#[test]
fn test_ts_utf8() {
assert_eq!(to_utf8_bytes("1234"), vec![49, 50, 51, 52]);
assert_eq!(to_utf8_bytes("\u{1234}"), vec![0xE1, 0x88, 0xB4]);
assert_eq!(
to_utf8_bytes("\u{1234}234"),
vec![0xE1, 0x88, 0xB4, 50, 51, 52]
);
}
#[test]
fn test_ts_reader() {
let buf = vec![0];
let mut reader = Reader::new(&buf);
assert_eq!(reader.read_u8().unwrap(), 0);
let buf = vec![1, 0];
let mut reader = Reader::new(&buf);
assert_eq!(reader.read_u16_le().unwrap(), 1);
let buf = vec![1, 0, 0, 0];
let mut reader = Reader::new(&buf);
assert_eq!(reader.read_u32_le().unwrap(), 1);
let buf = vec![0xFF];
let mut reader = Reader::new(&buf);
assert_eq!(reader.read_i8().unwrap(), -1);
let buf = vec![0xFF, 0xFF, 0xFF, 0xFF];
let mut reader = Reader::new(&buf);
assert_eq!(reader.read_i32_le().unwrap(), -1);
}
#[test]
fn test_ts_writer() {
let mut writer = Writer::new();
writer.write_u8(1);
assert_eq!(to_hex(writer.as_bytes()), "01");
let mut writer = Writer::new();
writer.write_i8(-1);
assert_eq!(to_hex(writer.as_bytes()), "ff");
let mut writer = Writer::new();
writer.write_u16_le(1);
assert_eq!(to_hex(writer.as_bytes()), "0100");
let mut writer = Writer::new();
writer.write_i16_le(-1);
assert_eq!(to_hex(writer.as_bytes()), "ffff");
let mut writer = Writer::new();
writer.write_u32_le(1);
assert_eq!(to_hex(writer.as_bytes()), "01000000");
let mut writer = Writer::new();
writer.write_i32_le(-1);
assert_eq!(to_hex(writer.as_bytes()), "ffffffff");
let mut writer = Writer::new();
writer.write_u64_le(1);
assert_eq!(to_hex(writer.as_bytes()), "0100000000000000");
}
#[test]
fn test_ts_varint_writer() {
let mut writer = Writer::new();
writer.write_var_int(1);
assert_eq!(writer.len(), 1);
let mut writer = Writer::new();
writer.write_var_int(1000);
assert_eq!(writer.len(), 3);
let mut writer = Writer::new();
writer.write_var_int(2u64.pow(17));
assert_eq!(writer.len(), 5);
let mut writer = Writer::new();
writer.write_var_int(2u64.pow(33));
assert_eq!(writer.len(), 9);
}
#[test]
fn test_reader_consumed_since() {
let data = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08];
let mut reader = Reader::new(&data);
reader.read_u8().unwrap();
reader.read_u8().unwrap();
let start = reader.position();
assert_eq!(start, 2);
reader.read_u8().unwrap();
reader.read_u8().unwrap();
reader.read_u8().unwrap();
let consumed = reader.consumed_since(start);
assert_eq!(consumed, &[0x03, 0x04, 0x05]);
let all = reader.consumed_since(0);
assert_eq!(all, &[0x01, 0x02, 0x03, 0x04, 0x05]);
let empty = reader.consumed_since(reader.position());
assert!(empty.is_empty());
}
#[test]
fn test_ts_varint_reader() {
let buf = vec![50];
let mut reader = Reader::new(&buf);
assert_eq!(reader.read_var_int().unwrap(), 50);
let buf = vec![253, 253, 0];
let mut reader = Reader::new(&buf);
assert_eq!(reader.read_var_int().unwrap(), 253);
let mut buf = vec![254, 0, 0, 0, 0];
buf[1..5].copy_from_slice(&50000u32.to_le_bytes());
let mut reader = Reader::new(&buf);
assert_eq!(reader.read_var_int().unwrap(), 50000);
}
}