Skip to content

Commit 9eb3c76

Browse files
committedNov 1, 2023
1 parent 43b269d commit 9eb3c76

22 files changed

+2636
-0
lines changed
 

‎.envrc

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
use flake .

‎Cargo.lock

+574
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎Cargo.toml

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
[package]
2+
name = "plutus-ledger-types"
3+
version = "0.1.0"
4+
edition = "2021"
5+
6+
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
7+
8+
[dependencies]
9+
proptest = "1.3.1"
10+
lbr-prelude = { git = "https://github.com/mlabs-haskell/lambda-buffers.git", rev = "ff133d96160e27554286ee4221de060debd6a031", optional = true }
11+
serde_json = { version = "1.0.107", features = [
12+
"arbitrary_precision",
13+
], optional = true }
14+
num-bigint = "0.4.4"
15+
serde = { version = "1.0.189", features = ["derive"], optional = true }
16+
true = { version = "0.1.0", optional = true }
17+
data-encoding = { version = "2.4.0", optional = true }
18+
thiserror = "1.0.50"
19+
20+
[features]
21+
serde = ["dep:serde", "num-bigint/serde"]
22+
lbf = ["dep:lbr-prelude", "dep:data-encoding", "dep:serde_json"]
23+
default = []

‎flake.lock

+321
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎flake.nix

+69
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
{
2+
inputs = {
3+
nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable";
4+
crane.url = "github:ipetkov/crane";
5+
crane.inputs.nixpkgs.follows = "nixpkgs";
6+
flake-parts.url = "github:hercules-ci/flake-parts";
7+
rust-overlay.url = "github:oxalica/rust-overlay";
8+
pre-commit-hooks-nix.url = "github:cachix/pre-commit-hooks.nix";
9+
pre-commit-hooks-nix.inputs.nixpkgs.follows = "nixpkgs";
10+
hercules-ci-effects.url = "github:hercules-ci/hercules-ci-effects";
11+
};
12+
13+
outputs = inputs@{ flake-parts, rust-overlay, nixpkgs, ... }:
14+
flake-parts.lib.mkFlake
15+
{
16+
inherit inputs;
17+
}
18+
{
19+
systems = [
20+
"x86_64-linux"
21+
"x86_64-darwin"
22+
];
23+
imports = [
24+
inputs.pre-commit-hooks-nix.flakeModule
25+
inputs.hercules-ci-effects.flakeModule
26+
];
27+
perSystem = { self', pkgs, system, ... }:
28+
let
29+
overlays = [ (import rust-overlay) ];
30+
crateName = "plutus-ledger-types-rust";
31+
rustWithTools = pkgs.rust-bin.stable.latest.default.override {
32+
extensions = [ "rustfmt" "rust-analyzer" "clippy" ];
33+
};
34+
craneLib = inputs.crane.lib.${system}.overrideToolchain rustWithTools;
35+
src = craneLib.cleanCargoSource (craneLib.path ./.);
36+
commonArgs = {
37+
inherit src;
38+
strictDeps = true;
39+
};
40+
cargoArtifacts = craneLib.buildDepsOnly commonArgs;
41+
in
42+
{
43+
_module.args.pkgs = import nixpkgs {
44+
inherit system overlays;
45+
};
46+
47+
devShells.default = craneLib.devShell { checks = self'.checks; };
48+
49+
packages.default = craneLib.buildPackage (commonArgs // {
50+
inherit cargoArtifacts;
51+
doTest = false;
52+
});
53+
54+
pre-commit.settings.hooks = {
55+
rustfmt.enable = true;
56+
clippy.enable = true;
57+
};
58+
59+
checks."${crateName}-test" = craneLib.cargoNextest (commonArgs // {
60+
inherit cargoArtifacts;
61+
});
62+
63+
checks."${crateName}-clippy" = craneLib.cargoClippy (commonArgs // {
64+
inherit cargoArtifacts;
65+
});
66+
};
67+
};
68+
69+
}

‎src/address.rs

+143
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
use crate::crypto::Ed25519PubKeyHash;
2+
use crate::ledger_state::Slot;
3+
use crate::script::ValidatorHash;
4+
#[cfg(feature = "lbf")]
5+
use lbr_prelude::json::{self, Error, Json};
6+
use num_bigint::BigInt;
7+
8+
#[cfg(feature = "serde")]
9+
use serde::{Deserialize, Serialize};
10+
11+
/// Shelley Address for wallets or validators
12+
///
13+
/// An address consists of a payment part (credential) and a delegation part (staking_credential).
14+
/// In order to serialize an address to `bech32`, the network kind must be known.
15+
/// For a better understanding of all the Cardano address types, read [CIP 19](https://cips.cardano.org/cips/cip19/)
16+
#[derive(Clone, Debug, PartialEq, Eq)]
17+
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
18+
#[cfg_attr(feature = "lbf", derive(Json))]
19+
pub struct Address {
20+
pub credential: Credential,
21+
pub staking_credential: Option<StakingCredential>,
22+
}
23+
24+
/// A public key hash or validator hash credential (used as a payment or a staking credential)
25+
#[derive(Clone, Debug, PartialEq, Eq)]
26+
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
27+
pub enum Credential {
28+
PubKey(Ed25519PubKeyHash),
29+
Script(ValidatorHash),
30+
}
31+
32+
#[cfg(feature = "lbf")]
33+
impl Json for Credential {
34+
fn to_json(&self) -> Result<serde_json::Value, Error> {
35+
match self {
36+
Credential::PubKey(pkh) => Ok(json::sum_constructor(
37+
"PubKeyCredential",
38+
vec![pkh.to_json()?],
39+
)),
40+
Credential::Script(val_hash) => Ok(json::sum_constructor(
41+
"ScriptCredential",
42+
vec![val_hash.to_json()?],
43+
)),
44+
}
45+
}
46+
47+
fn from_json(value: serde_json::Value) -> Result<Self, Error> {
48+
json::sum_parser(&value).and_then(|obj| match obj {
49+
("PubKeyCredential", ctor_fields) => match &ctor_fields[..] {
50+
[pkh] => Ok(Credential::PubKey(Json::from_json(pkh.clone())?)),
51+
_ => Err(Error::UnexpectedArrayLength {
52+
wanted: 1,
53+
got: ctor_fields.len(),
54+
}),
55+
},
56+
("ScriptCredential", ctor_fields) => match &ctor_fields[..] {
57+
[val_hash] => Ok(Credential::Script(Json::from_json(val_hash.clone())?)),
58+
_ => Err(Error::UnexpectedArrayLength {
59+
wanted: 1,
60+
got: ctor_fields.len(),
61+
}),
62+
},
63+
_ => Err(Error::UnexpectedJsonInvariant {
64+
wanted: "constructor names (Nothing, Just)".to_owned(),
65+
got: "unknown constructor name".to_owned(),
66+
}),
67+
})
68+
}
69+
}
70+
71+
/// Credential (public key hash or pointer) used for staking
72+
#[derive(Clone, Debug, PartialEq, Eq)]
73+
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
74+
pub enum StakingCredential {
75+
Hash(Credential),
76+
Pointer(ChainPointer),
77+
}
78+
79+
#[cfg(feature = "lbf")]
80+
impl Json for StakingCredential {
81+
fn to_json(&self) -> Result<serde_json::Value, Error> {
82+
match self {
83+
StakingCredential::Hash(pkh) => {
84+
Ok(json::sum_constructor("StakingHash", vec![pkh.to_json()?]))
85+
}
86+
StakingCredential::Pointer(val_hash) => Ok(json::sum_constructor(
87+
"StakingPtr",
88+
vec![val_hash.to_json()?],
89+
)),
90+
}
91+
}
92+
93+
fn from_json(value: serde_json::Value) -> Result<Self, Error> {
94+
json::sum_parser(&value).and_then(|obj| match obj {
95+
("StakingHash", ctor_fields) => match &ctor_fields[..] {
96+
[pkh] => Ok(StakingCredential::Hash(Json::from_json(pkh.clone())?)),
97+
_ => Err(Error::UnexpectedArrayLength {
98+
wanted: 1,
99+
got: ctor_fields.len(),
100+
}),
101+
},
102+
("StakingPtr", ctor_fields) => match &ctor_fields[..] {
103+
[val_hash] => Ok(StakingCredential::Pointer(Json::from_json(
104+
val_hash.clone(),
105+
)?)),
106+
_ => Err(Error::UnexpectedArrayLength {
107+
wanted: 1,
108+
got: ctor_fields.len(),
109+
}),
110+
},
111+
_ => Err(Error::UnexpectedJsonInvariant {
112+
wanted: "constructor names (Nothing, Just)".to_owned(),
113+
got: "unknown constructor name".to_owned(),
114+
}),
115+
})
116+
}
117+
}
118+
119+
/// In an address, a chain pointer refers to a point of the chain containing a stake key
120+
/// registration certificate. A point is identified by 3 coordinates:
121+
/// - An absolute slot number
122+
/// - A transaction inder (within that slot)
123+
/// - A (delegation) certificate index (within that transacton)
124+
#[derive(Clone, Debug, PartialEq, Eq)]
125+
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
126+
#[cfg_attr(feature = "lbf", derive(Json))]
127+
pub struct ChainPointer {
128+
pub slot_number: Slot,
129+
pub transaction_index: TransactionIndex,
130+
pub certificate_index: CertificateIndex,
131+
}
132+
/// Position of the certificate in a certain transaction
133+
#[derive(Clone, Debug, PartialEq, Eq)]
134+
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
135+
#[cfg_attr(feature = "lbf", derive(Json))]
136+
pub struct CertificateIndex(pub BigInt);
137+
138+
/// Position of a transaction in a given slot
139+
/// This is not identical to the index of a `TransactionInput`
140+
#[derive(Clone, Debug, PartialEq, Eq)]
141+
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
142+
#[cfg_attr(feature = "lbf", derive(Json))]
143+
pub struct TransactionIndex(pub BigInt);

