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

docs: Debugging instructions using IDEs #1309

Merged
merged 30 commits into from
Aug 22, 2023
Merged
Show file tree
Hide file tree
Changes from 11 commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
d378acd
Enable .env file loading and env feature
bvrooman Aug 16, 2023
401ef56
Update CHANGELOG.md
bvrooman Aug 16, 2023
158a2f1
Update use based on cfg
bvrooman Aug 16, 2023
636c3dc
Merge branch 'master' into bvrooman/feat/enable-env-file
Aug 16, 2023
b68630e
Update log statement with full path
bvrooman Aug 16, 2023
de75607
Merge branch 'bvrooman/feat/enable-env-file' of https://github.com/Fu…
bvrooman Aug 16, 2023
bdc1022
Debugging documentation
bvrooman Aug 17, 2023
86d92af
Update README.md
bvrooman Aug 17, 2023
ccd015c
minor
bvrooman Aug 17, 2023
c17b74f
Minor
bvrooman Aug 17, 2023
622d659
Update CHANGELOG.md
bvrooman Aug 17, 2023
431bfcf
Update docs/developers/debugging.md
Aug 18, 2023
7ff38fe
Update debugging.md
bvrooman Aug 21, 2023
eadcb55
Print error when using dotenv without .env file
bvrooman Aug 21, 2023
d1c8fa3
Add env to debug and production features
bvrooman Aug 22, 2023
fda375a
Merge branch 'master' into bvrooman/feat/enable-env-file
Aug 22, 2023
26540e2
Fix use statement for cfg
bvrooman Aug 22, 2023
0d24a11
Merge branch 'bvrooman/feat/enable-env-file' into bvrooman/docs/debug…
Aug 22, 2023
6d0bcd9
Merge branch 'master' into bvrooman/docs/debugging
xgreenx Aug 22, 2023
46de30f
Fix changelog after merge
bvrooman Aug 22, 2023
41e31ff
Link to vercel guide on networking
bvrooman Aug 22, 2023
ec870a5
Notes on CLion configurations
bvrooman Aug 22, 2023
a59106e
Replace instances of "Beta 3" with "Fuel Client"
bvrooman Aug 22, 2023
0760cdb
Add `common issues`
bvrooman Aug 22, 2023
6c44da6
Replace VS config png with copyable JSON
bvrooman Aug 22, 2023
b401d71
Fix whitespace
bvrooman Aug 22, 2023
3b5d29f
Update wording
bvrooman Aug 22, 2023
b07154a
Merge branch 'master' into bvrooman/docs/debugging
Aug 22, 2023
b1d3713
Update VS config steps
bvrooman Aug 22, 2023
15dc549
Merge branch 'bvrooman/docs/debugging' of https://github.com/FuelLabs…
bvrooman Aug 22, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,4 @@ version-compatibility/Cargo.lock
benches/benches-outputs/Cargo.lock
benches/benches-outputs/src/test_gas_costs_output.rs
.idea
.env
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ Description of the upcoming release here.

### Added

