infrablockchain-docs
en
en
  • InfraBlockchain
    • Learn
      • Architecture
        • Architecture
        • Network Participants
        • Parachain
          • System Parachains
      • Protocol
        • System Token
        • Transaction Fee
        • Proof of Transaction
      • Substrate
        • Learn
          • Basic
            • Cryptography
            • Blockchain Basics
            • Consensus
            • Networks and Nodes
            • Blockchain Transaction
            • Transaction Life Cycle
            • Offchain Operations
            • Light Client
            • Rust for Substrate
            • Introduction to Library
            • Architecture and Rust Libraries
            • File Architecture
            • Accounts, Addresses, and Keys
            • Transaction Format
            • Blockchain Randomness
          • FRAME
            • FRAME Pallets
            • FRAME Macros
            • Custom Pallets
            • Pallet Coupling
            • Origin
            • Events and Erros
            • Runtime Storage
            • State Transitions and Storage
            • SCALE Encoding
            • Weight and Fee
            • Runtime API
            • Runtime Development
          • Account
          • Address Format
          • Glossary
          • CLI
            • Archive
            • Memory Profiler
            • Node Template
            • sidecar
            • srtool
            • Subkey
            • subxt
            • try-runtime
            • tx-wrapper
          • Runtime Development
            • Basics
              • Configure Genesis State
              • Configure Runtime Constants
              • Customize a Chain Spec
              • Import a Pallet
              • Use Helper Function
            • Consensus Model
              • PoW
              • Create a Hybrid Node
            • Offchain Worker
              • Request Offchain HTTP
              • Offchain Indexing
              • Offchain Local Storage
            • Pallet Design
              • Create a Storage Structure
              • Implement Lockable Currency
              • Incorporate Randomness
              • Loose Coupling
              • Tight Coupling
            • Parachain Development
              • Add HRMP Channel
              • Add Paranodes
              • Connect to a Local Relay Chain
              • Convert a Solo Chain
              • Prepare to Launch
              • Select Collator
              • Upgrade a Parachain
            • Storage Migration
              • Basics
              • Trigger Migration
            • Test
              • Basics
              • Test a Transfer Transaction
            • Tools
              • Create a TxWrapper
              • Use Sidecar
              • try-runtime
              • Verify WASM
            • Weigths
              • Benchmark
              • Calculate Fees
              • Use Conditional Weights
              • Use Custom Weights
        • Build
          • Decide What to Build
          • Build Process
          • Determinisitc Runtime
          • Chain Spec
          • Genesis Configuration
          • Application Development
          • RPC
          • Troubleshoot Your Code
        • Tutorials
          • Install
            • Developer Tools
            • Linux
            • macOS
            • Rust Toolchain
            • Issues
            • Windows
          • Quick Start
            • Explore the Code
            • Modify Runtime
            • Start a Node
            • Substrate Basics
          • Build a Blockchain
            • Add Trusted Nodes
            • Authorize Specific Nodes
            • Build a Local Blockchain
            • Simulate Network
            • Upgrade a Running Network
          • Build Application Logic
            • Add a Pallet
            • Add Offchasin Workers
            • Publish Custom Pallets
            • Specify Origin for a Call
            • Use Macros in a Custom Pallet
          • Integrate with Tools
            • Access EVM Accounts
            • EVM Integration
            • Explore Sidecar Endpoints
            • Integrate a Light Client Node
          • Smart Contracts
            • Strategy
            • Build a Token Contract
            • Develop a Smart Contract
            • Prepare Your First Contract
            • Troubleshoot Smart Contracts
            • Use Maps for Storing Values
      • XCM
        • XCM
        • XCM Format
    • Service Chains
      • InfraDID
      • InfraEVM
      • URAuth(Universal Resource Auth)
    • DevOps
      • Build
      • Deploy
      • Monitoring
      • Runtime Upgrade
    • Tutorials
      • Basic
        • How to Interact with System Token
        • How To Pay Transaction Fee
        • How To Vote with TaaV
        • Hot to Get Validator Reward
      • Build
        • Build InfraRelayChain
        • Build Parachain
        • Open Message Passing Channels
        • Transfer Assets with XCM
      • Test
        • Benchmark
        • Check Runtime
        • Debug
        • Simulate Parachains
        • Unit Testing
      • Service Chains
        • Play with InfraDID
          • Build
          • Add Keys
          • Add Service Endpoint
          • Create InfraDID
        • Play with InfraEVM
          • Build
          • Deposit and Withdraw Token
          • Deploy ERC20 Contract
          • Deploy ERC721 Contract
          • Deploy ERC1155 Contract
  • Newnal Data Market
Powered by GitBook
On this page
  • Rust in Substrate
  • Compilation target
  • Macros
  • Generics and configuration traits
  • Where to go next
  1. InfraBlockchain
  2. Learn
  3. Substrate
  4. Learn
  5. Basic

Rust for Substrate

Highlights the Rust programming conventions that are of particular importance when developing a Substrate blockchain.

PreviousLight ClientNextIntroduction to Library

Last updated 1 year ago

Much of what makes Substrate a flexible and extensible framework for creating mission-critical software is owed to . Being the language of choice for Substrate, Rust is a highly performant programming language and a first choice for the following reasons:

  • Rust is fast: it's statically typed at compile time, making it possible for the compiler to optimize the code for speed and for developers to optimize for a specific compilation target.

  • Rust is portable: it's designed to run on embedded devices with support for any type of operating system.

  • Rust is memory safe: it has no garbage collector and it checks each and every variable you use and every memory address you reference to avoid any memory leaks.

  • Rust is Wasm first: it has first class support for compiling to WebAssembly.

Rust in Substrate

In the section, you will learn that Substrate is made of two distinct architectural components: the outer node and the runtime. While more complex features in Rust such as multithreading and asynchronous Rust are used in the outer node code, they aren't directly exposed to runtime engineers, making it easier for runtime engineers to focus on the business logic of their node.

Generally, depending on their focus, developers should expect to know:

  • Basic , and what macros are used and why (for runtime engineering).

  • (for more advanced developers working with outer node (client) code).

Although general familiarity with Rust is essential before diving into Substrate—and there are many resources available for learning Rust, including the and —the remainder of this section highlights ways Substrate uses some of Rust's core features for developers getting started with runtime engineering.

Compilation target

When building a Substrate node, we use the wasm32-unknown-unknown compilation target which means that Substrate runtime engineers are constrained to writing runtimes that must compile to Wasm. This implies that you can't rely on some typical standard library types and functions and must only use no_std compatible crates for the majority of runtime code. Substrate has a lot of its of own primitive types and associated traits that make it possible to work around the no_std requirement.

Macros

As you learn how to use and write FRAME pallets, you'll see there are many macros available as reusable code to abstract common tasks or enforce runtime-specific requirements. These macros allow you to focus on writing idiomatic Rust and application-specific logic instead of the common code required to interact with a runtime.

Rust macros are a powerful tool to help ensure certain requirements are met (without re-writing code) such as the logic to be formatted in a specific way, specific checks are made, or some logic consists of specific data structures. This is especially useful to help developers write code that can integrate with the complexity of a Substrate runtime. For example, the #[frame_system::pallet] macro is required in all FRAME pallets to help you correctly implement certain required attributes-such as storage items or externally callable functions-and make it compatible with the build process in construct_runtime.

Developing Substrate runtimes involves heavy use of Rust's attribute macros, which come in two flavors: derive attributes and custom attributes. When you're getting started with Substrate, it isn't so important to know exactly how they work, but rather to know that they exist that they empower you to write correct runtime code.

Derive attributes are useful for custom runtime types that need to satisfy certain traits, for instance, to have types be decodable by a node during runtime execution.

Other attribute like macros are also common throughout Substrate's codebase for:

  • Specifying whether a code snippet only compiles to no_std or can use the std library.

  • Building custom FRAME pallets.

  • Specifying the way the runtime is built.

Generics and configuration traits

Often compared to interfaces in languages like Java, traits in Rust provide ways to give advanced functionality to a type.

If you've read about pallets, you've probably noticed that every pallet has a Config trait which allows you to define the types and interfaces a pallet depends on.

This trait itself inherits a number of core runtime types from the frame_system::pallet::Config trait, making it easy to access common types when writing runtime logic. In addition, in any FRAME pallet the Config trait is generic over T (more on generics in the next section). Some common examples of these core runtime types could be T::AccountId, the common type for identifying user accounts in the runtime or T::BlockNumber, the block number type used by the runtime.

With Rust generics, Substrate runtime developers can write pallets that are completely agnostic to specific implementation details and therefore make full use of Substrate's flexibility, extensibility and modularity.

All types in the Config trait are defined generically using trait bounds and made concrete in the runtime implementation. This not only means that you can write pallets that support different specifications for the same type (e.g. addresses for both Substrate and Ethereum chains), but you can also customize generic implementations to your needs with minimal overhead (e.g. change block number to u32).

This gives developers the flexibility of writing code that makes no assumptions about the core blockchain architecture decisions you have made.

Substrate maximizes the use of generic types to provide maximum flexibility. You define how the generic types are resolved to suit your purpose.

Where to go next

Now that you know how Substrate relies on a few key Rust features—like traits, generic types, and macros—you can explore the following resources to learn more.

For more information about generic types and traits in Rust, see the sections on , and from the Rust book.

For more information about generic types and traits in Rust, see the sections on from the Rust book.

(blog by Parity)

(ink! documentation)

Rust
Architecture
Rust idioms
working with no_std
Asynchronous Rust
Rust Language Programming Book
Rust by Example
Generic Types
Traits
Advanced traits
Generic Types
Rust book
Why Rust?
Cargo and crates.io
Why Rust for smart contracts?