-
Notifications
You must be signed in to change notification settings - Fork 14
Encoded program cannot be decoded #286
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
The deserialized code for this program is as follows. I've adjusted the references to refer to absolute line numbers instead of relative line numbers to make reading the code "easier".
My analysis using the Haskell library is that type inference fails at The occurs check fails due to trying to unify α with ((β × β) × α), where α and β are type variables used during inference. I'll continue to look into this. |
Based on a combination of inspecting the above "assembly code" and hand computing the Simfony to Simplicity compilation process, I believe the following is the the Simplicity program that should be generated (modulo any errors I have made)
The generated untyped program seems correct, which suggests there is an error in the rust-simplicity's optimal expression sharing implementation. I'll continue to look into this. |
It looks to me like that for some reason rust-simplicity is improperly implementing sharing when serializing this expression.
This line is In particular, line 10
implements Later on, on line 25
this line is This time around How they ended up being shared, I don't know. Either the type inference is somehow wrong, and they ended up incorrectly with the same typed, and therefore shared, or the sharing implementation is somehow wrong. Not that the Why the |
Thanks for this detailed report. Maybe rust-simplicity is using the wrong Merkle root for sharing, or something. |
I've got the following program to fail
With hex_encoding |
I think there are really two bugs here. The first bug is that decoding this encoded program should throw a occurs-check failure instead of panicking with what appears to be a stack overflow. The second bug is that we shouldn't be generating ill-typed programs. |
Decoding of smaller program (with relative references changed to absolute references):
|
When I construct the above using rust-simplicity directly I get a type mismatch error (left target = right source) on the final comp. I manually double-checked and checked with ChatGPT that my mapping from your Haskell to Rust code was faithful. |
Lemme dig into how simfony is managing to construct this.. |
Try to construct a fully-unshared program in rust simplicity. That way we can test the sharing mechanism used during serialization. Assuming I did the hand construction correctly the unshared program (in Haskell syntax) is
|
I wasn't able to make any progress doing that -- I can't cajole rust-simplicity misbehave. I am now investigating It appears that the logic of |
Ok, can reproduce in rust-simplicity with diff --git a/src/node/construct.rs b/src/node/construct.rs
index ec7ef93..55ad8e6 100644
--- a/src/node/construct.rs
+++ b/src/node/construct.rs
@@ -517,4 +517,54 @@ mod tests {
.cmr()
);
}
+
+ #[test]
+ fn regression_286() {
+ use crate::bitcoin::hex::DisplayHex as _;
+ let ctx = types::Context::new();
+
+ let u0 = Arc::<ConstructNode<Core>>::unit(&ctx);
+ let i1 = Arc::<ConstructNode<Core>>::iden(&ctx);
+ let p2 = Arc::<ConstructNode<Core>>::pair(&u0, &i1).unwrap();
+ let u3 = Arc::<ConstructNode<Core>>::unit(&ctx);
+ let i4 = Arc::<ConstructNode<Core>>::iden(&ctx);
+ let p5 = Arc::<ConstructNode<Core>>::pair(&u3, &i4).unwrap();
+ let u6 = Arc::<ConstructNode<Core>>::unit(&ctx);
+ let c7 = Arc::<ConstructNode<Core>>::comp(&p5, &u6).unwrap();
+ let u8 = Arc::<ConstructNode<Core>>::unit(&ctx);
+ let i9 = Arc::<ConstructNode<Core>>::iden(&ctx);
+ let p10 = Arc::<ConstructNode<Core>>::pair(&u8, &i9).unwrap();
+ let i11 = Arc::<ConstructNode<Core>>::iden(&ctx);
+ let t12 = Arc::<ConstructNode<Core>>::take(&i11);
+ let i13 = Arc::<ConstructNode<Core>>::iden(&ctx);
+ let t14 = Arc::<ConstructNode<Core>>::take(&i13);
+ let u15 = Arc::<ConstructNode<Core>>::unit(&ctx);
+ let p16 = Arc::<ConstructNode<Core>>::pair(&t14, &u15).unwrap();
+ let i17 = Arc::<ConstructNode<Core>>::iden(&ctx);
+ let d18 = Arc::<ConstructNode<Core>>::drop_(&i17);
+ let c19 = Arc::<ConstructNode<Core>>::comp(&p16, &d18).unwrap();
+ let p20 = Arc::<ConstructNode<Core>>::pair(&t12, &c19).unwrap();
+ let i21 = Arc::<ConstructNode<Core>>::iden(&ctx);
+ let d22 = Arc::<ConstructNode<Core>>::drop_(&i21);
+ let c23 = Arc::<ConstructNode<Core>>::comp(&p20, &d22).unwrap();
+ let c24 = Arc::<ConstructNode<Core>>::comp(&p10, &c23).unwrap();
+ let p25 = Arc::<ConstructNode<Core>>::pair(&c7, &c24).unwrap();
+ let i26 = Arc::<ConstructNode<Core>>::iden(&ctx);
+ let d27 = Arc::<ConstructNode<Core>>::drop_(&i26);
+ let c28 = Arc::<ConstructNode<Core>>::comp(&p25, &d27).unwrap();
+ let c29 = Arc::<ConstructNode<Core>>::comp(&p2, &c28).unwrap();
+
+ let finalized: Arc<CommitNode<_>> = c29.finalize_types().unwrap();
+ let finalized: Arc<RedeemNode<_>> = finalized.finalize(&mut crate::node::SimpleFinalizer::new(core::iter::empty())).unwrap();
+ let (prog, wit) = finalized.encode_to_vec();
+
+ println!("encoded prog: {}", prog.as_hex());
+
+ let prog = BitIter::from(prog);
+ let wit = BitIter::from(wit);
+ let decode = RedeemNode::<Core>::decode(prog, wit).unwrap(); // will panic here
+
+ assert_eq!(finalized, decode);
+
+ }
} I obtained this program by looking at the program produced internally by simfony before the call to to_commit_node. I then call |
Correction: The expected behavior is that The correct shared DAG should be
And should be encoded as "e04940a1281424106cc4a7d2081600283485a00640de" |
Quick update before we sign off for the weekend -- we have a working fix, but it was produced by Claude 3.7-sonnet (a LLM) and we aren't yet confident in its correctness or why it works. |
Have fix up. Turn out the AI thing was a red herring. I'm just iterating on getting CI to pass (need to fix stuff for non-default features sets). |
Calling
encode_to_vec
and thenRedeemNode::decode
on the following program leads to a type unification error.See BlockstreamResearch/simfony#118
The Simplicity program is obtained by compiling the following Simfony program:
Calling
encode_to_vec
yields the following hex string (unpruned, without debug symbols):The fact that the encoding is broken makes it hard to describe the problematic Simplicity program in this issue. For now, the Simfony compiler must be used to obtain it.
For now, the code to reproduce the error lives on this Simfony branch. Run
cargo test --all-features
.The text was updated successfully, but these errors were encountered: