BeFunctional / haskell-foreign-rust

MIT License
9 stars 3 forks source link

Exception: deserialiseLazyOrPanic ... DeserialiseFailure 1 "Expected index < 2" #13

Open haroldcarr opened 1 year ago

haroldcarr commented 1 year ago

Do you have any ideas off-the-top-of-your-head.

I know from looking around that the "real" error is coming from Codec.Borsch.Decoding decodeEnum

Also, note the size - it is BIG.

groth16ProvingKeyJsonNew rng 8 eg
-- *** Exception: deserialiseLazyOrPanic for Proxy * (Either Text Groth16ProvingKeyJSON): DeserialiseFailure 1 "Expected index < 2"
.....
44,49,53,53,44,49,57,52,44,50,50,54,44,49,52,57,44,49,56,57,44,49,55,49,44,49,56,51,93,125] (14839025)
CallStack (from HasCallStack):
  error, called at src/Foreign/Rust/Marshall/Util.hs:39:19 in frgn-rst-0.1.0-bce6ec5d:Foreign.Rust.Marshall.Util
  deserialiseLazyOrPanic, called at src/Foreign/Rust/Marshall/Util.hs:31:28 in frgn-rst-0.1.0-bce6ec5d:Foreign.Rust.Marshall.Util
  deserialiseStrictOrPanic, called at src/Foreign/Rust/Marshall/Variable.hs:96:17 in frgn-rst-0.1.0-bce6ec5d:Foreign.Rust.Marshall.Variable

For serialization in Rust, I use this macro:

macro_rules! to_from_haskell_via_ark_compressed {
    ($impl_ty:ty) => {

        impl ToHaskell<DNC> for $impl_ty {
            fn to_haskell<W: Write>(&self, writer: &mut W, tag: PhantomData<DNC>) -> Result<()> {
                let mut serz = vec![];
                match CanonicalSerialize::serialize_compressed(self, &mut serz)
                {
                    Ok(()) => serz.to_haskell(writer, tag),
                    Err(e) =>
                        Err(Box::new(std::io::Error::new(
                            std::io::ErrorKind::InvalidData,
                            format!("to_haskell serialization error: {:?}", e)
                        )))

                }
            }
        }

        impl FromHaskell<DNC> for $impl_ty {
            fn from_haskell(buf: &mut &[u8], tag: PhantomData<DNC>) -> Result<Self> {
                let bytes = <Vec<u8>>::from_haskell(buf, tag)?;
                match CanonicalDeserialize::deserialize_compressed(&bytes[..])
                {
                    Ok(deserz) => Ok(deserz),
                    Err(e)     =>
                        Err(Box::new(std::io::Error::new(
                            std::io::ErrorKind::InvalidData,
                            format!("from_haskell deserialization error: {:?}", e)
                        )))
                }
            }
        }
    }
}

I have used that macro for other types with with smaller instances successfully.

edsko commented 11 months ago

Sorry for the very slow response, I've been inundated with stuff. One thought that comes to mind: in the Haskell side you need to make a choice between AsEnum versus AsStruct; the latter adds a tag for the constructor, the former does not. Could it be related to that perhaps?

haroldcarr commented 11 months ago

Thank you for the response. I can't try the AsEnum/Struct thing at the moment, but I will sometime and report back.

Question: in your purgatory article you only use via As* in ONE place : via AsStruct Color The rest just do deriving newtype (BorshSize, ToBorsh, FromBorsh) --- so that is what I have done everwhere. Is there a reason you only explicitly leave via As* out in other places?

edsko commented 11 months ago

The blog post refers to an earlier version of the library, where the default was AsEnum and you could use AsStruct if you really wanted to skip the tag for the constructor. However, that was error prone, and was leading to precisely the kinds of decoding errors that you are seeing, so we changed the library to force people to make an explicit choice between enums and structs.

haroldcarr commented 11 months ago

Got it. I will try being explicit and report back. Thank you.