‎src/crypto.rs

+51
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
#[cfg(feature = "lbf")]
2+
use data_encoding::HEXLOWER;
3+
#[cfg(feature = "lbf")]
4+
use lbr_prelude::json::{Error, Json};
5+
#[cfg(feature = "serde")]
6+
use serde::{Deserialize, Serialize};
7+
8+
/// ED25519 public key hash
9+
/// This is the standard cryptography in Cardano, commonly referred to as `PubKeyHash` in Plutus
10+
/// and other libraries
11+
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
12+
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
13+
#[cfg_attr(feature = "lbf", derive(Json))]
14+
pub struct Ed25519PubKeyHash(pub LedgerBytes);
15+
16+
/// Standard public key hash used to verify a transaction witness
17+
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
18+
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
19+
#[cfg_attr(feature = "lbf", derive(Json))]
20+
pub struct PaymentPubKeyHash(pub Ed25519PubKeyHash);
21+
22+
/// Standard public key hash used to verify a staking
23+
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
24+
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
25+
#[cfg_attr(feature = "lbf", derive(Json))]
26+
pub struct StakePubKeyHash(pub Ed25519PubKeyHash);
27+
28+
/// A bytestring in the Cardano ledger context
29+
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
30+
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
31+
pub struct LedgerBytes(pub Vec<u8>);
32+
33+
#[cfg(feature = "lbf")]
34+
impl Json for LedgerBytes {
35+
fn to_json(&self) -> Result<serde_json::Value, Error> {
36+
String::to_json(&HEXLOWER.encode(&self.0))
37+
}
38+
39+
fn from_json(value: serde_json::Value) -> Result<Self, Error> {
40+
let bytes = String::from_json(value).and_then(|str| {
41+
HEXLOWER
42+
.decode(&str.into_bytes())
43+
.map_err(|_| Error::UnexpectedJsonInvariant {
44+
wanted: "base16 string".to_owned(),
45+
got: "unexpected string".to_owned(),
46+
})
47+
})?;
48+
49+
Ok(Self(bytes))
50+
}
51+
}

‎src/datum.rs

+82
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
use crate::crypto::LedgerBytes;
2+
use crate::plutus_data::PlutusData;
3+
#[cfg(feature = "lbf")]
4+
use lbr_prelude::json::{self, Error, Json};
5+
6+
#[cfg(feature = "serde")]
7+
use serde::{Deserialize, Serialize};
8+
9+
/// Optional datum of a transaction
10+
///
11+
/// In case an inline datum is used, the data is embedded inside the transaction body, so it can be
12+
/// directly retrieved. In case of a datum hash, an off-chain indexer is required to find the
13+
/// associated datum by its hash.
14+
#[derive(Clone, Debug, PartialEq, Eq)]
15+
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
16+
pub enum OutputDatum {
17+
None,
18+
DatumHash(DatumHash),
19+
InlineDatum(Datum),
20+
}
21+
22+
#[cfg(feature = "lbf")]
23+
impl Json for OutputDatum {
24+
fn to_json(&self) -> Result<serde_json::Value, Error> {
25+
match self {
26+
OutputDatum::None => Ok(json::sum_constructor(
27+
"NoOutputDatum",
28+
Vec::with_capacity(0),
29+
)),
30+
OutputDatum::DatumHash(dat_hash) => Ok(json::sum_constructor(
31+
"OutputDatumHash",
32+
vec![dat_hash.to_json()?],
33+
)),
34+
OutputDatum::InlineDatum(datum) => {
35+
Ok(json::sum_constructor("OutputDatum", vec![datum.to_json()?]))
36+
}
37+
}
38+
}
39+
40+
fn from_json(value: serde_json::Value) -> Result<Self, Error> {
41+
json::sum_parser(&value).and_then(|obj| match obj {
42+
("NoOutputDatum", ctor_fields) => match &ctor_fields[..] {
43+
[] => Ok(OutputDatum::None),
44+
_ => Err(Error::UnexpectedArrayLength {
45+
wanted: 0,
46+
got: ctor_fields.len(),
47+
}),
48+
},
49+
("OutputDatumHash", ctor_fields) => match &ctor_fields[..] {
50+
[dat_hash] => Ok(OutputDatum::DatumHash(Json::from_json(dat_hash.clone())?)),
51+
_ => Err(Error::UnexpectedArrayLength {
52+
wanted: 1,
53+
got: ctor_fields.len(),
54+
}),
55+
},
56+
("OutputDatum", ctor_fields) => match &ctor_fields[..] {
57+
[datum] => Ok(OutputDatum::InlineDatum(Json::from_json(datum.clone())?)),
58+
_ => Err(Error::UnexpectedArrayLength {
59+
wanted: 1,
60+
got: ctor_fields.len(),
61+
}),
62+
},
63+
_ => Err(Error::UnexpectedJsonInvariant {
64+
wanted: "constructor names (PubKeyCredential, OutputDatumHash, OutputDatum)"
65+
.to_owned(),
66+
got: "unknown constructor name".to_owned(),
67+
}),
68+
})
69+
}
70+
}
71+
72+
/// blake2b-256 hash of a datum
73+
#[derive(Clone, Debug, PartialEq, Eq)]
74+
#[cfg_attr(feature = "lbf", derive(Json))]
75+
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
76+
pub struct DatumHash(pub LedgerBytes);
77+
78+
/// Piece of information associated with a UTxO encoded into a PlutusData type.
79+
#[derive(Clone, Debug, PartialEq, Eq)]
80+
#[cfg_attr(feature = "lbf", derive(Json))]
81+
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
82+
pub struct Datum(pub PlutusData);

‎src/feature_traits.rs

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
#[cfg(feature = "lbf")]
2+
use lbr_prelude::json::Json;
3+
4+
/// FeatureTraits is an intermediate trait which inherits different traits depending on the
5+
/// compilation feature flag. This makes it cleaner to implement structs with generics, with
6+
/// optional trait bounds.
7+
#[cfg(feature = "lbf")]
8+
pub trait FeatureTraits: Json {}
9+
#[cfg(feature = "lbf")]
10+
impl<T> FeatureTraits for T where T: Json {}
11+
12+
#[cfg(not(feature = "lbf"))]
13+
pub trait FeatureTraits {}
14+
#[cfg(not(feature = "lbf"))]
15+
impl<T> FeatureTraits for T {}

‎src/generators/correct.rs

