Skip to content

Commit

Permalink
introduce Digest32 newtype and use it token, box, tx ids;
Browse files Browse the repository at this point in the history
  • Loading branch information
greenhat committed Jun 26, 2020
1 parent 3de1fb7 commit 1ccfd20
Show file tree
Hide file tree
Showing 10 changed files with 144 additions and 102 deletions.
16 changes: 9 additions & 7 deletions sigma-tree/src/ast/constant.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
use crate::{chain::ErgoBox, sigma_protocol::SigmaProp, types::SType, Base16Bytes};
use crate::{
chain::ErgoBox, sigma_protocol::SigmaProp, types::SType, Base16DecodedBytes, Base16EncodedBytes,
};
#[cfg(feature = "with-serde")]
use serde::{Deserialize, Serialize};
use sigma_ser::serializer::SerializationError;
Expand Down Expand Up @@ -41,22 +43,22 @@ impl ConstantVal {
#[cfg_attr(feature = "with-serde", derive(Serialize, Deserialize))]
#[cfg_attr(
feature = "with-serde",
serde(into = "Base16Bytes", try_from = "Base16Bytes")
serde(into = "Base16EncodedBytes", try_from = "Base16DecodedBytes")
)]
pub struct Constant {
pub tpe: SType,
pub v: ConstantVal,
}

