-
Notifications
You must be signed in to change notification settings - Fork 74
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: Demystifying Predicates (#180)
* init * faster CI * spell check * intro to predicates * on to rust testing * CI fix * test * rust tests needs editing before importing into docs * ci * testing rust parts * try again * pause * Should be working now * review time * again * predicate update
- Loading branch information
1 parent
d56364d
commit 4dadebf
Showing
19 changed files
with
1,006 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -44,6 +44,7 @@ jobs: | |
guide: | ||
- "dev quickstart" | ||
- "intro to sway" | ||
- "intro to predicates" | ||
|
||
steps: | ||
# SETUP | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
--- | ||
title: Checkpoint | ||
category: Intro to Predicates | ||
parent: | ||
label: All Guides | ||
link: /guides | ||
--- | ||
|
||
# Checkpoint | ||
|
||
If you have followed the steps properly, your predicate `main.sw` should look like the code below: | ||
|
||
<CodeImport | ||
file="../../examples/intro-to-predicates/multisig-predicate/src/main.sw" | ||
comment="all" | ||
commentType="//" | ||
lang="sway" | ||
/> | ||
|
||
## Building the predicate | ||
|
||
To format your contract, execute the command: | ||
|
||
<TestAction | ||
id="format-predicate" | ||
action={{ | ||
name: 'runCommand', | ||
commandFolder: 'guides-testing/multisig-predicate/predicate' | ||
}} | ||
/> | ||
|
||
```sh | ||
forc fmt | ||
``` | ||
|
||
To get the predicate root, go to the predicate folder and run: | ||
|
||
<TestAction | ||
id="build-predicate" | ||
action={{ | ||
name: 'runCommand', | ||
commandFolder: 'guides-testing/multisig-predicate/predicate' | ||
}} | ||
/> | ||
|
||
```sh | ||
forc build | ||
``` | ||
|
||
Your predicate root should be exactly: | ||
|
||
```sh | ||
0x9cdce04cdb323e5982bbd0c07f667c6ea2b97781a8ce6f3e2d96c0e1b5acde73 | ||
``` | ||
|
||
That's it! You've created your first **stateless** decentralized application, and we didn't even have to deploy it! |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
--- | ||
title: Configurables | ||
category: Intro to Predicates | ||
parent: | ||
label: All Guides | ||
link: /guides | ||
--- | ||
|
||
# Configurables | ||
|
||
Configurables are special constants that can be modified at compile time. This is where we can define the signers responsible for protecting the funds in the predicate as well as the number of signatures required. | ||
|
||
This information can later be configured with SDKs before building a transaction. | ||
|
||
<TestAction | ||
id="sway-configurable" | ||
action={{ | ||
name: 'modifyFile', | ||
filepath: 'guides-testing/multisig-predicate/predicate/src/main.sw' | ||
}} | ||
/> | ||
|
||
<CodeImport | ||
file="../../examples/intro-to-predicates/multisig-predicate/src/main.sw" | ||
comment="configurable" | ||
commentType="//" | ||
lang="sway" | ||
/> | ||
|
||
Imagine you are a multisig provider assisting businesses and users in setting up their own multisigs. You wouldn't want to hard-code these details every time but rather provide a few parameters that users can configure themselves. |
83 changes: 83 additions & 0 deletions
83
docs/guides/docs/intro-to-predicates/debugging-with-scripts-rust.mdx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
--- | ||
title: Logging in Rust tests | ||
category: Intro to Predicates | ||
parent: | ||
label: All Guides | ||
link: /guides | ||
--- | ||
|
||
# Logging in Rust tests | ||
|
||
## Generating a Test Template in Rust | ||
|
||
To create your own test template using Rust, follow these steps with `cargo-generate` in the script project directory: | ||
|
||
1. Install `cargo-generate`: | ||
|
||
```bash | ||
cargo install cargo-generate --locked | ||
``` | ||
|
||
{/*markdownlint-disable*/} | ||
2. Generate the template: | ||
{/*markdownlint-disable*/} | ||
|
||
<TestAction | ||
id="cargo-generate-test" | ||
action={{ | ||
name: 'runCommand', | ||
commandFolder: 'guides-testing/predicate-script-logging/' | ||
}} | ||
/> | ||
|
||
```bash | ||
cargo generate --init fuellabs/sway templates/sway-test-rs --name sway-store | ||
``` | ||
|
||
## Logging | ||
|
||
We previously covered imports and setting up the predicate in an earlier introduction to Sway tutorial, specifically in the [Rust testing section](https://docs.fuel.network/guides/intro-to-sway/rust-sdk/). If you haven't checked that out yet, I highly recommend doing so. | ||
|
||
Copy and paste the rust test below: | ||
|
||
<TestAction | ||
id="sway-program-type" | ||
action={{ | ||
name: 'writeToFile', | ||
filepath: 'guides-testing/predicate-script-logging/tests/harness.rs' | ||
}} | ||
/> | ||
|
||
<CodeImport | ||
file="../../examples/intro-to-predicates/predicate-script-logging/tests/harness.rs" | ||
comment="all" | ||
commentType="//" | ||
lang="sway" | ||
/> | ||
|
||
Now, I want to draw your attention to a specific portion of the code here: | ||
|
||
<CodeImport | ||
file="../../examples/intro-to-predicates/predicate-script-logging/tests/harness.rs" | ||
comment="logs" | ||
commentType="//" | ||
lang="sway" | ||
/> | ||
|
||
We can now call `decode_logs` to extract our secret number, something we weren't able to do when testing with predicates. | ||
|
||
To enable print outputs to appear in the console during tests, you can use the `nocapture` flag. | ||
|
||
<TestAction | ||
id="cargo-test" | ||
action={{ | ||
name: 'runCommand', | ||
commandFolder: 'guides-testing/predicate-script-logging/' | ||
}} | ||
/> | ||
|
||
```sh | ||
cargo test -- --nocapture | ||
``` | ||
|
||
Remembering this method is essential when developing more complex predicates, especially as debugging becomes increasingly challenging. |
84 changes: 84 additions & 0 deletions
84
docs/guides/docs/intro-to-predicates/debugging-with-scripts.mdx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,84 @@ | ||
--- | ||
title: Debugging with Scripts | ||
category: Intro to Predicates | ||
parent: | ||
label: All Guides | ||
link: /guides | ||
--- | ||
|
||
# Debugging with Scripts | ||
|
||
In every aspect of development, trade-offs are inevitable. As previously mentioned, logging is not feasible when dealing with predicates, since predicates are required to be pure. This raises an important question: how do we debug predicates? | ||
|
||
Sway, a programming language, categorizes programs into four types, with scripts being one of them. Unlike predicates, scripts allow for shared logic. | ||
|
||
Let's move outside our MultiSig project | ||
|
||
```sh | ||
cd ../.. | ||
``` | ||
|
||
and create a separate project called `predicate-script-logging`. | ||
|
||
<TestAction | ||
id="create-predicate-script-logging" | ||
action={{ | ||
name: 'runCommand', | ||
commandFolder: 'guides-testing/' | ||
}} | ||
/> | ||
|
||
```sh | ||
forc new --predicate predicate-script-logging | ||
``` | ||
|
||
Copy and paste this new predicate in your `src/main.sw`. Attempting to build this predicate will result in an error, indicating that logging is an invalid operation. | ||
|
||
<CodeImport | ||
file="../../examples/intro-to-predicates/predicate-test-example/src/main.sw" | ||
comment="all" | ||
commentType="//" | ||
lang="sway" | ||
/> | ||
|
||
However, let's try switching the program type from a `predicate` to a `script`. | ||
|
||
<CodeImport | ||
file="../../examples/intro-to-predicates/predicate-script-logging/src/main.sw" | ||
comment="program_type" | ||
commentType="//" | ||
lang="sway" | ||
/> | ||
|
||
Your code should now look like this: | ||
|
||
<TestAction | ||
id="sway-program-type" | ||
action={{ | ||
name: 'writeToFile', | ||
filepath: 'guides-testing/predicate-script-logging/src/main.sw' | ||
}} | ||
/> | ||
|
||
<CodeImport | ||
file="../../examples/intro-to-predicates/predicate-script-logging/src/main.sw" | ||
comment="all" | ||
commentType="//" | ||
lang="sway" | ||
/> | ||
|
||
Now, if we attempt to build our script, it should compile without any issues. | ||
|
||
<TestAction | ||
id="build-predicate" | ||
action={{ | ||
name: 'runCommand', | ||
commandFolder: 'guides-testing/predicate-script-logging/' | ||
}} | ||
/> | ||
|
||
```sh | ||
forc build | ||
``` | ||
|
||
Next, we'll generate a Rust template to see it in action! |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,97 @@ | ||
--- | ||
title: Imports | ||
category: Intro to Predicates | ||
parent: | ||
label: All Guides | ||
link: /guides | ||
--- | ||
|
||
# Imports | ||
|
||
The predicate keyword is used to identify that the program is a predicate. | ||
|
||
<TestAction | ||
id="sway-program-type" | ||
action={{ | ||
name: 'writeToFile', | ||
filepath: 'guides-testing/multisig-predicate/predicate/src/main.sw' | ||
}} | ||
/> | ||
|
||
<CodeImport | ||
file="../../examples/intro-to-predicates/multisig-predicate/src/main.sw" | ||
comment="predicate" | ||
commentType="//" | ||
lang="sway" | ||
/> | ||
|
||
We're going to utilize the [Sway standard library](https://github.com/FuelLabs/sway/tree/master/sway-lib-std) in our predicate. Delete the template code except for the predicate keyword and copy in the imports below: | ||
|
||
<TestAction | ||
id="sway-import" | ||
action={{ | ||
name: 'modifyFile', | ||
filepath: 'guides-testing/multisig-predicate/predicate/src/main.sw' | ||
}} | ||
/> | ||
|
||
<CodeImport | ||
file="../../examples/intro-to-predicates/multisig-predicate/src/main.sw" | ||
comment="import_parent" | ||
commentType="//" | ||
lang="sway" | ||
/> | ||
|
||
## Transactions | ||
|
||
To construct the MultiSig, it's essential for us to obtain three specific components from the transaction through the standard library: | ||
|
||
<CodeImport | ||
file="../../examples/intro-to-predicates/multisig-predicate/src/main.sw" | ||
comment="import_tx" | ||
commentType="//" | ||
lang="sway" | ||
/> | ||
|
||
1. Transaction Witness Data: We'll use this to attach signatures on the transaction. | ||
2. Transaction Witness Count: This will help us determine the number of signatures attached. | ||
3. Transaction ID: The hash of the transaction. | ||
|
||
## Constants | ||
|
||
From the constants library, we'll be using `ZERO_B256` as a placeholder. | ||
|
||
<CodeImport | ||
file="../../examples/intro-to-predicates/multisig-predicate/src/main.sw" | ||
comment="import_zero_b256" | ||
commentType="//" | ||
lang="sway" | ||
/> | ||
|
||
## Signatures | ||
|
||
We'll need `b512` because signatures are of type `b512`. | ||
|
||
<CodeImport | ||
file="../../examples/intro-to-predicates/multisig-predicate/src/main.sw" | ||
comment="import_b512" | ||
commentType="//" | ||
lang="sway" | ||
/> | ||
|
||
## Elliptical Curve | ||
|
||
Lastly, we will be using `ec_recover_address`, short for elliptical curve recovery address. It's a function that allows us to cryptographically recover the address that signed a piece of data: | ||
|
||
```rust | ||
signing_address = ec_recover_address(signed_data, original_data) | ||
``` | ||
|
||
This step is crucial for safeguarding the funds and ensuring that only the correct wallets can provide the necessary signatures. | ||
|
||
<CodeImport | ||
file="../../examples/intro-to-predicates/multisig-predicate/src/main.sw" | ||
comment="import_ecr" | ||
commentType="//" | ||
lang="sway" | ||
/> |
Oops, something went wrong.