+360
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,360 @@
1+
use crate::address::{
2+
Address, CertificateIndex, ChainPointer, Credential, StakingCredential, TransactionIndex,
3+
};
4+
use crate::crypto::{Ed25519PubKeyHash, LedgerBytes};
5+
use crate::datum::{Datum, DatumHash, OutputDatum};
6+
use crate::feature_traits::FeatureTraits;
7+
use crate::interval::{Extended, LowerBound, PlutusInterval, UpperBound};
8+
use crate::ledger_state::Slot;
9+
use crate::plutus_data::PlutusData;
10+
use crate::redeemer::Redeemer;
11+
use crate::script::{MintingPolicyHash, ScriptHash, ValidatorHash};
12+
use crate::transaction::{
13+
POSIXTime, TransactionHash, TransactionInput, TransactionOutput, TxInInfo,
14+
};
15+
use crate::value::{ada_token_name, AssetClass, CurrencySymbol, TokenName, Value};
16+
use num_bigint::{BigInt, Sign};
17+
use proptest::arbitrary::{any, StrategyFor};
18+
use proptest::char::CharStrategy;
19+
use proptest::collection::vec;
20+
use proptest::collection::{btree_map, btree_set};
21+
use proptest::option;
22+
use proptest::prelude::{prop_oneof, Just};
23+
use proptest::result::maybe_err;
24+
use proptest::strategy::Strategy;
25+
use std::collections::{BTreeMap, BTreeSet};
26+
27+
/// Strategy to generate an arbitrary boolean
28+
pub fn arb_bool() -> StrategyFor<bool> {
29+
any::<bool>()
30+
}
31+
32+
/// Strategy to generate an arbitrary `Sign`
33+
/// Only used internally, to generate `BigInt`s
34+
fn arb_sign() -> impl Strategy<Value = Sign> {
35+
// NoSign is only used for 0 values so we're not generating it here
36+
prop_oneof![Just(Sign::Minus), Just(Sign::Plus)]
37+
}
38+
39+
/// Strategy to generate an arbitrary BigInt
40+
pub fn arb_integer() -> impl Strategy<Value = BigInt> {
41+
// Generating 5 vectors of with random u32 values, which gives a max bound of u32::MAX ^ 5
42+
(arb_sign(), vec(any::<u32>(), 5)).prop_map(|(sign, value)| {
43+
// As NoSign is only used for 0 values, we switch to NoSign when an empty vector is generated
44+
BigInt::new(if value.is_empty() { Sign::NoSign } else { sign }, value)
45+
})
46+
}
47+
48+
/// Strategy to generate an arbitrary character
49+
pub fn arb_char<'a>() -> CharStrategy<'a> {
50+
any::<char>()
51+
}
52+
53+
/// Strategy to generate an arbitrary bytestring
54+
pub fn arb_bytes() -> StrategyFor<Vec<u8>> {
55+
any::<Vec<u8>>()
56+
}
57+
58+
/// Strategy to generate an arbitrary bytestring with a fixed length
59+
pub fn arb_ledger_bytes(length: usize) -> impl Strategy<Value = LedgerBytes> {
60+
(vec(any::<u8>(), length)).prop_map(LedgerBytes)
61+
}
62+
63+
/// Strategy to generate an arbitrary string
64+
pub fn arb_text() -> StrategyFor<String> {
65+
any::<String>()
66+
}
67+
68+
/// Strategy to generate a complicated data structure
69+
pub fn arb_complicated(
70+
) -> impl Strategy<Value = BTreeMap<String, Result<BTreeSet<char>, Option<Result<Vec<u8>, bool>>>>>
71+
{
72+
btree_map(
73+
arb_text(),
74+
maybe_err(
75+
btree_set(arb_char(), 20),
76+
option::of(maybe_err(arb_bytes(), arb_bool())),
77+
),
78+
20,
79+
)
80+
}
81+
82+
/// Strategy to generate an asset class
83+
///
84+
/// This generator will only generate valid asset classes, the Ada token name will always be empty
85+
pub fn arb_asset_class() -> impl Strategy<Value = AssetClass> {
86+
(arb_currency_symbol(), arb_token_name()).prop_map(|(currency_symbol, token_name)| {
87+
let token_name = match currency_symbol {
88+
CurrencySymbol::Ada => ada_token_name(),
89+
CurrencySymbol::NativeToken(_) => token_name,
90+
};
91+
AssetClass {
92+
currency_symbol,
93+
token_name,
94+
}
95+
})
96+
}
97+
98+
/// Strategy to generate a currency symbol
99+
///
100+
/// In order to avoid generating too much Ada symbols, this generator is configured such that it
101+
/// only has 25% chance of getting Ada, and 75% of getting a native token
102+
pub fn arb_currency_symbol() -> impl Strategy<Value = CurrencySymbol> {
103+
prop_oneof![
104+
1 =>Just(CurrencySymbol::Ada),
105+
3 =>arb_minting_policy_hash().prop_map(CurrencySymbol::NativeToken)
106+
]
107+
}
108+
109+
/// Strategy to generate a token name
110+
pub fn arb_token_name() -> impl Strategy<Value = TokenName> {
111+
arb_ledger_bytes(32).prop_map(TokenName)
112+
}
113+
114+
/// Strategy to generate a minting policy hash
115+
pub fn arb_minting_policy_hash() -> impl Strategy<Value = MintingPolicyHash> {
116+
arb_script_hash().prop_map(MintingPolicyHash)
117+
}
118+
119+
/// Strategy to generate a validator hash
120+
pub fn arb_validator_hash() -> impl Strategy<Value = ValidatorHash> {
121+
arb_script_hash().prop_map(ValidatorHash)
122+
}
123+
124+
/// Strategy to generate a ScriptHash
125+
pub fn arb_script_hash() -> impl Strategy<Value = ScriptHash> {
126+
arb_ledger_bytes(28).prop_map(ScriptHash)
127+
}
128+
129+
/// Strategy to generate a Value
130+
///
131+
/// This generator will try to balance the result, such that there's a 50% chance that Ada is
132+
/// included in the Value
133+
pub fn arb_value() -> impl Strategy<Value = Value> {
134+
prop_oneof![
135+
arb_native_tokens(),
136+
(arb_native_tokens(), arb_integer()).prop_map(|(Value(outer_dict), amount)| {
137+
let mut outer_dict = outer_dict.clone();
138+
let inner_dict = BTreeMap::from([(ada_token_name(), amount)]);
139+
outer_dict.insert(CurrencySymbol::Ada, inner_dict);
140+
Value(outer_dict)
141+
})
142+
]
143+
}
144+
145+
/// Strategy to generate a Value
146+
pub fn arb_native_tokens() -> impl Strategy<Value = Value> {
147+
btree_map(
148+
arb_minting_policy_hash().prop_map(CurrencySymbol::NativeToken),
149+
btree_map(arb_token_name(), arb_integer(), 5),
150+
5,
151+
)
152+
.prop_map(Value)
153+
}
154+
155+
/// Strategy to generate an arbitrary PlutusData with a maximum depth of 5 recursions
156+
pub fn arb_plutus_data() -> impl Strategy<Value = PlutusData> {
157+
arb_plutus_data_leaf().prop_recursive(5, 64, 16, |arb_data| {
158+
prop_oneof![
159+
arb_integer().prop_map(PlutusData::Integer),
160+
arb_bytes().prop_map(PlutusData::Bytes),
161+
vec(arb_data.clone(), 5).prop_map(PlutusData::List),
162+
vec((arb_data.clone(), arb_data.clone()), 5).prop_map(PlutusData::Map),
163+
(arb_integer(), vec(arb_data.clone(), 5))
164+
.prop_map(|(id, fields)| PlutusData::Constr(id, fields)),
165+
]
166+
})
167+
}
168+
169+
/// Leaf generator for PlutusData recursive generator
170+
fn arb_plutus_data_leaf() -> impl Strategy<Value = PlutusData> {
171+
prop_oneof![
172+
arb_integer().prop_map(PlutusData::Integer),
173+
arb_bytes().prop_map(PlutusData::Bytes),
174+
]
175+
}
176+
177+
/// Strategy to generate Ed25519 public key hash
178+
pub fn arb_ed25519_pub_key_hash() -> impl Strategy<Value = Ed25519PubKeyHash> {
179+
arb_ledger_bytes(28).prop_map(Ed25519PubKeyHash)
180+
}
181+
182+
/// Strategy to generate a Datum hash
183+
pub fn arb_datum_hash() -> impl Strategy<Value = DatumHash> {
184+
arb_ledger_bytes(32).prop_map(DatumHash)
185+
}
186+
187+
/// Strategy to generate a Datum
188+
pub fn arb_datum() -> impl Strategy<Value = Datum> {
189+
arb_plutus_data().prop_map(Datum)
190+
}
191+
192+
/// Strategy to generate a Redeemer
193+
pub fn arb_redeemer() -> impl Strategy<Value = Redeemer> {
194+
arb_plutus_data().prop_map(Redeemer)
195+
}
196+
197+
/// Strategy to generate an Extended set
198+
pub fn arb_extended<T>(element: T) -> impl Strategy<Value = Extended<T::Value>>
199+
where
200+
T: Strategy,
201+
T::Value: FeatureTraits + Clone,
202+
{
203+
prop_oneof![
204+
Just(Extended::NegInf),
205+
Just(Extended::PosInf),
206+
element.prop_map(Extended::Finite)
207+
]
208+
}
209+
210+
/// Strategy to generate an extended POSIX time
211+
pub fn arb_extended_posix_time() -> impl Strategy<Value = Extended<POSIXTime>> {
212+
arb_extended(arb_posix_time())
213+
}
214+
215+
/// Strategy to generate a POSIX Time
216+
pub fn arb_posix_time() -> impl Strategy<Value = POSIXTime> {
217+
(0..1000000).prop_map(|int| POSIXTime(BigInt::from(int)))
218+
}
219+
220+
/// Strategy to generate an UpperBound
221+
pub fn arb_upper_bound<T>(element: T) -> impl Strategy<Value = UpperBound<T::Value>>
222+
where
223+
T: Strategy,
224+
T::Value: FeatureTraits + Clone,
225+
{
226+
(arb_extended(element), arb_bool()).prop_map(|(bound, closed)| UpperBound { bound, closed })
227+
}
228+
229+
/// Strategy to generate a LowerBound
230+
pub fn arb_lower_bound<T>(element: T) -> impl Strategy<Value = LowerBound<T::Value>>
231+
where
232+
T: Strategy,
233+
T::Value: FeatureTraits + Clone,
234+
{
235+
(arb_extended(element), arb_bool()).prop_map(|(bound, closed)| LowerBound { bound, closed })
236+
}
237+
238+
/// Strategy to generate a PlutusInterval
239+
///
240+
/// This implementation is not normalized, so impossible values might be generated
241+
pub fn arb_plutus_interval<T>(
242+
lower_bound: T,
243+
upper_bound: T,
244+
) -> impl Strategy<Value = PlutusInterval<T::Value>>
245+
where
246+
T: Strategy,
247+
T::Value: FeatureTraits + Clone,
248+
{
249+
(arb_lower_bound(lower_bound), arb_upper_bound(upper_bound))
250+
.prop_map(|(from, to)| PlutusInterval { from, to })
251+
}
252+
253+
/// Strategy to generate a PlutusInterval
254+
///
255+
/// This implementation is not normalized, so impossible values might be generated
256+
pub fn arb_plutus_interval_posix_time() -> impl Strategy<Value = PlutusInterval<POSIXTime>> {
257+
arb_plutus_interval(arb_posix_time(), arb_posix_time())
258+
}
259+
260+
/// Strategy to generate a Cardano address
261+
pub fn arb_address() -> impl Strategy<Value = Address> {
262+
(arb_credential(), option::of(arb_staking_credential())).prop_map(
263+
|(credential, staking_credential)| Address {
264+
credential,
265+
staking_credential,
266+
},
267+
)
268+
}
269+
270+
/// Strategy to generate a chain pointer
271+
pub fn arb_chain_pointer() -> impl Strategy<Value = ChainPointer> {
272+
(arb_slot(), arb_transaction_index(), arb_certificate_index()).prop_map(
273+
|(slot_number, transaction_index, certificate_index)| ChainPointer {
274+
slot_number,
275+
transaction_index,
276+
certificate_index,
277+
},
278+
)
279+
}
280+
281+
/// Strategy to generate a slot number
282+
pub fn arb_slot() -> impl Strategy<Value = Slot> {
283+
arb_integer().prop_map(Slot)
284+
}
285+
286+
/// Strategy to generate a transaction index
287+
pub fn arb_transaction_index() -> impl Strategy<Value = TransactionIndex> {
288+
arb_integer().prop_map(TransactionIndex)
289+
}
290+
291+
/// Strategy to generate a certificate index
292+
pub fn arb_certificate_index() -> impl Strategy<Value = CertificateIndex> {
293+
arb_integer().prop_map(CertificateIndex)
294+
}
295+
296+
/// Strategy to generate a staking credential
297+
pub fn arb_staking_credential() -> impl Strategy<Value = StakingCredential> {
298+
prop_oneof![
299+
arb_credential().prop_map(StakingCredential::Hash),
300+
arb_chain_pointer().prop_map(StakingCredential::Pointer)
301+
]
302+
}
303+
304+
/// Strategy to generate a credential
305+
pub fn arb_credential() -> impl Strategy<Value = Credential> {
306+
prop_oneof![
307+
arb_ed25519_pub_key_hash().prop_map(Credential::PubKey),
308+
arb_validator_hash().prop_map(Credential::Script)
309+
]
310+
}
311+
312+
/// Strategy to generate a transaction hash
313+
pub fn arb_transaction_hash() -> impl Strategy<Value = TransactionHash> {
314+
arb_ledger_bytes(32).prop_map(TransactionHash)
315+
}
316+
317+
/// Strategy to generate a transaction input
318+
pub fn arb_transaction_input() -> impl Strategy<Value = TransactionInput> {
319+
(arb_transaction_hash(), arb_integer()).prop_map(|(transaction_id, index)| TransactionInput {
320+
transaction_id,
321+
index,
322+
})
323+
}
324+
325+
/// Strategy to generate transaction output
326+
pub fn arb_transaction_output() -> impl Strategy<Value = TransactionOutput> {
327+
(
328+
arb_address(),
329+
arb_value(),
330+
arb_output_datum(),
331+
option::of(arb_script_hash()),
332+
)
333+
.prop_map(
334+
|(address, value, datum, reference_script)| TransactionOutput {
335+
address,
336+
value,
337+
datum,
338+
reference_script,
339+
},
340+
)
341+
}
342+
343+
/// Strategy to generate an output datum
344+
pub fn arb_output_datum() -> impl Strategy<Value = OutputDatum> {
345+
prop_oneof![
346+
Just(OutputDatum::None),
347+
arb_datum_hash().prop_map(OutputDatum::DatumHash),
348+
arb_datum().prop_map(OutputDatum::InlineDatum)
349+
]
350+
}
351+
352+
/// Strategy to generate a TxInInfo
353+
pub fn arb_tx_in_info() -> impl Strategy<Value = TxInInfo> {
354+
(arb_transaction_input(), arb_transaction_output()).prop_map(|(transaction_input, resolved)| {
355+
TxInInfo {
356+
transaction_input,
357+
resolved,
358+
}
359+
})
360+
}

