|
| 1 | +# Contributing to Torus |
| 2 | + |
| 3 | +Thanks for your interest in contributing to Torus! Follow this document to learn how we write our code and contribute. The guidelines are _not_ written in stone and each case has its own needs, so feel free to reach out to the team in our Discord server (we don't do DMs). |
| 4 | + |
| 5 | +## Table of contents |
| 6 | + |
| 7 | +- [Development environment setup](#development-environment-setup) |
| 8 | +- [Project structure](#project-structure) |
| 9 | +- [Code style and guidelines](#code-style-and-guidelines) |
| 10 | +- [Storage modifications and migrations](#storage-modifications-and-migrations) |
| 11 | +- [Development workflow](#development-workflow) |
| 12 | +- [Testing guidelines](#testing-guidelines) |
| 13 | +- [Pull request process](#pull-request-process) |
| 14 | + |
| 15 | +## Development environment setup |
| 16 | + |
| 17 | +The project uses Nix flakes to manage dependencies and ensure a consistent development environment across all contributors. It's worth your time setting up! Believe me, you don't want RocksDB building from scratch. |
| 18 | + |
| 19 | +1. Install Nix package manager by following the instructions at [nixos.org](https://nixos.org/download.html) |
| 20 | +2. Enable flakes by adding the following to your `~/.config/nix/nix.conf` or `/etc/nix/nix.conf`: |
| 21 | + ``` |
| 22 | + experimental-features = nix-command flakes |
| 23 | + ``` |
| 24 | +3. Enter the development environment: |
| 25 | + |
| 26 | + ```bash |
| 27 | + nix develop |
| 28 | + ``` |
| 29 | + |
| 30 | + This will set up the correct Rust version, git, and precompiled binaries for dependencies like RocksDB and OpenSSL. |
| 31 | + |
| 32 | +4. Build the project: |
| 33 | + ```bash |
| 34 | + cargo build --release |
| 35 | + ``` |
| 36 | + |
| 37 | +## Project structure |
| 38 | + |
| 39 | +Our project is organized into 5 main crates: |
| 40 | + |
| 41 | +- **`node/`**: Contains the actual node implementation including network setup, RPC call definitions, synchronization behavior, database configurations, and more. Mostly boilerplate from substrate. |
| 42 | + |
| 43 | +- **`pallets/`**: Contains the runtime logic modules separated by responsibility: |
| 44 | + |
| 45 | + - `emission0`: handles all token emission logic; |
| 46 | + - `governance`: manages proposals, allocators, votes, and new agent applications; |
| 47 | + - `torus0`: manages agent registrations and interactions with the network. |
| 48 | + |
| 49 | +- **`runtime/`**: Defines the configuration used by the node and lists all the used pallets. |
| 50 | + |
| 51 | +## Code style and guidelines |
| 52 | + |
| 53 | +We follow standard Rust coding conventions with some additional requirements specific to blockchain development. |
| 54 | + |
| 55 | +### General Rust guidelines |
| 56 | + |
| 57 | +Be idiomatic. Use `Iterator`s, `Result`s, etc. PLEASE. Take a look at [Rust's API guidelines](https://rust-lang.github.io/api-guidelines/). Our CI will reject your changes if they don't pass formatting (it's 202X, enable autoformatting FFS) or clippy check. Code must be reasonably documented. Not everything, of course, but things like storage values, extrinsics, errors, must be documented as this information is extracted to other places like JS SDKs. |
| 58 | + |
| 59 | +### Pallet-specific guidelines |
| 60 | + |
| 61 | +- **Always use the `polkadot_sdk` umbrella dependency** instead of individual substrate dependencies to maintain version consistency. Last thing you want is a massive Cargo file with 150 substrate dependencies written out manually. Don't ask me how the experience of bumping them feels like. Some parts of the ecosystem do not have umbrellas, that's the case of Frontier, but we do what we can. |
| 62 | +- **Avoid panicking in runtime code:** |
| 63 | + - Never use `unwrap()`, `expect()`, or other panic-causing operations in pallet code; |
| 64 | + - the WASM runtime that Substrate runs on cannot unwind, so panics in functions like `on_initialize` will halt the chain (been there - more than once); |
| 65 | + - use `Option` and `Result` types properly for error handling. NEVER allow `unused_must_use`. NEVER; |
| 66 | + - always prefer panic-free functions and treat all potential errors (`checked_div` in favor of `/`, etc.). |
| 67 | + |
| 68 | +## Storage modifications and migrations |
| 69 | + |
| 70 | +Modifying blockchain storage requires special care to maintain chain compatibility. When you modify a storage (creating/deleting storages, changing names, switching types, altering structs, reordering enum variants, ...) make sure to: |
| 71 | + |
| 72 | +1. Increment the storage version for the affected pallet if it hasn't been updated since the last runtime upgrade |
| 73 | + |
| 74 | + - Check the git history to determine if the version has already been incremented |
| 75 | + - Always use `VersionedMigration` from `frame_support` to handle version increments |
| 76 | + |
| 77 | +2. Create a storage migration when you alter existing storages. |
| 78 | + |
| 79 | +### Implementing migrations |
| 80 | + |
| 81 | +Migrations must be carefully implemented to ensure data consistency: |
| 82 | + |
| 83 | +1. Create a new migration module that maps old values to the new storage format |
| 84 | +2. ALWAYS use `VersionedMigration` |
| 85 | +3. Add the migration to the runtime's list of migrations |
| 86 | +4. Test the migration thoroughly with realistic data |
| 87 | +5. Document the migration process in your PR |
| 88 | + |
| 89 | +For detailed guidance on creating migrations, refer to the [Substrate Storage Migrations documentation](https://docs.polkadot.com/develop/parachains/maintenance/storage-migrations/). |
| 90 | + |
| 91 | +## Development workflow |
| 92 | + |
| 93 | +1. Fork the repo and create a new branch for your feature or bugfix: |
| 94 | + |
| 95 | + ```bash |
| 96 | + git checkout -b feature/your-feature-name |
| 97 | + ``` |
| 98 | + |
| 99 | +2. Make your changes, following our code guidelines and testing requirements |
| 100 | + |
| 101 | +3. Run tests and checks to ensure your changes don't break existing functionality: |
| 102 | + |
| 103 | + ```bash |
| 104 | + cargo fmt |
| 105 | + cargo clippy |
| 106 | + cargo test |
| 107 | + ``` |
| 108 | + |
| 109 | +4. Check code coverage to ensure sufficient test coverage: |
| 110 | + |
| 111 | + ```bash |
| 112 | + cargo xtask coverage |
| 113 | + ``` |
| 114 | + |
| 115 | +5. Submit a pull request with a clear description of your changes. |
| 116 | + We are very strict about title/descriptions. Your title SHOULD follow the conventional commits format (`feat(pallets/emission0): emitting 10x to myself`), but MUST be well described. Commits are squashed, so your PR's description will be the body of the merged commit, be generous! |
| 117 | + |
| 118 | +## Testing guidelines |
| 119 | + |
| 120 | +Strong test coverage is a core value for our project. All pallets must maintain high test coverage. Trust me, you want this. Of course, coverage alone doesn't mean it is _well_ tested. But it's a good enough metric. We will review your tests. |
| 121 | + |
| 122 | +### Test coverage |
| 123 | + |
| 124 | +> Code coverage is done via [cargo-llvm-cov](https://github.com/taiki-e/cargo-llvm-cov). It comes with Nix. |
| 125 | +
|
| 126 | +Run the following command to generate a `Cobertura` xml file on `target/cov.xml` that can be used with the [Coverage Gutters](https://marketplace.visualstudio.com/items?itemName=ryanluker.vscode-coverage-gutters) VSCode plugin to display which functions and branches are not covered by tests yet. |
| 127 | + |
| 128 | +```bash |
| 129 | +cargo xtask coverage |
| 130 | +``` |
| 131 | + |
| 132 | +If the `--html` attribute is passed to the command, an HTML website will be generated instead. It serves the same purpose as the plugin mentioned and can be accessed on `target/llvm-cov/html/index.html` |
| 133 | + |
| 134 | +When contributing, please: |
| 135 | + |
| 136 | +- Ensure your changes don't decrease overall test coverage |
| 137 | +- Add tests for new functionality |
| 138 | +- Update existing tests when modifying behavior |
| 139 | +- Write both unit tests and integration tests where appropriate |
| 140 | + |
| 141 | +While the `node/` and `runtime/` crates currently have simpler testing requirements, any complex logic added to these crates should also include appropriate tests. |
| 142 | + |
| 143 | +## Pull request process |
| 144 | + |
| 145 | +1. Ensure your code passes all tests and meets our quality standards |
| 146 | +2. Update documentation if necessary |
| 147 | +3. Include a clear description of the changes and the problem they solve |
| 148 | +4. Link to any relevant issues |
| 149 | +5. Request review from appropriate team members |
| 150 | +6. Address any review feedback |
| 151 | + |
| 152 | +Thank you for contributing to our project! |
0 commit comments