owned this note
owned this note
Published
Linked with GitHub
# Development env for `polkadot-sdk`
There are already a million setup blogs for a good dev environment. Here's mine.
My setup is pretty much identical between my MacBook and Archlinux rig. Substitute [`paru -S`](https://github.com/Morganamilo/paru) for `brew install` and you've got pretty much the same outcome.
### Terminal
Alacritty and vscode/cursor builtin terminal
Theme: [snazzy](https://github.com/alebelcor/alacritty-snazzy/blob/master/snazzy.yml) / Dark Modern
font: [FiraCode Nerd Font](https://www.nerdfonts.com/font-downloads)
shell: `fish`. I used to use `zsh` because it was compatible with bash/sh scripts and used those heavily, but `fish` is faster and nicer without needing `oh-my-zsh` and the start time baggage that comes with it. Still any time I want to do more than just piping a few commands together I still drop to `zsh`.
The following `config.fish`:
`~/.config/fish/config.fish`
```bash
source ~/.config/fish/alias.fish
zoxide init fish | source
starship init fish | source
```
and `~/.config/fish/alias.fish`:
```
alias pcr="cargo remote -d 1.88 --"
alias pcw='cargo remote -d 1.88 -b "SKIP_WASM_BUILD=1" --'
alias pcheck="cargo check --features try-runtime --features runtime-benchmarks"
alias pclip="SKIP_WASM_BUILD=1 cargo clippy --all-targets --locked --workspace"
alias pclip-all="SKIP_WASM_BUILD=1 cargo clippy --all-targets --locked --workspace --all-features"
alias pfmt="cargo +nightly-2025-06-27 fmt"
alias ptaplo="taplo format --config .config/taplo.toml"
alias pcov="cargo-remote tarpaulin --skip-clean -o Lcov --target-dir target/.coverage"
alias gl="git log --oneline"
alias gb="git branch"
alias gc="git commit"
alias gco="git checkout"
alias gcp="git cherry-pick"
alias gr="git rebase"
alias gs="git switch"
alias chopsticks="bunx --bun @acala-network/chopsticks@latest"
alias zombienet="bunx --bun @zombienet/cli@latest"
```
[`starship`](https://starship.rs/) with an empty `starship.toml` for the best no-config cross-shell prompt
`zoxide` for better `cd`
`asdf` for managing versions of all programming languages except `rust`.
Get it all with:
```bash
brew install zoxide asdf
```
Other utils:
`ripgrep` - (much) faster `grep` which respects `gitignore`
`fd` - better `find` without all the crazy non-POSIX black magic
`bat` - syntax highlighted `cat`
`delta` - syntax highlighted pager for better diffs and git diffs
`tealdeer` - distilled man pages for quick lookups, I'll check this before I resort to `man`
`rsync` - used for `cargo-remote`
`eza` - better `ls` but I only remember to use it when ls doesn't cut it
`hyperfine` - benchmarking
get them all:
```bash
brew install ripgrep fd bat git-delta tealdeer rsync eza hyperfine
```
VSCode or cursor with the following extensions:
Rust-analyzer
Vim - vim keybindings
GitLens - file and line history etc
ErrorLens - errors inline
Project Manager - better workspace management
CodeLLDB - debugging
Coverage Gutters - test coverage
Rewrap - comment line length enforcement
Even better toml - toml syntax highlighting
### Cargo binaries
cargo-cov - coverage (takes a bit of setting up)
cargo-nextest - test runner from CI
srtool - reproducible builds
zepter - feature propagation
cargo-expand - expand macros to make debugging easier
cargo-tarpaulin - code coverage
cargo-cache - clear all the caches, I've heard sweep is good too
cargo-fmt - format your code
cargo-remote - compile on a remote machine
prdoc
cargo-clippy - lints
framy - pallet scaffolder
taplo - toml formatting
### Selected dotfiles
TODO: update github dotfiles repo
`~/.gitconfig`
```
[user]
email = donal.murray@parity.io
name = Dónal Murray
signingkey = 0x72A0121F03B4B01BEFD4C5337C904D3BD738CF7D
[commit]
gpgsign = true
[init]
defaultBranch = main
[core]
pager = delta
[interactive]
diffFilter = delta --color-only --features=interactive
[delta]
features = decorations
[delta "interactive"]
keep-plus-minus-markers = false
[delta "decorations"]
commit-decoration-style = blue ol
commit-style = raw
file-style = omit
hunk-header-decoration-style = blue box
hunk-header-file-style = red
hunk-header-line-number-style = "#067a00"
hunk-header-style = file line-number syntax
```
`~/.ssh/config`
```
Host cargo-remote
HostName x.x.x.x
IdentityFile ~/.ssh/id_rsa
IdentitiesOnly yes
User donal
port n
ControlMaster auto
ControlPath ~/.ssh/control:%C
ControlPersist 600
Host github.com
HostName github.com
IdentityFile ~/.ssh/id_rsa
IdentitiesOnly yes
...
```
`~/.config/fish/aliases.fish`
```
# p-prefixed for polkadot-sdk CI settings
alias pcr="cargo remote -d 1.81 --"
alias pcheck="cargo check --features try-runtime --features runtime-benchmarks"
alias pclip="SKIP_WASM_BUILD=1 cargo clippy --all-targets --locked --workspace"
alias pclip-all="SKIP_WASM_BUILD=1 cargo clippy --all-targets --locked --workspace --all-features"
alias pfmt="cargo +nightly fmt"
alias ptaplo="taplo format --config .config/taplo.toml"
alias pcov="pcr tarpaulin --skip-clean -o Lcov --target-dir target/.coverage"
alias gl="git log --oneline"
alias gb="git branch"
alias gc="git commit"
alias gco="git checkout"
alias gcp="git cherry-pick"
alias gr="git rebase"
alias gs="git switch"
alias chopsticks="bunx --bun @acala-network/chopsticks@latest"
alias zombienet="bunx --bun @zombienet/cli@latest"
```
`~/.scripts/wdebug`
```
#!/usr/bin/env sh
# Make WASM debugging less awful
# Define the patch
patch=$(cat <<'EOF'
diff --git a/substrate/frame/support/procedural/src/lib.rs b/substrate/frame/support/procedural/src/lib.rs
index 349b6ee659..f74a9701af 100644
--- a/substrate/frame/support/procedural/src/lib.rs
+++ b/substrate/frame/support/procedural/src/lib.rs
@@ -429,28 +429,7 @@ pub fn derive_debug_no_bound(input: TokenStream) -> TokenStream {
/// This behaviour is useful to prevent bloating the runtime WASM blob from unneeded code.
#[proc_macro_derive(RuntimeDebugNoBound)]
pub fn derive_runtime_debug_no_bound(input: TokenStream) -> TokenStream {
- if cfg!(any(feature = "std", feature = "try-runtime")) {
no_bound::debug::derive_debug_no_bound(input)
- } else {
- let input: syn::DeriveInput = match syn::parse(input) {
- Ok(input) => input,
- Err(e) => return e.to_compile_error().into(),
- };
-
- let name = &input.ident;
- let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();
-
- quote::quote!(
- const _: () = {
- impl #impl_generics ::core::fmt::Debug for #name #ty_generics #where_clause {
- fn fmt(&self, fmt: &mut ::core::fmt::Formatter) -> core::fmt::Result {
- fmt.write_str("<wasm:stripped>")
- }
- }
- };
- )
- .into()
- }
}
/// Derive [`PartialEq`] but do not bound any generic. Docs are at
EOF
)
# Apply the patch
echo "$patch" | git apply -
echo 'Add this to the package you want to debug:'
echo 'sp-debug-derive = { path = "../../../../../substrate/primitives/debug-derive", default-features = false, features = [ "force-debug" ] }'
```
`"~/Library/Application Support/Code/User/settings.json"`
```
{
"workbench.startupEditor": "none",
"terminal.integrated.fontFamily": "'FiraMono Nerd Font Mono'",
"terminal.external.osxExec": "Alacritty.app",
"terminal.integrated.enableImages": true,
"terminal.integrated.tabStopWidth": 4,
"[rust]": {
"editor.formatOnSave": true,
"editor.defaultFormatter": "rust-lang.rust-analyzer",
},
// Use a separate target dir for Rust Analyzer. Helpful if you want to use Rust
// Analyzer and cargo on the command line at the same time.
"rust-analyzer.rust.analyzerTargetDir": "target/vscode-rust-analyzer",
// Improve stability
"rust-analyzer.server.extraEnv": {
"CHALK_OVERFLOW_DEPTH": "100000000",
"CHALK_SOLVER_MAX_SIZE": "10000000"
},
// Check feature-gated code
"rust-analyzer.cargo.features": "all",
"rust-analyzer.cargo.extraEnv": {
// Skip building WASM, there is never need for it here
"SKIP_WASM_BUILD": "1"
},
"rust-analyzer.cargo.buildScripts.overrideCommand": [
"cargo",
"remote",
"-b SKIP_WASM_BUILD=1",
"--",
"check",
"--quiet",
"--message-format=json",
"--all-targets",
"--features",
"runtime-benchmarks,try-runtime",
"--tests"
],
"rust-analyzer.check.overrideCommand": [
"cargo",
"remote",
"-b SKIP_WASM_BUILD=1",
"--",
"check",
"--quiet",
"--workspace",
"--message-format=json",
"--all-targets",
"--features",
"runtime-benchmarks,try-runtime",
"--tests"
],
// Don't expand some problematic proc_macros
"rust-analyzer.procMacro.ignored": {
"async-trait": [
"async_trait"
],
"napi-derive": [
"napi"
],
"async-recursion": [
"async_recursion"
],
"async-std": [
"async_std"
]
},
// Use nightly formatting.
// See the polkadot-sdk CI job that checks formatting for the current version used in
// polkadot-sdk.
"rust-analyzer.rustfmt.extraArgs": [
"+nightly"
],
"github.copilot.enable": {
"*": true,
"plaintext": false,
"markdown": false,
"scminput": false,
"rust": false
},
"terminal.integrated.scrollback": 10000000,
"projectManager.git.baseFolders": [
"~/dev"
],
"projectManager.openInNewWindowWhenClickingInStatusBar": true,
"projectManager.showParentFolderInfoOnDuplicates": true,
"files.associations": {
"*.prdoc": "yaml",
},
"yaml.schemas": {
"~/dev/polkadot-sdk/prdoc/schema_user.json": "*polkadot-sdk*/**/*.prdoc",
},
"coverage-gutters.showLineCoverage": true,
"coverage-gutters.coverageFileNames": [
"lcov.info",
"cov.xml",
"coverage.xml",
"jacoco.xml",
"coverage.cobertura.xml"
],
"rewrap.wrappingColumn": 100,
"editor.renderWhitespace": "all",
"diffEditor.ignoreTrimWhitespace": false,
"debug.allowBreakpointsEverywhere": true,
"editor.detectIndentation": false,
}
```