Skip to content

Commit

Permalink
Improvements to RGB structures serde serialization
Browse files Browse the repository at this point in the history
  • Loading branch information
dr-orlovsky committed Oct 11, 2020
1 parent d46973a commit 7b7284a
Show file tree
Hide file tree
Showing 8 changed files with 81 additions and 162 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@ v0.1.0-rc.2
### Other changes:
- Schema serialization
- More embedded procedures for RGB VM
- Serde serialization for all RGB structures
- Strict encoding and decoding of Curve25519 public keys and Ed25519 signatures
- Implementation of Curve25519 public keys and Ed25519 signatures as RGB state and metadata
- Bech types for Pedersen commitments, Bulletproofs, Curve25519 data

v0.1.0-rc.1
-----------
Expand Down
11 changes: 11 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 5 additions & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,8 @@ lnpbp_derive = { path = "derive" }
# ----------------------------------------------------
bitcoin = "~0.25.0"
bitcoin_hashes = "~0.9.0" # we need macro from here
# lightning = { version = "~0.0.11", optional = true }
# we need this until bitcoin will integrate this crate
bitcoin_num = { version = "~0.2.3", features = ["serde"], optional = true }
miniscript = "~2.0.0"
bech32 = "~0.7.2"
# Used only as a part of RGB for encoding Ed25519 key data (for instance as
Expand All @@ -53,7 +54,7 @@ ed25519-dalek = { version = "~1.0.0", optional = true }
# <https://github.com/rust-lang/api-guidelines/issues/180> for the explanation
# and references.
serde_crate = { package = "serde", version = "~1.0.106", features = ["derive"], optional = true }
serde_with = { version = "~1.5.0", optional = true }
serde_with = { version = "~1.5.1", optional = true, features = ["hex"] }
tokio = { version = "~0.2.18", features = ["tcp", "sync"], optional = true }
lazy_static = "~1.4.0"
# Networking deps
Expand Down Expand Up @@ -132,7 +133,8 @@ rgb = ["bulletproofs", "ed25519-dalek", "deflate", "inflate"]
# ----------------------------
# These also include re-assembly of necessary features from dependencies
async = ["async-trait", "amplify/async"]
serde = ["serde_crate", "serde_with", "bitcoin/use-serde", "miniscript/serde", "amplify/serde"]
serde = ["serde_crate", "serde_with", "bitcoin/use-serde", "bitcoin_num/serde",
"miniscript/serde", "amplify/serde"]
# Optional cryptographic functionality
# ------------------------------------
bulletproofs = ["grin_secp256k1zkp"] # Auto-required and used only by RGB
Expand Down
2 changes: 2 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@ extern crate async_trait;

#[cfg(feature = "serde")]
#[macro_use]
extern crate serde_with;
#[cfg(feature = "serde")]
extern crate serde_crate as serde;

// Bitcoin-specific imports. We make them public while we use custom versions
Expand Down
182 changes: 41 additions & 141 deletions src/rgb/contract/amount.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,21 @@ pub type Amount = u64;
pub type BlindingFactor = secp256k1zkp::key::SecretKey;

#[derive(Clone, PartialEq, Eq, Debug, Display, AsAny)]
#[cfg_attr(
feature = "serde",
derive(Serialize, Deserialize),
serde(crate = "serde_crate")
)]
#[display(Debug)]
pub struct Revealed {
pub amount: Amount,
#[cfg_attr(
feature = "serde",
serde(
serialize_with = "serde_helpers::to_hex",
deserialize_with = "serde_helpers::from_hex"
)
)]
pub blinding: BlindingFactor,
}

Expand Down Expand Up @@ -358,151 +370,39 @@ mod strict_encoding {
}
}