‎src/generators/mod.rs

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
pub mod correct;

‎src/interval.rs

+138
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
use crate::feature_traits::FeatureTraits;
2+
#[cfg(feature = "lbf")]
3+
use lbr_prelude::json::Json;
4+
#[cfg(feature = "serde")]
5+
use serde::{Deserialize, Serialize};
6+
7+
/// An abstraction over `PlutusInterval`, allowing valid values only
8+
#[derive(Clone, Debug, PartialEq, Eq)]
9+
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
10+
pub enum Interval<T> {
11+
Finite(T, T),
12+
StartAt(T),
13+
EndAt(T),
14+
Always,
15+
Never,
16+
}
17+
18+
/// Loosely following the CTL implementation of `intervalToPlutusInterval`
19+
/// However, as we don't have Semiring classes, the interval upper bounds are always closed
20+
impl<T> From<Interval<T>> for PlutusInterval<T>
21+
where
22+
T: FeatureTraits,
23+
{
24+
fn from(interval: Interval<T>) -> Self {
25+
match interval {
26+
Interval::Finite(start, end) => PlutusInterval {
27+
from: LowerBound {
28+
bound: Extended::Finite(start),
29+
closed: true,
30+
},
31+
to: UpperBound {
32+
bound: Extended::Finite(end),
33+
closed: true,
34+
},
35+
},
36+
Interval::StartAt(end) => PlutusInterval {
37+
from: LowerBound {
38+
bound: Extended::NegInf,
39+
closed: true,
40+
},
41+
to: UpperBound {
42+
bound: Extended::Finite(end),
43+
closed: true,
44+
},
45+
},
46+
Interval::EndAt(start) => PlutusInterval {
47+
from: LowerBound {
48+
bound: Extended::Finite(start),
49+
closed: true,
50+
},
51+
to: UpperBound {
52+
bound: Extended::PosInf,
53+
closed: true,
54+
},
55+
},
56+
Interval::Always => PlutusInterval {
57+
from: LowerBound {
58+
bound: Extended::NegInf,
59+
closed: true,
60+
},
61+
to: UpperBound {
62+
bound: Extended::PosInf,
63+
closed: true,
64+
},
65+
},
66+
Interval::Never => PlutusInterval {
67+
from: LowerBound {
68+
bound: Extended::PosInf,
69+
closed: true,
70+
},
71+
to: UpperBound {
72+
bound: Extended::NegInf,
73+
closed: true,
74+
},
75+
},
76+
}
77+
}
78+
}
79+
80+
/// An interval of `T`s.
81+
///
82+
/// The interval may be either closed or open at either end, meaning
83+
/// that the endpoints may or may not be included in the interval.
84+
///
85+
/// The interval can also be unbounded on either side.
86+
///
87+
/// The 'Eq' instance gives equality of the intervals, not structural equality.
88+
/// There is no 'Ord' instance, but 'contains' gives a partial order.
89+
///
90+
/// Note that some of the functions on `Interval` rely on `Enum` in order to
91+
/// handle non-inclusive endpoints. For this reason, it may not be safe to
92+
/// use `Interval`s with non-inclusive endpoints on types whose `Enum`
93+
/// instances have partial methods.
94+
#[derive(Clone, Debug, PartialEq, Eq)]
95+
#[cfg_attr(feature = "lbf", derive(Json))]
96+
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
97+
pub struct PlutusInterval<T>
98+
where
99+
T: FeatureTraits,
100+
{
101+
pub from: LowerBound<T>,
102+
pub to: UpperBound<T>,
103+
}
104+
105+
#[derive(Clone, Debug, PartialEq, Eq)]
106+
#[cfg_attr(feature = "lbf", derive(Json))]
107+
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
108+
pub struct UpperBound<T>
109+
where
110+
T: FeatureTraits,
111+
{
112+
pub bound: Extended<T>,
113+
pub closed: bool,
114+
}
115+
116+
#[derive(Clone, Debug, PartialEq, Eq)]
117+
#[cfg_attr(feature = "lbf", derive(Json))]
118+
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
119+
pub struct LowerBound<T>
120+
where
121+
T: FeatureTraits,
122+
{
123+
pub bound: Extended<T>,
124+
pub closed: bool,
125+
}
126+
127+
/// A set extended with a positive and negative infinity.
128+
#[derive(Clone, Debug, PartialEq, Eq)]
129+
#[cfg_attr(feature = "lbf", derive(Json))]
130+
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
131+
pub enum Extended<T>
132+
where
133+
T: FeatureTraits,
134+
{
135+
NegInf,
136+
Finite(T),
137+
PosInf,
138+
}

