parent
7fe00c6e22
commit
43c3cbd457
33 changed files with 402 additions and 450 deletions
|
|
@ -14,9 +14,8 @@ authors = [
|
|||
]
|
||||
|
||||
[dependencies]
|
||||
minicbor = { version = "0.14", features = ["std", "half"] }
|
||||
minicbor-derive = "0.9.0"
|
||||
hex = "0.4.3"
|
||||
log = "0.4.14"
|
||||
pallas-crypto = { version = "0.7.0-alpha.0", path = "../pallas-crypto" }
|
||||
pallas-codec = { version = "0.7.0-alpha.0", path = "../pallas-codec" }
|
||||
base58 = "0.2.0"
|
||||
|
|
|
|||
|
|
@ -2,12 +2,14 @@
|
|||
//!
|
||||
//! Handcrafted, idiomatic rust artifacts based on based on the [Alonzo CDDL](https://github.com/input-output-hk/cardano-ledger/blob/master/eras/alonzo/test-suite/cddl-files/alonzo.cddl) file in IOHK repo.
|
||||
|
||||
use minicbor::{bytes::ByteVec, data::Tag};
|
||||
use minicbor_derive::{Decode, Encode};
|
||||
use pallas_codec::minicbor::{bytes::ByteVec, data::Tag, Decode, Encode};
|
||||
use pallas_crypto::hash::Hash;
|
||||
use std::ops::Deref;
|
||||
|
||||
use crate::utils::{KeyValuePairs, MaybeIndefArray};
|
||||
use pallas_codec::utils::{KeyValuePairs, MaybeIndefArray};
|
||||
|
||||
// required for derive attrs to work
|
||||
use pallas_codec::minicbor;
|
||||
|
||||
#[derive(Encode, Decode, Debug, PartialEq, Clone)]
|
||||
pub struct VrfCert(#[n(0)] pub ByteVec, #[n(1)] pub ByteVec);
|
||||
|
|
@ -1263,7 +1265,7 @@ impl<'b> minicbor::Decode<'b> for Metadatum {
|
|||
}
|
||||
minicbor::data::Type::I64 => {
|
||||
let i = d.i64()?;
|
||||
Ok(Metadatum::Int(i as i64))
|
||||
Ok(Metadatum::Int(i))
|
||||
}
|
||||
minicbor::data::Type::Bytes => Ok(Metadatum::Bytes(d.decode()?)),
|
||||
minicbor::data::Type::String => Ok(Metadatum::Text(d.decode()?)),
|
||||
|
|
@ -1396,7 +1398,7 @@ pub struct BlockWrapper(#[n(0)] pub u16, #[n(1)] pub Block);
|
|||
mod tests {
|
||||
use super::BlockWrapper;
|
||||
use crate::Fragment;
|
||||
use minicbor::{self, to_vec};
|
||||
use pallas_codec::minicbor::to_vec;
|
||||
|
||||
#[test]
|
||||
fn block_isomorphic_decoding_encoding() {
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ use crate::Error;
|
|||
|
||||
use super::Address;
|
||||
use base58::ToBase58;
|
||||
use minicbor::to_vec;
|
||||
use pallas_codec::minicbor::to_vec;
|
||||
|
||||
impl Address {
|
||||
pub fn to_addr_string(&self) -> Result<String, Error> {
|
||||
|
|
@ -13,10 +13,9 @@ impl Address {
|
|||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::ops::Deref;
|
||||
|
||||
use crate::byron::Block;
|
||||
use crate::Fragment;
|
||||
use std::ops::Deref;
|
||||
|
||||
const KNOWN_ADDRESSES: &[&str] = &[
|
||||
"DdzFFzCqrht8QHTQXbWy2qoyPaqTN8BjyfKygGmpy9dtot1tvkBfCaVTnR22XCaaDVn3M1U6aiMShoCLzw6VWSwzQKhhJrM3YjYp3wyy",
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
use crate::Error;
|
||||
|
||||
use super::TxPayload;
|
||||
use minicbor::to_vec;
|
||||
use pallas_codec::minicbor::to_vec;
|
||||
|
||||
pub struct PolicyParams {
|
||||
constant: u64,
|
||||
|
|
|
|||
|
|
@ -2,15 +2,17 @@
|
|||
//!
|
||||
//! Handcrafted, idiomatic rust artifacts based on based on the [Byron CDDL](https://github.com/input-output-hk/cardano-ledger/blob/master/eras/byron/cddl-spec/byron.cddl) file in IOHK repo.
|
||||
|
||||
use minicbor::bytes::ByteVec;
|
||||
use minicbor_derive::{Decode, Encode};
|
||||
use pallas_codec::minicbor::{bytes::ByteVec, Decode, Encode};
|
||||
use pallas_crypto::hash::Hash;
|
||||
|
||||
use crate::utils::{
|
||||
use pallas_codec::utils::{
|
||||
CborWrap, EmptyMap, KeyValuePairs, MaybeIndefArray, OrderPreservingProperties, TagWrap,
|
||||
ZeroOrOneArray,
|
||||
};
|
||||
|
||||
// required for derive attrs to work
|
||||
use pallas_codec::minicbor;
|
||||
|
||||
// Basic Cardano Types
|
||||
|
||||
pub type Blake2b256 = Hash<32>;
|
||||
|
|
@ -957,7 +959,7 @@ mod tests {
|
|||
use crate::byron::{Block, BlockHead};
|
||||
use crate::Fragment;
|
||||
|
||||
use minicbor::{self, to_vec};
|
||||
use pallas_codec::minicbor::to_vec;
|
||||
|
||||
#[test]
|
||||
fn block_isomorphic_decoding_encoding() {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
pub type Error = Box<dyn std::error::Error>;
|
||||
|
||||
use pallas_codec::minicbor::{decode, to_vec, Decode, Encode};
|
||||
|
||||
pub trait Fragment<'a>
|
||||
where
|
||||
Self: Sized,
|
||||
|
|
@ -10,14 +12,14 @@ where
|
|||
|
||||
impl<'a, T> Fragment<'a> for T
|
||||
where
|
||||
T: minicbor::Encode + minicbor::Decode<'a> + Sized,
|
||||
T: Encode + Decode<'a> + Sized,
|
||||
{
|
||||
fn encode_fragment(&self) -> Result<Vec<u8>, Error> {
|
||||
minicbor::to_vec(self).map_err(|e| e.into())
|
||||
to_vec(self).map_err(|e| e.into())
|
||||
}
|
||||
|
||||
fn decode_fragment(bytes: &'a [u8]) -> Result<Self, Error> {
|
||||
minicbor::decode(bytes).map_err(|e| e.into())
|
||||
decode(bytes).map_err(|e| e.into())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -5,6 +5,5 @@ mod framework;
|
|||
pub mod alonzo;
|
||||
pub mod byron;
|
||||
pub mod probing;
|
||||
pub mod utils;
|
||||
|
||||
pub use framework::*;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
//! Heuristics for detecting cbor content without decoding
|
||||
|
||||
use minicbor::decode::{Token, Tokenizer};
|
||||
use pallas_codec::minicbor::decode::{Token, Tokenizer};
|
||||
|
||||
use crate::Era;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,378 +0,0 @@
|
|||
use std::ops::Deref;
|
||||
|
||||
use minicbor::{data::Tag, Decode, Encode};
|
||||
|
||||
/// Utility for skipping parts of the CBOR payload, use only for debugging
|
||||
#[derive(Debug, PartialEq, PartialOrd, Eq, Ord)]
|
||||
pub struct SkipCbor<const N: usize> {}
|
||||
|
||||
impl<'b, const N: usize> minicbor::Decode<'b> for SkipCbor<N> {
|
||||
fn decode(d: &mut minicbor::Decoder<'b>) -> Result<Self, minicbor::decode::Error> {
|
||||
{
|
||||
let probe = d.probe();
|
||||
log::warn!("skipped cbor value {}: {:?}", N, probe.datatype()?);
|
||||
println!("skipped cbor value {}: {:?}", N, probe.datatype()?);
|
||||
}
|
||||
|
||||
d.skip()?;
|
||||
Ok(SkipCbor {})
|
||||
}
|
||||
}
|
||||
|
||||
impl<const N: usize> minicbor::Encode for SkipCbor<N> {
|
||||
fn encode<W: minicbor::encode::Write>(
|
||||
&self,
|
||||
_e: &mut minicbor::Encoder<W>,
|
||||
) -> Result<(), minicbor::encode::Error<W::Error>> {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
/// Custom collection to ensure ordered pairs of values
|
||||
///
|
||||
/// Since the ordering of the entries requires a particular order to maintain
|
||||
/// canonicalization for isomorphic decoding / encoding operators, we use a Vec
|
||||
/// as the underlaying struct for storage of the items (as opposed to a BTreeMap
|
||||
/// or HashMap).
|
||||
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
|
||||
pub enum KeyValuePairs<K, V> {
|
||||
Def(Vec<(K, V)>),
|
||||
Indef(Vec<(K, V)>),
|
||||
}
|
||||
|
||||
impl<K, V> Deref for KeyValuePairs<K, V> {
|
||||
type Target = Vec<(K, V)>;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
match self {
|
||||
KeyValuePairs::Def(x) => x,
|
||||
KeyValuePairs::Indef(x) => x,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'b, K, V> minicbor::decode::Decode<'b> for KeyValuePairs<K, V>
|
||||
where
|
||||
K: Encode + Decode<'b>,
|
||||
V: Encode + Decode<'b>,
|
||||
{
|
||||
fn decode(d: &mut minicbor::Decoder<'b>) -> Result<Self, minicbor::decode::Error> {
|
||||
let datatype = d.datatype()?;
|
||||
|
||||
let items: Result<Vec<_>, _> = d.map_iter::<K, V>()?.collect();
|
||||
let items = items?;
|
||||
|
||||
match datatype {
|
||||
minicbor::data::Type::Map => Ok(KeyValuePairs::Def(items)),
|
||||
minicbor::data::Type::MapIndef => Ok(KeyValuePairs::Indef(items)),
|
||||
_ => Err(minicbor::decode::Error::message(
|
||||
"invalid data type for keyvaluepairs",
|
||||
)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<K, V> minicbor::encode::Encode for KeyValuePairs<K, V>
|
||||
where
|
||||
K: Encode,
|
||||
V: Encode,
|
||||
{
|
||||
fn encode<W: minicbor::encode::Write>(
|
||||
&self,
|
||||
e: &mut minicbor::Encoder<W>,
|
||||
) -> Result<(), minicbor::encode::Error<W::Error>> {
|
||||
match self {
|
||||
KeyValuePairs::Def(x) => {
|
||||
e.map(x.len() as u64)?;
|
||||
|
||||
for (k, v) in x.iter() {
|
||||
k.encode(e)?;
|
||||
v.encode(e)?;
|
||||
}
|
||||
}
|
||||
KeyValuePairs::Indef(x) => {
|
||||
e.begin_map()?;
|
||||
|
||||
for (k, v) in x.iter() {
|
||||
k.encode(e)?;
|
||||
v.encode(e)?;
|
||||
}
|
||||
|
||||
e.end()?;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// A struct that maintains a reference to whether a cbor array was indef or not
|
||||
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
|
||||
pub enum MaybeIndefArray<A> {
|
||||
Def(Vec<A>),
|
||||
Indef(Vec<A>),
|
||||
}
|
||||
|
||||
impl<A> Deref for MaybeIndefArray<A> {
|
||||
type Target = Vec<A>;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
match self {
|
||||
MaybeIndefArray::Def(x) => x,
|
||||
MaybeIndefArray::Indef(x) => x,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'b, A> minicbor::decode::Decode<'b> for MaybeIndefArray<A>
|
||||
where
|
||||
A: minicbor::decode::Decode<'b>,
|
||||
{
|
||||
fn decode(d: &mut minicbor::Decoder<'b>) -> Result<Self, minicbor::decode::Error> {
|
||||
let datatype = d.datatype()?;
|
||||
|
||||
match datatype {
|
||||
minicbor::data::Type::Array => Ok(Self::Def(d.decode()?)),
|
||||
minicbor::data::Type::ArrayIndef => Ok(Self::Indef(d.decode()?)),
|
||||
_ => Err(minicbor::decode::Error::message(
|
||||
"unknown data type of maybe indef array",
|
||||
)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<A> minicbor::encode::Encode for MaybeIndefArray<A>
|
||||
where
|
||||
A: minicbor::encode::Encode,
|
||||
{
|
||||
fn encode<W: minicbor::encode::Write>(
|
||||
&self,
|
||||
e: &mut minicbor::Encoder<W>,
|
||||
) -> Result<(), minicbor::encode::Error<W::Error>> {
|
||||
match self {
|
||||
MaybeIndefArray::Def(x) => {
|
||||
e.encode(x)?;
|
||||
}
|
||||
// TODO: this seemed necesary on alonzo, but breaks on byron. We need to double check.
|
||||
//MaybeIndefArray::Indef(x) if x.is_empty() => {
|
||||
// e.encode(x)?;
|
||||
//}
|
||||
MaybeIndefArray::Indef(x) => {
|
||||
e.begin_array()?;
|
||||
|
||||
for v in x.iter() {
|
||||
e.encode(v)?;
|
||||
}
|
||||
|
||||
e.end()?;
|
||||
}
|
||||
};
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// Order-preserving set of attributes
|
||||
///
|
||||
/// There's no guarantee that the entries on a Cardano cbor entity that uses
|
||||
/// maps for its representation will follow the canonical order specified by the
|
||||
/// standard. To implement an isomorphic codec, we need a way of preserving the
|
||||
/// original order in which the entries were encoded. To acomplish this, we
|
||||
/// transform key-value structures into an orderer vec of `properties`, where
|
||||
/// each entry represents a a cbor-encodable variant of an attribute of the
|
||||
/// struct.
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub struct OrderPreservingProperties<P>(Vec<P>);
|
||||
|
||||
impl<P> Deref for OrderPreservingProperties<P> {
|
||||
type Target = Vec<P>;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl<'b, P> minicbor::decode::Decode<'b> for OrderPreservingProperties<P>
|
||||
where
|
||||
P: Decode<'b>,
|
||||
{
|
||||
fn decode(d: &mut minicbor::Decoder<'b>) -> Result<Self, minicbor::decode::Error> {
|
||||
let len = d.map()?.unwrap_or_default();
|
||||
|
||||
let components: Result<_, _> = (0..len).map(|_| d.decode()).collect();
|
||||
|
||||
Ok(Self(components?))
|
||||
}
|
||||
}
|
||||
|
||||
impl<P> minicbor::encode::Encode for OrderPreservingProperties<P>
|
||||
where
|
||||
P: Encode,
|
||||
{
|
||||
fn encode<W: minicbor::encode::Write>(
|
||||
&self,
|
||||
e: &mut minicbor::Encoder<W>,
|
||||
) -> Result<(), minicbor::encode::Error<W::Error>> {
|
||||
e.map(self.0.len() as u64)?;
|
||||
for component in &self.0 {
|
||||
e.encode(component)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// Wraps a struct so that it is encoded/decoded as a cbor bytes
|
||||
#[derive(Debug)]
|
||||
pub struct CborWrap<T>(pub T);
|
||||
|
||||
impl<'b, T> minicbor::Decode<'b> for CborWrap<T>
|
||||
where
|
||||
T: minicbor::Decode<'b>,
|
||||
{
|
||||
fn decode(d: &mut minicbor::Decoder<'b>) -> Result<Self, minicbor::decode::Error> {
|
||||
d.tag()?;
|
||||
let cbor = d.bytes()?;
|
||||
let wrapped = minicbor::decode(cbor)?;
|
||||
|
||||
Ok(CborWrap(wrapped))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> minicbor::Encode for CborWrap<T>
|
||||
where
|
||||
T: minicbor::Encode,
|
||||
{
|
||||
fn encode<W: minicbor::encode::Write>(
|
||||
&self,
|
||||
e: &mut minicbor::Encoder<W>,
|
||||
) -> Result<(), minicbor::encode::Error<W::Error>> {
|
||||
let buf = minicbor::to_vec(&self.0).map_err(|_| {
|
||||
minicbor::encode::Error::message("error encoding cbor-wrapped structure")
|
||||
})?;
|
||||
|
||||
e.tag(Tag::Cbor)?;
|
||||
e.bytes(&buf)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Deref for CborWrap<T> {
|
||||
type Target = T;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct TagWrap<I, const T: u64>(I);
|
||||
|
||||
impl<'b, I, const T: u64> minicbor::Decode<'b> for TagWrap<I, T>
|
||||
where
|
||||
I: minicbor::Decode<'b>,
|
||||
{
|
||||
fn decode(d: &mut minicbor::Decoder<'b>) -> Result<Self, minicbor::decode::Error> {
|
||||
d.tag()?;
|
||||
|
||||
Ok(TagWrap(d.decode()?))
|
||||
}
|
||||
}
|
||||
|
||||
impl<I, const T: u64> minicbor::Encode for TagWrap<I, T>
|
||||
where
|
||||
I: minicbor::Encode,
|
||||
{
|
||||
fn encode<W: minicbor::encode::Write>(
|
||||
&self,
|
||||
e: &mut minicbor::Encoder<W>,
|
||||
) -> Result<(), minicbor::encode::Error<W::Error>> {
|
||||
e.tag(Tag::Unassigned(T))?;
|
||||
e.encode(&self.0)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// An empty map
|
||||
///
|
||||
/// don't ask me why, that's what the CDDL asks for.
|
||||
#[derive(Debug)]
|
||||
pub struct EmptyMap;
|
||||
|
||||
impl<'b> minicbor::decode::Decode<'b> for EmptyMap {
|
||||
fn decode(d: &mut minicbor::Decoder<'b>) -> Result<Self, minicbor::decode::Error> {
|
||||
d.skip()?;
|
||||
Ok(EmptyMap)
|
||||
}
|
||||
}
|
||||
|
||||
impl minicbor::encode::Encode for EmptyMap {
|
||||
fn encode<W: minicbor::encode::Write>(
|
||||
&self,
|
||||
e: &mut minicbor::Encoder<W>,
|
||||
) -> Result<(), minicbor::encode::Error<W::Error>> {
|
||||
e.map(0)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// An array with zero or one elements
|
||||
///
|
||||
/// A common pattern seen in the CDDL is to represent optional values as an
|
||||
/// array containing zero or more items. This structure reflects that pattern
|
||||
/// while providing semantic meaning.
|
||||
#[derive(Debug)]
|
||||
pub struct ZeroOrOneArray<T>(Option<T>);
|
||||
|
||||
impl<T> Deref for ZeroOrOneArray<T> {
|
||||
type Target = Option<T>;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl<'b, T> minicbor::decode::Decode<'b> for ZeroOrOneArray<T>
|
||||
where
|
||||
T: Decode<'b>,
|
||||
{
|
||||
fn decode(d: &mut minicbor::Decoder<'b>) -> Result<Self, minicbor::decode::Error> {
|
||||
let len = d.array()?;
|
||||
|
||||
match len {
|
||||
Some(0) => Ok(ZeroOrOneArray(None)),
|
||||
Some(1) => Ok(ZeroOrOneArray(Some(d.decode()?))),
|
||||
Some(_) => Err(minicbor::decode::Error::message(
|
||||
"found invalid len for zero-or-one pattern",
|
||||
)),
|
||||
None => Err(minicbor::decode::Error::message(
|
||||
"found invalid indefinite len array for zero-or-one pattern",
|
||||
)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> minicbor::encode::Encode for ZeroOrOneArray<T>
|
||||
where
|
||||
T: minicbor::Encode,
|
||||
{
|
||||
fn encode<W: minicbor::encode::Write>(
|
||||
&self,
|
||||
e: &mut minicbor::Encoder<W>,
|
||||
) -> Result<(), minicbor::encode::Error<W::Error>> {
|
||||
match &self.0 {
|
||||
Some(x) => {
|
||||
e.array(1)?;
|
||||
e.encode(x)?;
|
||||
}
|
||||
None => {
|
||||
e.array(0)?;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue