fix(alonzo): avoid indef arrays isomorphic codec issues
This commit is contained in:
parent
866deb0211
commit
002ad622dc
2 changed files with 146 additions and 80 deletions
|
|
@ -5,9 +5,9 @@
|
||||||
use log::warn;
|
use log::warn;
|
||||||
use minicbor::{bytes::ByteVec, data::Tag};
|
use minicbor::{bytes::ByteVec, data::Tag};
|
||||||
use minicbor_derive::{Decode, Encode};
|
use minicbor_derive::{Decode, Encode};
|
||||||
use std::collections::BTreeMap;
|
use std::{collections::BTreeMap, ops::Deref};
|
||||||
|
|
||||||
use crate::utils::KeyValuePairs;
|
use crate::utils::{KeyValuePairs, MaybeIndefArray};
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, PartialOrd, Eq, Ord)]
|
#[derive(Debug, PartialEq, PartialOrd, Eq, Ord)]
|
||||||
pub struct SkipCbor<const N: usize> {}
|
pub struct SkipCbor<const N: usize> {}
|
||||||
|
|
@ -616,22 +616,21 @@ pub enum NetworkId {
|
||||||
|
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq)]
|
||||||
pub enum TransactionBodyComponent {
|
pub enum TransactionBodyComponent {
|
||||||
Inputs(Vec<TransactionInput>),
|
Inputs(MaybeIndefArray<TransactionInput>),
|
||||||
Outputs(Vec<TransactionOutput>),
|
Outputs(MaybeIndefArray<TransactionOutput>),
|
||||||
Fee(u64),
|
Fee(u64),
|
||||||
Ttl(Option<u64>),
|
Ttl(u64),
|
||||||
Certificates(Option<Vec<Certificate>>),
|
Certificates(Vec<Certificate>),
|
||||||
Withdrawals(Option<BTreeMap<RewardAccount, Coin>>),
|
Withdrawals(KeyValuePairs<RewardAccount, Coin>),
|
||||||
Update(Option<SkipCbor<22>>),
|
Update(Option<SkipCbor<22>>),
|
||||||
AuxiliaryDataHash(Option<ByteVec>),
|
AuxiliaryDataHash(ByteVec),
|
||||||
ValidityIntervalStart(Option<u64>),
|
ValidityIntervalStart(u64),
|
||||||
Mint(Option<Multiasset<i64>>),
|
Mint(Multiasset<i64>),
|
||||||
ScriptDataHash(Option<Hash32>),
|
ScriptDataHash(Hash32),
|
||||||
Collateral(Option<Vec<TransactionInput>>),
|
Collateral(MaybeIndefArray<TransactionInput>),
|
||||||
RequiredSigners(Option<Vec<AddrKeyhash>>),
|
RequiredSigners(MaybeIndefArray<AddrKeyhash>),
|
||||||
NetworkId(Option<NetworkId>),
|
NetworkId(NetworkId),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'b> minicbor::decode::Decode<'b> for TransactionBodyComponent {
|
impl<'b> minicbor::decode::Decode<'b> for TransactionBodyComponent {
|
||||||
fn decode(d: &mut minicbor::Decoder<'b>) -> Result<Self, minicbor::decode::Error> {
|
fn decode(d: &mut minicbor::Decoder<'b>) -> Result<Self, minicbor::decode::Error> {
|
||||||
let key: u32 = d.decode()?;
|
let key: u32 = d.decode()?;
|
||||||
|
|
@ -731,6 +730,14 @@ impl minicbor::encode::Encode for TransactionBodyComponent {
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq)]
|
||||||
pub struct TransactionBody(Vec<TransactionBodyComponent>);
|
pub struct TransactionBody(Vec<TransactionBodyComponent>);
|
||||||
|
|
||||||
|
impl Deref for TransactionBody {
|
||||||
|
type Target = Vec<TransactionBodyComponent>;
|
||||||
|
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
&self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<'b> minicbor::decode::Decode<'b> for TransactionBody {
|
impl<'b> minicbor::decode::Decode<'b> for TransactionBody {
|
||||||
fn decode(d: &mut minicbor::Decoder<'b>) -> Result<Self, minicbor::decode::Error> {
|
fn decode(d: &mut minicbor::Decoder<'b>) -> Result<Self, minicbor::decode::Error> {
|
||||||
let len = d.map()?.unwrap_or_default();
|
let len = d.map()?.unwrap_or_default();
|
||||||
|
|
@ -767,9 +774,9 @@ pub struct VKeyWitness {
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq)]
|
||||||
pub enum NativeScript {
|
pub enum NativeScript {
|
||||||
ScriptPubkey(AddrKeyhash),
|
ScriptPubkey(AddrKeyhash),
|
||||||
ScriptAll(Vec<NativeScript>),
|
ScriptAll(MaybeIndefArray<NativeScript>),
|
||||||
ScriptAny(Vec<NativeScript>),
|
ScriptAny(MaybeIndefArray<NativeScript>),
|
||||||
ScriptNOfK(u32, Vec<NativeScript>),
|
ScriptNOfK(u32, MaybeIndefArray<NativeScript>),
|
||||||
InvalidBefore(u64),
|
InvalidBefore(u64),
|
||||||
InvalidHereafter(u64),
|
InvalidHereafter(u64),
|
||||||
}
|
}
|
||||||
|
|
@ -904,11 +911,11 @@ impl minicbor::encode::Encode for BigInt {
|
||||||
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
|
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
|
||||||
pub enum PlutusData {
|
pub enum PlutusData {
|
||||||
Constr(Constr<PlutusData>),
|
Constr(Constr<PlutusData>),
|
||||||
Map(BTreeMap<PlutusData, PlutusData>),
|
Map(KeyValuePairs<PlutusData, PlutusData>),
|
||||||
BigInt(BigInt),
|
BigInt(BigInt),
|
||||||
BoundedBytes(ByteVec),
|
BoundedBytes(ByteVec),
|
||||||
Array(Vec<PlutusData>),
|
Array(MaybeIndefArray<PlutusData>),
|
||||||
ArrayIndef(IndefVec<PlutusData>),
|
ArrayIndef(MaybeIndefArray<PlutusData>),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'b> minicbor::decode::Decode<'b> for PlutusData {
|
impl<'b> minicbor::decode::Decode<'b> for PlutusData {
|
||||||
|
|
@ -938,6 +945,7 @@ impl<'b> minicbor::decode::Decode<'b> for PlutusData {
|
||||||
| minicbor::data::Type::I64 => Ok(Self::BigInt(d.decode()?)),
|
| minicbor::data::Type::I64 => Ok(Self::BigInt(d.decode()?)),
|
||||||
minicbor::data::Type::Map => Ok(Self::Map(d.decode()?)),
|
minicbor::data::Type::Map => Ok(Self::Map(d.decode()?)),
|
||||||
minicbor::data::Type::Bytes => Ok(Self::BoundedBytes(d.decode()?)),
|
minicbor::data::Type::Bytes => Ok(Self::BoundedBytes(d.decode()?)),
|
||||||
|
minicbor::data::Type::BytesIndef => Ok(Self::BoundedBytes(d.decode()?)),
|
||||||
minicbor::data::Type::Array => Ok(Self::Array(d.decode()?)),
|
minicbor::data::Type::Array => Ok(Self::Array(d.decode()?)),
|
||||||
minicbor::data::Type::ArrayIndef => Ok(Self::ArrayIndef(d.decode()?)),
|
minicbor::data::Type::ArrayIndef => Ok(Self::ArrayIndef(d.decode()?)),
|
||||||
|
|
||||||
|
|
@ -978,48 +986,11 @@ impl minicbor::encode::Encode for PlutusData {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A struct that forces encode / decode using indef arrays
|
|
||||||
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
|
|
||||||
pub struct IndefVec<A>(pub Vec<A>);
|
|
||||||
|
|
||||||
impl<'b, A> minicbor::decode::Decode<'b> for IndefVec<A>
|
|
||||||
where
|
|
||||||
A: minicbor::decode::Decode<'b>,
|
|
||||||
{
|
|
||||||
fn decode(d: &mut minicbor::Decoder<'b>) -> Result<Self, minicbor::decode::Error> {
|
|
||||||
let values: Vec<A> = d.decode()?;
|
|
||||||
|
|
||||||
Ok(IndefVec(values))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<A> minicbor::encode::Encode for IndefVec<A>
|
|
||||||
where
|
|
||||||
A: minicbor::encode::Encode,
|
|
||||||
{
|
|
||||||
fn encode<W: minicbor::encode::Write>(
|
|
||||||
&self,
|
|
||||||
e: &mut minicbor::Encoder<W>,
|
|
||||||
) -> Result<(), minicbor::encode::Error<W::Error>> {
|
|
||||||
if self.0.is_empty() {
|
|
||||||
e.begin_array()?;
|
|
||||||
for v in &self.0 {
|
|
||||||
e.encode(v)?;
|
|
||||||
}
|
|
||||||
e.end()?;
|
|
||||||
} else {
|
|
||||||
e.array(0)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
|
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
|
||||||
pub struct Constr<A> {
|
pub struct Constr<A> {
|
||||||
pub tag: u64,
|
pub tag: u64,
|
||||||
pub prefix: Option<u32>,
|
pub prefix: Option<u32>,
|
||||||
pub values: IndefVec<A>,
|
pub values: MaybeIndefArray<A>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'b, A> minicbor::decode::Decode<'b> for Constr<A>
|
impl<'b, A> minicbor::decode::Decode<'b> for Constr<A>
|
||||||
|
|
@ -1146,22 +1117,22 @@ pub struct BootstrapWitness {
|
||||||
#[cbor(map)]
|
#[cbor(map)]
|
||||||
pub struct TransactionWitnessSet {
|
pub struct TransactionWitnessSet {
|
||||||
#[n(0)]
|
#[n(0)]
|
||||||
pub vkeywitness: Option<Vec<VKeyWitness>>,
|
pub vkeywitness: Option<MaybeIndefArray<VKeyWitness>>,
|
||||||
|
|
||||||
#[n(1)]
|
#[n(1)]
|
||||||
pub native_script: Option<Vec<NativeScript>>,
|
pub native_script: Option<MaybeIndefArray<NativeScript>>,
|
||||||
|
|
||||||
#[n(2)]
|
#[n(2)]
|
||||||
pub bootstrap_witness: Option<Vec<BootstrapWitness>>,
|
pub bootstrap_witness: Option<MaybeIndefArray<BootstrapWitness>>,
|
||||||
|
|
||||||
#[n(3)]
|
#[n(3)]
|
||||||
pub plutus_script: Option<Vec<PlutusScript>>,
|
pub plutus_script: Option<MaybeIndefArray<PlutusScript>>,
|
||||||
|
|
||||||
#[n(4)]
|
#[n(4)]
|
||||||
pub plutus_data: Option<Vec<PlutusData>>,
|
pub plutus_data: Option<MaybeIndefArray<PlutusData>>,
|
||||||
|
|
||||||
#[n(5)]
|
#[n(5)]
|
||||||
pub redeemer: Option<Vec<Redeemer>>,
|
pub redeemer: Option<MaybeIndefArray<Redeemer>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Encode, Decode, Debug, PartialEq)]
|
#[derive(Encode, Decode, Debug, PartialEq)]
|
||||||
|
|
@ -1170,7 +1141,7 @@ pub struct AlonzoAuxiliaryData {
|
||||||
#[n(0)]
|
#[n(0)]
|
||||||
pub metadata: Option<Metadata>,
|
pub metadata: Option<Metadata>,
|
||||||
#[n(1)]
|
#[n(1)]
|
||||||
pub native_scripts: Option<Vec<NativeScript>>,
|
pub native_scripts: Option<MaybeIndefArray<NativeScript>>,
|
||||||
#[n(2)]
|
#[n(2)]
|
||||||
pub plutus_scripts: Option<PlutusScript>,
|
pub plutus_scripts: Option<PlutusScript>,
|
||||||
}
|
}
|
||||||
|
|
@ -1180,7 +1151,7 @@ pub enum Metadatum {
|
||||||
Int(i64),
|
Int(i64),
|
||||||
Bytes(ByteVec),
|
Bytes(ByteVec),
|
||||||
Text(String),
|
Text(String),
|
||||||
Array(Vec<Metadatum>),
|
Array(MaybeIndefArray<Metadatum>),
|
||||||
Map(Metadata),
|
Map(Metadata),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1329,16 +1300,16 @@ pub struct Block {
|
||||||
pub header: Header,
|
pub header: Header,
|
||||||
|
|
||||||
#[n(1)]
|
#[n(1)]
|
||||||
pub transaction_bodies: Vec<TransactionBody>,
|
pub transaction_bodies: MaybeIndefArray<TransactionBody>,
|
||||||
|
|
||||||
#[n(2)]
|
#[n(2)]
|
||||||
pub transaction_witness_sets: Vec<TransactionWitnessSet>,
|
pub transaction_witness_sets: MaybeIndefArray<TransactionWitnessSet>,
|
||||||
|
|
||||||
#[n(3)]
|
#[n(3)]
|
||||||
pub auxiliary_data_set: BTreeMap<TransactionIndex, AuxiliaryData>,
|
pub auxiliary_data_set: KeyValuePairs<TransactionIndex, AuxiliaryData>,
|
||||||
|
|
||||||
#[n(4)]
|
#[n(4)]
|
||||||
pub invalid_transactions: Vec<TransactionIndex>,
|
pub invalid_transactions: MaybeIndefArray<TransactionIndex>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Encode, Decode, Debug)]
|
#[derive(Encode, Decode, Debug)]
|
||||||
|
|
@ -1360,8 +1331,7 @@ mod tests {
|
||||||
include_str!("test_data/test6.block"),
|
include_str!("test_data/test6.block"),
|
||||||
include_str!("test_data/test7.block"),
|
include_str!("test_data/test7.block"),
|
||||||
include_str!("test_data/test8.block"),
|
include_str!("test_data/test8.block"),
|
||||||
// indef arrays giving trouble, re-encoding doesn't match
|
include_str!("test_data/test9.block"),
|
||||||
//include_str!("test_data/test9.block"),
|
|
||||||
];
|
];
|
||||||
|
|
||||||
for (idx, block_str) in test_blocks.iter().enumerate() {
|
for (idx, block_str) in test_blocks.iter().enumerate() {
|
||||||
|
|
@ -1371,6 +1341,7 @@ mod tests {
|
||||||
.expect(&format!("error decoding cbor for file {}", idx));
|
.expect(&format!("error decoding cbor for file {}", idx));
|
||||||
let bytes2 =
|
let bytes2 =
|
||||||
to_vec(block).expect(&format!("error encoding block cbor for file {}", idx));
|
to_vec(block).expect(&format!("error encoding block cbor for file {}", idx));
|
||||||
|
|
||||||
assert_eq!(bytes, bytes2);
|
assert_eq!(bytes, bytes2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,13 +9,19 @@ use minicbor::{Decode, Encode};
|
||||||
/// as the underlaying struct for storage of the items (as opposed to a BTreeMap
|
/// as the underlaying struct for storage of the items (as opposed to a BTreeMap
|
||||||
/// or HashMap).
|
/// or HashMap).
|
||||||
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
|
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
|
||||||
pub struct KeyValuePairs<K, V>(Vec<(K, V)>);
|
pub enum KeyValuePairs<K, V> {
|
||||||
|
Def(Vec<(K, V)>),
|
||||||
|
Indef(Vec<(K, V)>),
|
||||||
|
}
|
||||||
|
|
||||||
impl<K, V> Deref for KeyValuePairs<K, V> {
|
impl<K, V> Deref for KeyValuePairs<K, V> {
|
||||||
type Target = Vec<(K, V)>;
|
type Target = Vec<(K, V)>;
|
||||||
|
|
||||||
fn deref(&self) -> &Self::Target {
|
fn deref(&self) -> &Self::Target {
|
||||||
&self.0
|
match self {
|
||||||
|
KeyValuePairs::Def(x) => x,
|
||||||
|
KeyValuePairs::Indef(x) => x,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -25,9 +31,18 @@ where
|
||||||
V: Encode + Decode<'b>,
|
V: Encode + Decode<'b>,
|
||||||
{
|
{
|
||||||
fn decode(d: &mut minicbor::Decoder<'b>) -> Result<Self, minicbor::decode::Error> {
|
fn decode(d: &mut minicbor::Decoder<'b>) -> Result<Self, minicbor::decode::Error> {
|
||||||
|
let datatype = d.datatype()?;
|
||||||
|
|
||||||
let items: Result<Vec<_>, _> = d.map_iter::<K, V>()?.collect();
|
let items: Result<Vec<_>, _> = d.map_iter::<K, V>()?.collect();
|
||||||
let items = items?;
|
let items = items?;
|
||||||
Ok(KeyValuePairs(items))
|
|
||||||
|
match datatype {
|
||||||
|
minicbor::data::Type::Map => Ok(KeyValuePairs::Def(items)),
|
||||||
|
minicbor::data::Type::MapIndef => Ok(KeyValuePairs::Indef(items)),
|
||||||
|
_ => Err(minicbor::decode::Error::Message(
|
||||||
|
"invalid data type for keyvaluepairs",
|
||||||
|
)),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -40,12 +55,92 @@ where
|
||||||
&self,
|
&self,
|
||||||
e: &mut minicbor::Encoder<W>,
|
e: &mut minicbor::Encoder<W>,
|
||||||
) -> Result<(), minicbor::encode::Error<W::Error>> {
|
) -> Result<(), minicbor::encode::Error<W::Error>> {
|
||||||
e.map(self.0.len() as u64)?;
|
match self {
|
||||||
for (k, v) in &self.0 {
|
KeyValuePairs::Def(x) => {
|
||||||
k.encode(e)?;
|
e.map(x.len() as u64)?;
|
||||||
v.encode(e)?;
|
|
||||||
|
for (k, v) in x.iter() {
|
||||||
|
k.encode(e)?;
|
||||||
|
v.encode(e)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
KeyValuePairs::Indef(x) => {
|
||||||
|
e.begin_map()?;
|
||||||
|
|
||||||
|
for (k, v) in x.iter() {
|
||||||
|
k.encode(e)?;
|
||||||
|
v.encode(e)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
e.end()?;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A struct that maintains a reference to whether a cbor array was indef or not
|
||||||
|
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
|
||||||
|
pub enum MaybeIndefArray<A> {
|
||||||
|
Def(Vec<A>),
|
||||||
|
Indef(Vec<A>),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<A> Deref for MaybeIndefArray<A> {
|
||||||
|
type Target = Vec<A>;
|
||||||
|
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
match self {
|
||||||
|
MaybeIndefArray::Def(x) => &x,
|
||||||
|
MaybeIndefArray::Indef(x) => &x,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'b, A> minicbor::decode::Decode<'b> for MaybeIndefArray<A>
|
||||||
|
where
|
||||||
|
A: minicbor::decode::Decode<'b>,
|
||||||
|
{
|
||||||
|
fn decode(d: &mut minicbor::Decoder<'b>) -> Result<Self, minicbor::decode::Error> {
|
||||||
|
let datatype = d.datatype()?;
|
||||||
|
|
||||||
|
match datatype {
|
||||||
|
minicbor::data::Type::Array => Ok(Self::Def(d.decode()?)),
|
||||||
|
minicbor::data::Type::ArrayIndef => Ok(Self::Indef(d.decode()?)),
|
||||||
|
_ => Err(minicbor::decode::Error::Message(
|
||||||
|
"unknown data type of maybe indef array",
|
||||||
|
)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<A> minicbor::encode::Encode for MaybeIndefArray<A>
|
||||||
|
where
|
||||||
|
A: minicbor::encode::Encode,
|
||||||
|
{
|
||||||
|
fn encode<W: minicbor::encode::Write>(
|
||||||
|
&self,
|
||||||
|
e: &mut minicbor::Encoder<W>,
|
||||||
|
) -> Result<(), minicbor::encode::Error<W::Error>> {
|
||||||
|
match self {
|
||||||
|
MaybeIndefArray::Def(x) => {
|
||||||
|
e.encode(x)?;
|
||||||
|
}
|
||||||
|
MaybeIndefArray::Indef(x) if x.is_empty() => {
|
||||||
|
e.encode(x)?;
|
||||||
|
}
|
||||||
|
MaybeIndefArray::Indef(x) => {
|
||||||
|
e.begin_array()?;
|
||||||
|
|
||||||
|
for v in x.iter() {
|
||||||
|
e.encode(v)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
e.end()?;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue