You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
## Description
This PR:
- extends the docs on Irrecoverable Errors by explaining the ABI
Backtracing.
- adds docs for the `#[trace]` attribute.
- adds docs for the `backtrace` build option.
It is the final step in implementing the #7276.
## Checklist
- [x] I have linked to any relevant issues.
- [ ] I have commented my code, particularly in hard-to-understand
areas.
- [x] I have updated the documentation where relevant (API docs, the
reference, and the Sway book).
- [ ] If my change requires substantial documentation changes, I have
[requested support from the DevRel
team](https://github.com/FuelLabs/devrel-requests/issues/new/choose)
- [ ] I have added tests that prove my fix is effective or that my
feature works.
- [ ] I have added (or requested a maintainer to add) the necessary
`Breaking*` or `New Feature` labels where relevant.
- [x] I have done my best to ensure that my PR adheres to [the Fuel Labs
Code Review
Standards](https://github.com/FuelLabs/rfcs/blob/master/text/code-standards/external-contributors.md).
- [x] I have requested a review from the relevant team or maintainers.
At runtime, the `panic` expression aborts and reverts the execution of the entire program. At compile time, for each `panic` encountered in code, Sway compiler will generate a unique revert code and create an entry in the ABI JSON `errorCodes` section. The generated `errorCodes` entry will contain the information about source location at which the `panic` occurs, as well as the error message.
23
+
At runtime, the `panic` expression aborts and reverts the execution of the entire program. At compile time, for each `panic` encountered in code, Sway compiler will generate a unique revert code and create an entry in the ABI JSON `errorCodes` section. The generated `errorCodes` entry will contain the information about the source location at which the `panic` occurs, as well as the error message.
24
24
25
-
**This mechanism allows for getting a rich troubleshooting information, without an additional on-chain cost.** The generated bytecode will contain only the revert instruction, and the remaining information, the error message and the error location, are stored off-chain, in the ABI JSON file.
25
+
In addition, for each function call that might panic, compiler will generate an entry in the ABI JSON `panickingCalls` section. Those entries will contain source locations of functions whose calls might eventually end up in calling a `panic` somewhere in the call chain.
26
26
27
-
For example, let's assume that the above code is situated in the module `some_module`, contained within the version `v1.2.3` of the package `some_package`.
27
+
**Combined together, these two ABI JSON entries, `errorCodes` and `panickingCalls`, allow for getting a rich troubleshooting information, that contains the error location and a partial backtrace, without any or negligible additional on-chain cost.**
28
28
29
-
At runtime, the `panic` will result in a compiler generated revert code, e.g., 18446744069414584323. At compile time, an entry similar to this will be added to the ABI JSON `errorCodes` section:
29
+
The generated bytecode will contain only the revert instructions, while error messages and error locations will be stored off-chain, in the ABI JSON file, making the `panic`king a zero on-chain cost operation. Panic backtrace comes with only a negligible on-chain cost, that can additionally be opted-in or out, as explained in detail in the chapter [Configuring the Backtrace Content](#configuring-the-backtrace-content).
_Partial_ backtrace means that the _backtrace is limited to up to five function calls_. In practice, deeper call chains are rare. Also, it is possible to choose which functions should be a part of the reported backtrace. This is done by using the `backtrace` build option and the `#[trace]` attribute, as also explained in detail in the chapter [Configuring the Backtrace Content](#configuring-the-backtrace-content).
45
32
46
-
Rust and TypeScript SDK, as well as `forc test`, recognize revert codes generated from`panic` expressions. E.g., if a Sway unit test fails because of a revert caused by the above `panic` line, the `forc test`will display the following:
33
+
Tools like Rust and TypeScript SDKs and `forc test` recognize revert codes generated by`panic` expressions. E.g., if a Sway unit test fails because of a revert caused by the above `panic` line, `forc test`might display an output similar to the following:
What the above panic location and the backtrace are telling us, is that `some_test` has called `some_function` that has called `some_error_occurred` which has panicked with the message "Some error has occurred."
48
+
55
49
### Error Types
56
50
57
-
Passing textual error messages directly as a `panic` argument is the most convenient way to provide a helpful error message. It is sufficient for many use-cases. However, often we want:
51
+
Passing textual error messages directly as a `panic` argument is the most convenient way to provide a helpful error message. It is sufficient for many use-cases. However, sometimes we want:
58
52
59
-
- to provide an additional runtime information about the error.
60
-
- group a certain family of errors together.
53
+
- to provide an additional runtime information about the error,
54
+
-or to group a certain family of errors together.
61
55
62
56
For these use-cases, you can use _error types_. Error types are enums annotated with the `#[error_type]` attribute, whose all variants are attributed with the `#[error(m = "<error message>")]` attributes. Each variant represent a particular error, and the enum itself the family of errors. The convention is to postfix the names of error type enums with `Error`.
Assuming we have a failing test for the above function, the test output will show the error message, but also the provided `Identity`. E.g.:
85
+
Assuming we have a failing test for the above function, the test output will show the error message, but also the provided `Identity` as the _panic value_. E.g.:
86
+
87
+
```console
88
+
test some_test_for_admin_access, "/test.sw":42
89
+
revert code: 8100000000000000
90
+
├─ panic message: The provided identity is not an administrator.
// Position within the `check_admin` where `only_admin` is called.
130
+
"file": "src/preconditions.sw",
131
+
"line": 4,
132
+
"column": 9
133
+
},
134
+
"function": "auth_package::admin_access::only_admin"// The called function, `only_admin`.
135
+
},
136
+
// Other panicking calls.
137
+
}
138
+
```
139
+
140
+
Those unique error and panicking call IDs are embedded by the compiler into the revert code generated for a particular `panic` call.
141
+
142
+
In case of a revert, tools like SDKs and `forc test` will extract those IDs from the received revert code and using the information contained in the ABI JSON provide a rich troubleshooting details. In the above example, in case of a failing test, `forc test` might display an output similar to the following:
93
143
94
144
```console
95
-
test some_test_for_admin_access, "path/to/failing/test.sw":42
96
-
revert code: ffffffff00000007
145
+
test some_test, "/tests.sw":42
146
+
revert code: 8280000000000003
97
147
├─ panic message: The provided identity is not an administrator.
Backtracing comes with a minimal on-chain cost, in terms of the bytecode size and gas usage. To additionally allow you to opt-in even for this minimal cost, backtracing is configurable via dedicated `backtrace` build option, with different default values for `debug` and `release` builds.
166
+
167
+
To explain this build option, let us use the following example. We will have five functions named `first`, `second`, ..., `fifth` that call each other sequentially, and the function `fifth` finally calling a failing `assert_eq` that `panic`s.
168
+
169
+
In the default `debug` build, the output of a failing `forc test` will look similar to this (package names and code locations are omitted for brevity):
170
+
171
+
```console
172
+
test some_test, "test.sw":42
173
+
revert code: 8280000000000003
174
+
├─ panic message: The provided `expected` and `actual` values are not equal.
Where this difference in backtrace in `debug` and `release` build is coming from? In other words, how the compiler knows which functions to include into backtrace in different build profiles?
201
+
202
+
The backtrace can be directly influenced by using the `#[trace]` attribute in your code. Similarly to the `#[inline]` attribute, the `#[trace]` attribute can be used on all functions that have implementations. Same like `#[inline]`, it also comes with two arguments, `always` and `never`.
203
+
204
+
The `#[trace(always)]` instructs the compiler to include the calls of annotated functions in the backtrace in default `release` builds. This attribute should be used to annotate guard functions, like, e.g., `assert`, `assert_eq`, `require`, and `only_owner`, or methods like `Option::unwrap`. When such functions panic, we are actually interested in the places in code in which a failing call happens. E.g., having `#[trace(always)]` on the `assert` function helps us to see _which actual `assert` call has failed_.
205
+
206
+
**By default, `release` builds will include in the backtrace only the calls to functions annotated with `#[trace(always)]`.** This minimizes the anyhow low on-chain cost of backtrace calculation only to function calls of those function, giving almost a zero on-chain impact while still providing a valuable troubleshooting information.
207
+
208
+
By using `#[trace(never)]` you can instruct the compiler _not to include a function in a backtrace_, even not in a default `debug` build, which otherwise includes all the panicking calls into backtrace. This is useful, considering that the backtrace will be limited to five functions only. If an intermediate function call can be easily deducted, it might be worth not having it in the backtrace.
209
+
210
+
E.g., let's assume that the functions `fourth` and `second` are annotated with `#[trace(never)]`. The default `debug` build would then output the following backtrace:
To change this default behavior, use the `backtrace` build option. The possible values for the `backtrace` build option, and their meanings are given in the below table.
227
+
228
+
| Value | Meaning |
229
+
| ----- | ------- |
230
+
| all | Backtrace all function calls, even of functions annotated with `#[trace(never)]`. |
231
+
| all_except_never | Backtrace all function calls, except those of functions annotated with `#[trace(never)]`. This is the default value for `debug` builds. |
232
+
| only_always | Backtrace only calls of functions annotated with `#[trace(always)]`. This is the default value for `release` builds. |
233
+
| none | Do not backtrace any function calls. Use this option only if you need to fully remove the on-chain cost of backtracing. Considering how negligible the cost is, this will very likely never be needed. |
234
+
235
+
To learn more about custom builds, see [The `[build-profile.*]` Section](../forc/manifest_reference.md#the-build-profile-section).
Copy file name to clipboardExpand all lines: docs/book/src/forc/manifest_reference.md
+6-5Lines changed: 6 additions & 5 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -31,7 +31,7 @@ The `Forc.toml` (the _manifest_ file) is a compulsory file for each package and
31
31
32
32
*[`[contract-dependencies]`](#the-contract-dependencies-section) - Defines the contract dependencies.
33
33
34
-
## The `[project]`section
34
+
## The `[project]`Section
35
35
36
36
An example `Forc.toml` is shown below. Under `[project]` the following fields are optional:
37
37
@@ -145,7 +145,7 @@ This allows for a streamlined developer experience while maintaining clear separ
145
145
*[forc-index-ts](https://github.com/FuelLabs/example-forc-plugins/tree/master/forc-index-ts): A TypeScript CLI tool for parsing `Forc.toml` metadata to read contract ABI JSON file.
146
146
*[forc-index-rs](https://github.com/FuelLabs/example-forc-plugins/tree/master/forc-index-rs): A Rust CLI tool for parsing `Forc.toml` metadata to read contract ABI JSON file.
147
147
148
-
## The `[dependencies]`section
148
+
## The `[dependencies]`Section
149
149
150
150
The following fields can be provided with a dependency:
151
151
@@ -159,13 +159,13 @@ The following fields can be provided with a dependency:
159
159
160
160
Please see [dependencies](./dependencies.md) for details
161
161
162
-
## The `[network]`section
162
+
## The `[network]`Section
163
163
164
164
For the following fields, a default value is provided so omitting them is allowed:
165
165
166
166
*`URL` - (default: _<http://127.0.0.1:4000>_)
167
167
168
-
## The `[build-profile.*]`section
168
+
## The `[build-profile.*]`Section
169
169
170
170
The `[build-profile]` tables provide a way to customize compiler settings such as debug options.
171
171
@@ -180,6 +180,7 @@ The following fields can be provided for a build-profile:
180
180
*`time_phases` - Whether to output the time elapsed over each part of the compilation process, defaults to false.
181
181
*`include_tests` - Whether or not to include test functions in parsing, type-checking, and code generation. This is set to true by invocations like `forc test`, but defaults to false.
182
182
*`error_on_warnings` - Whether to treat errors as warnings, defaults to false.
183
+
*`backtrace` - Defines which panicking functions to include in a `panic` backtrace. Possible values are `all`, `all_except_never`, `only_always`, and `none`. Defaults to `all_except_never` and `only_always` in the default `debug` and `release` profiles, respectively. For more information on backtracing see the chapter [Irrecoverable Errors](../basics/error_handling.md#irrecoverable-errors).
183
184
184
185
There are two default `[build-profile]` available with every manifest file. These are `debug` and `release` profiles. If you want to override these profiles, you can provide them explicitly in the manifest file like the following example:
185
186
@@ -217,7 +218,7 @@ error-on-warnings = false
217
218
experimental-private-modules = false
218
219
```
219
220
220
-
## The `[patch]`section
221
+
## The `[patch]`Section
221
222
222
223
The [patch] section of `Forc.toml` can be used to override dependencies with other copies. The example provided below patches `https://github.com/fuellabs/sway` with the `test` branch of the same repo.
0 commit comments