impl Into<Base16Bytes> for Constant {
fn into(self) -> Base16Bytes {
Base16Bytes(self.sigma_serialise_bytes())
impl Into<Base16EncodedBytes> for Constant {
fn into(self) -> Base16EncodedBytes {
Base16EncodedBytes::new(&self.sigma_serialise_bytes())
}
}

impl TryFrom<Base16Bytes> for Constant {
impl TryFrom<Base16DecodedBytes> for Constant {
type Error = SerializationError;
fn try_from(bytes: Base16Bytes) -> Result<Self, Self::Error> {
fn try_from(bytes: Base16DecodedBytes) -> Result<Self, Self::Error> {
Constant::sigma_parse_bytes(bytes.0)
}
}
Expand Down
3 changes: 2 additions & 1 deletion sigma-tree/src/chain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,5 +19,6 @@ pub use box_id::*;
pub use contract::*;
pub use ergo_box::*;
pub use input::*;
pub use json::Base16Bytes;
pub use json::Base16DecodedBytes;
pub use json::Base16EncodedBytes;
pub use transaction::*;
32 changes: 11 additions & 21 deletions sigma-tree/src/chain/box_id.rs
Original file line number Diff line number Diff line change
@@ -1,55 +1,45 @@
//! Box id type
use super::digest32::{self, DIGEST32_SIZE};
use sigma_ser::serializer::SerializationError;
use sigma_ser::serializer::SigmaSerializable;
use sigma_ser::vlq_encode;
use std::{convert::TryFrom, io};
use std::io;

#[cfg(feature = "with-serde")]
use serde::{Deserialize, Serialize};

use super::digest32::Digest32;
#[cfg(test)]
use proptest_derive::Arbitrary;

/// newtype for box ids
#[derive(PartialEq, Eq, Hash, Debug, Clone, Copy)]
#[derive(PartialEq, Eq, Hash, Debug, Clone)]
#[cfg_attr(feature = "with-serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "with-serde", serde(into = "String", try_from = "String"))]
#[cfg_attr(test, derive(Arbitrary))]
pub struct BoxId(pub [u8; BoxId::SIZE]);
pub struct BoxId(pub Digest32);

impl BoxId {
/// Size in bytes
pub const SIZE: usize = DIGEST32_SIZE;
pub const SIZE: usize = Digest32::SIZE;

/// All zeros
pub fn zero() -> BoxId {
BoxId([0u8; BoxId::SIZE])
BoxId(Digest32::zero())
}
}

impl Into<String> for BoxId {
fn into(self) -> String {
digest32::encode_base16(&self.0)
}
}

impl TryFrom<String> for BoxId {
type Error = digest32::Digest32DecodeError;
fn try_from(value: String) -> Result<Self, Self::Error> {
Ok(BoxId(digest32::decode_base16(value)?))
impl From<Digest32> for BoxId {
fn from(v: Digest32) -> Self {
BoxId(v)
}
}

impl SigmaSerializable for BoxId {
fn sigma_serialize<W: vlq_encode::WriteSigmaVlqExt>(&self, w: &mut W) -> Result<(), io::Error> {
w.write_all(&self.0)?;
self.0.sigma_serialize(w)?;
Ok(())
}
fn sigma_parse<R: vlq_encode::ReadSigmaVlqExt>(r: &mut R) -> Result<Self, SerializationError> {
let mut bytes = [0; DIGEST32_SIZE];
r.read_exact(&mut bytes)?;
Ok(Self(bytes))
Ok(Self(Digest32::sigma_parse(r)?.into()))
}
}

Expand Down
86 changes: 62 additions & 24 deletions sigma-tree/src/chain/digest32.rs
Original file line number Diff line number Diff line change
@@ -1,38 +1,76 @@
use std::convert::TryInto;
use crate::Base16DecodedBytes;
use crate::Base16EncodedBytes;
#[cfg(test)]
use proptest_derive::Arbitrary;
#[cfg(feature = "with-serde")]
use serde::{Deserialize, Serialize};
use sigma_ser::{
serializer::{SerializationError, SigmaSerializable},
vlq_encode,
};
use std::{
convert::{TryFrom, TryInto},
io,
};
use thiserror::Error;

/// Digest size 32 bytes
pub const DIGEST32_SIZE: usize = 32;
#[cfg_attr(feature = "with-serde", derive(Serialize, Deserialize))]
#[cfg_attr(
feature = "with-serde",
serde(into = "Base16EncodedBytes", try_from = "Base16DecodedBytes")
)]
#[derive(PartialEq, Eq, Hash, Debug, Clone)]
#[cfg_attr(test, derive(Arbitrary))]
pub struct Digest32(pub Box<[u8; Digest32::SIZE]>);

/// Errors when decoding Digest32 from Base16 encoded string
#[derive(Error, Debug)]
pub enum Digest32DecodeError {
/// Error on decoding from Base16
#[error("Base16 decoding error: {0}")]
Base16DecodeError(base16::DecodeError),
/// Invalid size of the decoded byte array
#[error("Invalid byte array size")]
InvalidSize,
impl Digest32 {
/// Digest size 32 bytes
pub const SIZE: usize = 32;

/// All zeros
pub fn zero() -> Digest32 {
Digest32(Box::new([0u8; Digest32::SIZE]))
}
}

impl From<base16::DecodeError> for Digest32DecodeError {
fn from(e: base16::DecodeError) -> Self {
Digest32DecodeError::Base16DecodeError(e)
impl From<[u8; Digest32::SIZE]> for Digest32 {
fn from(bytes: [u8; Digest32::SIZE]) -> Self {
Digest32(Box::new(bytes))
}
}

impl From<std::array::TryFromSliceError> for Digest32DecodeError {
fn from(_: std::array::TryFromSliceError) -> Self {
Digest32DecodeError::InvalidSize
impl Into<Base16EncodedBytes> for Digest32 {
fn into(self) -> Base16EncodedBytes {
Base16EncodedBytes::new(self.0.as_ref())
}
}

pub fn decode_base16(value: String) -> Result<[u8; DIGEST32_SIZE], Digest32DecodeError> {
let bytes = base16::decode(&value)?;
let arr: [u8; DIGEST32_SIZE] = bytes.as_slice().try_into()?;
Ok(arr)
impl TryFrom<Base16DecodedBytes> for Digest32 {
type Error = Digest32Error;
fn try_from(bytes: Base16DecodedBytes) -> Result<Self, Self::Error> {
let arr: [u8; Digest32::SIZE] = bytes.0.as_slice().try_into()?;
Ok(Digest32(Box::new(arr)))
}
}

pub fn encode_base16(value: &[u8; DIGEST32_SIZE]) -> String {
base16::encode_lower(value)
impl SigmaSerializable for Digest32 {
fn sigma_serialize<W: vlq_encode::WriteSigmaVlqExt>(&self, w: &mut W) -> Result<(), io::Error> {
w.write_all(self.0.as_ref())?;
Ok(())
}
fn sigma_parse<R: vlq_encode::ReadSigmaVlqExt>(r: &mut R) -> Result<Self, SerializationError> {
let mut bytes = [0; Digest32::SIZE];
r.read_exact(&mut bytes)?;
Ok(Self(bytes.into()))
}
}

#[derive(Error, Debug)]
#[error("Invalid byte array size ({0})")]
pub struct Digest32Error(std::array::TryFromSliceError);

impl From<std::array::TryFromSliceError> for Digest32Error {
fn from(err: std::array::TryFromSliceError) -> Self {
Digest32Error(err)
}
}
4 changes: 2 additions & 2 deletions sigma-tree/src/chain/ergo_box.rs
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ impl ErgoBox {

/// Box id (Blake2b256 hash of serialized box)
pub fn box_id(&self) -> BoxId {
self.box_id
self.box_id.clone()
}

/// Create ErgoBox from ErgoBoxCandidate by adding transaction id
Expand Down Expand Up @@ -249,7 +249,7 @@ impl ErgoBoxCandidate {
Some(digests) => {
let digest_index = r.get_u32()?;
match digests.get_index(digest_index as usize) {
Some(i) => Ok(*i),
Some(i) => Ok((*i).clone()),
None => Err(SerializationError::Misc(
"failed to find token id in tx digests".to_string(),
)),
Expand Down
3 changes: 2 additions & 1 deletion sigma-tree/src/chain/json.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@

mod base16_bytes;

pub use base16_bytes::Base16Bytes;
pub use base16_bytes::Base16DecodedBytes;
pub use base16_bytes::Base16EncodedBytes;

use serde::Serializer;

Expand Down
32 changes: 26 additions & 6 deletions sigma-tree/src/chain/json/base16_bytes.rs
Original file line number Diff line number Diff line change
@@ -1,23 +1,43 @@
//! Transitioning type for Base16 encoded bytes in JSON serialization

use core::fmt;
use serde::{Deserialize, Serialize};
use std::convert::TryFrom;

/// Transitioning type for Base16 encoded bytes
#[cfg_attr(feature = "with-serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "with-serde", serde(into = "String", try_from = "String"))]
#[cfg_attr(feature = "with-serde", serde(into = "String"))]
#[derive(PartialEq, Eq, Debug, Clone)]
pub struct Base16Bytes(pub Vec<u8>);
pub struct Base16EncodedBytes(String);

impl Into<String> for Base16Bytes {
impl Base16EncodedBytes {
/// Create from byte array ref (&[u8])
pub fn new<T: ?Sized + AsRef<[u8]>>(input: &T) -> Base16EncodedBytes {
Base16EncodedBytes(base16::encode_lower(input))
}
}

impl Into<String> for Base16EncodedBytes {
fn into(self) -> String {
base16::encode_lower(&self.0)
self.0
}
}

impl TryFrom<String> for Base16Bytes {
impl fmt::Display for Base16EncodedBytes {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_tuple("TokenId").field(&self.0).finish()
}
}

/// Transitioning type for Base16 decoded bytes
#[cfg_attr(feature = "with-serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "with-serde", serde(try_from = "String"))]
#[derive(PartialEq, Eq, Debug, Clone)]
pub struct Base16DecodedBytes(pub Vec<u8>);

impl TryFrom<String> for Base16DecodedBytes {
type Error = base16::DecodeError;
fn try_from(str: String) -> Result<Self, Self::Error> {
Ok(Base16Bytes(base16::decode(&str)?))
Ok(Base16DecodedBytes(base16::decode(&str)?))
}
}
49 changes: 20 additions & 29 deletions sigma-tree/src/chain/token.rs
Original file line number Diff line number Diff line change
@@ -1,59 +1,50 @@
//! Token related types

use core::fmt;
use sigma_ser::serializer::SerializationError;
use sigma_ser::serializer::SigmaSerializable;
use sigma_ser::vlq_encode;
use std::io;

/// token id size in bytes
pub const TOKEN_ID_SIZE: usize = crate::chain::digest32::DIGEST32_SIZE;

use super::digest32::Digest32;
#[cfg(test)]
use proptest_derive::Arbitrary;
#[cfg(feature = "with-serde")]
use serde::{Deserialize, Serialize};

/// newtype for token id
#[derive(PartialEq, Eq, Hash, Debug, Clone, Copy)]
#[derive(PartialEq, Eq, Hash, Debug, Clone)]
#[cfg_attr(test, derive(Arbitrary))]
#[cfg_attr(feature = "with-serde", derive(Serialize, Deserialize))]
pub struct TokenId(pub [u8; TOKEN_ID_SIZE]);
pub struct TokenId(pub Digest32);

impl TokenId {
/// token id size in bytes
pub const SIZE: usize = Digest32::SIZE;
}

impl SigmaSerializable for TokenId {
fn sigma_serialize<W: vlq_encode::WriteSigmaVlqExt>(&self, w: &mut W) -> Result<(), io::Error> {
self.0.sigma_serialize(w)?;
Ok(())
}
fn sigma_parse<R: vlq_encode::ReadSigmaVlqExt>(r: &mut R) -> Result<Self, SerializationError> {
Ok(Self(Digest32::sigma_parse(r)?.into()))
}
}

/// Token amount represented with token id paired with it's amount
#[derive(PartialEq, Eq, Debug, Clone)]
#[cfg_attr(test, derive(Arbitrary))]
#[cfg_attr(feature = "with-serde", derive(Serialize, Deserialize))]
pub struct TokenAmount {
/// token id
#[serde(rename = "tokenId")]
pub token_id: TokenId,
/// token amount
#[serde(rename = "amount")]
pub amount: u64,
}

impl fmt::Display for TokenId {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let mut bytes = io::Cursor::new(Vec::new());
let _ = self.sigma_serialize(&mut bytes);

f.debug_tuple("TokenId")
.field(&base16::encode_lower(bytes.get_ref()))
.finish()
}
}

impl SigmaSerializable for TokenId {
fn sigma_serialize<W: vlq_encode::WriteSigmaVlqExt>(&self, w: &mut W) -> Result<(), io::Error> {
w.write_all(&self.0)?;
Ok(())
}
fn sigma_parse<R: vlq_encode::ReadSigmaVlqExt>(r: &mut R) -> Result<Self, SerializationError> {
let mut bytes = [0; TOKEN_ID_SIZE];
r.read_exact(&mut bytes)?;
Ok(Self(bytes))
}
}

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

0 comments on commit 1ccfd20

Please sign in to comment.