‎src/ledger_state.rs

+36
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
#[cfg(feature = "lbf")]
2+
use lbr_prelude::json::Json;
3+
use num_bigint::BigInt;
4+
5+
#[cfg(feature = "serde")]
6+
use serde::{Deserialize, Serialize};
7+
8+
/// Number of epochs elapsed since genesis
9+
#[derive(Clone, Debug, PartialEq, Eq)]
10+
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
11+
#[cfg_attr(feature = "lbf", derive(Json))]
12+
pub struct Epoch(pub BigInt);
13+
14+
/// Number of slots elapsed since genesis
15+
#[derive(Clone, Debug, PartialEq, Eq)]
16+
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
17+
#[cfg_attr(feature = "lbf", derive(Json))]
18+
pub struct Slot(pub BigInt);
19+
20+
/// Kind of a network
21+
#[derive(Clone, Debug, PartialEq, Eq)]
22+
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
23+
#[cfg_attr(feature = "lbf", derive(Json))]
24+
pub enum NetworkKind {
25+
Testnet,
26+
Mainnet,
27+
}
28+
29+
/// Network kind and id (in case of a testnet)
30+
#[derive(Clone, Debug, PartialEq, Eq)]
31+
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
32+
#[cfg_attr(feature = "lbf", derive(Json))]
33+
pub enum NetworkId {
34+
Testnet(BigInt),
35+
Mainnet,
36+
}

‎src/lib.rs

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
pub mod address;
2+
pub mod crypto;
3+
pub mod datum;
4+
pub(crate) mod feature_traits;
5+
pub mod generators;
6+
pub mod interval;
7+
pub mod ledger_state;
8+
pub mod plutus_data;
9+
pub mod redeemer;
10+
pub mod script;
11+
pub mod transaction;
12+
pub mod value;

‎src/plutus_data.rs

+455
Large diffs are not rendered by default.

‎src/redeemer.rs

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
use crate::plutus_data::PlutusData;
2+
#[cfg(feature = "lbf")]
3+
use lbr_prelude::json::Json;
4+
#[cfg(feature = "serde")]
5+
use serde::{Deserialize, Serialize};
6+
7+
/// Piece of information attached to a transaction when redeeming a value from a validator or a
8+
/// minting policy
9+
#[derive(Clone, Debug, PartialEq, Eq)]
10+
#[cfg_attr(feature = "lbf", derive(Json))]
11+
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
12+
pub struct Redeemer(pub PlutusData);

‎src/script.rs

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
use crate::crypto::LedgerBytes;
2+
#[cfg(feature = "lbf")]
3+
use lbr_prelude::json::Json;
4+
#[cfg(feature = "serde")]
5+
use serde::{Deserialize, Serialize};
6+
7+
/// Identifier of a validator script
8+
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
9+
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
10+
#[cfg_attr(feature = "lbf", derive(Json))]
11+
pub struct ValidatorHash(pub ScriptHash);
12+
13+
/// Hash of a minting policy script
14+
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
15+
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
16+
#[cfg_attr(feature = "lbf", derive(Json))]
17+
pub struct MintingPolicyHash(pub ScriptHash);
18+
19+
/// Hash of a Plutus script
20+
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
21+
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
22+
#[cfg_attr(feature = "lbf", derive(Json))]
23+
pub struct ScriptHash(pub LedgerBytes);

‎src/transaction.rs

+64
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
use crate::address::Address;
2+
use crate::crypto::LedgerBytes;
3+
use crate::datum::OutputDatum;
4+
use crate::interval::PlutusInterval;
5+
use crate::script::ScriptHash;
6+
use crate::value::Value;
7+
#[cfg(feature = "lbf")]
8+
use lbr_prelude::json::Json;
9+
use num_bigint::BigInt;
10+
11+
#[cfg(feature = "serde")]
12+
use serde::{Deserialize, Serialize};
13+
14+
/// An input of a transaction
15+
///
16+
/// Also know as `TxOutRef` from Plutus, this identifies a UTxO by its transacton hash and index
17+
/// inside the transaction
18+
#[derive(Clone, Debug, PartialEq, Eq)]
19+
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
20+
#[cfg_attr(feature = "lbf", derive(Json))]
21+
pub struct TransactionInput {
22+
pub transaction_id: TransactionHash,
23+
pub index: BigInt,
24+
}
25+
26+
/// 32-bytes blake2b256 hash of a transaction body.
27+
///
28+
/// Also known as Transaction ID or `TxID`.
29+
/// Note: Plutus docs might incorrectly state that it uses SHA256.
30+
#[derive(Clone, Debug, PartialEq, Eq)]
31+
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
32+
#[cfg_attr(feature = "lbf", derive(Json))]
33+
pub struct TransactionHash(pub LedgerBytes);
34+
35+
/// An output of a transaction
36+
///
37+
/// This must include a target address, an amount, an optional datum and an optional reference
38+
/// script
39+
#[derive(Clone, Debug, PartialEq, Eq)]
40+
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
41+
#[cfg_attr(feature = "lbf", derive(Json))]
42+
pub struct TransactionOutput {
43+
pub address: Address,
44+
pub datum: OutputDatum,
45+
pub reference_script: Option<ScriptHash>,
46+
pub value: Value,
47+
}
48+
49+
/// POSIX time is measured as the number of milliseconds since 1970-01-01T00:00:00Z
50+
#[derive(Clone, Debug, PartialEq, Eq)]
51+
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
52+
#[cfg_attr(feature = "lbf", derive(Json))]
53+
pub struct POSIXTime(pub BigInt);
54+
55+
pub type POSIXTimeRange = PlutusInterval<POSIXTime>;
56+
57+
/// An input of a pending transaction.
58+
#[derive(Clone, Debug, PartialEq, Eq)]
59+
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
60+
#[cfg_attr(feature = "lbf", derive(Json))]
61+
pub struct TxInInfo {
62+
pub transaction_input: TransactionInput,
63+
pub resolved: TransactionOutput,
64+
}

‎src/value.rs

+70
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
use crate::crypto::LedgerBytes;
2+
use crate::script::MintingPolicyHash;
3+
#[cfg(feature = "lbf")]
4+
use lbr_prelude::json::{Error, Json, JsonType};
5+
use num_bigint::BigInt;
6+
#[cfg(feature = "serde")]
7+
use serde::{Deserialize, Serialize};
8+
#[cfg(feature = "lbf")]
9+
use serde_json;
10+
use std::collections::BTreeMap;
11+
12+
/// Identifier of a currency, which could be either Ada (or tAda), or a native token represented by
13+
/// it's minting policy hash. A currency may be associated with multiple `AssetClass`es.
14+
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
15+
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
16+
pub enum CurrencySymbol {
17+
Ada,
18+
NativeToken(MintingPolicyHash),
19+
}
20+
21+
#[cfg(feature = "lbf")]
22+
impl Json for CurrencySymbol {
23+
fn to_json(&self) -> Result<serde_json::Value, Error> {
24+
match self {
25+
CurrencySymbol::Ada => Ok(serde_json::Value::String(String::new())),
26+
CurrencySymbol::NativeToken(policy_hash) => policy_hash.to_json(),
27+
}
28+
}
29+
30+
fn from_json(value: serde_json::Value) -> Result<Self, Error> {
31+
match value.clone() {
32+
serde_json::Value::String(str) => {
33+
if str.is_empty() {
34+
Ok(CurrencySymbol::Ada)
35+
} else {
36+
Ok(CurrencySymbol::NativeToken(Json::from_json(value)?))
37+
}
38+
}
39+
_ => Err(Error::UnexpectedJsonType {
40+
wanted: JsonType::String,
41+
got: JsonType::from(&value),
42+
}),
43+
}
44+
}
45+
}
46+
47+
/// A value that can contain multiple asset classes
48+
#[derive(Clone, Debug, PartialEq, Eq)]
49+
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
50+
#[cfg_attr(feature = "lbf", derive(Json))]
51+
pub struct Value(pub BTreeMap<CurrencySymbol, BTreeMap<TokenName, BigInt>>);
52+
53+
/// Name of a token. This can be any arbitrary bytearray
54+
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
55+
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
56+
#[cfg_attr(feature = "lbf", derive(Json))]
57+
pub struct TokenName(pub LedgerBytes);
58+
59+
pub fn ada_token_name() -> TokenName {
60+
TokenName(LedgerBytes(Vec::with_capacity(0)))
61+
}
62+
63+
/// AssetClass is uniquely identifying a specific asset
64+
#[derive(Clone, Debug, PartialEq, Eq)]
65+
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
66+
#[cfg_attr(feature = "lbf", derive(Json))]
67+
pub struct AssetClass {
68+
pub currency_symbol: CurrencySymbol,
69+
pub token_name: TokenName,
70+
}

‎tests/json.proptest-regressions

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
# Seeds for failure cases proptest has generated in the past. It is
2+
# automatically read and these particular cases re-run before any
3+
# novel cases are generated.
4+
#
5+
# It is recommended to check this file in to source control so that
6+
# everyone who runs the test benefits from these saved cases.
7+
cc dffdc0d6882ec07da81b350b8df24cc308c6254ffac926906b225a0c4c1d7a3c # shrinks to val = None
8+
cc 00ae5808c2087260e959510a407f52841db61f4768d9d9fbbf10c81e72cbfed0 # shrinks to val = TransactionOutput { address: Address { credential: PubKey(Ed25519PubKeyHash(LedgerBytes([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]))), staking_credential: Some(Hash(PubKey(Ed25519PubKeyHash(LedgerBytes([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 162, 65, 191, 121, 179, 69]))))) }, datum: None, reference_script: Some(ScriptHash(LedgerBytes([239, 97, 230, 88, 184, 228, 99, 176, 146, 148, 167, 196, 117, 32, 97, 38, 86, 9, 90, 209, 252, 201, 25, 187, 205, 229, 143, 178]))), value: Value({NativeToken(MintingPolicyHash(ScriptHash(LedgerBytes([11, 88, 175, 168, 164, 59, 135, 55, 243, 64, 224, 122, 199, 213, 156, 203, 6, 99, 2, 251, 245, 127, 219, 158, 61, 46, 29, 53])))): {TokenName(LedgerBytes([20, 144, 68, 149, 223, 25, 94, 96, 239, 215, 38, 158, 255, 36, 251, 88, 152, 94, 83, 172, 26, 25, 158, 91, 84, 55, 211, 69, 34, 184, 95, 95])): -76608536071469390922120019135675850800043542500, TokenName(LedgerBytes([126, 159, 231, 110, 76, 246, 61, 164, 172, 230, 96, 17, 45, 62, 45, 110, 1, 253, 210, 224, 229, 193, 128, 125, 245, 181, 143, 252, 73, 31, 137, 12])): -869519927606458777036033605556971787784221345636, TokenName(LedgerBytes([175, 120, 135, 8, 67, 182, 74, 177, 40, 228, 131, 46, 213, 72, 29, 161, 130, 112, 216, 205, 54, 240, 56, 138, 243, 165, 161, 87, 154, 6, 80, 77])): -1161652464071255915489810453507807521668634874359, TokenName(LedgerBytes([186, 174, 23, 208, 164, 229, 252, 3, 89, 70, 93, 104, 224, 250, 36, 147, 48, 181, 123, 6, 116, 231, 99, 13, 54, 95, 248, 224, 123, 16, 157, 178])): 1216247099708657134764566498423302015219070158021, TokenName(LedgerBytes([215, 139, 159, 177, 96, 175, 86, 150, 222, 6, 174, 149, 149, 94, 113, 82, 210, 180, 120, 197, 206, 85, 10, 246, 226, 44, 100, 239, 141, 155, 17, 219])): -1143454733591678735118362719269199650202157894026}, NativeToken(MintingPolicyHash(ScriptHash(LedgerBytes([84, 44, 221, 32, 17, 40, 142, 104, 97, 34, 23, 116, 76, 213, 191, 180, 157, 32, 35, 172, 189, 147, 126, 172, 146, 183, 7, 188])))): {TokenName(LedgerBytes([7, 251, 254, 143, 98, 206, 150, 151, 10, 165, 16, 254, 161, 210, 156, 20, 129, 1, 191, 68, 215, 137, 234, 190, 97, 250, 3, 176, 87, 7, 96, 226])): 705313204239017645043119957319775641925556614700, TokenName(LedgerBytes([42, 152, 236, 110, 210, 189, 51, 69, 49, 189, 239, 145, 187, 193, 143, 34, 26, 218, 94, 188, 156, 57, 130, 53, 249, 171, 19, 195, 134, 30, 76, 189])): -1240475875082917352106105223785008621782823546366, TokenName(LedgerBytes([75, 97, 177, 196, 76, 180, 209, 107, 129, 73, 236, 123, 32, 219, 184, 236, 78, 27, 95, 2, 140, 117, 255, 235, 136, 3, 191, 133, 251, 183, 102, 88])): -976020070016100520506948879093747528807265456386, TokenName(LedgerBytes([104, 190, 54, 114, 133, 189, 104, 159, 148, 121, 54, 210, 103, 181, 24, 10, 207, 30, 170, 119, 51, 191, 99, 61, 226, 236, 196, 231, 255, 192, 18, 173])): -489940020290243915087924158197726235516485450080, TokenName(LedgerBytes([122, 54, 178, 199, 32, 243, 96, 185, 38, 58, 128, 93, 90, 3, 129, 35, 133, 197, 70, 66, 107, 137, 186, 236, 210, 8, 88, 96, 144, 203, 97, 191])): -309872201149998496290310461313409073691611236239}, NativeToken(MintingPolicyHash(ScriptHash(LedgerBytes([116, 136, 146, 173, 228, 147, 104, 198, 35, 92, 8, 150, 163, 67, 52, 145, 111, 15, 37, 148, 55, 111, 121, 139, 9, 182, 253, 58])))): {TokenName(LedgerBytes([23, 190, 194, 110, 105, 232, 209, 14, 188, 187, 119, 2, 22, 203, 200, 220, 71, 203, 108, 198, 34, 145, 53, 0, 26, 27, 15, 98, 69, 50, 59, 160])): -459649877668364465992643874915351728409910463512, TokenName(LedgerBytes([62, 2, 226, 121, 51, 119, 158, 17, 245, 211, 93, 192, 129, 254, 91, 153, 160, 236, 249, 92, 54, 92, 31, 138, 231, 32, 9, 159, 243, 30, 218, 189])): -1158326859220016292364740683185655895046178393660, TokenName(LedgerBytes([136, 233, 1, 124, 233, 163, 121, 45, 208, 249, 18, 108, 14, 88, 19, 105, 158, 108, 112, 157, 227, 206, 113, 2, 115, 197, 57, 67, 223, 170, 11, 161])): 746152174603737932670214892352554859801601529040, TokenName(LedgerBytes([187, 166, 22, 52, 71, 107, 249, 46, 104, 88, 110, 197, 130, 44, 15, 237, 220, 156, 215, 45, 253, 87, 148, 159, 107, 251, 183, 37, 60, 105, 59, 132])): 608021313453555983489699298823687107456610881841, TokenName(LedgerBytes([204, 175, 64, 88, 196, 142, 238, 8, 248, 101, 81, 177, 1, 10, 1, 10, 148, 128, 223, 181, 236, 102, 115, 108, 205, 27, 199, 60, 71, 151, 7, 192])): -591780814015796864176719543748119161920463071536}, NativeToken(MintingPolicyHash(ScriptHash(LedgerBytes([125, 248, 150, 2, 198, 77, 109, 13, 18, 88, 159, 194, 52, 206, 161, 134, 252, 230, 98, 161, 203, 251, 130, 127, 6, 18, 94, 192])))): {TokenName(LedgerBytes([18, 51, 220, 47, 100, 103, 22, 144, 76, 169, 202, 191, 3, 252, 30, 229, 21, 103, 187, 28, 209, 223, 237, 160, 209, 27, 203, 117, 38, 13, 231, 189])): -926535279994085164240682830832833370778699612685, TokenName(LedgerBytes([40, 55, 121, 151, 31, 157, 55, 115, 114, 71, 107, 86, 138, 220, 204, 176, 239, 81, 27, 23, 103, 177, 85, 117, 77, 2, 149, 198, 104, 106, 5, 0])): -161354577078241417939487255425021383300272874347, TokenName(LedgerBytes([44, 24, 140, 153, 86, 150, 193, 46, 218, 202, 152, 147, 152, 184, 236, 68, 131, 191, 217, 11, 85, 104, 74, 97, 157, 223, 77, 100, 230, 65, 100, 135])): -1319414797052919783578966533121851572832034360747, TokenName(LedgerBytes([109, 97, 1, 126, 28, 143, 60, 208, 0, 86, 130, 62, 121, 110, 149, 222, 25, 168, 55, 147, 233, 57, 123, 144, 43, 103, 107, 119, 5, 58, 158, 132])): -112858397416914908625705428100185331153645922261, TokenName(LedgerBytes([122, 130, 160, 200, 102, 251, 66, 16, 155, 218, 149, 114, 22, 182, 63, 41, 186, 251, 13, 123, 51, 75, 114, 231, 111, 233, 73, 132, 29, 255, 37, 26])): 1347687554504200503476114943462602528171219467136}, NativeToken(MintingPolicyHash(ScriptHash(LedgerBytes([141, 241, 173, 235, 51, 135, 210, 206, 95, 68, 45, 54, 82, 172, 139, 97, 3, 193, 10, 214, 180, 250, 176, 204, 227, 31, 172, 42])))): {TokenName(LedgerBytes([6, 22, 111, 152, 116, 117, 234, 92, 105, 26, 63, 59, 47, 186, 164, 183, 40, 34, 169, 198, 50, 41, 158, 95, 137, 35, 216, 85, 194, 205, 209, 247])): -1099915819309362501335256240953429530457999367312, TokenName(LedgerBytes([78, 131, 98, 73, 94, 234, 86, 21, 74, 31, 9, 200, 208, 105, 115, 55, 218, 9, 37, 45, 242, 20, 174, 233, 164, 44, 15, 227, 34, 24, 98, 69])): 957019749453260958303441375065518739407739913268, TokenName(LedgerBytes([161, 164, 6, 20, 218, 151, 180, 221, 20, 212, 33, 116, 166, 184, 160, 188, 106, 14, 103, 61, 219, 192, 132, 239, 91, 179, 64, 251, 113, 82, 182, 15])): -1314746826793609427111821896470868225144891692200, TokenName(LedgerBytes([236, 22, 184, 40, 140, 181, 237, 200, 26, 48, 108, 37, 250, 243, 193, 109, 248, 63, 200, 186, 149, 24, 56, 102, 160, 179, 11, 60, 37, 228, 206, 203])): 713245849113819181643622728802880367243439203560, TokenName(LedgerBytes([236, 221, 30, 199, 225, 221, 83, 102, 170, 42, 204, 119, 97, 106, 10, 177, 13, 113, 163, 175, 48, 242, 22, 120, 189, 197, 45, 170, 68, 91, 68, 141])): -468589402323672995922072259181172764203058336264}}) }
9+
cc 23e856bf45ffdb419c9142a87bde85132d61afcb9189ec0f20bb0194a8d6a295 # shrinks to val = TxInInfo { transaction_input: TransactionInput { transaction_id: TransactionHash(LedgerBytes([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])), index: 0 }, resolved: TransactionOutput { address: Address { credential: PubKey(Ed25519PubKeyHash(LedgerBytes([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]))), staking_credential: None }, datum: None, reference_script: None, value: Value({NativeToken(MintingPolicyHash(ScriptHash(LedgerBytes([0, 0, 0, 0, 0, 202, 228, 235, 82, 143, 19, 65, 20, 120, 91, 167, 241, 223, 52, 113, 57, 189, 255, 84, 211, 127, 54, 230])))): {TokenName(LedgerBytes([19, 108, 229, 149, 180, 151, 26, 200, 139, 125, 224, 18, 81, 18, 219, 194, 64, 138, 174, 243, 193, 84, 67, 174, 67, 158, 218, 211, 227, 37, 153, 39])): -1067346056204877888232052891195485758496431962871, TokenName(LedgerBytes([24, 102, 47, 76, 42, 99, 205, 120, 205, 200, 232, 81, 22, 75, 235, 149, 37, 240, 8, 78, 132, 86, 176, 246, 63, 132, 186, 228, 232, 36, 26, 239])): -989762596757165910996265236330121959086490904636, TokenName(LedgerBytes([42, 208, 52, 55, 30, 51, 7, 66, 7, 53, 123, 128, 10, 237, 129, 182, 180, 207, 9, 248, 26, 109, 192, 194, 241, 137, 113, 242, 124, 174, 179, 53])): 1008240247202896369655076190385322914737396945533, TokenName(LedgerBytes([94, 100, 99, 146, 217, 147, 68, 28, 20, 192, 223, 57, 65, 143, 14, 132, 159, 143, 40, 4, 87, 110, 224, 240, 12, 144, 176, 123, 194, 73, 134, 146])): 237647232805922288416528373386098483738090989479, TokenName(LedgerBytes([116, 224, 50, 116, 125, 35, 160, 78, 116, 151, 255, 40, 255, 65, 62, 182, 208, 232, 241, 188, 121, 131, 72, 40, 39, 135, 240, 63, 52, 74, 55, 149])): 570505488649379814922013567045668861167795909850}, NativeToken(MintingPolicyHash(ScriptHash(LedgerBytes([34, 51, 216, 175, 110, 3, 232, 156, 142, 166, 221, 7, 142, 242, 14, 165, 47, 235, 223, 208, 119, 78, 122, 72, 169, 1, 7, 34])))): {TokenName(LedgerBytes([33, 205, 52, 70, 19, 7, 73, 51, 60, 161, 1, 37, 48, 51, 203, 177, 247, 132, 159, 133, 210, 92, 86, 22, 135, 90, 219, 12, 141, 135, 229, 186])): 578510690027268871217970828275763781021102109322, TokenName(LedgerBytes([48, 211, 235, 63, 230, 178, 91, 10, 144, 172, 37, 81, 71, 245, 38, 150, 152, 224, 74, 216, 240, 101, 246, 18, 144, 137, 228, 77, 62, 36, 222, 233])): -1294203911311073546477611086600497939317102205875, TokenName(LedgerBytes([59, 206, 75, 96, 186, 120, 181, 219, 49, 81, 14, 142, 182, 66, 226, 134, 240, 123, 103, 254, 97, 204, 209, 210, 152, 99, 177, 92, 222, 249, 102, 22])): -770995797977529854896577301417884152081299121486, TokenName(LedgerBytes([115, 185, 33, 148, 241, 52, 62, 20, 208, 149, 25, 188, 222, 136, 190, 63, 28, 138, 91, 131, 77, 162, 245, 144, 4, 227, 157, 21, 218, 202, 210, 134])): 1342562893383127162412644217597176597680806494231, TokenName(LedgerBytes([116, 47, 227, 102, 40, 146, 5, 227, 59, 92, 187, 42, 127, 233, 108, 46, 43, 195, 201, 220, 41, 44, 147, 81, 45, 87, 124, 23, 252, 69, 90, 5])): 611220300449284999825166316014198030944977976548}, NativeToken(MintingPolicyHash(ScriptHash(LedgerBytes([72, 209, 86, 135, 76, 141, 168, 49, 60, 120, 84, 97, 65, 0, 21, 19, 235, 63, 61, 74, 126, 117, 254, 239, 126, 176, 144, 254])))): {TokenName(LedgerBytes([50, 194, 251, 63, 155, 155, 68, 117, 128, 251, 86, 197, 251, 217, 152, 202, 109, 159, 186, 15, 241, 173, 172, 236, 40, 121, 38, 242, 99, 135, 235, 34])): -382326041301001476161683039898871272831848330732, TokenName(LedgerBytes([116, 141, 120, 115, 158, 191, 75, 191, 154, 114, 10, 250, 131, 18, 135, 120, 188, 9, 156, 22, 191, 206, 58, 215, 45, 97, 177, 234, 134, 19, 45, 67])): 694291972102096145012642420831989351885355325655, TokenName(LedgerBytes([138, 168, 113, 213, 186, 255, 134, 10, 45, 79, 3, 160, 28, 209, 174, 47, 57, 251, 190, 48, 75, 195, 216, 140, 247, 151, 77, 167, 120, 224, 136, 98])): -358116560418816488912580133289096357847344129849, TokenName(LedgerBytes([188, 108, 160, 41, 79, 236, 105, 197, 228, 145, 253, 57, 201, 218, 12, 43, 206, 144, 165, 189, 125, 135, 83, 108, 225, 184, 156, 150, 124, 16, 153, 5])): 427674039222312770043446767752713941352129860336, TokenName(LedgerBytes([221, 70, 250, 2, 132, 41, 204, 117, 77, 119, 210, 104, 111, 228, 234, 80, 91, 182, 66, 97, 64, 121, 97, 207, 227, 88, 189, 82, 238, 84, 96, 158])): 552027470377161046349829525131962688053207070655}, NativeToken(MintingPolicyHash(ScriptHash(LedgerBytes([95, 67, 31, 228, 239, 11, 109, 20, 176, 176, 172, 70, 125, 254, 228, 228, 244, 208, 102, 144, 231, 96, 251, 7, 204, 139, 124, 205])))): {TokenName(LedgerBytes([32, 158, 47, 142, 150, 126, 105, 57, 230, 249, 57, 221, 205, 8, 159, 37, 95, 110, 153, 111, 40, 167, 67, 226, 78, 217, 34, 43, 112, 1, 23, 25])): -723219481928837099537908449694100762440175911293, TokenName(LedgerBytes([85, 209, 175, 38, 59, 43, 141, 44, 151, 178, 107, 190, 9, 54, 204, 61, 253, 147, 144, 29, 147, 179, 44, 98, 208, 7, 222, 106, 155, 188, 80, 110])): 766781946858097192769897252769839049794563248538, TokenName(LedgerBytes([181, 240, 152, 171, 241, 214, 82, 157, 132, 175, 211, 107, 100, 198, 188, 93, 131, 158, 156, 6, 188, 112, 4, 81, 255, 170, 63, 104, 150, 10, 144, 230])): 1331204098450598836888074768153621809017589982909, TokenName(LedgerBytes([182, 179, 93, 146, 197, 102, 20, 81, 235, 121, 12, 46, 155, 67, 249, 73, 217, 233, 203, 54, 46, 179, 255, 56, 80, 100, 18, 62, 83, 109, 239, 221])): 971548505869887759803994513484688026755393067304, TokenName(LedgerBytes([185, 200, 229, 133, 5, 105, 33, 194, 123, 213, 38, 124, 15, 127, 127, 180, 232, 199, 201, 28, 224, 100, 227, 46, 102, 87, 186, 226, 90, 163, 184, 244])): 1287924349628769871867727420530890417139699964875}, NativeToken(MintingPolicyHash(ScriptHash(LedgerBytes([188, 150, 57, 200, 13, 120, 253, 25, 157, 144, 83, 178, 238, 225, 17, 222, 94, 252, 21, 71, 226, 213, 43, 57, 201, 240, 36, 129])))): {TokenName(LedgerBytes([3, 143, 126, 250, 200, 34, 19, 200, 97, 55, 157, 73, 100, 79, 158, 211, 35, 53, 192, 48, 41, 133, 185, 85, 17, 240, 67, 143, 23, 68, 136, 3])): 1132739483556721969062033724384482318516360703507, TokenName(LedgerBytes([72, 217, 158, 5, 41, 59, 111, 107, 131, 175, 240, 80, 141, 229, 253, 117, 189, 43, 12, 82, 223, 248, 30, 64, 197, 141, 141, 226, 113, 73, 184, 105])): 866763940070325994637997003539860704097024179699, TokenName(LedgerBytes([130, 20, 14, 242, 131, 104, 146, 190, 158, 30, 35, 239, 52, 27, 247, 81, 246, 216, 18, 116, 186, 211, 165, 101, 254, 242, 234, 107, 245, 127, 8, 114])): 613808508758035814530718737524105816676378563022, TokenName(LedgerBytes([224, 211, 34, 201, 66, 10, 187, 54, 15, 243, 79, 29, 53, 38, 115, 78, 2, 57, 117, 50, 133, 26, 122, 243, 180, 134, 184, 17, 153, 59, 97, 152])): 881537823246237591831003081409664657239031112892, TokenName(LedgerBytes([252, 80, 172, 35, 152, 94, 14, 179, 165, 176, 75, 55, 219, 33, 138, 74, 97, 225, 235, 210, 254, 188, 34, 80, 77, 22, 157, 3, 202, 194, 216, 65])): -1284471749425626604022864319172057837940698847572}}) } }

