refactor: Re-organize and clean-up pallas-primitives (#523)

* Re-organize and clean-up pallas-primitives

  Namely:

  - Move _common_ (i.e. era-independent) types and structures up to the
    `lib` module; to be shared across all eras. If any of those deviate
    in a subsequent era, it is easy to bring them down and define new
    types from the point of divergence onward. This simplifies the scope
    of each era-specific module and make them slightly easier to
    navigate.

    Note that, each era module still re-export all of the common types
    that's relevant to that particular era. So technically, this
    reorganization doesn't really change anything for callers/users of
    the library.

  - Rename `Scripthash` to `ScriptHash`. Before this commit, both
    actually existed as `ScriptHash` was introduced with the Conway era.
    Yet, they refer to the same thing, so the duplication is simply
    confusing.

  - Rename `One` / `Two` constructors for `NetworkId` to `Testnet` and
    `Mainnet` respectively. Also defined idiomatic `From` & `TryFrom`
    implementation for conversion to and from `u8`. This is a lot let
    confusing!

  - Generalize `PlutusScript` with a constant generic, to avoid
    repetition for each plutus script generated for specific version.
    Note that a distinction is still _necessary_ if we want to provie
    out-of-the-box serialisers for Plutus scripts, which are serialised
    with a tag prefix depending on the language. All else apart, they
    are strictly similar types.

  - Rename `CostMdls` to `CostModels`. Because, common.

  - Rename `plutus_script` to `plutus_v1_script` in the Alonzo's witness
    set, for consistency with other eras.

* Fix ordering of ScriptHash variants.

  This is an odd one. See the note.

* Bump minicbor to v0.25.1

* Add aliases with deprecation warnings to various fields and types.

* revert renaming plutus_script to plutus_v1_script in Alonzo witness

  See https://github.com/txpipe/pallas/pull/523#discussion_r1807329742
This commit is contained in:
Matthias Benkort 2024-10-22 13:57:21 +02:00 committed by GitHub
parent 4871342a8d
commit 969d5612b7
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
26 changed files with 972 additions and 1071 deletions

View file

@ -3,18 +3,17 @@
//! 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 serde::{Deserialize, Serialize};
use std::{fmt, hash::Hash as StdHash, ops::Deref};
use pallas_codec::minicbor::{data::Tag, Decode, Encode};
use pallas_crypto::hash::Hash;
use pallas_codec::minicbor::{self, data::Tag, Decode, Encode};
use pallas_codec::utils::{Bytes, Int, KeepRaw, KeyValuePairs, MaybeIndefArray, Nullable};
// required for derive attrs to work
use pallas_codec::minicbor;
#[derive(Serialize, Deserialize, Encode, Decode, Debug, PartialEq, Eq, Clone)]
pub struct VrfCert(#[n(0)] pub Bytes, #[n(1)] pub Bytes);
pub use crate::{
plutus_data::*, AddrKeyhash, AssetName, Bytes, Coin, CostModel, DatumHash, DnsName, Epoch,
ExUnitPrices, ExUnits, GenesisDelegateHash, Genesishash, Hash, IPv4, IPv6, Int, KeepRaw,
KeyValuePairs, MaybeIndefArray, Metadata, Metadatum, MetadatumLabel, NetworkId, Nonce,
NonceVariant, Nullable, PlutusScript, PolicyId, PoolKeyhash, PoolMetadata, PoolMetadataHash,
Port, PositiveInterval, ProtocolVersion, RationalNumber, Relay, RewardAccount, ScriptHash,
StakeCredential, TransactionIndex, TransactionInput, UnitInterval, VrfCert, VrfKeyhash,
};
#[derive(Serialize, Deserialize, Encode, Decode, Debug, PartialEq, Eq, Clone)]
pub struct HeaderBody {
@ -64,11 +63,6 @@ pub struct HeaderBody {
pub protocol_minor: u64,
}
pub type ProtocolVersion = (u64, u64);
#[derive(Serialize, Deserialize, Encode, Decode, Debug, PartialEq, Eq)]
pub struct KesSignature {}
pub type MintedHeaderBody<'a> = KeepRaw<'a, HeaderBody>;
#[derive(Serialize, Deserialize, Encode, Decode, Debug, PartialEq, Eq, Clone)]
@ -100,50 +94,10 @@ impl<'a> From<MintedHeaderBody<'a>> for HeaderBody {
}
}
#[derive(
Serialize, Deserialize, Encode, Decode, Debug, PartialEq, Eq, PartialOrd, Ord, Clone, StdHash,
)]
pub struct TransactionInput {
#[n(0)]
pub transaction_id: Hash<32>,
#[n(1)]
pub index: u64,
}
// $nonce /= [ 0 // 1, bytes .size 32 ]
#[derive(Serialize, Deserialize, Encode, Decode, Debug, PartialEq, Eq, Clone)]
#[cbor(index_only)]
pub enum NonceVariant {
#[n(0)]
NeutralNonce,
#[n(1)]
Nonce,
}
#[derive(Serialize, Deserialize, Encode, Decode, Debug, PartialEq, Eq, Clone)]
pub struct Nonce {
#[n(0)]
pub variant: NonceVariant,
#[n(1)]
pub hash: Option<Hash<32>>,
}
pub type ScriptHash = Hash<28>;
pub type PolicyId = Hash<28>;
pub type AssetName = Bytes;
pub type Multiasset<A> = KeyValuePairs<PolicyId, KeyValuePairs<AssetName, A>>;
pub type Mint = Multiasset<i64>;
pub type Coin = u64;
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
pub enum Value {
Coin(Coin),
@ -201,15 +155,9 @@ pub struct TransactionOutput {
pub amount: Value,
#[n(2)]
pub datum_hash: Option<Hash<32>>,
pub datum_hash: Option<DatumHash>,
}
pub type PoolKeyhash = Hash<28>;
pub type Epoch = u64;
pub type Genesishash = Bytes;
pub type GenesisDelegateHash = Bytes;
pub type VrfKeyhash = Hash<32>;
/* move_instantaneous_reward = [ 0 / 1, { * stake_credential => delta_coin } / coin ]
; The first field determines where the funds are drawn from.
; 0 denotes the reserves, 1 denotes the treasury.
@ -298,7 +246,7 @@ impl<C> minicbor::encode::Encode<C> for InstantaneousRewardTarget {
}
#[derive(Serialize, Deserialize, Encode, Decode, Debug, PartialEq, Eq, PartialOrd, Ord, Clone)]
#[cbor]
#[cbor()]
pub struct MoveInstantaneousReward {
#[n(0)]
pub source: InstantaneousRewardSource,
@ -307,180 +255,10 @@ pub struct MoveInstantaneousReward {
pub target: InstantaneousRewardTarget,
}
pub type RewardAccount = Bytes;
pub type Withdrawals = KeyValuePairs<RewardAccount, Coin>;
pub type RequiredSigners = Vec<AddrKeyhash>;
pub type Port = u32;
pub type IPv4 = Bytes;
pub type IPv6 = Bytes;
pub type DnsName = String;
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
pub enum Relay {
SingleHostAddr(Nullable<Port>, Nullable<IPv4>, Nullable<IPv6>),
SingleHostName(Nullable<Port>, DnsName),
MultiHostName(DnsName),
}
impl<'b, C> minicbor::decode::Decode<'b, C> for Relay {
fn decode(d: &mut minicbor::Decoder<'b>, ctx: &mut C) -> Result<Self, minicbor::decode::Error> {
d.array()?;
let variant = d.u16()?;
match variant {
0 => Ok(Relay::SingleHostAddr(
d.decode_with(ctx)?,
d.decode_with(ctx)?,
d.decode_with(ctx)?,
)),
1 => Ok(Relay::SingleHostName(
d.decode_with(ctx)?,
d.decode_with(ctx)?,
)),
2 => Ok(Relay::MultiHostName(d.decode_with(ctx)?)),
_ => Err(minicbor::decode::Error::message(
"invalid variant id for Relay",
)),
}
}
}
impl<C> minicbor::encode::Encode<C> for Relay {
fn encode<W: minicbor::encode::Write>(
&self,
e: &mut minicbor::Encoder<W>,
ctx: &mut C,
) -> Result<(), minicbor::encode::Error<W::Error>> {
match self {
Relay::SingleHostAddr(a, b, c) => {
e.array(4)?;
e.encode_with(0, ctx)?;
e.encode_with(a, ctx)?;
e.encode_with(b, ctx)?;
e.encode_with(c, ctx)?;
Ok(())
}
Relay::SingleHostName(a, b) => {
e.array(3)?;
e.encode_with(1, ctx)?;
e.encode_with(a, ctx)?;
e.encode_with(b, ctx)?;
Ok(())
}
Relay::MultiHostName(a) => {
e.array(2)?;
e.encode_with(2, ctx)?;
e.encode_with(a, ctx)?;
Ok(())
}
}
}
}
pub type PoolMetadataHash = Hash<32>;
#[derive(Serialize, Deserialize, Encode, Decode, Debug, PartialEq, Eq, Clone)]
pub struct PoolMetadata {
#[n(0)]
pub url: String,
#[n(1)]
pub hash: PoolMetadataHash,
}
pub type AddrKeyhash = Hash<28>;
pub type Scripthash = Hash<28>;
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
pub struct RationalNumber {
pub numerator: u64,
pub denominator: u64,
}
impl<'b, C> minicbor::decode::Decode<'b, C> for RationalNumber {
fn decode(d: &mut minicbor::Decoder<'b>, ctx: &mut C) -> Result<Self, minicbor::decode::Error> {
d.tag()?;
d.array()?;
Ok(RationalNumber {
numerator: d.decode_with(ctx)?,
denominator: d.decode_with(ctx)?,
})
}
}
impl<C> minicbor::encode::Encode<C> for RationalNumber {
fn encode<W: minicbor::encode::Write>(
&self,
e: &mut minicbor::Encoder<W>,
ctx: &mut C,
) -> Result<(), minicbor::encode::Error<W::Error>> {
// TODO: check if this is the correct tag
e.tag(Tag::Unassigned(30))?;
e.array(2)?;
e.encode_with(self.numerator, ctx)?;
e.encode_with(self.denominator, ctx)?;
Ok(())
}
}
pub type UnitInterval = RationalNumber;
pub type PositiveInterval = RationalNumber;
#[derive(Serialize, Deserialize, Debug, PartialEq, PartialOrd, Eq, Ord, Clone, Hash)]
pub enum StakeCredential {
AddrKeyhash(AddrKeyhash),
Scripthash(Scripthash),
}
impl<'b, C> minicbor::decode::Decode<'b, C> for StakeCredential {
fn decode(d: &mut minicbor::Decoder<'b>, ctx: &mut C) -> Result<Self, minicbor::decode::Error> {
d.array()?;
let variant = d.u16()?;
match variant {
0 => Ok(StakeCredential::AddrKeyhash(d.decode_with(ctx)?)),
1 => Ok(StakeCredential::Scripthash(d.decode_with(ctx)?)),
_ => Err(minicbor::decode::Error::message(
"invalid variant id for StakeCredential",
)),
}
}
}
impl<C> minicbor::encode::Encode<C> for StakeCredential {
fn encode<W: minicbor::encode::Write>(
&self,
e: &mut minicbor::Encoder<W>,
ctx: &mut C,
) -> Result<(), minicbor::encode::Error<W::Error>> {
match self {
StakeCredential::AddrKeyhash(a) => {
e.array(2)?;
e.encode_with(0, ctx)?;
e.encode_with(a, ctx)?;
Ok(())
}
StakeCredential::Scripthash(a) => {
e.array(2)?;
e.encode_with(1, ctx)?;
e.encode_with(a, ctx)?;
Ok(())
}
}
}
}
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
pub enum Certificate {
StakeRegistration(StakeCredential),
@ -649,17 +427,6 @@ impl<C> minicbor::encode::Encode<C> for Certificate {
}
}
#[derive(
Serialize, Deserialize, Encode, Decode, Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy,
)]
#[cbor(index_only)]
pub enum NetworkId {
#[n(0)]
One,
#[n(1)]
Two,
}
#[derive(Serialize, Deserialize, Encode, Decode, Debug, PartialEq, Eq, PartialOrd, Ord, Clone)]
#[cbor(index_only)]
pub enum Language {
@ -667,9 +434,10 @@ pub enum Language {
PlutusV1,
}
pub type CostModel = Vec<i64>;
#[deprecated(since = "0.31.0", note = "use `CostModels` instead")]
pub type CostMdls = CostModels;
pub type CostMdls = KeyValuePairs<Language, CostModel>;
pub type CostModels = KeyValuePairs<Language, CostModel>;
#[derive(Serialize, Deserialize, Encode, Decode, Debug, PartialEq, Eq, Clone)]
#[cbor(map)]
@ -709,7 +477,7 @@ pub struct ProtocolParamUpdate {
#[n(17)]
pub ada_per_utxo_byte: Option<Coin>,
#[n(18)]
pub cost_models_for_script_languages: Option<CostMdls>,
pub cost_models_for_script_languages: Option<CostModels>,
#[n(19)]
pub execution_costs: Option<ExUnitPrices>,
#[n(20)]
@ -862,380 +630,6 @@ impl<C> minicbor::encode::Encode<C> for NativeScript {
}
}
#[derive(Serialize, Deserialize, Encode, Decode, Debug, PartialEq, Eq, Clone)]
#[cbor(transparent)]
pub struct PlutusScript(#[n(0)] pub Bytes);
impl AsRef<[u8]> for PlutusScript {
fn as_ref(&self) -> &[u8] {
self.0.as_slice()
}
}
/// Defined to encode PlutusData bytestring as it is done in the canonical
/// plutus implementation
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
#[serde(into = "String")]
#[serde(try_from = "String")]
pub struct BoundedBytes(Vec<u8>);
impl From<Vec<u8>> for BoundedBytes {
fn from(xs: Vec<u8>) -> Self {
BoundedBytes(xs)
}
}
impl From<BoundedBytes> for Vec<u8> {
fn from(b: BoundedBytes) -> Self {
b.0
}
}
impl Deref for BoundedBytes {
type Target = Vec<u8>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl TryFrom<String> for BoundedBytes {
type Error = hex::FromHexError;
fn try_from(value: String) -> Result<Self, Self::Error> {
let v = hex::decode(value)?;
Ok(BoundedBytes(v))
}
}
impl From<BoundedBytes> for String {
fn from(b: BoundedBytes) -> Self {
hex::encode(b.deref())
}
}
impl fmt::Display for BoundedBytes {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let bytes: Vec<u8> = self.clone().into();
f.write_str(&hex::encode(bytes))
}
}
impl<C> Encode<C> for BoundedBytes {
fn encode<W: minicbor::encode::Write>(
&self,
e: &mut minicbor::Encoder<W>,
_: &mut C,
) -> Result<(), minicbor::encode::Error<W::Error>> {
// we match the haskell implementation by encoding bytestrings longer than 64
// bytes as indefinite lists of bytes
const CHUNK_SIZE: usize = 64;
let bs: &Vec<u8> = self.deref();
if bs.len() <= 64 {
e.bytes(bs)?;
} else {
e.begin_bytes()?;
for b in bs.chunks(CHUNK_SIZE) {
e.bytes(b)?;
}
e.end()?;
}
Ok(())
}
}
impl<'b, C> minicbor::decode::Decode<'b, C> for BoundedBytes {
fn decode(d: &mut minicbor::Decoder<'b>, _: &mut C) -> Result<Self, minicbor::decode::Error> {
let mut res = Vec::new();
for chunk in d.bytes_iter()? {
let bs = chunk?;
res.extend_from_slice(bs);
}
Ok(BoundedBytes::from(res))
}
}
/*
big_int = int / big_uint / big_nint ; New
big_uint = #6.2(bounded_bytes) ; New
big_nint = #6.3(bounded_bytes) ; New
*/
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, PartialOrd, Ord, Clone)]
pub enum BigInt {
Int(Int),
BigUInt(BoundedBytes),
BigNInt(BoundedBytes),
}
impl<'b, C> minicbor::decode::Decode<'b, C> for BigInt {
fn decode(d: &mut minicbor::Decoder<'b>, ctx: &mut C) -> Result<Self, minicbor::decode::Error> {
let datatype = d.datatype()?;
match datatype {
minicbor::data::Type::U8
| minicbor::data::Type::U16
| minicbor::data::Type::U32
| minicbor::data::Type::U64
| minicbor::data::Type::I8
| minicbor::data::Type::I16
| minicbor::data::Type::I32
| minicbor::data::Type::I64
| minicbor::data::Type::Int => Ok(Self::Int(d.decode_with(ctx)?)),
minicbor::data::Type::Tag => {
let tag = d.tag()?;
match tag {
minicbor::data::Tag::PosBignum => Ok(Self::BigUInt(d.decode_with(ctx)?)),
minicbor::data::Tag::NegBignum => Ok(Self::BigNInt(d.decode_with(ctx)?)),
_ => Err(minicbor::decode::Error::message(
"invalid cbor tag for big int",
)),
}
}
_ => Err(minicbor::decode::Error::message(
"invalid cbor data type for big int",
)),
}
}
}
impl<C> minicbor::encode::Encode<C> for BigInt {
fn encode<W: minicbor::encode::Write>(
&self,
e: &mut minicbor::Encoder<W>,
ctx: &mut C,
) -> Result<(), minicbor::encode::Error<W::Error>> {
match self {
BigInt::Int(x) => {
e.encode_with(x, ctx)?;
}
BigInt::BigUInt(x) => {
e.tag(Tag::PosBignum)?;
e.encode_with(x, ctx)?;
}
BigInt::BigNInt(x) => {
e.tag(Tag::NegBignum)?;
e.encode_with(x, ctx)?;
}
};
Ok(())
}
}
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, PartialOrd, Ord, Clone)]
pub enum PlutusData {
Constr(Constr<PlutusData>),
Map(KeyValuePairs<PlutusData, PlutusData>),
BigInt(BigInt),
BoundedBytes(BoundedBytes),
Array(Vec<PlutusData>),
}
impl<'b, C> minicbor::decode::Decode<'b, C> for PlutusData {
fn decode(d: &mut minicbor::Decoder<'b>, ctx: &mut C) -> Result<Self, minicbor::decode::Error> {
let type_ = d.datatype()?;
match type_ {
minicbor::data::Type::Tag => {
let mut probe = d.probe();
let tag = probe.tag()?;
match tag {
Tag::Unassigned(121..=127 | 1280..=1400 | 102) => {
Ok(Self::Constr(d.decode_with(ctx)?))
}
Tag::PosBignum | Tag::NegBignum => Ok(Self::BigInt(d.decode_with(ctx)?)),
_ => Err(minicbor::decode::Error::message(
"unknown tag for plutus data tag",
)),
}
}
minicbor::data::Type::U8
| minicbor::data::Type::U16
| minicbor::data::Type::U32
| minicbor::data::Type::U64
| minicbor::data::Type::I8
| minicbor::data::Type::I16
| minicbor::data::Type::I32
| minicbor::data::Type::I64
| minicbor::data::Type::Int => Ok(Self::BigInt(d.decode_with(ctx)?)),
minicbor::data::Type::Map | minicbor::data::Type::MapIndef => {
Ok(Self::Map(d.decode_with(ctx)?))
}
minicbor::data::Type::Bytes => Ok(Self::BoundedBytes(d.decode_with(ctx)?)),
minicbor::data::Type::BytesIndef => {
let mut full = Vec::new();
for slice in d.bytes_iter()? {
full.extend(slice?);
}
Ok(Self::BoundedBytes(BoundedBytes::from(full)))
}
minicbor::data::Type::Array | minicbor::data::Type::ArrayIndef => {
Ok(Self::Array(d.decode_with(ctx)?))
}
any => Err(minicbor::decode::Error::message(format!(
"bad cbor data type ({any:?}) for plutus data"
))),
}
}
}
fn encode_list<C, W: minicbor::encode::Write, A: minicbor::encode::Encode<C>>(
a: &Vec<A>,
e: &mut minicbor::Encoder<W>,
ctx: &mut C,
) -> Result<(), minicbor::encode::Error<W::Error>> {
// Mimics default haskell list encoding from cborg:
// We use indef array for non-empty arrays but definite 0-length array for empty
if a.is_empty() {
e.array(0)?;
} else {
e.begin_array()?;
for v in a {
e.encode_with(v, ctx)?;
}
e.end()?;
}
Ok(())
}
impl<C> minicbor::encode::Encode<C> for PlutusData {
fn encode<W: minicbor::encode::Write>(
&self,
e: &mut minicbor::Encoder<W>,
ctx: &mut C,
) -> Result<(), minicbor::encode::Error<W::Error>> {
match self {
Self::Constr(a) => {
e.encode_with(a, ctx)?;
}
Self::Map(a) => {
// we use definite array to match the approach used by haskell's plutus
// implementation https://github.com/input-output-hk/plutus/blob/9538fc9829426b2ecb0628d352e2d7af96ec8204/plutus-core/plutus-core/src/PlutusCore/Data.hs#L152
e.map(a.len().try_into().unwrap())?;
for (k, v) in a.iter() {
k.encode(e, ctx)?;
v.encode(e, ctx)?;
}
}
Self::BigInt(a) => {
e.encode_with(a, ctx)?;
}
Self::BoundedBytes(a) => {
e.encode_with(a, ctx)?;
}
Self::Array(a) => {
// we use definite array for empty array or indef array otherwise to match
// haskell implementation https://github.com/input-output-hk/plutus/blob/9538fc9829426b2ecb0628d352e2d7af96ec8204/plutus-core/plutus-core/src/PlutusCore/Data.hs#L153
// default encoder for a list:
// https://github.com/well-typed/cborg/blob/4bdc818a1f0b35f38bc118a87944630043b58384/serialise/src/Codec/Serialise/Class.hs#L181
encode_list(a, e, ctx)?;
}
};
Ok(())
}
}
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, PartialOrd, Ord, Clone)]
pub struct Constr<A> {
pub tag: u64,
pub any_constructor: Option<u64>,
pub fields: Vec<A>,
}
impl<'b, C, A> minicbor::decode::Decode<'b, C> for Constr<A>
where
A: minicbor::decode::Decode<'b, C>,
{
fn decode(d: &mut minicbor::Decoder<'b>, ctx: &mut C) -> Result<Self, minicbor::decode::Error> {
let tag = d.tag()?;
match tag {
Tag::Unassigned(x) => match x {
121..=127 | 1280..=1400 => Ok(Constr {
tag: x,
fields: d.decode_with(ctx)?,
any_constructor: None,
}),
102 => {
d.array()?;
Ok(Constr {
tag: x,
any_constructor: Some(d.decode_with(ctx)?),
fields: d.decode_with(ctx)?,
})
}
_ => Err(minicbor::decode::Error::message(
"bad tag code for plutus data",
)),
},
_ => Err(minicbor::decode::Error::message(
"bad tag code for plutus data",
)),
}
}
}
impl<C, A> minicbor::encode::Encode<C> for Constr<A>
where
A: minicbor::encode::Encode<C>,
{
fn encode<W: minicbor::encode::Write>(
&self,
e: &mut minicbor::Encoder<W>,
ctx: &mut C,
) -> Result<(), minicbor::encode::Error<W::Error>> {
e.tag(Tag::Unassigned(self.tag))?;
match self.tag {
102 => {
// definite length array here
// https://github.com/input-output-hk/plutus/blob/9538fc9829426b2ecb0628d352e2d7af96ec8204/plutus-core/plutus-core/src/PlutusCore/Data.hs#L152
e.array(2)?;
e.encode_with(self.any_constructor.unwrap_or_default(), ctx)?;
// we use definite array for empty array or indef array otherwise to match
// haskell implementation https://github.com/input-output-hk/plutus/blob/9538fc9829426b2ecb0628d352e2d7af96ec8204/plutus-core/plutus-core/src/PlutusCore/Data.hs#L144
// default encoder for a list:
// https://github.com/well-typed/cborg/blob/4bdc818a1f0b35f38bc118a87944630043b58384/serialise/src/Codec/Serialise/Class.hs#L181
encode_list(&self.fields, e, ctx)?;
Ok(())
}
_ => {
// we use definite array for empty array or indef array otherwise to match
// haskell implementation. See above reference.
encode_list(&self.fields, e, ctx)?;
Ok(())
}
}
}
}
#[derive(Serialize, Deserialize, Encode, Decode, Debug, PartialEq, Eq, Clone, Copy)]
pub struct ExUnits {
#[n(0)]
pub mem: u64,
#[n(1)]
pub steps: u64,
}
#[derive(Serialize, Deserialize, Encode, Decode, Debug, PartialEq, Eq, Clone)]
pub struct ExUnitPrices {
#[n(0)]
pub mem_price: PositiveInterval,
#[n(1)]
pub step_price: PositiveInterval,
}
#[derive(Serialize, Deserialize, Encode, Decode, Debug, PartialEq, Eq, Clone, Copy)]
#[cbor(index_only)]
pub enum RedeemerTag {
@ -1308,7 +702,7 @@ pub struct WitnessSet {
pub bootstrap_witness: Option<Vec<BootstrapWitness>>,
#[n(3)]
pub plutus_script: Option<Vec<PlutusScript>>,
pub plutus_script: Option<Vec<PlutusScript<1>>>,
#[n(4)]
pub plutus_data: Option<Vec<PlutusData>>,
@ -1330,7 +724,7 @@ pub struct MintedWitnessSet<'b> {
pub bootstrap_witness: Option<Vec<BootstrapWitness>>,
#[n(3)]
pub plutus_script: Option<Vec<PlutusScript>>,
pub plutus_script: Option<Vec<PlutusScript<1>>>,
#[b(4)]
pub plutus_data: Option<Vec<KeepRaw<'b, PlutusData>>>,
@ -1340,6 +734,7 @@ pub struct MintedWitnessSet<'b> {
}
impl<'b> From<MintedWitnessSet<'b>> for WitnessSet {
#[allow(deprecated)]
fn from(x: MintedWitnessSet<'b>) -> Self {
WitnessSet {
vkeywitness: x.vkeywitness,
@ -1366,80 +761,9 @@ pub struct PostAlonzoAuxiliaryData {
pub native_scripts: Option<Vec<NativeScript>>,
#[n(2)]
pub plutus_scripts: Option<Vec<PlutusScript>>,
pub plutus_scripts: Option<Vec<PlutusScript<1>>>,
}
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, PartialOrd, Ord, Clone)]
pub enum Metadatum {
Int(Int),
Bytes(Bytes),
Text(String),
Array(Vec<Metadatum>),
Map(KeyValuePairs<Metadatum, Metadatum>),
}
impl<'b, C> minicbor::Decode<'b, C> for Metadatum {
fn decode(d: &mut minicbor::Decoder<'b>, ctx: &mut C) -> Result<Self, minicbor::decode::Error> {
match d.datatype()? {
minicbor::data::Type::U8
| minicbor::data::Type::U16
| minicbor::data::Type::U32
| minicbor::data::Type::U64
| minicbor::data::Type::I8
| minicbor::data::Type::I16
| minicbor::data::Type::I32
| minicbor::data::Type::I64
| minicbor::data::Type::Int => {
let i = d.decode()?;
Ok(Metadatum::Int(i))
}
minicbor::data::Type::Bytes => Ok(Metadatum::Bytes(d.decode_with(ctx)?)),
minicbor::data::Type::String => Ok(Metadatum::Text(d.decode_with(ctx)?)),
minicbor::data::Type::Array | minicbor::data::Type::ArrayIndef => {
Ok(Metadatum::Array(d.decode_with(ctx)?))
}
minicbor::data::Type::Map | minicbor::data::Type::MapIndef => {
Ok(Metadatum::Map(d.decode_with(ctx)?))
}
_ => Err(minicbor::decode::Error::message(
"Can't turn data type into metadatum",
)),
}
}
}
impl<C> minicbor::Encode<C> for Metadatum {
fn encode<W: minicbor::encode::Write>(
&self,
e: &mut minicbor::Encoder<W>,
ctx: &mut C,
) -> Result<(), minicbor::encode::Error<W::Error>> {
match self {
Metadatum::Int(a) => {
e.encode_with(a, ctx)?;
}
Metadatum::Bytes(a) => {
e.encode_with(a, ctx)?;
}
Metadatum::Text(a) => {
e.encode_with(a, ctx)?;
}
Metadatum::Array(a) => {
e.encode_with(a, ctx)?;
}
Metadatum::Map(a) => {
e.encode_with(a, ctx)?;
}
};
Ok(())
}
}
pub type MetadatumLabel = u64;
pub type Metadata = KeyValuePairs<MetadatumLabel, Metadatum>;
#[derive(Serialize, Deserialize, Encode, Decode, Debug, PartialEq, Clone)]
pub struct ShelleyMaAuxiliaryData {
#[n(0)]
@ -1489,7 +813,7 @@ impl<C> minicbor::Encode<C> for AuxiliaryData {
}
AuxiliaryData::PostAlonzo(v) => {
// TODO: check if this is the correct tag
e.tag(Tag::Unassigned(259))?;
e.tag(Tag::new(259))?;
e.encode_with(v, ctx)?;
}
};
@ -1498,8 +822,6 @@ impl<C> minicbor::Encode<C> for AuxiliaryData {
}
}
pub type TransactionIndex = u32;
#[derive(Serialize, Deserialize, Encode, Decode, Debug, PartialEq, Clone)]
pub struct Block {
#[n(0)]

View file

@ -4,15 +4,19 @@
use serde::{Deserialize, Serialize};
use pallas_codec::minicbor::{Decode, Encode};
use pallas_codec::{
minicbor::{self, Decode, Encode},
utils::{Bytes, CborWrap, KeepRaw, KeyValuePairs, MaybeIndefArray, Nullable},
};
use pallas_crypto::hash::{Hash, Hasher};
use pallas_codec::utils::{Bytes, CborWrap, KeepRaw, KeyValuePairs, MaybeIndefArray, Nullable};
// required for derive attrs to work
use pallas_codec::minicbor;
use crate::alonzo::VrfCert;
pub use crate::{
plutus_data::*, AddrKeyhash, AssetName, DatumHash, DnsName, Epoch, ExUnitPrices, ExUnits,
GenesisDelegateHash, Genesishash, IPv4, IPv6, Metadata, Metadatum, MetadatumLabel, NetworkId,
Nonce, NonceVariant, PlutusScript, PolicyId, PoolKeyhash, PoolMetadata, PoolMetadataHash, Port,
PositiveInterval, ProtocolVersion, RationalNumber, Relay, ScriptHash, StakeCredential,
TransactionIndex, TransactionInput, UnitInterval, VrfCert, VrfKeyhash,
};
#[derive(Serialize, Deserialize, Encode, Decode, Debug, PartialEq, Eq, Clone)]
pub struct HeaderBody {
@ -62,10 +66,6 @@ pub struct OperationalCert {
pub operational_cert_sigma: Bytes,
}
pub use crate::alonzo::ProtocolVersion;
pub use crate::alonzo::KesSignature;
pub type MintedHeaderBody<'a> = KeepRaw<'a, HeaderBody>;
#[derive(Serialize, Deserialize, Encode, Decode, Debug, PartialEq, Eq, Clone)]
@ -97,18 +97,6 @@ impl<'a> From<MintedHeaderBody<'a>> for HeaderBody {
}
}
pub use crate::alonzo::TransactionInput;
pub use crate::alonzo::NonceVariant;
pub use crate::alonzo::Nonce;
pub use crate::alonzo::ScriptHash;
pub use crate::alonzo::PolicyId;
pub use crate::alonzo::AssetName;
pub use crate::alonzo::Multiasset;
pub use crate::alonzo::Mint;
@ -119,16 +107,6 @@ pub use crate::alonzo::Value;
pub use crate::alonzo::TransactionOutput as LegacyTransactionOutput;
pub use crate::alonzo::PoolKeyhash;
pub use crate::alonzo::Epoch;
pub use crate::alonzo::Genesishash;
pub use crate::alonzo::GenesisDelegateHash;
pub use crate::alonzo::VrfKeyhash;
pub use crate::alonzo::InstantaneousRewardSource;
pub use crate::alonzo::InstantaneousRewardTarget;
@ -137,40 +115,12 @@ pub use crate::alonzo::MoveInstantaneousReward;
pub use crate::alonzo::RewardAccount;
pub type Withdrawals = KeyValuePairs<RewardAccount, Coin>;
pub use crate::alonzo::Withdrawals;
pub type RequiredSigners = Vec<AddrKeyhash>;
pub use crate::alonzo::Port;
pub use crate::alonzo::IPv4;
pub use crate::alonzo::IPv6;
pub use crate::alonzo::DnsName;
pub use crate::alonzo::Relay;
pub use crate::alonzo::PoolMetadataHash;
pub use crate::alonzo::PoolMetadata;
pub use crate::alonzo::AddrKeyhash;
pub use crate::alonzo::Scripthash;
pub use crate::alonzo::RationalNumber;
pub use crate::alonzo::UnitInterval;
pub use crate::alonzo::PositiveInterval;
pub use crate::alonzo::StakeCredential;
pub use crate::alonzo::RequiredSigners;
pub use crate::alonzo::Certificate;
pub use crate::alonzo::NetworkId;
#[derive(Serialize, Deserialize, Encode, Decode, Debug, PartialEq, Eq, Clone)]
#[cbor(index_only)]
pub enum Language {
@ -181,11 +131,14 @@ pub enum Language {
PlutusV2,
}
#[deprecated(since = "0.31.0", note = "use `CostModels` instead")]
pub type CostMdls = CostModels;
pub use crate::alonzo::CostModel;
#[derive(Serialize, Deserialize, Encode, Decode, Debug, PartialEq, Eq, Clone)]
#[cbor(map)]
pub struct CostMdls {
pub struct CostModels {
#[n(0)]
pub plutus_v1: Option<CostModel>,
@ -228,7 +181,7 @@ pub struct ProtocolParamUpdate {
#[n(17)]
pub ada_per_utxo_byte: Option<Coin>,
#[n(18)]
pub cost_models_for_script_languages: Option<CostMdls>,
pub cost_models_for_script_languages: Option<CostModels>,
#[n(19)]
pub execution_costs: Option<ExUnitPrices>,
#[n(20)]
@ -455,28 +408,6 @@ pub use crate::alonzo::VKeyWitness;
pub use crate::alonzo::NativeScript;
pub use crate::alonzo::PlutusScript as PlutusV1Script;
#[derive(Serialize, Deserialize, Encode, Decode, Debug, PartialEq, Eq, Clone)]
#[cbor(transparent)]
pub struct PlutusV2Script(#[n(0)] pub Bytes);
impl AsRef<[u8]> for PlutusV2Script {
fn as_ref(&self) -> &[u8] {
self.0.as_slice()
}
}
pub use crate::alonzo::BigInt;
pub use crate::alonzo::PlutusData;
pub use crate::alonzo::Constr;
pub use crate::alonzo::ExUnits;
pub use crate::alonzo::ExUnitPrices;
pub use crate::alonzo::RedeemerTag;
pub use crate::alonzo::Redeemer;
@ -496,7 +427,7 @@ pub struct WitnessSet {
pub bootstrap_witness: Option<Vec<BootstrapWitness>>,
#[n(3)]
pub plutus_v1_script: Option<Vec<PlutusV1Script>>,
pub plutus_v1_script: Option<Vec<PlutusScript<1>>>,
#[n(4)]
pub plutus_data: Option<Vec<PlutusData>>,
@ -505,7 +436,7 @@ pub struct WitnessSet {
pub redeemer: Option<Vec<Redeemer>>,
#[n(6)]
pub plutus_v2_script: Option<Vec<PlutusV2Script>>,
pub plutus_v2_script: Option<Vec<PlutusScript<2>>>,
}
#[derive(Encode, Decode, Debug, PartialEq, Clone)]
@ -521,7 +452,7 @@ pub struct MintedWitnessSet<'b> {
pub bootstrap_witness: Option<Vec<BootstrapWitness>>,
#[n(3)]
pub plutus_v1_script: Option<Vec<PlutusV1Script>>,
pub plutus_v1_script: Option<Vec<PlutusScript<1>>>,
#[b(4)]
pub plutus_data: Option<Vec<KeepRaw<'b, PlutusData>>>,
@ -530,7 +461,7 @@ pub struct MintedWitnessSet<'b> {
pub redeemer: Option<Vec<Redeemer>>,
#[n(6)]
pub plutus_v2_script: Option<Vec<PlutusV2Script>>,
pub plutus_v2_script: Option<Vec<PlutusScript<2>>>,
}
impl<'b> From<MintedWitnessSet<'b>> for WitnessSet {
@ -561,20 +492,16 @@ pub struct PostAlonzoAuxiliaryData {
pub native_scripts: Option<Vec<NativeScript>>,
#[n(2)]
pub plutus_v1_scripts: Option<Vec<PlutusV1Script>>,
pub plutus_v1_scripts: Option<Vec<PlutusScript<1>>>,
#[n(3)]
pub plutus_v2_scripts: Option<Vec<PlutusV2Script>>,
pub plutus_v2_scripts: Option<Vec<PlutusScript<2>>>,
}
pub type DatumHash = Hash<32>;
//pub type Data = CborWrap<PlutusData>;
// datum_option = [ 0, $hash32 // 1, data ]
#[derive(Debug, PartialEq, Eq, Clone)]
pub enum PseudoDatumOption<T1> {
Hash(Hash<32>),
Hash(DatumHash),
Data(CborWrap<T1>),
}
@ -626,12 +553,18 @@ impl<'b> From<MintedDatumOption<'b>> for DatumOption {
}
}
#[deprecated(since = "0.31.0", note = "use `PlutusScript<1>` instead")]
pub type PlutusV1Script = PlutusScript<1>;
#[deprecated(since = "0.31.0", note = "use `PlutusScript<2>` instead")]
pub type PlutusV2Script = PlutusScript<2>;
// script = [ 0, native_script // 1, plutus_v1_script // 2, plutus_v2_script ]
#[derive(Debug, PartialEq, Eq, Clone)]
pub enum PseudoScript<T1> {
NativeScript(T1),
PlutusV1Script(PlutusV1Script),
PlutusV2Script(PlutusV2Script),
PlutusV1Script(PlutusScript<1>),
PlutusV2Script(PlutusScript<2>),
}
// script_ref = #6.24(bytes .cbor script)
@ -689,16 +622,8 @@ where
}
}
pub use crate::alonzo::Metadatum;
pub use crate::alonzo::MetadatumLabel;
pub use crate::alonzo::Metadata;
pub use crate::alonzo::AuxiliaryData;
pub use crate::alonzo::TransactionIndex;
#[derive(Serialize, Deserialize, Encode, Decode, Debug, PartialEq, Clone)]
pub struct PseudoBlock<T1, T2, T3, T4>
where

View file

@ -2,53 +2,34 @@
//!
//! Handcrafted, idiomatic rust artifacts based on based on the [Conway CDDL](https://github.com/IntersectMBO/cardano-ledger/blob/master/eras/conway/impl/cddl-files/conway.cddl) file in IntersectMBO repo.
use serde::{Deserialize, Serialize};
use std::ops::Deref;
use pallas_codec::minicbor::decode::Error;
use serde::{Deserialize, Serialize};
use pallas_codec::minicbor::{self, decode::Error, Decode, Encode};
use pallas_codec::utils::CborWrap;
use pallas_codec::minicbor::{Decode, Encode};
use pallas_crypto::hash::Hash;
use pallas_codec::utils::{
Bytes, CborWrap, KeepRaw, KeyValuePairs, MaybeIndefArray, NonEmptyKeyValuePairs, NonEmptySet,
NonZeroInt, Nullable, PositiveCoin, Set,
pub use crate::{
plutus_data::*, AddrKeyhash, AssetName, Bytes, Coin, CostModel, DnsName, Epoch, ExUnits,
GenesisDelegateHash, Genesishash, Hash, IPv4, IPv6, KeepRaw, KeyValuePairs, MaybeIndefArray,
Metadata, Metadatum, MetadatumLabel, NetworkId, NonEmptyKeyValuePairs, NonEmptySet, NonZeroInt,
Nonce, NonceVariant, Nullable, PlutusScript, PolicyId, PoolKeyhash, PoolMetadata,
PoolMetadataHash, Port, PositiveCoin, PositiveInterval, ProtocolVersion, RationalNumber, Relay,
RewardAccount, ScriptHash, Set, StakeCredential, TransactionIndex, TransactionInput,
UnitInterval, VrfCert, VrfKeyhash,
};
// required for derive attrs to work
use pallas_codec::minicbor;
pub use crate::alonzo::VrfCert;
use crate::babbage;
pub use crate::babbage::HeaderBody;
pub use crate::babbage::OperationalCert;
pub use crate::alonzo::ProtocolVersion;
pub use crate::alonzo::KesSignature;
pub use crate::babbage::Header;
pub use crate::alonzo::TransactionInput;
pub use crate::alonzo::NonceVariant;
pub use crate::alonzo::Nonce;
pub use crate::alonzo::ScriptHash;
pub use crate::alonzo::PolicyId;
pub use crate::alonzo::AssetName;
pub type Multiasset<A> = NonEmptyKeyValuePairs<PolicyId, NonEmptyKeyValuePairs<AssetName, A>>;
pub type Mint = Multiasset<NonZeroInt>;
pub use crate::alonzo::Coin;
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
pub enum Value {
Coin(Coin),
@ -99,54 +80,10 @@ impl<C> minicbor::encode::Encode<C> for Value {
pub use crate::alonzo::TransactionOutput as LegacyTransactionOutput;
pub use crate::alonzo::PoolKeyhash;
pub use crate::alonzo::Epoch;
pub use crate::alonzo::Genesishash;
pub use crate::alonzo::GenesisDelegateHash;
pub use crate::alonzo::VrfKeyhash;
pub use crate::alonzo::InstantaneousRewardSource;
pub use crate::alonzo::InstantaneousRewardTarget;
pub use crate::alonzo::MoveInstantaneousReward;
pub use crate::alonzo::RewardAccount;
pub type Withdrawals = NonEmptyKeyValuePairs<RewardAccount, Coin>;
pub type RequiredSigners = NonEmptySet<AddrKeyhash>;
pub use crate::alonzo::Port;
pub use crate::alonzo::IPv4;
pub use crate::alonzo::IPv6;
pub use crate::alonzo::DnsName;
pub use crate::alonzo::Relay;
pub use crate::alonzo::PoolMetadataHash;
pub use crate::alonzo::PoolMetadata;
pub use crate::alonzo::AddrKeyhash;
pub use crate::alonzo::Scripthash;
pub use crate::alonzo::RationalNumber;
pub use crate::alonzo::UnitInterval;
pub use crate::alonzo::PositiveInterval;
pub use crate::alonzo::StakeCredential;
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
pub enum Certificate {
StakeRegistration(StakeCredential),
@ -442,7 +379,7 @@ impl<C> minicbor::encode::Encode<C> for Certificate {
#[derive(Serialize, Deserialize, Debug, PartialEq, PartialOrd, Eq, Ord, Clone)]
pub enum DRep {
Key(AddrKeyhash),
Script(Scripthash),
Script(ScriptHash),
Abstain,
NoConfidence,
}
@ -507,8 +444,6 @@ pub type CommitteeColdCredential = StakeCredential;
pub type CommitteeHotCredential = StakeCredential;
pub use crate::alonzo::NetworkId;
#[derive(Serialize, Deserialize, Encode, Decode, Debug, PartialEq, Eq, Clone)]
#[cbor(index_only)]
pub enum Language {
@ -522,11 +457,12 @@ pub enum Language {
PlutusV3,
}
pub use crate::alonzo::CostModel;
#[deprecated(since = "0.31.0", note = "use `CostModels` instead")]
pub type CostMdls = CostModels;
#[derive(Serialize, Deserialize, Encode, Decode, Debug, PartialEq, Eq, Clone)]
#[cbor(map)]
pub struct CostMdls {
pub struct CostModels {
#[n(0)]
pub plutus_v1: Option<CostModel>,
@ -570,7 +506,7 @@ pub struct ProtocolParamUpdate {
#[n(17)]
pub ada_per_utxo_byte: Option<Coin>,
#[n(18)]
pub cost_models_for_script_languages: Option<CostMdls>,
pub cost_models_for_script_languages: Option<CostModels>,
#[n(19)]
pub execution_costs: Option<ExUnitPrices>,
#[n(20)]
@ -1285,28 +1221,6 @@ pub use crate::alonzo::VKeyWitness;
pub use crate::alonzo::NativeScript;
pub use crate::alonzo::PlutusScript as PlutusV1Script;
pub use crate::babbage::PlutusV2Script;
#[derive(Serialize, Deserialize, Encode, Decode, Debug, PartialEq, Eq, Clone)]
#[cbor(transparent)]
pub struct PlutusV3Script(#[n(0)] pub Bytes);
impl AsRef<[u8]> for PlutusV3Script {
fn as_ref(&self) -> &[u8] {
self.0.as_slice()
}
}
pub use crate::alonzo::BigInt;
pub use crate::alonzo::PlutusData;
pub use crate::alonzo::Constr;
pub use crate::alonzo::ExUnits;
#[derive(Serialize, Deserialize, Encode, Decode, Debug, PartialEq, Eq, Clone)]
pub struct ExUnitPrices {
#[n(0)]
@ -1446,7 +1360,7 @@ pub struct WitnessSet {
pub bootstrap_witness: Option<NonEmptySet<BootstrapWitness>>,
#[n(3)]
pub plutus_v1_script: Option<NonEmptySet<PlutusV1Script>>,
pub plutus_v1_script: Option<NonEmptySet<PlutusScript<1>>>,
#[n(4)]
pub plutus_data: Option<NonEmptySet<PlutusData>>,
@ -1455,10 +1369,10 @@ pub struct WitnessSet {
pub redeemer: Option<Redeemers>,
#[n(6)]
pub plutus_v2_script: Option<NonEmptySet<PlutusV2Script>>,
pub plutus_v2_script: Option<NonEmptySet<PlutusScript<2>>>,
#[n(7)]
pub plutus_v3_script: Option<NonEmptySet<PlutusV3Script>>,
pub plutus_v3_script: Option<NonEmptySet<PlutusScript<3>>>,
}
#[derive(Encode, Decode, Debug, PartialEq, Clone)]
@ -1474,7 +1388,7 @@ pub struct MintedWitnessSet<'b> {
pub bootstrap_witness: Option<NonEmptySet<BootstrapWitness>>,
#[n(3)]
pub plutus_v1_script: Option<NonEmptySet<PlutusV1Script>>,
pub plutus_v1_script: Option<NonEmptySet<PlutusScript<1>>>,
#[b(4)]
pub plutus_data: Option<NonEmptySet<KeepRaw<'b, PlutusData>>>,
@ -1483,10 +1397,10 @@ pub struct MintedWitnessSet<'b> {
pub redeemer: Option<KeepRaw<'b, Redeemers>>,
#[n(6)]
pub plutus_v2_script: Option<NonEmptySet<PlutusV2Script>>,
pub plutus_v2_script: Option<NonEmptySet<PlutusScript<2>>>,
#[n(7)]
pub plutus_v3_script: Option<NonEmptySet<PlutusV3Script>>,
pub plutus_v3_script: Option<NonEmptySet<PlutusScript<3>>>,
}
impl<'b> From<MintedWitnessSet<'b>> for WitnessSet {
@ -1514,13 +1428,13 @@ pub struct PostAlonzoAuxiliaryData {
pub native_scripts: Option<Vec<NativeScript>>,
#[n(2)]
pub plutus_v1_scripts: Option<Vec<PlutusV1Script>>,
pub plutus_v1_scripts: Option<Vec<PlutusScript<1>>>,
#[n(3)]
pub plutus_v2_scripts: Option<Vec<PlutusV2Script>>,
pub plutus_v2_scripts: Option<Vec<PlutusScript<2>>>,
#[n(4)]
pub plutus_v3_scripts: Option<Vec<PlutusV3Script>>,
pub plutus_v3_scripts: Option<Vec<PlutusScript<3>>>,
}
pub use crate::babbage::DatumHash;
@ -1531,13 +1445,22 @@ pub use crate::babbage::DatumOption;
pub use crate::babbage::MintedDatumOption;
#[deprecated(since = "0.31.0", note = "use `PlutusScript<1>` instead")]
pub type PlutusV1Script = PlutusScript<1>;
#[deprecated(since = "0.31.0", note = "use `PlutusScript<2>` instead")]
pub type PlutusV2Script = PlutusScript<2>;
#[deprecated(since = "0.31.0", note = "use `PlutusScript<3>` instead")]
pub type PlutusV3Script = PlutusScript<3>;
// script = [ 0, native_script // 1, plutus_v1_script // 2, plutus_v2_script ]
#[derive(Debug, PartialEq, Eq, Clone)]
pub enum PseudoScript<T1> {
NativeScript(T1),
PlutusV1Script(PlutusV1Script),
PlutusV2Script(PlutusV2Script),
PlutusV3Script(PlutusV3Script),
PlutusV1Script(PlutusScript<1>),
PlutusV2Script(PlutusScript<2>),
PlutusV3Script(PlutusScript<3>),
}
// script_ref = #6.24(bytes .cbor script)
@ -1610,15 +1533,8 @@ where
}
}
pub use crate::alonzo::Metadatum;
pub use crate::alonzo::MetadatumLabel;
pub use crate::alonzo::Metadata;
pub use crate::alonzo::AuxiliaryData;
pub use crate::alonzo::TransactionIndex;
use crate::babbage::MintedHeader;
#[derive(Serialize, Deserialize, Encode, Decode, Debug, PartialEq, Clone)]

View file

@ -1,10 +1,402 @@
//! Ledger primitives and cbor codec for the Cardano eras
mod framework;
mod plutus_data;
pub mod alonzo;
pub mod babbage;
pub mod byron;
pub mod conway;
pub use plutus_data::*;
pub use framework::*;
pub use pallas_codec::utils::{
Bytes, Int, KeepRaw, KeyValuePairs, MaybeIndefArray, NonEmptyKeyValuePairs, NonEmptySet,
NonZeroInt, Nullable, PositiveCoin, Set,
};
pub use pallas_crypto::hash::Hash;
use pallas_codec::minicbor::{self, data::Tag, Decode, Encode};
use serde::{Deserialize, Serialize};
// ----- Common type definitions
pub type AddrKeyhash = Hash<28>;
pub type AssetName = Bytes;
pub type Coin = u64;
pub type CostModel = Vec<i64>;
pub type DatumHash = Hash<32>;
pub type DnsName = String;
pub type Epoch = u64;
#[derive(Serialize, Deserialize, Encode, Decode, Debug, PartialEq, Eq, Clone, Copy)]
pub struct ExUnits {
#[n(0)]
pub mem: u64,
#[n(1)]
pub steps: u64,
}
#[derive(Serialize, Deserialize, Encode, Decode, Debug, PartialEq, Eq, Clone)]
pub struct ExUnitPrices {
#[n(0)]
pub mem_price: PositiveInterval,
#[n(1)]
pub step_price: PositiveInterval,
}
pub type Genesishash = Bytes;
pub type GenesisDelegateHash = Bytes;
pub type IPv4 = Bytes;
pub type IPv6 = Bytes;
pub type Metadata = KeyValuePairs<MetadatumLabel, Metadatum>;
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, PartialOrd, Ord, Clone)]
pub enum Metadatum {
Int(Int),
Bytes(Bytes),
Text(String),
Array(Vec<Metadatum>),
Map(KeyValuePairs<Metadatum, Metadatum>),
}
impl<'b, C> minicbor::Decode<'b, C> for Metadatum {
fn decode(d: &mut minicbor::Decoder<'b>, ctx: &mut C) -> Result<Self, minicbor::decode::Error> {
match d.datatype()? {
minicbor::data::Type::U8
| minicbor::data::Type::U16
| minicbor::data::Type::U32
| minicbor::data::Type::U64
| minicbor::data::Type::I8
| minicbor::data::Type::I16
| minicbor::data::Type::I32
| minicbor::data::Type::I64
| minicbor::data::Type::Int => {
let i = d.decode()?;
Ok(Metadatum::Int(i))
}
minicbor::data::Type::Bytes => Ok(Metadatum::Bytes(d.decode_with(ctx)?)),
minicbor::data::Type::String => Ok(Metadatum::Text(d.decode_with(ctx)?)),
minicbor::data::Type::Array | minicbor::data::Type::ArrayIndef => {
Ok(Metadatum::Array(d.decode_with(ctx)?))
}
minicbor::data::Type::Map | minicbor::data::Type::MapIndef => {
Ok(Metadatum::Map(d.decode_with(ctx)?))
}
_ => Err(minicbor::decode::Error::message(
"Can't turn data type into metadatum",
)),
}
}
}
impl<C> minicbor::Encode<C> for Metadatum {
fn encode<W: minicbor::encode::Write>(
&self,
e: &mut minicbor::Encoder<W>,
ctx: &mut C,
) -> Result<(), minicbor::encode::Error<W::Error>> {
match self {
Metadatum::Int(a) => {
e.encode_with(a, ctx)?;
}
Metadatum::Bytes(a) => {
e.encode_with(a, ctx)?;
}
Metadatum::Text(a) => {
e.encode_with(a, ctx)?;
}
Metadatum::Array(a) => {
e.encode_with(a, ctx)?;
}
Metadatum::Map(a) => {
e.encode_with(a, ctx)?;
}
};
Ok(())
}
}
pub type MetadatumLabel = u64;
#[derive(
Serialize, Deserialize, Encode, Decode, Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy,
)]
#[cbor(index_only)]
pub enum NetworkId {
#[n(0)]
Testnet,
#[n(1)]
Mainnet,
}
impl From<NetworkId> for u8 {
fn from(network_id: NetworkId) -> u8 {
match network_id {
NetworkId::Testnet => 0,
NetworkId::Mainnet => 1,
}
}
}
impl TryFrom<u8> for NetworkId {
type Error = ();
fn try_from(i: u8) -> Result<Self, Self::Error> {
match i {
0 => Ok(Self::Testnet),
1 => Ok(Self::Mainnet),
_ => Err(()),
}
}
}
#[derive(Serialize, Deserialize, Encode, Decode, Debug, PartialEq, Eq, Clone)]
pub struct Nonce {
#[n(0)]
pub variant: NonceVariant,
#[n(1)]
pub hash: Option<Hash<32>>,
}
#[derive(Serialize, Deserialize, Encode, Decode, Debug, PartialEq, Eq, Clone)]
#[cbor(index_only)]
pub enum NonceVariant {
#[n(0)]
NeutralNonce,
#[n(1)]
Nonce,
}
#[derive(Serialize, Deserialize, Encode, Decode, Debug, PartialEq, Eq, Clone)]
#[cbor(transparent)]
pub struct PlutusScript<const VERSION: usize>(#[n(0)] pub Bytes);
impl<const VERSION: usize> AsRef<[u8]> for PlutusScript<VERSION> {
fn as_ref(&self) -> &[u8] {
self.0.as_slice()
}
}
pub type PolicyId = Hash<28>;
pub type PoolKeyhash = Hash<28>;
#[derive(Serialize, Deserialize, Encode, Decode, Debug, PartialEq, Eq, Clone)]
pub struct PoolMetadata {
#[n(0)]
pub url: String,
#[n(1)]
pub hash: PoolMetadataHash,
}
pub type PoolMetadataHash = Hash<32>;
pub type Port = u32;
pub type PositiveInterval = RationalNumber;
pub type ProtocolVersion = (u64, u64);
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
pub struct RationalNumber {
pub numerator: u64,
pub denominator: u64,
}
impl<'b, C> minicbor::decode::Decode<'b, C> for RationalNumber {
fn decode(d: &mut minicbor::Decoder<'b>, ctx: &mut C) -> Result<Self, minicbor::decode::Error> {
// TODO: Enforce tag == 30 & array of size 2
d.tag()?;
d.array()?;
Ok(RationalNumber {
numerator: d.decode_with(ctx)?,
denominator: d.decode_with(ctx)?,
})
}
}
impl<C> minicbor::encode::Encode<C> for RationalNumber {
fn encode<W: minicbor::encode::Write>(
&self,
e: &mut minicbor::Encoder<W>,
ctx: &mut C,
) -> Result<(), minicbor::encode::Error<W::Error>> {
e.tag(Tag::new(30))?;
e.array(2)?;
e.encode_with(self.numerator, ctx)?;
e.encode_with(self.denominator, ctx)?;
Ok(())
}
}
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
pub enum Relay {
SingleHostAddr(Nullable<Port>, Nullable<IPv4>, Nullable<IPv6>),
SingleHostName(Nullable<Port>, DnsName),
MultiHostName(DnsName),
}
impl<'b, C> minicbor::decode::Decode<'b, C> for Relay {
fn decode(d: &mut minicbor::Decoder<'b>, ctx: &mut C) -> Result<Self, minicbor::decode::Error> {
d.array()?;
let variant = d.u16()?;
match variant {
0 => Ok(Relay::SingleHostAddr(
d.decode_with(ctx)?,
d.decode_with(ctx)?,
d.decode_with(ctx)?,
)),
1 => Ok(Relay::SingleHostName(
d.decode_with(ctx)?,
d.decode_with(ctx)?,
)),
2 => Ok(Relay::MultiHostName(d.decode_with(ctx)?)),
_ => Err(minicbor::decode::Error::message(
"invalid variant id for Relay",
)),
}
}
}
impl<C> minicbor::encode::Encode<C> for Relay {
fn encode<W: minicbor::encode::Write>(
&self,
e: &mut minicbor::Encoder<W>,
ctx: &mut C,
) -> Result<(), minicbor::encode::Error<W::Error>> {
match self {
Relay::SingleHostAddr(a, b, c) => {
e.array(4)?;
e.encode_with(0, ctx)?;
e.encode_with(a, ctx)?;
e.encode_with(b, ctx)?;
e.encode_with(c, ctx)?;
Ok(())
}
Relay::SingleHostName(a, b) => {
e.array(3)?;
e.encode_with(1, ctx)?;
e.encode_with(a, ctx)?;
e.encode_with(b, ctx)?;
Ok(())
}
Relay::MultiHostName(a) => {
e.array(2)?;
e.encode_with(2, ctx)?;
e.encode_with(a, ctx)?;
Ok(())
}
}
}
}
pub type RewardAccount = Bytes;
pub type ScriptHash = Hash<28>;
#[derive(Serialize, Deserialize, Debug, PartialEq, PartialOrd, Eq, Ord, Clone, Hash)]
// !! NOTE / IMPORTANT !!
// It is tempting to swap the order of the two constructors so that AddrKeyHash
// comes first. This indeed nicely maps the binary representation which
// associates 0 to AddrKeyHash and 1 to ScriptHash.
//
// However, for historical reasons, the ScriptHash variant comes first in the
// Haskell reference codebase. From this ordering is derived the `PartialOrd`
// and `Ord` instances; which impacts how Maps/Dictionnaries indexed by
// StakeCredential will be ordered. So, it is crucial to preserve this quirks to
// avoid hard to troubleshoot issues down the line.
pub enum StakeCredential {
ScriptHash(ScriptHash),
AddrKeyhash(AddrKeyhash),
}
impl<'b, C> minicbor::decode::Decode<'b, C> for StakeCredential {
fn decode(d: &mut minicbor::Decoder<'b>, ctx: &mut C) -> Result<Self, minicbor::decode::Error> {
d.array()?;
let variant = d.u16()?;
match variant {
0 => Ok(StakeCredential::AddrKeyhash(d.decode_with(ctx)?)),
1 => Ok(StakeCredential::ScriptHash(d.decode_with(ctx)?)),
_ => Err(minicbor::decode::Error::message(
"invalid variant id for StakeCredential",
)),
}
}
}
impl<C> minicbor::encode::Encode<C> for StakeCredential {
fn encode<W: minicbor::encode::Write>(
&self,
e: &mut minicbor::Encoder<W>,
ctx: &mut C,
) -> Result<(), minicbor::encode::Error<W::Error>> {
match self {
StakeCredential::AddrKeyhash(a) => {
e.array(2)?;
e.encode_with(0, ctx)?;
e.encode_with(a, ctx)?;
Ok(())
}
StakeCredential::ScriptHash(a) => {
e.array(2)?;
e.encode_with(1, ctx)?;
e.encode_with(a, ctx)?;
Ok(())
}
}
}
}
pub type TransactionIndex = u32;
#[derive(
Serialize,
Deserialize,
Encode,
Decode,
Debug,
PartialEq,
Eq,
PartialOrd,
Ord,
Clone,
std::hash::Hash,
)]
pub struct TransactionInput {
#[n(0)]
pub transaction_id: Hash<32>,
#[n(1)]
pub index: u64,
}
pub type UnitInterval = RationalNumber;
#[derive(Serialize, Deserialize, Encode, Decode, Debug, PartialEq, Eq, Clone)]
pub struct VrfCert(#[n(0)] pub Bytes, #[n(1)] pub Bytes);
pub type VrfKeyhash = Hash<32>;

View file

@ -0,0 +1,353 @@
use crate::KeyValuePairs;
use pallas_codec::minicbor::{
self,
data::{IanaTag, Tag},
Encode,
};
use pallas_codec::utils::Int;
use serde::{Deserialize, Serialize};
use std::{fmt, ops::Deref};
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, PartialOrd, Ord, Clone)]
pub enum PlutusData {
Constr(Constr<PlutusData>),
Map(KeyValuePairs<PlutusData, PlutusData>),
BigInt(BigInt),
BoundedBytes(BoundedBytes),
Array(Vec<PlutusData>),
}
impl<'b, C> minicbor::decode::Decode<'b, C> for PlutusData {
fn decode(d: &mut minicbor::Decoder<'b>, ctx: &mut C) -> Result<Self, minicbor::decode::Error> {
let type_ = d.datatype()?;
match type_ {
minicbor::data::Type::Tag => {
let mut probe = d.probe();
let tag = probe.tag()?;
if tag == IanaTag::PosBignum.tag() || tag == IanaTag::NegBignum.tag() {
Ok(Self::BigInt(d.decode_with(ctx)?))
} else {
match tag.as_u64() {
(121..=127) | (1280..=1400) | 102 => Ok(Self::Constr(d.decode_with(ctx)?)),
_ => Err(minicbor::decode::Error::message(
"unknown tag for plutus data tag",
)),
}
}
}
minicbor::data::Type::U8
| minicbor::data::Type::U16
| minicbor::data::Type::U32
| minicbor::data::Type::U64
| minicbor::data::Type::I8
| minicbor::data::Type::I16
| minicbor::data::Type::I32
| minicbor::data::Type::I64
| minicbor::data::Type::Int => Ok(Self::BigInt(d.decode_with(ctx)?)),
minicbor::data::Type::Map | minicbor::data::Type::MapIndef => {
Ok(Self::Map(d.decode_with(ctx)?))
}
minicbor::data::Type::Bytes => Ok(Self::BoundedBytes(d.decode_with(ctx)?)),
minicbor::data::Type::BytesIndef => {
let mut full = Vec::new();
for slice in d.bytes_iter()? {
full.extend(slice?);
}
Ok(Self::BoundedBytes(BoundedBytes::from(full)))
}
minicbor::data::Type::Array | minicbor::data::Type::ArrayIndef => {
Ok(Self::Array(d.decode_with(ctx)?))
}
any => Err(minicbor::decode::Error::message(format!(
"bad cbor data type ({any:?}) for plutus data"
))),
}
}
}
impl<C> minicbor::encode::Encode<C> for PlutusData {
fn encode<W: minicbor::encode::Write>(
&self,
e: &mut minicbor::Encoder<W>,
ctx: &mut C,
) -> Result<(), minicbor::encode::Error<W::Error>> {
match self {
Self::Constr(a) => {
e.encode_with(a, ctx)?;
}
Self::Map(a) => {
// we use definite array to match the approach used by haskell's plutus
// implementation https://github.com/input-output-hk/plutus/blob/9538fc9829426b2ecb0628d352e2d7af96ec8204/plutus-core/plutus-core/src/PlutusCore/Data.hs#L152
e.map(a.len().try_into().unwrap())?;
for (k, v) in a.iter() {
k.encode(e, ctx)?;
v.encode(e, ctx)?;
}
}
Self::BigInt(a) => {
e.encode_with(a, ctx)?;
}
Self::BoundedBytes(a) => {
e.encode_with(a, ctx)?;
}
Self::Array(a) => {
// we use definite array for empty array or indef array otherwise to match
// haskell implementation https://github.com/input-output-hk/plutus/blob/9538fc9829426b2ecb0628d352e2d7af96ec8204/plutus-core/plutus-core/src/PlutusCore/Data.hs#L153
// default encoder for a list:
// https://github.com/well-typed/cborg/blob/4bdc818a1f0b35f38bc118a87944630043b58384/serialise/src/Codec/Serialise/Class.hs#L181
encode_list(a, e, ctx)?;
}
};
Ok(())
}
}
/*
big_int = int / big_uint / big_nint ; New
big_uint = #6.2(bounded_bytes) ; New
big_nint = #6.3(bounded_bytes) ; New
*/
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, PartialOrd, Ord, Clone)]
pub enum BigInt {
Int(Int),
BigUInt(BoundedBytes),
BigNInt(BoundedBytes),
}
impl<'b, C> minicbor::decode::Decode<'b, C> for BigInt {
fn decode(d: &mut minicbor::Decoder<'b>, ctx: &mut C) -> Result<Self, minicbor::decode::Error> {
let datatype = d.datatype()?;
match datatype {
minicbor::data::Type::U8
| minicbor::data::Type::U16
| minicbor::data::Type::U32
| minicbor::data::Type::U64
| minicbor::data::Type::I8
| minicbor::data::Type::I16
| minicbor::data::Type::I32
| minicbor::data::Type::I64
| minicbor::data::Type::Int => Ok(Self::Int(d.decode_with(ctx)?)),
minicbor::data::Type::Tag => {
let tag = d.tag()?;
if tag == IanaTag::PosBignum.tag() {
Ok(Self::BigUInt(d.decode_with(ctx)?))
} else if tag == IanaTag::NegBignum.tag() {
Ok(Self::BigNInt(d.decode_with(ctx)?))
} else {
Err(minicbor::decode::Error::message(
"invalid cbor tag for big int",
))
}
}
_ => Err(minicbor::decode::Error::message(
"invalid cbor data type for big int",
)),
}
}
}
impl<C> minicbor::encode::Encode<C> for BigInt {
fn encode<W: minicbor::encode::Write>(
&self,
e: &mut minicbor::Encoder<W>,
ctx: &mut C,
) -> Result<(), minicbor::encode::Error<W::Error>> {
match self {
BigInt::Int(x) => {
e.encode_with(x, ctx)?;
}
BigInt::BigUInt(x) => {
e.tag(IanaTag::PosBignum)?;
e.encode_with(x, ctx)?;
}
BigInt::BigNInt(x) => {
e.tag(IanaTag::NegBignum)?;
e.encode_with(x, ctx)?;
}
};
Ok(())
}
}
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, PartialOrd, Ord, Clone)]
pub struct Constr<A> {
pub tag: u64,
pub any_constructor: Option<u64>,
pub fields: Vec<A>,
}
impl<'b, C, A> minicbor::decode::Decode<'b, C> for Constr<A>
where
A: minicbor::decode::Decode<'b, C>,
{
fn decode(d: &mut minicbor::Decoder<'b>, ctx: &mut C) -> Result<Self, minicbor::decode::Error> {
let tag = d.tag()?;
let x = tag.as_u64();
match x {
121..=127 | 1280..=1400 => Ok(Constr {
tag: x,
fields: d.decode_with(ctx)?,
any_constructor: None,
}),
102 => {
d.array()?;
Ok(Constr {
tag: x,
any_constructor: Some(d.decode_with(ctx)?),
fields: d.decode_with(ctx)?,
})
}
_ => Err(minicbor::decode::Error::message(
"bad tag code for plutus data",
)),
}
}
}
impl<C, A> minicbor::encode::Encode<C> for Constr<A>
where
A: minicbor::encode::Encode<C>,
{
fn encode<W: minicbor::encode::Write>(
&self,
e: &mut minicbor::Encoder<W>,
ctx: &mut C,
) -> Result<(), minicbor::encode::Error<W::Error>> {
e.tag(Tag::new(self.tag))?;
match self.tag {
102 => {
// definite length array here
// https://github.com/input-output-hk/plutus/blob/9538fc9829426b2ecb0628d352e2d7af96ec8204/plutus-core/plutus-core/src/PlutusCore/Data.hs#L152
e.array(2)?;
e.encode_with(self.any_constructor.unwrap_or_default(), ctx)?;
// we use definite array for empty array or indef array otherwise to match
// haskell implementation https://github.com/input-output-hk/plutus/blob/9538fc9829426b2ecb0628d352e2d7af96ec8204/plutus-core/plutus-core/src/PlutusCore/Data.hs#L144
// default encoder for a list:
// https://github.com/well-typed/cborg/blob/4bdc818a1f0b35f38bc118a87944630043b58384/serialise/src/Codec/Serialise/Class.hs#L181
encode_list(&self.fields, e, ctx)?;
Ok(())
}
_ => {
// we use definite array for empty array or indef array otherwise to match
// haskell implementation. See above reference.
encode_list(&self.fields, e, ctx)?;
Ok(())
}
}
}
}
/// Defined to encode PlutusData bytestring as it is done in the canonical
/// plutus implementation
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
#[serde(into = "String")]
#[serde(try_from = "String")]
pub struct BoundedBytes(Vec<u8>);
impl From<Vec<u8>> for BoundedBytes {
fn from(xs: Vec<u8>) -> Self {
BoundedBytes(xs)
}
}
impl From<BoundedBytes> for Vec<u8> {
fn from(b: BoundedBytes) -> Self {
b.0
}
}
impl Deref for BoundedBytes {
type Target = Vec<u8>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl TryFrom<String> for BoundedBytes {
type Error = hex::FromHexError;
fn try_from(value: String) -> Result<Self, Self::Error> {
let v = hex::decode(value)?;
Ok(BoundedBytes(v))
}
}
impl From<BoundedBytes> for String {
fn from(b: BoundedBytes) -> Self {
hex::encode(b.deref())
}
}
impl fmt::Display for BoundedBytes {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let bytes: Vec<u8> = self.clone().into();
f.write_str(&hex::encode(bytes))
}
}
impl<C> Encode<C> for BoundedBytes {
fn encode<W: minicbor::encode::Write>(
&self,
e: &mut minicbor::Encoder<W>,
_: &mut C,
) -> Result<(), minicbor::encode::Error<W::Error>> {
// we match the haskell implementation by encoding bytestrings longer than 64
// bytes as indefinite lists of bytes
const CHUNK_SIZE: usize = 64;
let bs: &Vec<u8> = self.deref();
if bs.len() <= 64 {
e.bytes(bs)?;
} else {
e.begin_bytes()?;
for b in bs.chunks(CHUNK_SIZE) {
e.bytes(b)?;
}
e.end()?;
}
Ok(())
}
}
impl<'b, C> minicbor::decode::Decode<'b, C> for BoundedBytes {
fn decode(d: &mut minicbor::Decoder<'b>, _: &mut C) -> Result<Self, minicbor::decode::Error> {
let mut res = Vec::new();
for chunk in d.bytes_iter()? {
let bs = chunk?;
res.extend_from_slice(bs);
}
Ok(BoundedBytes::from(res))
}
}
fn encode_list<C, W: minicbor::encode::Write, A: minicbor::encode::Encode<C>>(
a: &Vec<A>,
e: &mut minicbor::Encoder<W>,
ctx: &mut C,
) -> Result<(), minicbor::encode::Error<W::Error>> {
// Mimics default haskell list encoding from cborg:
// We use indef array for non-empty arrays but definite 0-length array for empty
if a.is_empty() {
e.array(0)?;
} else {
e.begin_array()?;
for v in a {
e.encode_with(v, ctx)?;
}
e.end()?;
}
Ok(())
}