#[cfg(feature = "serde")]
mod serde_impl {
use super::*;
use core::fmt::{self, Formatter};
use serde::de::{self, Deserializer, MapAccess, SeqAccess, Visitor};
use serde::ser::{SerializeStruct, Serializer};
use serde::{Deserialize, Serialize};

impl Serialize for Revealed {
fn serialize<S>(
&self,
serializer: S,
) -> Result<<S as Serializer>::Ok, <S as Serializer>::Error>
where
S: Serializer,
{
let mut state =
serializer.serialize_struct("amount::Revealed", 2)?;
state.serialize_field("amount", &self.amount)?;
state.serialize_field("blinding", &self.blinding.0)?;
state.end()
}
}

impl<'de> Deserialize<'de> for Revealed {
fn deserialize<D>(
deserializer: D,
) -> Result<Self, <D as Deserializer<'de>>::Error>
where
D: Deserializer<'de>,
{
enum Field {
Amount,
Blinding,
};

impl<'de> Deserialize<'de> for Field {
fn deserialize<D>(deserializer: D) -> Result<Field, D::Error>
where
D: Deserializer<'de>,
{
struct FieldVisitor;

impl<'de> Visitor<'de> for FieldVisitor {
type Value = Field;

fn expecting(
&self,
formatter: &mut fmt::Formatter,
) -> fmt::Result {
formatter.write_str("`amount` or `blinding`")
}

fn visit_str<E>(self, value: &str) -> Result<Field, E>
where
E: de::Error,
{
match value {
"amount" => Ok(Field::Amount),
"blinding" => Ok(Field::Blinding),
_ => {
Err(de::Error::unknown_field(value, FIELDS))
}
}
}
}

deserializer.deserialize_identifier(FieldVisitor)
}
}

struct RevealedVisitor;
impl<'de> Visitor<'de> for RevealedVisitor {
type Value = Revealed;

fn expecting(
&self,
formatter: &mut Formatter<'_>,
) -> fmt::Result {
formatter.write_str("struct Revealed")
}
// TODO: Remove this once bitcion will adopt new bitcoin_num crate
pub(crate) mod serde_helpers {
//! Serde serialization helpers
fn visit_seq<A>(
self,
mut seq: A,
) -> Result<Self::Value, <A as SeqAccess<'de>>::Error>
where
A: SeqAccess<'de>,
{
Ok(Revealed {
amount: seq.next_element()?.ok_or_else(|| {
de::Error::invalid_length(0, &self)
})?,
blinding: seq.next_element()?.ok_or_else(|| {
de::Error::invalid_length(0, &self)
})?,
})
}
use bitcoin::hashes::hex::{FromHex, ToHex};
use serde::{Deserialize, Deserializer, Serializer};

fn visit_map<A>(
self,
mut map: A,
) -> Result<Self::Value, <A as MapAccess<'de>>::Error>
where
A: MapAccess<'de>,
{
let mut amount = None;
let mut blinding = None;
while let Some(key) = map.next_key()? {
match key {
Field::Amount => {
if amount.is_some() {
return Err(de::Error::duplicate_field(
"amount",
));
}
amount = Some(map.next_value()?);
}
Field::Blinding => {
if blinding.is_some() {
return Err(de::Error::duplicate_field(
"blinding",
));
}
blinding = Some(map.next_value()?);
}
}
}
let amount = amount
.ok_or_else(|| de::Error::missing_field("amount"))?;
let blinding =
secp256k1zkp::key::SecretKey(blinding.ok_or_else(
|| de::Error::missing_field("blinding"),
)?);
Ok(Revealed { amount, blinding })
}
}
/// Serializes `buffer` to a lowercase hex string.
pub fn to_hex<T, S>(buffer: &T, serializer: S) -> Result<S::Ok, S::Error>
where
T: AsRef<[u8]>,
S: Serializer,
{
serializer.serialize_str(&buffer.as_ref().to_hex())
}

const FIELDS: &'static [&'static str] = &["amount", "blinding"];
deserializer.deserialize_struct(
"amount::Revealed",
FIELDS,
RevealedVisitor,
/// Deserializes a lowercase hex string to a `Vec<u8>`.
pub fn from_hex<'de, D>(
deserializer: D,
) -> Result<secp256k1zkp::SecretKey, D::Error>
where
D: Deserializer<'de>,
{
use serde::de::Error;
String::deserialize(deserializer).and_then(|string| {
secp256k1zkp::SecretKey::from_slice(
&crate::rgb::contract::SECP256K1_ZKP,
&Vec::<u8>::from_hex(&string).map_err(|_| {
D::Error::custom("wrong hex data for SecretKey")
})?[..],
)
}
.map_err(|err| Error::custom(err.to_string()))
})
}
}

Expand Down
12 changes: 6 additions & 6 deletions src/rgb/schema/script.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ where
#[cfg_attr(
feature = "serde",
derive(Serialize, Deserialize),
serde(crate = "serde_crate")
serde(crate = "serde_crate", rename_all = "snake_case")
)]
#[display(Debug)]
pub enum GenesisAction {
Expand Down Expand Up @@ -73,7 +73,7 @@ impl Default for GenesisAction {
#[cfg_attr(
feature = "serde",
derive(Serialize, Deserialize),
serde(crate = "serde_crate")
serde(crate = "serde_crate", rename_all = "snake_case")
)]
#[display(Debug)]
pub enum ExtensionAction {
Expand Down Expand Up @@ -104,7 +104,7 @@ impl Default for ExtensionAction {
#[cfg_attr(
feature = "serde",
derive(Serialize, Deserialize),
serde(crate = "serde_crate")
serde(crate = "serde_crate", rename_all = "snake_case")
)]
#[display(Debug)]
#[repr(u16)]
Expand Down Expand Up @@ -136,7 +136,7 @@ impl Default for TransitionAction {
#[cfg_attr(
feature = "serde",
derive(Serialize, Deserialize),
serde(crate = "serde_crate")
serde(crate = "serde_crate", rename_all = "snake_case")
)]
#[display(Debug)]
#[repr(u16)]
Expand All @@ -160,7 +160,7 @@ pub type AssignmentAbi = BTreeMap<AssignmentAction, Procedure>;
#[cfg_attr(
feature = "serde",
derive(Serialize, Deserialize),
serde(crate = "serde_crate")
serde(crate = "serde_crate", rename_all = "snake_case")
)]
#[display(Debug)]
pub enum Procedure {
Expand All @@ -184,7 +184,7 @@ pub enum Procedure {
#[cfg_attr(
feature = "serde",
derive(Serialize, Deserialize),
serde(crate = "serde_crate")
serde(crate = "serde_crate", rename_all = "snake_case")
)]
#[display(Debug)]
#[repr(u8)]
Expand Down
8 changes: 4 additions & 4 deletions src/rgb/schema/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ pub struct StateSchema {
#[cfg_attr(
feature = "serde",
derive(Serialize, Deserialize),
serde(crate = "serde_crate")
serde(crate = "serde_crate", rename_all = "snake_case")
)]
#[non_exhaustive]
#[repr(u8)]
Expand All @@ -61,7 +61,7 @@ pub enum StateType {
#[cfg_attr(
feature = "serde",
derive(Serialize, Deserialize),
serde(crate = "serde_crate")
serde(crate = "serde_crate", rename_all = "snake_case")
)]
#[non_exhaustive]
#[display(Debug)]
Expand All @@ -75,7 +75,7 @@ pub enum StateFormat {
#[cfg_attr(
feature = "serde",
derive(Serialize, Deserialize),
serde(crate = "serde_crate")
serde(crate = "serde_crate", rename_all = "lowercase")
)]
#[display(Debug)]
#[non_exhaustive]
Expand All @@ -95,7 +95,7 @@ pub enum DiscreteFiniteFieldFormat {
#[cfg_attr(
feature = "serde",
derive(Serialize, Deserialize),
serde(crate = "serde_crate")
serde(crate = "serde_crate", rename_all = "lowercase")
)]
#[display(Debug)]
#[non_exhaustive]
Expand Down
Loading

0 comments on commit 7b7284a

Please sign in to comment.