Skip to content
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

Add debug symbols #87

Merged

Conversation

uncomputable
Copy link
Collaborator

Track fallible Simfony expressions via debug symbols that are included in the Simplicity target code (more details are in the commit message).

Add public methods to convert debug symbols into helpful error messages by providing the values that the Bit Machine sees at runtime. Debug symbols cover all failure cases, so the Bit Machine should always be able to display a helpful Simfony error.

Add dbg! expressions that can be used print their input value at runtime.

@apoelstra
Copy link
Contributor

code review ack 88d15d3

CI failure looks real (I'll wait til it's green to run my local CI).

Super cool concept!

Introduce a helper method for each step of the analysis. Analyze each
call variant in terms of the steps. This refactor makes the code easier
to read.
I find it much easier to read hex arrays than long decimal strings.
A Simfony function call f(x) is usually compiled as the following
Simplicity expression, where [x] is the compilation of x, and so on.

comp [x] [f]

However, we can write a different Simplicity target expression that has
the same semantics. The input is paired with a false bit. This is piped
into an assertion that checks if the bit is false. The assertion always
succeeds.

comp (pair false [x]) (assertl (drop [f]) CMR)

The lower expression is a more convoluted way of writing the upper
expression. The benefit of the lower expression is that it includes a
CMR that we can use to inject arbitrary data. We use the hash of the
position of the call inside the original Simfony source code as CMR.
This is the debug symbol.

For now, I insert debug symbols into every call that is fallible.
Any failure on the Simplicity Bit Machine can be associated with a
Simfony call expression via the CMR.

Currently, debug symbols are inserted into every compiled program. We
don't want programs bloated with debug symbols on the blockchain. It is
easy to add a "release" mode next to a "debug" mode to the Simfony
compiler. For brevity, I chose to leave this for later.

Note that I had to compile unwraps with slightly more combinators in
order to fit the shape comp [function args] [function body]. I plan to
revert this change in the "release" mod of the Simfony compiler.
We want to use debug symbols to produce helpful error messages on the
Bit Machine. The debug symbols cover all cases where the Simplicity
target code may fail (assertl, assertr, fail).

We want to produce error messages of the following kind:

Assertion failed: false

Called `unwrap()` on a `None` value

Called `unwrap_left()` on a `Right` value: 1

Called `unwrap_right()` on a `Left` value: 1

Some errors display the input value (unwrap_left, unwrap_right);
some errors are always the same (assert, unwrap). TrackedCallName
includes type information to reconstruct the input value at runtime
from the Bit Machine. FallibleCallName includes the reconstructed value.

TrackedCall and FallibleCall include the Simfony text of the call
expression, so we can print it alongside the error. We might choose to
include the span, too, in the future, depending on where we want to go
with this design.
Return a plain-old-data type that wraps the Simplicity target code and
its debug symbols. When we add a "release" mode to the Simfony compiler,
we won't return debug symbols.
dbg!(x) behaves in Simfony like in Rust: It is a NOP that prints its
input value as a side effect. The Simfony compiler adds a debug symbol
for this purpose.

I split FallibleCall from DebugValue in the debug symbol API because
FallibleCall is supposed to be used in error messages, while DebugValue
is used for logging on the side. I don't want to handle dbg! as a case
in an error message, even though dbg! is infallible.
@uncomputable
Copy link
Collaborator Author

Fixed CI.

Also made sure that dbg! expressions capture the span of their input, in order to produce output of the following kind:

jet::le_32(min_height, oracle_height) = false

Copy link
Contributor

@apoelstra apoelstra left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ACK 0a67719 successfully ran local tests

@uncomputable uncomputable merged commit 6137606 into BlockstreamResearch:master Sep 16, 2024
5 checks passed
@uncomputable uncomputable deleted the 2024-09-debug-symbols branch September 16, 2024 17:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants