fix(primitives): contemplate Conway's CBOR set tag (#421)

Co-authored-by: jmhrpr <25673452+jmhrpr@users.noreply.github.com>
This commit is contained in:
Santiago Carmuega 2024-03-08 19:32:03 -03:00 committed by GitHub
parent 655efad6c2
commit 54997daf66
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 114 additions and 31 deletions

View file

@ -1,7 +1,13 @@
use minicbor::{data::Tag, Decode, Encode};
use minicbor::{
data::{Tag, Type},
decode::Error,
Decode, Encode,
};
use serde::{Deserialize, Serialize};
use std::{fmt, hash::Hash as StdHash, ops::Deref};
static TAG_SET: u64 = 258;
/// Utility for skipping parts of the CBOR payload, use only for debugging
#[derive(Debug, PartialEq, PartialOrd, Eq, Ord)]
pub struct SkipCbor<const N: usize> {}
@ -474,6 +480,83 @@ where
}
}
/// Set
///
/// Optional 258 tag (until era after Conway, at which point is it required)
/// with a vec of items which should contain no duplicates
#[derive(Debug, PartialEq, Eq, Clone, PartialOrd, Serialize, Deserialize)]
pub struct Set<T>(Vec<T>);
impl<T> Set<T> {
pub fn to_vec(self) -> Vec<T> {
self.0
}
}
impl<T> Deref for Set<T> {
type Target = Vec<T>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl<T> From<Vec<T>> for Set<T> {
fn from(value: Vec<T>) -> Self {
Set(value)
}
}
impl<T> From<Set<KeepRaw<'_, T>>> for Set<T> {
fn from(value: Set<KeepRaw<'_, T>>) -> Self {
let inner = value.0.into_iter().map(|x| x.unwrap()).collect();
Self(inner)
}
}
impl<'a, T> IntoIterator for &'a Set<T> {
type Item = &'a T;
type IntoIter = std::slice::Iter<'a, T>;
fn into_iter(self) -> Self::IntoIter {
self.0.iter()
}
}
impl<'b, C, T> minicbor::decode::Decode<'b, C> for Set<T>
where
T: Decode<'b, C>,
{
fn decode(d: &mut minicbor::Decoder<'b>, ctx: &mut C) -> Result<Self, minicbor::decode::Error> {
// decode optional set tag (this will be required in era following Conway)
if d.datatype()? == Type::Tag {
let found_tag = d.tag()?;
if found_tag != Tag::Unassigned(TAG_SET) {
return Err(Error::message(format!("Unrecognised tag: {found_tag:?}")));
}
}
Ok(Self(d.decode_with(ctx)?))
}
}
impl<C, T> minicbor::encode::Encode<C> for Set<T>
where
T: 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(TAG_SET))?;
e.encode_with(&self.0, ctx)?;
Ok(())
}
}
/// A uint structure that preserves original int length
#[derive(Debug, PartialEq, Copy, Clone, PartialOrd, Eq, Ord, Hash)]
pub enum AnyUInt {

View file

@ -7,7 +7,7 @@ use serde::{Deserialize, Serialize};
use pallas_codec::minicbor::{Decode, Encode};
use pallas_crypto::hash::Hash;
use pallas_codec::utils::{Bytes, KeepRaw, KeyValuePairs, MaybeIndefArray, Nullable};
use pallas_codec::utils::{Bytes, KeepRaw, KeyValuePairs, MaybeIndefArray, Nullable, Set};
// required for derive attrs to work
use pallas_codec::minicbor;
@ -66,7 +66,7 @@ pub use crate::alonzo::RewardAccount;
pub type Withdrawals = KeyValuePairs<RewardAccount, Coin>;
pub type RequiredSigners = Vec<AddrKeyhash>;
pub type RequiredSigners = Set<AddrKeyhash>; // TODO: NON EMPTY SET
pub use crate::alonzo::Port;
@ -106,7 +106,7 @@ pub enum Certificate {
cost: Coin,
margin: UnitInterval,
reward_account: RewardAccount,
pool_owners: Vec<AddrKeyhash>,
pool_owners: Set<AddrKeyhash>,
relays: Vec<Relay>,
pool_metadata: Option<PoolMetadata>,
},
@ -645,7 +645,7 @@ impl<C> minicbor::Encode<C> for DRepVotingThresholds {
#[cbor(map)]
pub struct PseudoTransactionBody<T1> {
#[n(0)]
pub inputs: Vec<TransactionInput>,
pub inputs: Set<TransactionInput>,
#[n(1)]
pub outputs: Vec<T1>,
@ -657,7 +657,7 @@ pub struct PseudoTransactionBody<T1> {
pub ttl: Option<u64>,
#[n(4)]
pub certificates: Option<Vec<Certificate>>, // TODO: NON EMPTY
pub certificates: Option<Set<Certificate>>, // TODO: NON EMPTY ORDERED SET
#[n(5)]
pub withdrawals: Option<KeyValuePairs<RewardAccount, Coin>>, // TODO: NON EMPTY
@ -677,7 +677,7 @@ pub struct PseudoTransactionBody<T1> {
pub script_data_hash: Option<Hash<32>>,
#[n(13)]
pub collateral: Option<Vec<TransactionInput>>, // TODO: NON EMPTY SET
pub collateral: Option<Set<TransactionInput>>, // TODO: NON EMPTY SET
#[n(14)]
pub required_signers: Option<Vec<AddrKeyhash>>, // TODO: NON EMPTY SET
@ -692,14 +692,14 @@ pub struct PseudoTransactionBody<T1> {
pub total_collateral: Option<Coin>,
#[n(18)]
pub reference_inputs: Option<Vec<TransactionInput>>, // TODO: NON EMPTY SET
pub reference_inputs: Option<Set<TransactionInput>>, // TODO: NON EMPTY SET
// -- NEW IN CONWAY
#[n(19)]
pub voting_procedures: Option<VotingProcedures>,
#[n(20)]
pub proposal_procedures: Option<Vec<ProposalProcedure>>, // TODO: NON EMPTY MAP
pub proposal_procedures: Option<Set<ProposalProcedure>>, // TODO: NON EMPTY ORDERED SET
#[n(21)]
pub treasury_value: Option<Coin>,
@ -858,7 +858,7 @@ pub enum GovAction {
NoConfidence(Option<GovActionId>),
UpdateCommittee(
Option<GovActionId>,
Vec<CommitteeColdCredential>,
Set<CommitteeColdCredential>,
KeyValuePairs<CommitteeColdCredential, Epoch>,
UnitInterval,
),
@ -1229,70 +1229,66 @@ pub use crate::alonzo::BootstrapWitness;
#[cbor(map)]
pub struct WitnessSet {
#[n(0)]
pub vkeywitness: Option<Vec<VKeyWitness>>,
pub vkeywitness: Option<Set<VKeyWitness>>, // TODO: NON EMPTY SET
#[n(1)]
pub native_script: Option<Vec<NativeScript>>,
pub native_script: Option<Set<NativeScript>>, // TODO: NON EMPTY SET
#[n(2)]
pub bootstrap_witness: Option<Vec<BootstrapWitness>>,
pub bootstrap_witness: Option<Set<BootstrapWitness>>, // TODO: NON EMPTY SET
#[n(3)]
pub plutus_v1_script: Option<Vec<PlutusV1Script>>,
pub plutus_v1_script: Option<Set<PlutusV1Script>>, // TODO: NON EMPTY SET
#[n(4)]
pub plutus_data: Option<Vec<PlutusData>>,
pub plutus_data: Option<Set<PlutusData>>, // TODO: NON EMPTY SET
#[n(5)]
pub redeemer: Option<Vec<Redeemer>>,
#[n(6)]
pub plutus_v2_script: Option<Vec<PlutusV2Script>>,
pub plutus_v2_script: Option<Set<PlutusV2Script>>, // TODO: NON EMPTY SET
#[n(7)]
pub plutus_v3_script: Option<Vec<PlutusV3Script>>,
pub plutus_v3_script: Option<Set<PlutusV3Script>>, // TODO: NON EMPTY SET
}
#[derive(Encode, Decode, Debug, PartialEq, Clone)]
#[cbor(map)]
pub struct MintedWitnessSet<'b> {
#[n(0)]
pub vkeywitness: Option<Vec<VKeyWitness>>,
pub vkeywitness: Option<Set<VKeyWitness>>, // TODO: NON EMPTY SET
#[n(1)]
pub native_script: Option<Vec<KeepRaw<'b, NativeScript>>>,
pub native_script: Option<Set<KeepRaw<'b, NativeScript>>>, // TODO: NON EMPTY SET
#[n(2)]
pub bootstrap_witness: Option<Vec<BootstrapWitness>>,
pub bootstrap_witness: Option<Set<BootstrapWitness>>, // TODO: NON EMPTY SET
#[n(3)]
pub plutus_v1_script: Option<Vec<PlutusV1Script>>,
pub plutus_v1_script: Option<Set<PlutusV1Script>>, // TODO: NON EMPTY SET
#[b(4)]
pub plutus_data: Option<Vec<KeepRaw<'b, PlutusData>>>,
pub plutus_data: Option<Set<KeepRaw<'b, PlutusData>>>, // TODO: NON EMPTY SET
#[n(5)]
pub redeemer: Option<Vec<Redeemer>>,
#[n(6)]
pub plutus_v2_script: Option<Vec<PlutusV2Script>>,
pub plutus_v2_script: Option<Set<PlutusV2Script>>, // TODO: NON EMPTY SET
#[n(7)]
pub plutus_v3_script: Option<Vec<PlutusV3Script>>,
pub plutus_v3_script: Option<Set<PlutusV3Script>>, // TODO: NON EMPTY SET
}
impl<'b> From<MintedWitnessSet<'b>> for WitnessSet {
fn from(x: MintedWitnessSet<'b>) -> Self {
WitnessSet {
vkeywitness: x.vkeywitness,
native_script: x
.native_script
.map(|x| x.into_iter().map(|x| x.unwrap()).collect()),
native_script: x.native_script.map(Into::into),
bootstrap_witness: x.bootstrap_witness,
plutus_v1_script: x.plutus_v1_script,
plutus_data: x
.plutus_data
.map(|x| x.into_iter().map(|x| x.unwrap()).collect()),
plutus_data: x.plutus_data.map(Into::into),
redeemer: x.redeemer,
plutus_v2_script: x.plutus_v2_script,
plutus_v3_script: x.plutus_v3_script,
@ -1520,7 +1516,10 @@ mod tests {
#[test]
fn block_isomorphic_decoding_encoding() {
let test_blocks = [include_str!("../../../test_data/conway1.artificial.block")];
let test_blocks = [
include_str!("../../../test_data/conway1.block"),
include_str!("../../../test_data/conway1.artificial.block"),
];
for (idx, block_str) in test_blocks.iter().enumerate() {
println!("decoding test block {}", idx + 1);

1
test_data/conway1.block Normal file
View file

@ -0,0 +1 @@
820785828a1a0010afaa1a0150d7925820a22f65265e7a71cfc3b637d6aefe8f8241d562f5b1b787ff36697ae4c3886f185820e856c84a3d90c8526891bd58d957afadc522de37b14ae04c395db8a7a1b08c4a582015587d5633be324f8de97168399ab59d7113f0a74bc7412b81f7cc1007491671825840af9ff8cb146880eba1b12beb72d86be46fbc98f6b88110cd009bd6746d255a14bb0637e3a29b7204bff28236c1b9f73e501fed1eb5634bd741be120332d25e5e5850a9f1de24d01ba43b025a3351b25de50cc77f931ed8cdd0be632ad1a437ec9cf327b24eb976f91dbf68526f15bacdf8f0c1ea4a2072df9412796b34836a816760f4909b98c0e76b160d9aec6b2da060071903705820b5858c659096fcc19f2f3baef5fdd6198641a623bd43e792157b5ea3a2ecc85c8458200ca1ec2c1c2af308bd9e7a86eb12d603a26157752f3f71c337781c456e6ed0c90018a558408e554b644a2b25cb5892d07a26c273893829f1650ec33bf6809d953451c519c32cfd48d044cd897a17cdef154d5f5c9b618d9b54f8c49e170082c08c236524098209005901c05a96b747789ef6678b2f4a2a7caca92e270f736e9b621686f95dd1332005102faee21ed50cf6fa6c67e38b33df686c79c91d55f30769f7c964d98aa84cbefe0a808ee6f45faaf9badcc3f746e6a51df1aa979195871fd5ffd91037ea216803be7e7fccbf4c13038c459c7a14906ab57f3306fe155af7877c88866eede7935f642f6a72f1368c33ed5cc7607c995754af787a5af486958edb531c0ae65ce9fdce423ad88925e13ef78700950093ae707bb1100299a66a5bb15137f7ba62132ba1c9b74495aac50e1106bacb5db2bed4592f66b610c2547f485d061c6c149322b0c92bdde644eb672267fdab5533157ff398b9e16dd6a06edfd67151e18a3ac93fc28a51f9a73f8b867f5f432b1d9b5ae454ef63dea7e1a78631cf3fee1ba82db61726701ac5db1c4fee4bb6316768c82c0cdc4ebd58ccc686be882f9608592b3c718e4b5d356982a6b83433fe76d37394eff9f3a8e4773e3bab9a8b93b4ea90fa33bfbcf0dc5a21bfe64be2eefaa82c0494ab729e50596110f60ae9ad64b3eb9ddb54001b03cc264b65634c071d3b24a44322f39a9eae239fd886db8d429969433cb2d0a82d7877f174b0e154262f1af44ce5bc053b62daadd2926f957440ff3981a600d9010281825820af09d312a642fecb47da719156517bec678469c15789bcf002ce2ef563edf54200018182581d6052e63f22c5107ed776b70f7b92248b02552fd08f3e747bc745099441821b00000001373049f4a1581c34250edd1e9836f5378702fbf9416b709bc140e04f668cc355208518a1494154414441636f696e1953a6021a000306b5031a01525e0209a1581c34250edd1e9836f5378702fbf9416b709bc140e04f668cc355208518a1494154414441636f696e010758206cf243cc513691d9edc092b1030c6d1e5f9a8621a4d4383032b3d292d4679d5c81a200d90102828258201287e9ce9e00a603d250b557146aa0581fc4edf277a244ce39d3b2f2ced5072f5840d40fbe736892d8dab09e864a25f2e59fb7bfe445d960bbace30996965dc12a34c59746febf9d32ade65b6a9e1a1a6efc53830a3acaab699972cd4f240c024c0f825820742d8af3543349b5b18f3cba28f23b2d6e465b9c136c42e1fae6b2390f565427584005637b5645784bd998bb8ed837021d520200211fdd958b9a4d4b3af128fa6e695fb86abad7a9ddad6f1db946f8b812113fa16cfb7025e2397277b14e8c9bed0a01d90102818200581c45d70e54f3b5e9c5a2b0cd417028197bd6f5fa5378c2f5eba896678da100d90103a100a11902a2a1636d73678f78264175746f2d4c6f6f702d5472616e73616374696f6e202336323733363820627920415441444160783c4c6976652045706f6368203235352c207765206861766520303131682035396d20323573206c65667420756e74696c20746865206e657874206f6e6578344974277320536f6e6e746167202d20323520466562727561722032303234202d2031333a33303a333520696e20417573747269616060607820412072616e646f6d205a656e2d51756f746520666f7220796f753a20f09f998f78344974206973206e6576657220746f6f206c61746520746f206265207768617420796f75206d696768742068617665206265656e2e6f202d2047656f72676520456c696f746078374e6f64652d5265766973696f6e3a203462623230343864623737643632336565366533363738363138633264386236633436373633333360782953616e63686f4e657420697320617765736f6d652c206861766520736f6d652066756e2120f09f988d7819204265737420726567617264732c204d617274696e203a2d2980