‎tests/json.rs

+84
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
#[cfg(test)]
2+
#[cfg(feature = "lbf")]
3+
mod json_roundtrip_tests {
4+
use lbr_prelude::json::{Error, Json};
5+
use plutus_ledger_types::generators::correct::*;
6+
use proptest::prelude::*;
7+
8+
fn from_to_json<T>(val: &T) -> Result<T, Error>
9+
where
10+
T: Json + PartialEq,
11+
{
12+
T::from_json(val.to_json()?)
13+
}
14+
15+
proptest! {
16+
#[test]
17+
fn test_asset_class(val in arb_asset_class()) {
18+
assert_eq!(val, from_to_json(&val)?);
19+
}
20+
}
21+
22+
proptest! {
23+
#[test]
24+
fn test_value(val in arb_value()) {
25+
assert_eq!(val, from_to_json(&val)?);
26+
}
27+
}
28+
29+
proptest! {
30+
#[test]
31+
fn test_plutus_data(val in arb_plutus_data()) {
32+
assert_eq!(val, from_to_json(&val)?);
33+
}
34+
}
35+
36+
proptest! {
37+
#[test]
38+
fn test_plutus_interval(val in arb_plutus_interval_posix_time()) {
39+
assert_eq!(val, from_to_json(&val)?);
40+
}
41+
}
42+
43+
proptest! {
44+
#[test]
45+
fn test_address(val in arb_address()) {
46+
assert_eq!(val, from_to_json(&val)?);
47+
}
48+
}
49+
50+
proptest! {
51+
#[test]
52+
fn test_transaction_input(val in arb_transaction_input()) {
53+
assert_eq!(val, from_to_json(&val)?);
54+
}
55+
}
56+
57+
proptest! {
58+
#[test]
59+
fn test_transaction_output(val in arb_transaction_output()) {
60+
assert_eq!(val, from_to_json(&val)?);
61+
}
62+
}
63+
64+
proptest! {
65+
#[test]
66+
fn test_tx_in_info(val in arb_tx_in_info()) {
67+
assert_eq!(val, from_to_json(&val)?);
68+
}
69+
}
70+
71+
proptest! {
72+
#[test]
73+
fn test_output_datum(val in arb_output_datum()) {
74+
assert_eq!(val, from_to_json(&val)?);
75+
}
76+
}
77+
78+
proptest! {
79+
#[test]
80+
fn test_redeemeer(val in arb_redeemer()) {
81+
assert_eq!(val, from_to_json(&val)?);
82+
}
83+
}
84+
}