- [#1309](https://github.com/FuelLabs/fuel-core/pull/1309): Add documentation for running debug builds with CLion and Visual Studio Code.
- [#1308](https://github.com/FuelLabs/fuel-core/pull/1308): Add support for loading .env files when compiling with the `env` feature. This allows users to conveniently supply CLI arguments in a secure and IDE-agnostic way.
- [#1263](https://github.com/FuelLabs/fuel-core/pull/1263): Add gas benchmarks for `ED19` and `ECR1` instructions.
- [#1286](https://github.com/FuelLabs/fuel-core/pull/1286): Include readable names for test cases where missing.
- [#1304](https://github.com/FuelLabs/fuel-core/pull/1304): Implemented `submit_and_await_commit_with_receipts` method for `FuelClient`.
Expand Down
7 changes: 7 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,10 @@ The service relies on the environment variable `RUST_LOG`. For more information,

Human logging can be disabled with the environment variable `HUMAN_LOGGING=false`

## Debugging

See the guide on [debugging](docs/developers/debugging.md) for an overview on running a debug build of a local node.

## Docker & Kubernetes

```sh
Expand Down
2 changes: 2 additions & 0 deletions bin/fuel-core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ anyhow = { workspace = true }
clap = { workspace = true, features = ["derive", "env"] }
const_format = { version = "0.2", optional = true }
dirs = "4.0"
dotenvy = { version = "0.15", optional = true }
fuel-core = { workspace = true }
humantime = "2.1"
lazy_static = { workspace = true }
Expand All @@ -40,6 +41,7 @@ test-case = { workspace = true }
[features]
debug = ["fuel-core/debug"]
default = ["debug", "metrics", "relayer", "rocksdb"]
env = ["dep:dotenvy"]
metrics = ["fuel-core/metrics"]
p2p = ["fuel-core/p2p", "const_format"]
relayer = ["fuel-core/relayer", "dep:url", "dep:serde_json"]
Expand Down
23 changes: 22 additions & 1 deletion bin/fuel-core/src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,20 @@ use std::{
path::PathBuf,
str::FromStr,
};
use tracing::warn;
use tracing::{
info,
warn,
};
use tracing_subscriber::{
filter::EnvFilter,
layer::SubscriberExt,
registry,
Layer,
};

#[cfg(feature = "env")]
use dotenvy::dotenv;

lazy_static::lazy_static! {
pub static ref DEFAULT_DB_PATH: PathBuf = dirs::home_dir().unwrap().join(".fuel").join("db");
}
Expand Down Expand Up @@ -41,6 +47,16 @@ pub enum Fuel {
pub const LOG_FILTER: &str = "RUST_LOG";
pub const HUMAN_LOGGING: &str = "HUMAN_LOGGING";

#[cfg(feature = "env")]
fn init_environment() -> Option<PathBuf> {
dotenv().ok()
}

#[cfg(not(feature = "env"))]
fn init_environment() -> Option<PathBuf> {
None
}

pub async fn init_logging() -> anyhow::Result<()> {
let filter = match env::var_os(LOG_FILTER) {
Some(_) => {
Expand Down Expand Up @@ -87,6 +103,11 @@ pub async fn init_logging() -> anyhow::Result<()> {
}

pub async fn run_cli() -> anyhow::Result<()> {
init_logging().await?;
if let Some(path) = init_environment() {
let path = path.display();
info!("Loading environment variables from {path}");
}
let opt = Opt::try_parse();
if opt.is_err() {
let command = run::Command::try_parse();
Expand Down
2 changes: 0 additions & 2 deletions bin/fuel-core/src/cli/run.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
#![allow(unused_variables)]
use crate::{
cli::{
init_logging,
run::consensus::PoATriggerArgs,
DEFAULT_DB_PATH,
},
Expand Down Expand Up @@ -333,7 +332,6 @@ impl Command {
}

pub async fn exec(command: Command) -> anyhow::Result<()> {
init_logging().await?;
let config = command.get_config()?;
let network_name = {
#[cfg(feature = "p2p")]
Expand Down
4 changes: 2 additions & 2 deletions bin/fuel-core/src/cli/run/relayer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ pub struct RelayerArgs {
#[arg(long = "relayer", env)]
#[arg(required_if_eq("enable_relayer", "true"))]
#[arg(requires_if(IsPresent, "enable_relayer"))]
pub eth_client: Option<url::Url>,
pub relayer: Option<url::Url>,

/// Ethereum contract address. Create EthAddress into fuel_types
#[arg(long = "relayer-v2-listening-contracts", value_parser = parse_h160, env)]
Expand Down Expand Up @@ -71,7 +71,7 @@ impl RelayerArgs {
let config = Config {
da_deploy_height: DaBlockHeight(self.da_deploy_height),
da_finalization: DaBlockHeight(self.da_finalization),
eth_client: self.eth_client,
relayer: self.relayer,
eth_v2_listening_contracts: self.eth_v2_listening_contracts,
log_page_size: self.log_page_size,
sync_minimum_duration: Duration::from_secs(self.sync_minimum_duration_secs),
Expand Down
2 changes: 0 additions & 2 deletions bin/fuel-core/src/cli/snapshot.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,6 @@ pub async fn exec(command: Command) -> anyhow::Result<()> {

#[cfg(any(feature = "rocksdb", feature = "rocksdb-production"))]
pub async fn exec(command: Command) -> anyhow::Result<()> {
use crate::cli::init_logging;
use anyhow::Context;
use fuel_core::{
chain_config::{
Expand All @@ -60,7 +59,6 @@ pub async fn exec(command: Command) -> anyhow::Result<()> {
},
database::Database,
};
init_logging().await?;
let path = command.database_path;
let data_source =
fuel_core::state::rocks_db::RocksDb::default_open(&path, None).context(
Expand Down
4 changes: 2 additions & 2 deletions crates/services/relayer/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ pub struct Config {
/// Number of da blocks after which messages/stakes/validators become finalized.
pub da_finalization: DaBlockHeight,
/// Uri address to ethereum client.
pub eth_client: Option<url::Url>,
pub relayer: Option<url::Url>,
// TODO: Create `EthAddress` into `fuel_core_types`.
/// Ethereum contract address.
pub eth_v2_listening_contracts: Vec<H160>,
Expand Down Expand Up @@ -58,7 +58,7 @@ impl Default for Config {
Self {
da_deploy_height: DaBlockHeight::from(Self::DEFAULT_DA_DEPLOY_HEIGHT),
da_finalization: DaBlockHeight::from(Self::DEFAULT_DA_FINALIZATION),
eth_client: None,
relayer: None,
eth_v2_listening_contracts: vec![H160::from_str(
"0x03E4538018285e1c03CCce2F92C9538c87606911",
)
Expand Down
2 changes: 1 addition & 1 deletion crates/services/relayer/src/service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -348,7 +348,7 @@ pub fn new_service<D>(database: D, config: Config) -> anyhow::Result<Service<D>>
where
D: RelayerDb + Clone + 'static,
{
let url = config.eth_client.clone().ok_or_else(|| {
let url = config.relayer.clone().ok_or_else(|| {
anyhow::anyhow!(
"Tried to start Relayer without setting an eth_client in the config"
)
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/developers/assets/vs_code_configuration.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
131 changes: 131 additions & 0 deletions docs/developers/debugging.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
# Debugging

## Setup Requirements

Building Fuel is supported on macOS and Linux.

The Fuel client is written in Rust. For developers who wish to build the Fuel client locally, it is recommended to use the latest version of Rust. The build process uses the stable Rust toolchain.

See the [Fuel Client system requirements](../../README.md#system-requirements).

## Building and Running

Building and running debug builds of the Fuel client is done using Cargo.

By default, when using the `cargo build` or `cargo run` commands, Cargo generates a debug build. This build is optimized for debugging and development purposes, including debug symbols and minimal optimizations. IDEs rely on debug builds to provide robust debugging features.

The `cargo run` command will compile and execute the Fuel client application directly from source code. When running `cargo run`, Cargo compiles the Fuel client, and runs the resulting binary. During development and debugging, this should be used instead of installing the client (`cargo install`) or running the executable directly.

When building or running the Fuel client, it is recommended to pass the `--all-features` flag to Cargo. This will instruct Cargo to compile the client with features such as P2P and the Relayer service.

To run the Fuel client, the following command can be used:

```bash
cargo run --all-features --bin fuel-core -- run <ARGUMENTS>
```

where `<ARGUMENTS>` is the desired set of arguments.

The list of arguments can be found by running the `help` command:

```bash
cargo run --bin fuel-core run --help
```

It is suggested to run the client with the P2P and Relayer services enabled. This is communicated to the CLI with the flags `--enable-p2p` and `--enable-relayer` respectively. Enabling these services requires that the client is compiled with the relevant features (`p2p` and `relayer`). These features are specified implicitly when the `--all-features` flag is specified.


## Environment

Users can supply CLI arguments to their node indirectly by populating the relevant environment variables. The list of CLI arguments and their environment variables can be found by running the `help` command.

Users can define environment variables by configuring their shell or setting them inside the current terminal.

Additionally, users can add a `.env` file to the root directory of their local copy of their Fuel node (or wherever the working directory is). Using a `.env` file requires compiling the client with the `env` feature. This can be accomplished by including `env` in the list of features or by passing the `--all-features` flag.

Using environment variables for CLI arguments allows these values to be reused across IDEs and IDE configurations seamlessly.


## P2P Network

When running the client with the P2P service enabled, i.e., building the binary with the `p2p` feature and supplying the runtime argument `--enable-p2p`, the client will connect to a Fuel network. This requires additional CLI arguments, including the `--keypair` and `--network` arguments.

A key pair can be generated by running the utility binary `fuel-core-keygen`:

```bash
cargo run --bin fuel-core-keygen new
```

The resulting key pair printed to the console contains an address and secret. The `address` can be provided to the `--keypair` argument when running the node.
bvrooman marked this conversation as resolved.
Show resolved Hide resolved

The `--network` argument identifies the name of the network to join. The network name is used during peer discovery. For example, users can specify `--network beta3-prod` to join the Beta 3 Production network. Similarly, setting the environment variable `NETWORK="beta3-prod"` will produce the same result.
xgreenx marked this conversation as resolved.
Show resolved Hide resolved

## Recommended IDEs

During development, it is recommended to delegate the execution of Cargo instructions to an IDE and connect the application to the IDE's debugger, instead of running these instructions manually.

Recommended IDEs include:
- CLion
- Visual Studio Code

## CLion

### Prerequisites

Running Fuel Core with CLion requires the official JetBrains Rust plugin. Find the Rust plugin by navigating to CLion's Plugin menu, entering "Rust" in the search. Install it by clicking "Install".

### Create A Run Configuration

1. In the top-right corner of the CLion window, click on the configurations dropdown menu and select "Edit Configurations..."
2. In the "Run/Debug Configurations" window, click on the "+" button and select "Cargo"
3. In the "Name" field, give your configuration a descriptive name, such as "Run Beta 3"
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
3. In the "Name" field, give your configuration a descriptive name, such as "Run Beta 3"
3. In the "Name" field, give your configuration a descriptive name, such as "Run Fuel Client"

Just to remove the need to update the docs. Maybe is better to set a generic name

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yep, that makes sense 👍

4. In the "Command" field, enter `run --all-features --bin fuel-core -- run <ARGUMENTS>`, where `<ARGUMENTS>` represents the desired CLI arguments. Refer to the CLI documentation for guidance on which options and arguments to use.
Copy link
Member

Choose a reason for hiding this comment

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

I think we could add the example --db-type in-memory just to avoid errors.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I added a Common Issues section to mention using --db-type in-memory in case of some errors.

5. If you use environment variables for configuration (as indicated in the CLI documentation), you can set them in the "Environment variables" section. Enter the variables and their values as needed. It is recommended to set the `RUST_LOG` environment variable to either `info` or `debug`.
6. Click "Apply" or "OK" to save your run configuration.

### Example Configuration

![clion_configuration.png](assets/clion_configuration.png)
Copy link
Member

@luizstacio luizstacio Aug 22, 2023

Choose a reason for hiding this comment

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

Following the steps, I had to do two more things;
5. Select the workspace folder
6. Remove on the before start section of the build action

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thanks for going through the steps!

I think it would be a good idea for me to add a quick line adding the workspace folder. Usually, CLion should populate this line for you to your repository root (don't change it to what's exactly in the example!) But if that is missing for whatever reason, it would be helpful to know that you should set this to the root yourself. I see that I omitted that instruction.

The "Before start" settings are optional. CLion adds "Build" by default, but it's okay because cargo run does a build by default. I will add a note on these settings too.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Once I try to run it throws the error:

ERROR fuel_core::cli: 57: Unable to load .env environment variables: path not found. Please check that you have created a .env file in your working directory.

This is actually a new feature and it's deliberate. It simply means the client is expecting you to provide a .env file (probably because you compiled with --all-features), but it didn't find it. Simply add a .env file in the root of your repo with your specific configuration values, and you're good to go.

Copy link
Member

Choose a reason for hiding this comment

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

Yeah, it worked even with the error. The real error was on the database folder:

thread 'main' panicked at 'source slice length (64) does not match destination slice length (32)', <>/.cargo/registry/src/index.crates.io-6f17d22bba15001f/fuel-types-0.36.0/src/array_types.rs:389:16


### Running and Debugging

1. With your configuration selected in the dropdown menu, click on the Run button to start running your Fuel client node.
2. Alternatively, click on the Debug button to start your client node in debug mode.
3. Set breakpoints in the code where inspections are necessary. CLion will halt execution at these breakpoints, allowing variable inspection and step-by-step code execution.

## Visual Studio Code

### Prerequisites

Running Fuel Core with Visual Studio Code requires the CodeLLDB extension. Find the CodeLLDB extension by navigating to the "Extensions" tab and searching "CodeLLDB". Install it by clicking "Install".

### Create A Run Configuration

1. In VS Code, click on the "Run and Debug" icon in the left sidebar.
2. VS Code will offer to create a `launch.json` file to configure how your client node is run. Clicking this will prompt you to select a debugger. Select the CodeLLDB debugger to proceed. VS Code will generate a `launch.json` file for you.
3. In the "Run and Debug" menu, click the dropdown menu and select "Add Configuration..."
4. In the `"type"` field, enter `"lldb"`. In the `"request"` field, enter `"launch"`.
5. In the `"name"` field, give your configuration a descriptive name, such as `"Run Beta 3"`
Copy link
Member

@luizstacio luizstacio Aug 22, 2023

Choose a reason for hiding this comment

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

Suggested change
5. In the `"name"` field, give your configuration a descriptive name, such as `"Run Beta 3"`
5. In the `"name"` field, give your configuration a descriptive name, such as `"Run Fuel Client"`

6. In the `"args"` array nested under `"cargo"`, enter the following arguments: `"run"`, `"--all-features"`, `"--bin"`, `"fuel-core"`, `"--"`, `"run"`, `<ARGUMENTS>`, where `<ARGUMENTS>` is a list of CLI values and arguments encapsulated by quotes. Refer to the CLI documentation for guidance on which options and arguments to use.
7. Save these changes made to your `launch.json` file.

### Example Configuration

![vs_code_configuration.png](assets/vs_code_configuration.png)
Copy link
Member

Choose a reason for hiding this comment

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

We could just past here the plain json, to make it easier to copy and paste

Copy link
Member

Choose a reason for hiding this comment

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

I was not able to make the debug work, it looks like the command never finishes. It starts but not finishes.

My config;

[
    "run",
    "--all-features",
    "--bin",
    "fuel-core",
    "--",
    "run",
    "--ip", "0.0.0.0",
    "--port", "4004",
    "--db-type", "in-memory",
    "--utxo-validation",
    "--vm-backtrace",
    "--poa-interval-period",
    "30s"
]

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Luiz and I discussed this specific issue over a call: It appears that the client is starting correctly, and producing the expected output in the terminal, but the VS Code debugger is not correctly attaching to the running process. Luiz and I will spend some time independently looking into this.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I updated the example with a more reliable config that users can copy + paste to get started.


### Running and Debugging

1. Navigate to the "Run and Debug" tab. With your configuration selected in the configuration dropdown menu, click on the Run button to start running your Fuel client node.
2. Set breakpoints in the code where inspections are necessary. VS Code will halt execution at these breakpoints, allowing variable inspection and step-by-step code execution.

## Alternative Configurations

Developers can create additional configurations with alternative CLI arguments to experiment with different setups or debug specific features. For example, omitting the `--enable-p2p` flag (and related P2P arguments) will start the node without the P2P service. Similarly, omitting the `--enable-relayer` (and related relayer arguments) will start the node without the relayer service. Developers can create additional configurations to save specific combinations of CLI arguments and to conveniently switch between them.

Developers can also configure builds by selecting the desired compile-time features. For example, developers can omit the `p2p` service from compilation by explicitly passing a custom feature set to Cargo:

```bash
cargo run --features "relayer" --bin fuel-core -- run --enable-relayer <ARGUMENTS>
```


4 changes: 2 additions & 2 deletions tests/tests/relayer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ async fn relayer_can_download_logs() {
let eth_node = Arc::new(eth_node);
let eth_node_handle = spawn_eth_node(eth_node).await;

relayer_config.eth_client = Some(
relayer_config.relayer = Some(
format!("http://{}", eth_node_handle.address)
.as_str()
.try_into()
Expand Down Expand Up @@ -153,7 +153,7 @@ async fn messages_are_spendable_after_relayer_is_synced() {
let eth_node = Arc::new(eth_node);
let eth_node_handle = spawn_eth_node(eth_node).await;

relayer_config.eth_client = Some(
relayer_config.relayer = Some(
format!("http://{}", eth_node_handle.address)
.as_str()
.try_into()
Expand Down