‎tests/plutus_data.rs

+93
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
#[cfg(test)]
2+
mod plutusdata_roundtrip_tests {
3+
use plutus_ledger_types::generators::correct::*;
4+
use plutus_ledger_types::plutus_data::{FromPlutusData, PlutusDataError, ToPlutusData};
5+
use proptest::collection::{btree_map, btree_set, vec};
6+
use proptest::option;
7+
use proptest::prelude::*;
8+
use proptest::result::maybe_err;
9+
10+
fn from_to_plutus_data<T>(val: &T) -> Result<T, PlutusDataError>
11+
where
12+
T: ToPlutusData + FromPlutusData + PartialEq,
13+
{
14+
T::from_plutus_data(val.to_plutus_data())
15+
}
16+
17+
proptest! {
18+
#[test]
19+
fn test_integer(val in arb_integer()) {
20+
assert_eq!(val, from_to_plutus_data(&val)?);
21+
}
22+
}
23+
24+
proptest! {
25+
#[test]
26+
fn test_bool(val in arb_bool() ) {
27+
assert_eq!(val, from_to_plutus_data(&val)?);
28+
}
29+
}
30+
31+
proptest! {
32+
#[test]
33+
fn test_char(val in arb_char() ) {
34+
assert_eq!(val, from_to_plutus_data(&val)?);
35+
}
36+
}
37+
38+
proptest! {
39+
#[test]
40+
fn test_bytes(val in arb_bytes() ) {
41+
assert_eq!(val, from_to_plutus_data(&val)?);
42+
}
43+
}
44+
45+
proptest! {
46+
#[test]
47+
fn test_text(val in arb_text() ) {
48+
assert_eq!(val, from_to_plutus_data(&val)?);
49+
}
50+
}
51+
52+
proptest! {
53+
#[test]
54+
fn test_maybe(val in option::of(arb_integer())) {
55+
assert_eq!(val, from_to_plutus_data(&val)?);
56+
}
57+
}
58+
59+
proptest! {
60+
#[test]
61+
fn test_result(val in maybe_err(arb_bool(), arb_integer())) {
62+
assert_eq!(val, from_to_plutus_data(&val)?);
63+
}
64+
}
65+
66+
proptest! {
67+
#[test]
68+
fn test_vec(val in vec(arb_integer(), 20)) {
69+
assert_eq!(val, from_to_plutus_data(&val)?);
70+
}
71+
}
72+
73+
proptest! {
74+
#[test]
75+
fn test_set(val in btree_set(arb_integer(), 20)) {
76+
assert_eq!(val, from_to_plutus_data(&val)?);
77+
}
78+
}
79+
80+
proptest! {
81+
#[test]
82+
fn test_map(val in btree_map(arb_integer(), arb_text(), 20)) {
83+
assert_eq!(val, from_to_plutus_data(&val)?);
84+
}
85+
}
86+
87+
proptest! {
88+
#[test]
89+
fn test_complicated(val in arb_complicated()) {
90+
assert_eq!(val, from_to_plutus_data(&val)?);
91+
}
92+
}
93+
}

0 commit comments

Comments
 (0)
Please sign in to comment.