diff --git a/.ai/categories/basics.md b/.ai/categories/basics.md index 22ff34846..95a840c58 100644 --- a/.ai/categories/basics.md +++ b/.ai/categories/basics.md @@ -3188,6 +3188,109 @@ Your deployed contract will appear in the **Deployed Contracts** section, ready +--- + +Page Title: Dual Virtual Machine Stack + +- Source (raw): https://raw.githubusercontent.com/polkadot-developers/polkadot-docs/master/.ai/pages/smart-contracts-for-eth-devs-dual-vm-stack.md +- Canonical (HTML): https://docs.polkadot.com/smart-contracts/for-eth-devs/dual-vm-stack/ +- Summary: Compare Polkadot’s dual smart contract VMs—REVM for EVM compatibility and PolkaVM for RISC-V performance, flexibility, and efficiency. + +# Dual Virtual Machine Stack + +!!! smartcontract "PolkaVM Preview Release" + PolkaVM smart contracts with Ethereum compatibility are in **early-stage development and may be unstable or incomplete**. +## Introduction + +Polkadot's smart contract platform supports two distinct virtual machine (VM) architectures, providing developers with flexibility in selecting the optimal execution backend for their specific needs. This approach strikes a balance between immediate Ethereum compatibility and long-term innovation, enabling developers to deploy either unmodified (Ethereum Virtual Machine) EVM contracts using Rust Ethereum Virtual Machine (REVM) or optimize for higher performance using PolkaVM (PVM). + +Both VM options share common infrastructure, including RPC interfaces, tooling support, and precompiles. The following sections compare architectures and guide you in selecting the best VM for your project's needs. + +## Migrate from EVM + +The [REVM backend](https://github.com/bluealloy/revm){target=\_blank} integrates a complete Rust implementation of the EVM, enabling Solidity contracts to run unchanged on Polkadot's smart contract platform. + +REVM allows developers to use their existing Ethereum tooling and infrastructure to build on Polkadot. Choose REVM to: + +- Migrate existing Ethereum contracts without modifications. +- Retain exact EVM behavior for audit tools. +- Use developer tools that rely upon inspecting EVM bytecode. +- Prioritize rapid deployment over optimization. +- Work with established Ethereum infrastructure and tooling to build on Polkadot. + +REVM enables Ethereum developers to seamlessly migrate to Polkadot, achieving performance and fee improvements without modifying their existing contracts or developer tooling stack. + +## Upgrade to PolkaVM + +[**PolkaVM**](https://github.com/paritytech/polkavm){target=\_blank} is a custom virtual machine optimized for performance with [RISC-V-based](https://en.wikipedia.org/wiki/RISC-V){target=\_blank} architecture, supporting Solidity and additional high-performance languages. It serves as the core execution environment, integrated directly within the runtime. Choose the PolkaVM for: + +- An efficient interpreter for immediate code execution. +- A planned [Just In Time (JIT)](https://en.wikipedia.org/wiki/Just-in-time_compilation){target=\_blank} compiler for optimized performance. +- Dual-mode execution capability, allowing selection of the most appropriate backend for specific workloads. +- Optimized performance for short-running contract calls through the interpreter. + +The interpreter remains particularly beneficial for contracts with minimal code execution, as it enables immediate code execution through lazy interpretation. + +## Architecture + +The following key components of PolkaVM work together to enable Ethereum compatibility on Polkadot-based chains. + +### Revive Pallet + +[**`pallet_revive`**](https://paritytech.github.io/polkadot-sdk/master/pallet_revive/index.html){target=\_blank} is a runtime module that executes smart contracts by adding extrinsics, runtime APIs, and logic to convert Ethereum-style transactions into formats compatible with Polkadot SDK-based blockchains. It processes Ethereum-style transactions through the following workflow: + +```mermaid +sequenceDiagram + participant User as User/dApp + participant Proxy as Ethereum JSON RPC Proxy + participant Chain as Blockchain Node + participant Pallet as pallet_revive + + User->>Proxy: Submit Ethereum Transaction + Proxy->>Chain: Repackage as Polkadot Compatible Transaction + Chain->>Pallet: Process Transaction + Pallet->>Pallet: Decode Ethereum Transaction + Pallet->>Pallet: Execute Contract via PolkaVM + Pallet->>Chain: Return Results + Chain->>Proxy: Forward Results + Proxy->>User: Return Ethereum-compatible Response +``` + +This proxy-based approach eliminates the need for node binary modifications, maintaining compatibility across different client implementations. Preserving the original Ethereum transaction payload simplifies the adaptation of existing tools, which can continue processing familiar transaction formats. + +### PolkaVM Design Fundamentals + +PolkaVM differs from the EVM in two key ways that make it faster, more hardware-efficient, and easier to extend: + +- **Register-based design**: Instead of a stack machine, PolkaVM uses a RISC-V–style register model. This design: + + - Uses a fixed set of registers to pass arguments, not an infinite stack. + - Maps cleanly to real hardware like x86-64. + - Simplifies compilation and boosts runtime efficiency. + - Enables tighter control over register allocation and performance tuning. + +- **64-bit word size**: PolkaVM runs on a native 64-bit word size, aligning directly with modern CPUs. This design: + + - Executes arithmetic operations with direct hardware support. + - Maintains compatibility with Solidity’s 256-bit types via YUL translation. + - Accelerates computation-heavy workloads through native word alignment. + - Integrates easily with low-level, performance-focused components. + +## Where To Go Next + +
+ +- Learn __Contract Deployment__ + + --- + + Learn how REVM and PVM compare for compiling and deploying smart contracts. + + [:octicons-arrow-right-24: Reference](/smart-contracts/for-eth-devs/contract-deployment/) + +
+ + --- Page Title: EVM vs PolkaVM @@ -6552,121 +6655,6 @@ Support for encoding and decoding Polkadot SDK SS58 addresses has been implement - **TypeScript**: [`subsquid/squid-sdk`](https://github.com/subsquid/squid-sdk){target=\_blank} ---- - -Page Title: PolkaVM Design - -- Source (raw): https://raw.githubusercontent.com/polkadot-developers/polkadot-docs/master/.ai/pages/smart-contracts-for-eth-devs-dual-vm-stack.md -- Canonical (HTML): https://docs.polkadot.com/smart-contracts/for-eth-devs/dual-vm-stack/ -- Summary: Discover PolkaVM, a high-performance smart contract VM for Polkadot, enabling Ethereum compatibility via pallet_revive, Solidity support & optimized execution. - -# PolkaVM Design - -!!! smartcontract "PolkaVM Preview Release" - PolkaVM smart contracts with Ethereum compatibility are in **early-stage development and may be unstable or incomplete**. -## Introduction - -The Asset Hub smart contracts solution includes multiple components to ensure Ethereum compatibility and high performance. Its architecture allows for integration with current Ethereum tools, while its innovative virtual machine design enhances performance characteristics. - -## PolkaVM - -[**PolkaVM**](https://github.com/paritytech/polkavm){target=\_blank} is a custom virtual machine optimized for performance with [RISC-V-based](https://en.wikipedia.org/wiki/RISC-V){target=\_blank} architecture, supporting Solidity and additional high-performance languages. It serves as the core execution environment, integrated directly within the runtime. It features: - -- An efficient interpreter for immediate code execution. -- A planned JIT compiler for optimized performance. -- Dual-mode execution capability, allowing selection of the most appropriate backend for specific workloads. -- Optimized performance for short-running contract calls through the interpreter. - -The interpreter remains particularly beneficial for contracts with minimal code execution, as it eliminates JIT compilation overhead and enables immediate code execution through lazy interpretation. - -## Architecture - -The smart contract solution consists of the following key components that work together to enable Ethereum compatibility on Polkadot-based chains. - -### Pallet Revive - -[**`pallet_revive`**](https://paritytech.github.io/polkadot-sdk/master/pallet_revive/index.html){target=\_blank} is a runtime module that executes smart contracts by adding extrinsics, runtime APIs, and logic to convert Ethereum-style transactions into formats compatible with Polkadot SDK-based blockchains. It processes Ethereum-style transactions through the following workflow: - -```mermaid -sequenceDiagram - participant User as User/dApp - participant Proxy as Ethereum JSON RPC Proxy - participant Chain as Blockchain Node - participant Pallet as pallet_revive - - User->>Proxy: Submit Ethereum Transaction - Proxy->>Chain: Repackage as Polkadot Compatible Transaction - Chain->>Pallet: Process Transaction - Pallet->>Pallet: Decode Ethereum Transaction - Pallet->>Pallet: Execute Contract via PolkaVM - Pallet->>Chain: Return Results - Chain->>Proxy: Forward Results - Proxy->>User: Return Ethereum-compatible Response -``` - -This proxy-based approach eliminates the need for node binary modifications, maintaining compatibility across different client implementations. Preserving the original Ethereum transaction payload simplifies adapting existing tools, which can continue processing familiar transaction formats. - -### PolkaVM Design Fundamentals - -PolkaVM introduces two fundamental architectural differences compared to the Ethereum Virtual Machine (EVM): - -```mermaid -flowchart TB - subgraph "EVM Architecture" - EVMStack[Stack-Based] - EVM256[256-bit Word Size] - end - - subgraph "PolkaVM Architecture" - PVMReg[Register-Based] - PVM64[64-bit Word Size] - end -``` - -- **Register-based design**: PolkaVM utilizes a RISC-V register-based approach. This design: - - - Employs a finite set of registers for argument passing instead of an infinite stack. - - Facilitates efficient translation to underlying hardware architectures. - - Optimizes register allocation through careful register count selection. - - Enables simple 1:1 mapping to x86-64 instruction sets. - - Reduces compilation complexity through strategic register limitation. - - Improves overall execution performance through hardware-aligned design. - -- **64-bit word size**: PolkaVM operates with a 64-bit word size. This design: - - - Enables direct hardware-supported arithmetic operations. - - Maintains compatibility with Solidity's 256-bit operations through YUL translation. - - Allows integration of performance-critical components written in lower-level languages. - - Optimizes computation-intensive operations through native word size alignment. - - Reduces overhead for operations not requiring extended precision. - - Facilitates efficient integration with modern CPU architectures. - -## Compilation Process - -When compiling a Solidity smart contract, the code passes through the following stages: - -```mermaid -flowchart LR - Dev[Developer] --> |Solidity
Source
Code| Solc - - subgraph "Compilation Process" - direction LR - Solc[solc] --> |YUL
IR| Revive - Revive[Revive Compiler] --> |LLVM
IR| LLVM - LLVM[LLVM
Optimizer] --> |RISC-V ELF
Shared Object| PVMLinker - end - - PVMLinker[PVM Linker] --> PVM[PVM Blob
with Metadata] -``` - -The compilation process integrates several specialized components: - -1. **Solc**: The standard Ethereum Solidity compiler that translates Solidity source code to [YUL IR](https://docs.soliditylang.org/en/latest/yul.html){target=\_blank}. -2. **Revive Compiler**: Takes YUL IR and transforms it to [LLVM IR](https://llvm.org/){target=\_blank}. -3. **LLVM**: A compiler infrastructure that optimizes the code and generates RISC-V ELF objects. -4. **PVM linker**: Links the RISC-V ELF object into a final PolkaVM blob with metadata. - - --- Page Title: Randomness diff --git a/.ai/categories/dapps.md b/.ai/categories/dapps.md index 2892f77a4..9d2d80162 100644 --- a/.ai/categories/dapps.md +++ b/.ai/categories/dapps.md @@ -4052,6 +4052,109 @@ To build on this foundation, you could extend this project by implementing funct This knowledge can be leveraged to build more complex DeFi applications or to integrate Uniswap V2 functionality into your existing projects on Polkadot. +--- + +Page Title: Dual Virtual Machine Stack + +- Source (raw): https://raw.githubusercontent.com/polkadot-developers/polkadot-docs/master/.ai/pages/smart-contracts-for-eth-devs-dual-vm-stack.md +- Canonical (HTML): https://docs.polkadot.com/smart-contracts/for-eth-devs/dual-vm-stack/ +- Summary: Compare Polkadot’s dual smart contract VMs—REVM for EVM compatibility and PolkaVM for RISC-V performance, flexibility, and efficiency. + +# Dual Virtual Machine Stack + +!!! smartcontract "PolkaVM Preview Release" + PolkaVM smart contracts with Ethereum compatibility are in **early-stage development and may be unstable or incomplete**. +## Introduction + +Polkadot's smart contract platform supports two distinct virtual machine (VM) architectures, providing developers with flexibility in selecting the optimal execution backend for their specific needs. This approach strikes a balance between immediate Ethereum compatibility and long-term innovation, enabling developers to deploy either unmodified (Ethereum Virtual Machine) EVM contracts using Rust Ethereum Virtual Machine (REVM) or optimize for higher performance using PolkaVM (PVM). + +Both VM options share common infrastructure, including RPC interfaces, tooling support, and precompiles. The following sections compare architectures and guide you in selecting the best VM for your project's needs. + +## Migrate from EVM + +The [REVM backend](https://github.com/bluealloy/revm){target=\_blank} integrates a complete Rust implementation of the EVM, enabling Solidity contracts to run unchanged on Polkadot's smart contract platform. + +REVM allows developers to use their existing Ethereum tooling and infrastructure to build on Polkadot. Choose REVM to: + +- Migrate existing Ethereum contracts without modifications. +- Retain exact EVM behavior for audit tools. +- Use developer tools that rely upon inspecting EVM bytecode. +- Prioritize rapid deployment over optimization. +- Work with established Ethereum infrastructure and tooling to build on Polkadot. + +REVM enables Ethereum developers to seamlessly migrate to Polkadot, achieving performance and fee improvements without modifying their existing contracts or developer tooling stack. + +## Upgrade to PolkaVM + +[**PolkaVM**](https://github.com/paritytech/polkavm){target=\_blank} is a custom virtual machine optimized for performance with [RISC-V-based](https://en.wikipedia.org/wiki/RISC-V){target=\_blank} architecture, supporting Solidity and additional high-performance languages. It serves as the core execution environment, integrated directly within the runtime. Choose the PolkaVM for: + +- An efficient interpreter for immediate code execution. +- A planned [Just In Time (JIT)](https://en.wikipedia.org/wiki/Just-in-time_compilation){target=\_blank} compiler for optimized performance. +- Dual-mode execution capability, allowing selection of the most appropriate backend for specific workloads. +- Optimized performance for short-running contract calls through the interpreter. + +The interpreter remains particularly beneficial for contracts with minimal code execution, as it enables immediate code execution through lazy interpretation. + +## Architecture + +The following key components of PolkaVM work together to enable Ethereum compatibility on Polkadot-based chains. + +### Revive Pallet + +[**`pallet_revive`**](https://paritytech.github.io/polkadot-sdk/master/pallet_revive/index.html){target=\_blank} is a runtime module that executes smart contracts by adding extrinsics, runtime APIs, and logic to convert Ethereum-style transactions into formats compatible with Polkadot SDK-based blockchains. It processes Ethereum-style transactions through the following workflow: + +```mermaid +sequenceDiagram + participant User as User/dApp + participant Proxy as Ethereum JSON RPC Proxy + participant Chain as Blockchain Node + participant Pallet as pallet_revive + + User->>Proxy: Submit Ethereum Transaction + Proxy->>Chain: Repackage as Polkadot Compatible Transaction + Chain->>Pallet: Process Transaction + Pallet->>Pallet: Decode Ethereum Transaction + Pallet->>Pallet: Execute Contract via PolkaVM + Pallet->>Chain: Return Results + Chain->>Proxy: Forward Results + Proxy->>User: Return Ethereum-compatible Response +``` + +This proxy-based approach eliminates the need for node binary modifications, maintaining compatibility across different client implementations. Preserving the original Ethereum transaction payload simplifies the adaptation of existing tools, which can continue processing familiar transaction formats. + +### PolkaVM Design Fundamentals + +PolkaVM differs from the EVM in two key ways that make it faster, more hardware-efficient, and easier to extend: + +- **Register-based design**: Instead of a stack machine, PolkaVM uses a RISC-V–style register model. This design: + + - Uses a fixed set of registers to pass arguments, not an infinite stack. + - Maps cleanly to real hardware like x86-64. + - Simplifies compilation and boosts runtime efficiency. + - Enables tighter control over register allocation and performance tuning. + +- **64-bit word size**: PolkaVM runs on a native 64-bit word size, aligning directly with modern CPUs. This design: + + - Executes arithmetic operations with direct hardware support. + - Maintains compatibility with Solidity’s 256-bit types via YUL translation. + - Accelerates computation-heavy workloads through native word alignment. + - Integrates easily with low-level, performance-focused components. + +## Where To Go Next + +
+ +- Learn __Contract Deployment__ + + --- + + Learn how REVM and PVM compare for compiling and deploying smart contracts. + + [:octicons-arrow-right-24: Reference](/smart-contracts/for-eth-devs/contract-deployment/) + +
+ + --- Page Title: EVM vs PolkaVM @@ -9292,121 +9395,6 @@ The `alice` keypair in the example comes from a `Keyring` object. For more detai For more detailed information about the Polkadot.js API, check the [official documentation](https://polkadot.js.org/docs/){target=\_blank}. ---- - -Page Title: PolkaVM Design - -- Source (raw): https://raw.githubusercontent.com/polkadot-developers/polkadot-docs/master/.ai/pages/smart-contracts-for-eth-devs-dual-vm-stack.md -- Canonical (HTML): https://docs.polkadot.com/smart-contracts/for-eth-devs/dual-vm-stack/ -- Summary: Discover PolkaVM, a high-performance smart contract VM for Polkadot, enabling Ethereum compatibility via pallet_revive, Solidity support & optimized execution. - -# PolkaVM Design - -!!! smartcontract "PolkaVM Preview Release" - PolkaVM smart contracts with Ethereum compatibility are in **early-stage development and may be unstable or incomplete**. -## Introduction - -The Asset Hub smart contracts solution includes multiple components to ensure Ethereum compatibility and high performance. Its architecture allows for integration with current Ethereum tools, while its innovative virtual machine design enhances performance characteristics. - -## PolkaVM - -[**PolkaVM**](https://github.com/paritytech/polkavm){target=\_blank} is a custom virtual machine optimized for performance with [RISC-V-based](https://en.wikipedia.org/wiki/RISC-V){target=\_blank} architecture, supporting Solidity and additional high-performance languages. It serves as the core execution environment, integrated directly within the runtime. It features: - -- An efficient interpreter for immediate code execution. -- A planned JIT compiler for optimized performance. -- Dual-mode execution capability, allowing selection of the most appropriate backend for specific workloads. -- Optimized performance for short-running contract calls through the interpreter. - -The interpreter remains particularly beneficial for contracts with minimal code execution, as it eliminates JIT compilation overhead and enables immediate code execution through lazy interpretation. - -## Architecture - -The smart contract solution consists of the following key components that work together to enable Ethereum compatibility on Polkadot-based chains. - -### Pallet Revive - -[**`pallet_revive`**](https://paritytech.github.io/polkadot-sdk/master/pallet_revive/index.html){target=\_blank} is a runtime module that executes smart contracts by adding extrinsics, runtime APIs, and logic to convert Ethereum-style transactions into formats compatible with Polkadot SDK-based blockchains. It processes Ethereum-style transactions through the following workflow: - -```mermaid -sequenceDiagram - participant User as User/dApp - participant Proxy as Ethereum JSON RPC Proxy - participant Chain as Blockchain Node - participant Pallet as pallet_revive - - User->>Proxy: Submit Ethereum Transaction - Proxy->>Chain: Repackage as Polkadot Compatible Transaction - Chain->>Pallet: Process Transaction - Pallet->>Pallet: Decode Ethereum Transaction - Pallet->>Pallet: Execute Contract via PolkaVM - Pallet->>Chain: Return Results - Chain->>Proxy: Forward Results - Proxy->>User: Return Ethereum-compatible Response -``` - -This proxy-based approach eliminates the need for node binary modifications, maintaining compatibility across different client implementations. Preserving the original Ethereum transaction payload simplifies adapting existing tools, which can continue processing familiar transaction formats. - -### PolkaVM Design Fundamentals - -PolkaVM introduces two fundamental architectural differences compared to the Ethereum Virtual Machine (EVM): - -```mermaid -flowchart TB - subgraph "EVM Architecture" - EVMStack[Stack-Based] - EVM256[256-bit Word Size] - end - - subgraph "PolkaVM Architecture" - PVMReg[Register-Based] - PVM64[64-bit Word Size] - end -``` - -- **Register-based design**: PolkaVM utilizes a RISC-V register-based approach. This design: - - - Employs a finite set of registers for argument passing instead of an infinite stack. - - Facilitates efficient translation to underlying hardware architectures. - - Optimizes register allocation through careful register count selection. - - Enables simple 1:1 mapping to x86-64 instruction sets. - - Reduces compilation complexity through strategic register limitation. - - Improves overall execution performance through hardware-aligned design. - -- **64-bit word size**: PolkaVM operates with a 64-bit word size. This design: - - - Enables direct hardware-supported arithmetic operations. - - Maintains compatibility with Solidity's 256-bit operations through YUL translation. - - Allows integration of performance-critical components written in lower-level languages. - - Optimizes computation-intensive operations through native word size alignment. - - Reduces overhead for operations not requiring extended precision. - - Facilitates efficient integration with modern CPU architectures. - -## Compilation Process - -When compiling a Solidity smart contract, the code passes through the following stages: - -```mermaid -flowchart LR - Dev[Developer] --> |Solidity
Source
Code| Solc - - subgraph "Compilation Process" - direction LR - Solc[solc] --> |YUL
IR| Revive - Revive[Revive Compiler] --> |LLVM
IR| LLVM - LLVM[LLVM
Optimizer] --> |RISC-V ELF
Shared Object| PVMLinker - end - - PVMLinker[PVM Linker] --> PVM[PVM Blob
with Metadata] -``` - -The compilation process integrates several specialized components: - -1. **Solc**: The standard Ethereum Solidity compiler that translates Solidity source code to [YUL IR](https://docs.soliditylang.org/en/latest/yul.html){target=\_blank}. -2. **Revive Compiler**: Takes YUL IR and transforms it to [LLVM IR](https://llvm.org/){target=\_blank}. -3. **LLVM**: A compiler infrastructure that optimizes the code and generates RISC-V ELF objects. -4. **PVM linker**: Links the RISC-V ELF object into a final PolkaVM blob with metadata. - - --- Page Title: Python Substrate Interface diff --git a/.ai/categories/infrastructure.md b/.ai/categories/infrastructure.md index 1c8bca8a0..05dd80a97 100644 --- a/.ai/categories/infrastructure.md +++ b/.ai/categories/infrastructure.md @@ -3189,6 +3189,109 @@ Your deployed contract will appear in the **Deployed Contracts** section, ready +--- + +Page Title: Dual Virtual Machine Stack + +- Source (raw): https://raw.githubusercontent.com/polkadot-developers/polkadot-docs/master/.ai/pages/smart-contracts-for-eth-devs-dual-vm-stack.md +- Canonical (HTML): https://docs.polkadot.com/smart-contracts/for-eth-devs/dual-vm-stack/ +- Summary: Compare Polkadot’s dual smart contract VMs—REVM for EVM compatibility and PolkaVM for RISC-V performance, flexibility, and efficiency. + +# Dual Virtual Machine Stack + +!!! smartcontract "PolkaVM Preview Release" + PolkaVM smart contracts with Ethereum compatibility are in **early-stage development and may be unstable or incomplete**. +## Introduction + +Polkadot's smart contract platform supports two distinct virtual machine (VM) architectures, providing developers with flexibility in selecting the optimal execution backend for their specific needs. This approach strikes a balance between immediate Ethereum compatibility and long-term innovation, enabling developers to deploy either unmodified (Ethereum Virtual Machine) EVM contracts using Rust Ethereum Virtual Machine (REVM) or optimize for higher performance using PolkaVM (PVM). + +Both VM options share common infrastructure, including RPC interfaces, tooling support, and precompiles. The following sections compare architectures and guide you in selecting the best VM for your project's needs. + +## Migrate from EVM + +The [REVM backend](https://github.com/bluealloy/revm){target=\_blank} integrates a complete Rust implementation of the EVM, enabling Solidity contracts to run unchanged on Polkadot's smart contract platform. + +REVM allows developers to use their existing Ethereum tooling and infrastructure to build on Polkadot. Choose REVM to: + +- Migrate existing Ethereum contracts without modifications. +- Retain exact EVM behavior for audit tools. +- Use developer tools that rely upon inspecting EVM bytecode. +- Prioritize rapid deployment over optimization. +- Work with established Ethereum infrastructure and tooling to build on Polkadot. + +REVM enables Ethereum developers to seamlessly migrate to Polkadot, achieving performance and fee improvements without modifying their existing contracts or developer tooling stack. + +## Upgrade to PolkaVM + +[**PolkaVM**](https://github.com/paritytech/polkavm){target=\_blank} is a custom virtual machine optimized for performance with [RISC-V-based](https://en.wikipedia.org/wiki/RISC-V){target=\_blank} architecture, supporting Solidity and additional high-performance languages. It serves as the core execution environment, integrated directly within the runtime. Choose the PolkaVM for: + +- An efficient interpreter for immediate code execution. +- A planned [Just In Time (JIT)](https://en.wikipedia.org/wiki/Just-in-time_compilation){target=\_blank} compiler for optimized performance. +- Dual-mode execution capability, allowing selection of the most appropriate backend for specific workloads. +- Optimized performance for short-running contract calls through the interpreter. + +The interpreter remains particularly beneficial for contracts with minimal code execution, as it enables immediate code execution through lazy interpretation. + +## Architecture + +The following key components of PolkaVM work together to enable Ethereum compatibility on Polkadot-based chains. + +### Revive Pallet + +[**`pallet_revive`**](https://paritytech.github.io/polkadot-sdk/master/pallet_revive/index.html){target=\_blank} is a runtime module that executes smart contracts by adding extrinsics, runtime APIs, and logic to convert Ethereum-style transactions into formats compatible with Polkadot SDK-based blockchains. It processes Ethereum-style transactions through the following workflow: + +```mermaid +sequenceDiagram + participant User as User/dApp + participant Proxy as Ethereum JSON RPC Proxy + participant Chain as Blockchain Node + participant Pallet as pallet_revive + + User->>Proxy: Submit Ethereum Transaction + Proxy->>Chain: Repackage as Polkadot Compatible Transaction + Chain->>Pallet: Process Transaction + Pallet->>Pallet: Decode Ethereum Transaction + Pallet->>Pallet: Execute Contract via PolkaVM + Pallet->>Chain: Return Results + Chain->>Proxy: Forward Results + Proxy->>User: Return Ethereum-compatible Response +``` + +This proxy-based approach eliminates the need for node binary modifications, maintaining compatibility across different client implementations. Preserving the original Ethereum transaction payload simplifies the adaptation of existing tools, which can continue processing familiar transaction formats. + +### PolkaVM Design Fundamentals + +PolkaVM differs from the EVM in two key ways that make it faster, more hardware-efficient, and easier to extend: + +- **Register-based design**: Instead of a stack machine, PolkaVM uses a RISC-V–style register model. This design: + + - Uses a fixed set of registers to pass arguments, not an infinite stack. + - Maps cleanly to real hardware like x86-64. + - Simplifies compilation and boosts runtime efficiency. + - Enables tighter control over register allocation and performance tuning. + +- **64-bit word size**: PolkaVM runs on a native 64-bit word size, aligning directly with modern CPUs. This design: + + - Executes arithmetic operations with direct hardware support. + - Maintains compatibility with Solidity’s 256-bit types via YUL translation. + - Accelerates computation-heavy workloads through native word alignment. + - Integrates easily with low-level, performance-focused components. + +## Where To Go Next + +
+ +- Learn __Contract Deployment__ + + --- + + Learn how REVM and PVM compare for compiling and deploying smart contracts. + + [:octicons-arrow-right-24: Reference](/smart-contracts/for-eth-devs/contract-deployment/) + +
+ + --- Page Title: EVM vs PolkaVM @@ -8740,121 +8843,6 @@ Support for encoding and decoding Polkadot SDK SS58 addresses has been implement - **TypeScript**: [`subsquid/squid-sdk`](https://github.com/subsquid/squid-sdk){target=\_blank} ---- - -Page Title: PolkaVM Design - -- Source (raw): https://raw.githubusercontent.com/polkadot-developers/polkadot-docs/master/.ai/pages/smart-contracts-for-eth-devs-dual-vm-stack.md -- Canonical (HTML): https://docs.polkadot.com/smart-contracts/for-eth-devs/dual-vm-stack/ -- Summary: Discover PolkaVM, a high-performance smart contract VM for Polkadot, enabling Ethereum compatibility via pallet_revive, Solidity support & optimized execution. - -# PolkaVM Design - -!!! smartcontract "PolkaVM Preview Release" - PolkaVM smart contracts with Ethereum compatibility are in **early-stage development and may be unstable or incomplete**. -## Introduction - -The Asset Hub smart contracts solution includes multiple components to ensure Ethereum compatibility and high performance. Its architecture allows for integration with current Ethereum tools, while its innovative virtual machine design enhances performance characteristics. - -## PolkaVM - -[**PolkaVM**](https://github.com/paritytech/polkavm){target=\_blank} is a custom virtual machine optimized for performance with [RISC-V-based](https://en.wikipedia.org/wiki/RISC-V){target=\_blank} architecture, supporting Solidity and additional high-performance languages. It serves as the core execution environment, integrated directly within the runtime. It features: - -- An efficient interpreter for immediate code execution. -- A planned JIT compiler for optimized performance. -- Dual-mode execution capability, allowing selection of the most appropriate backend for specific workloads. -- Optimized performance for short-running contract calls through the interpreter. - -The interpreter remains particularly beneficial for contracts with minimal code execution, as it eliminates JIT compilation overhead and enables immediate code execution through lazy interpretation. - -## Architecture - -The smart contract solution consists of the following key components that work together to enable Ethereum compatibility on Polkadot-based chains. - -### Pallet Revive - -[**`pallet_revive`**](https://paritytech.github.io/polkadot-sdk/master/pallet_revive/index.html){target=\_blank} is a runtime module that executes smart contracts by adding extrinsics, runtime APIs, and logic to convert Ethereum-style transactions into formats compatible with Polkadot SDK-based blockchains. It processes Ethereum-style transactions through the following workflow: - -```mermaid -sequenceDiagram - participant User as User/dApp - participant Proxy as Ethereum JSON RPC Proxy - participant Chain as Blockchain Node - participant Pallet as pallet_revive - - User->>Proxy: Submit Ethereum Transaction - Proxy->>Chain: Repackage as Polkadot Compatible Transaction - Chain->>Pallet: Process Transaction - Pallet->>Pallet: Decode Ethereum Transaction - Pallet->>Pallet: Execute Contract via PolkaVM - Pallet->>Chain: Return Results - Chain->>Proxy: Forward Results - Proxy->>User: Return Ethereum-compatible Response -``` - -This proxy-based approach eliminates the need for node binary modifications, maintaining compatibility across different client implementations. Preserving the original Ethereum transaction payload simplifies adapting existing tools, which can continue processing familiar transaction formats. - -### PolkaVM Design Fundamentals - -PolkaVM introduces two fundamental architectural differences compared to the Ethereum Virtual Machine (EVM): - -```mermaid -flowchart TB - subgraph "EVM Architecture" - EVMStack[Stack-Based] - EVM256[256-bit Word Size] - end - - subgraph "PolkaVM Architecture" - PVMReg[Register-Based] - PVM64[64-bit Word Size] - end -``` - -- **Register-based design**: PolkaVM utilizes a RISC-V register-based approach. This design: - - - Employs a finite set of registers for argument passing instead of an infinite stack. - - Facilitates efficient translation to underlying hardware architectures. - - Optimizes register allocation through careful register count selection. - - Enables simple 1:1 mapping to x86-64 instruction sets. - - Reduces compilation complexity through strategic register limitation. - - Improves overall execution performance through hardware-aligned design. - -- **64-bit word size**: PolkaVM operates with a 64-bit word size. This design: - - - Enables direct hardware-supported arithmetic operations. - - Maintains compatibility with Solidity's 256-bit operations through YUL translation. - - Allows integration of performance-critical components written in lower-level languages. - - Optimizes computation-intensive operations through native word size alignment. - - Reduces overhead for operations not requiring extended precision. - - Facilitates efficient integration with modern CPU architectures. - -## Compilation Process - -When compiling a Solidity smart contract, the code passes through the following stages: - -```mermaid -flowchart LR - Dev[Developer] --> |Solidity
Source
Code| Solc - - subgraph "Compilation Process" - direction LR - Solc[solc] --> |YUL
IR| Revive - Revive[Revive Compiler] --> |LLVM
IR| LLVM - LLVM[LLVM
Optimizer] --> |RISC-V ELF
Shared Object| PVMLinker - end - - PVMLinker[PVM Linker] --> PVM[PVM Blob
with Metadata] -``` - -The compilation process integrates several specialized components: - -1. **Solc**: The standard Ethereum Solidity compiler that translates Solidity source code to [YUL IR](https://docs.soliditylang.org/en/latest/yul.html){target=\_blank}. -2. **Revive Compiler**: Takes YUL IR and transforms it to [LLVM IR](https://llvm.org/){target=\_blank}. -3. **LLVM**: A compiler infrastructure that optimizes the code and generates RISC-V ELF objects. -4. **PVM linker**: Links the RISC-V ELF object into a final PolkaVM blob with metadata. - - --- Page Title: Randomness diff --git a/.ai/categories/networks.md b/.ai/categories/networks.md index eaf0fc920..282068cfa 100644 --- a/.ai/categories/networks.md +++ b/.ai/categories/networks.md @@ -3189,6 +3189,109 @@ Your deployed contract will appear in the **Deployed Contracts** section, ready +--- + +Page Title: Dual Virtual Machine Stack + +- Source (raw): https://raw.githubusercontent.com/polkadot-developers/polkadot-docs/master/.ai/pages/smart-contracts-for-eth-devs-dual-vm-stack.md +- Canonical (HTML): https://docs.polkadot.com/smart-contracts/for-eth-devs/dual-vm-stack/ +- Summary: Compare Polkadot’s dual smart contract VMs—REVM for EVM compatibility and PolkaVM for RISC-V performance, flexibility, and efficiency. + +# Dual Virtual Machine Stack + +!!! smartcontract "PolkaVM Preview Release" + PolkaVM smart contracts with Ethereum compatibility are in **early-stage development and may be unstable or incomplete**. +## Introduction + +Polkadot's smart contract platform supports two distinct virtual machine (VM) architectures, providing developers with flexibility in selecting the optimal execution backend for their specific needs. This approach strikes a balance between immediate Ethereum compatibility and long-term innovation, enabling developers to deploy either unmodified (Ethereum Virtual Machine) EVM contracts using Rust Ethereum Virtual Machine (REVM) or optimize for higher performance using PolkaVM (PVM). + +Both VM options share common infrastructure, including RPC interfaces, tooling support, and precompiles. The following sections compare architectures and guide you in selecting the best VM for your project's needs. + +## Migrate from EVM + +The [REVM backend](https://github.com/bluealloy/revm){target=\_blank} integrates a complete Rust implementation of the EVM, enabling Solidity contracts to run unchanged on Polkadot's smart contract platform. + +REVM allows developers to use their existing Ethereum tooling and infrastructure to build on Polkadot. Choose REVM to: + +- Migrate existing Ethereum contracts without modifications. +- Retain exact EVM behavior for audit tools. +- Use developer tools that rely upon inspecting EVM bytecode. +- Prioritize rapid deployment over optimization. +- Work with established Ethereum infrastructure and tooling to build on Polkadot. + +REVM enables Ethereum developers to seamlessly migrate to Polkadot, achieving performance and fee improvements without modifying their existing contracts or developer tooling stack. + +## Upgrade to PolkaVM + +[**PolkaVM**](https://github.com/paritytech/polkavm){target=\_blank} is a custom virtual machine optimized for performance with [RISC-V-based](https://en.wikipedia.org/wiki/RISC-V){target=\_blank} architecture, supporting Solidity and additional high-performance languages. It serves as the core execution environment, integrated directly within the runtime. Choose the PolkaVM for: + +- An efficient interpreter for immediate code execution. +- A planned [Just In Time (JIT)](https://en.wikipedia.org/wiki/Just-in-time_compilation){target=\_blank} compiler for optimized performance. +- Dual-mode execution capability, allowing selection of the most appropriate backend for specific workloads. +- Optimized performance for short-running contract calls through the interpreter. + +The interpreter remains particularly beneficial for contracts with minimal code execution, as it enables immediate code execution through lazy interpretation. + +## Architecture + +The following key components of PolkaVM work together to enable Ethereum compatibility on Polkadot-based chains. + +### Revive Pallet + +[**`pallet_revive`**](https://paritytech.github.io/polkadot-sdk/master/pallet_revive/index.html){target=\_blank} is a runtime module that executes smart contracts by adding extrinsics, runtime APIs, and logic to convert Ethereum-style transactions into formats compatible with Polkadot SDK-based blockchains. It processes Ethereum-style transactions through the following workflow: + +```mermaid +sequenceDiagram + participant User as User/dApp + participant Proxy as Ethereum JSON RPC Proxy + participant Chain as Blockchain Node + participant Pallet as pallet_revive + + User->>Proxy: Submit Ethereum Transaction + Proxy->>Chain: Repackage as Polkadot Compatible Transaction + Chain->>Pallet: Process Transaction + Pallet->>Pallet: Decode Ethereum Transaction + Pallet->>Pallet: Execute Contract via PolkaVM + Pallet->>Chain: Return Results + Chain->>Proxy: Forward Results + Proxy->>User: Return Ethereum-compatible Response +``` + +This proxy-based approach eliminates the need for node binary modifications, maintaining compatibility across different client implementations. Preserving the original Ethereum transaction payload simplifies the adaptation of existing tools, which can continue processing familiar transaction formats. + +### PolkaVM Design Fundamentals + +PolkaVM differs from the EVM in two key ways that make it faster, more hardware-efficient, and easier to extend: + +- **Register-based design**: Instead of a stack machine, PolkaVM uses a RISC-V–style register model. This design: + + - Uses a fixed set of registers to pass arguments, not an infinite stack. + - Maps cleanly to real hardware like x86-64. + - Simplifies compilation and boosts runtime efficiency. + - Enables tighter control over register allocation and performance tuning. + +- **64-bit word size**: PolkaVM runs on a native 64-bit word size, aligning directly with modern CPUs. This design: + + - Executes arithmetic operations with direct hardware support. + - Maintains compatibility with Solidity’s 256-bit types via YUL translation. + - Accelerates computation-heavy workloads through native word alignment. + - Integrates easily with low-level, performance-focused components. + +## Where To Go Next + +
+ +- Learn __Contract Deployment__ + + --- + + Learn how REVM and PVM compare for compiling and deploying smart contracts. + + [:octicons-arrow-right-24: Reference](/smart-contracts/for-eth-devs/contract-deployment/) + +
+ + --- Page Title: EVM vs PolkaVM @@ -7792,121 +7895,6 @@ Support for encoding and decoding Polkadot SDK SS58 addresses has been implement - **TypeScript**: [`subsquid/squid-sdk`](https://github.com/subsquid/squid-sdk){target=\_blank} ---- - -Page Title: PolkaVM Design - -- Source (raw): https://raw.githubusercontent.com/polkadot-developers/polkadot-docs/master/.ai/pages/smart-contracts-for-eth-devs-dual-vm-stack.md -- Canonical (HTML): https://docs.polkadot.com/smart-contracts/for-eth-devs/dual-vm-stack/ -- Summary: Discover PolkaVM, a high-performance smart contract VM for Polkadot, enabling Ethereum compatibility via pallet_revive, Solidity support & optimized execution. - -# PolkaVM Design - -!!! smartcontract "PolkaVM Preview Release" - PolkaVM smart contracts with Ethereum compatibility are in **early-stage development and may be unstable or incomplete**. -## Introduction - -The Asset Hub smart contracts solution includes multiple components to ensure Ethereum compatibility and high performance. Its architecture allows for integration with current Ethereum tools, while its innovative virtual machine design enhances performance characteristics. - -## PolkaVM - -[**PolkaVM**](https://github.com/paritytech/polkavm){target=\_blank} is a custom virtual machine optimized for performance with [RISC-V-based](https://en.wikipedia.org/wiki/RISC-V){target=\_blank} architecture, supporting Solidity and additional high-performance languages. It serves as the core execution environment, integrated directly within the runtime. It features: - -- An efficient interpreter for immediate code execution. -- A planned JIT compiler for optimized performance. -- Dual-mode execution capability, allowing selection of the most appropriate backend for specific workloads. -- Optimized performance for short-running contract calls through the interpreter. - -The interpreter remains particularly beneficial for contracts with minimal code execution, as it eliminates JIT compilation overhead and enables immediate code execution through lazy interpretation. - -## Architecture - -The smart contract solution consists of the following key components that work together to enable Ethereum compatibility on Polkadot-based chains. - -### Pallet Revive - -[**`pallet_revive`**](https://paritytech.github.io/polkadot-sdk/master/pallet_revive/index.html){target=\_blank} is a runtime module that executes smart contracts by adding extrinsics, runtime APIs, and logic to convert Ethereum-style transactions into formats compatible with Polkadot SDK-based blockchains. It processes Ethereum-style transactions through the following workflow: - -```mermaid -sequenceDiagram - participant User as User/dApp - participant Proxy as Ethereum JSON RPC Proxy - participant Chain as Blockchain Node - participant Pallet as pallet_revive - - User->>Proxy: Submit Ethereum Transaction - Proxy->>Chain: Repackage as Polkadot Compatible Transaction - Chain->>Pallet: Process Transaction - Pallet->>Pallet: Decode Ethereum Transaction - Pallet->>Pallet: Execute Contract via PolkaVM - Pallet->>Chain: Return Results - Chain->>Proxy: Forward Results - Proxy->>User: Return Ethereum-compatible Response -``` - -This proxy-based approach eliminates the need for node binary modifications, maintaining compatibility across different client implementations. Preserving the original Ethereum transaction payload simplifies adapting existing tools, which can continue processing familiar transaction formats. - -### PolkaVM Design Fundamentals - -PolkaVM introduces two fundamental architectural differences compared to the Ethereum Virtual Machine (EVM): - -```mermaid -flowchart TB - subgraph "EVM Architecture" - EVMStack[Stack-Based] - EVM256[256-bit Word Size] - end - - subgraph "PolkaVM Architecture" - PVMReg[Register-Based] - PVM64[64-bit Word Size] - end -``` - -- **Register-based design**: PolkaVM utilizes a RISC-V register-based approach. This design: - - - Employs a finite set of registers for argument passing instead of an infinite stack. - - Facilitates efficient translation to underlying hardware architectures. - - Optimizes register allocation through careful register count selection. - - Enables simple 1:1 mapping to x86-64 instruction sets. - - Reduces compilation complexity through strategic register limitation. - - Improves overall execution performance through hardware-aligned design. - -- **64-bit word size**: PolkaVM operates with a 64-bit word size. This design: - - - Enables direct hardware-supported arithmetic operations. - - Maintains compatibility with Solidity's 256-bit operations through YUL translation. - - Allows integration of performance-critical components written in lower-level languages. - - Optimizes computation-intensive operations through native word size alignment. - - Reduces overhead for operations not requiring extended precision. - - Facilitates efficient integration with modern CPU architectures. - -## Compilation Process - -When compiling a Solidity smart contract, the code passes through the following stages: - -```mermaid -flowchart LR - Dev[Developer] --> |Solidity
Source
Code| Solc - - subgraph "Compilation Process" - direction LR - Solc[solc] --> |YUL
IR| Revive - Revive[Revive Compiler] --> |LLVM
IR| LLVM - LLVM[LLVM
Optimizer] --> |RISC-V ELF
Shared Object| PVMLinker - end - - PVMLinker[PVM Linker] --> PVM[PVM Blob
with Metadata] -``` - -The compilation process integrates several specialized components: - -1. **Solc**: The standard Ethereum Solidity compiler that translates Solidity source code to [YUL IR](https://docs.soliditylang.org/en/latest/yul.html){target=\_blank}. -2. **Revive Compiler**: Takes YUL IR and transforms it to [LLVM IR](https://llvm.org/){target=\_blank}. -3. **LLVM**: A compiler infrastructure that optimizes the code and generates RISC-V ELF objects. -4. **PVM linker**: Links the RISC-V ELF object into a final PolkaVM blob with metadata. - - --- Page Title: Randomness diff --git a/.ai/categories/parachains.md b/.ai/categories/parachains.md index 95774b6d9..a4efa3983 100644 --- a/.ai/categories/parachains.md +++ b/.ai/categories/parachains.md @@ -3245,6305 +3245,6678 @@ You can find this event in the list of recent events. It should look similar to --- -Page Title: Create a Smart Contract +Page Title: Create a Custom Pallet -- Source (raw): https://raw.githubusercontent.com/polkadot-developers/polkadot-docs/master/.ai/pages/tutorials-smart-contracts-launch-your-first-project-create-contracts.md -- Canonical (HTML): https://docs.polkadot.com/tutorials/smart-contracts/launch-your-first-project/create-contracts/ -- Summary: Learn how to write a basic smart contract using just a text editor. This guide covers creating and preparing a contract for deployment on Polkadot Hub. +- Source (raw): https://raw.githubusercontent.com/polkadot-developers/polkadot-docs/master/.ai/pages/parachains-customize-runtime-pallet-development-create-a-pallet.md +- Canonical (HTML): https://docs.polkadot.com/parachains/customize-runtime/pallet-development/create-a-pallet/ +- Summary: Learn how to create custom pallets using FRAME, allowing for flexible, modular, and scalable blockchain development. Follow the step-by-step guide. -# Create a Smart Contract +# Create a Custom Pallet -!!! smartcontract "PolkaVM Preview Release" - PolkaVM smart contracts with Ethereum compatibility are in **early-stage development and may be unstable or incomplete**. ## Introduction -Creating [smart contracts](/smart-contracts/get-started/){target=\_blank} is fundamental to blockchain development. While many frameworks and tools are available, understanding how to write a contract from scratch with just a text editor is essential knowledge. +[Framework for Runtime Aggregation of Modular Entities (FRAME)](https://paritytech.github.io/polkadot-sdk/master/polkadot_sdk_docs/polkadot_sdk/frame_runtime/index.html){target=\_blank} provides a powerful set of tools for blockchain development through modular components called [pallets](https://paritytech.github.io/polkadot-sdk/master/polkadot_sdk_docs/polkadot_sdk/frame_runtime/pallet/index.html){target=\_blank}. These Rust-based runtime modules allow you to build custom blockchain functionality with precision and flexibility. While FRAME includes a library of pre-built pallets, its true strength lies in creating custom pallets tailored to your specific needs. -This tutorial will guide you through creating a basic smart contract that can be used with other tutorials for deployment and integration on Polkadot Hub. To understand how smart contracts work in Polkadot Hub, check the [Smart Contract Basics](/polkadot-protocol/smart-contract-basics/){target=\_blank} guide for more information. +In this guide, you'll learn how to build a custom counter pallet from scratch that demonstrates core pallet development concepts. ## Prerequisites -Before starting, make sure you have: +Before you begin, ensure you have: -- A text editor of your choice ([VS Code](https://code.visualstudio.com/){target=\_blank}, [Sublime Text](https://www.sublimetext.com/){target=\_blank}, etc.). -- Basic understanding of programming concepts. -- Familiarity with the Solidity programming language syntax. For further references, check the official [Solidity documentation](https://docs.soliditylang.org/en/latest/){target=\_blank}. +- [Polkadot SDK dependencies installed](/parachains/install-polkadot-sdk/){target=\_blank}. +- A [Polkadot SDK Parchain Template](/parachains/launch-a-parachain/set-up-the-parachain-template/){target=\_blank} set up locally. +- Basic familiarity with [FRAME concepts](/parachains/customize-runtime/){target=\_blank}. -## Understanding Smart Contract Structure +## Core Pallet Components -Let's explore these components before building the contract: +As you build your custom pallet, you'll work with these key sections: -- **[SPDX license identifier](https://docs.soliditylang.org/en/v0.6.8/layout-of-source-files.html){target=\_blank}**: A standardized way to declare the license under which your code is released. This helps with legal compliance and is required by the Solidity compiler to avoid warnings. -- **Pragma directive**: Specifies which version of Solidity compiler should be used for your contract. -- **Contract declaration**: Similar to a class in object-oriented programming, it defines the boundaries of your smart contract. -- **State variables**: Data stored directly in the contract that persists between function calls. These represent the contract's "state" on the blockchain. -- **Functions**: Executable code that can read or modify the contract's state variables. -- **Events**: Notification mechanisms that applications can subscribe to in order to track blockchain changes. +- **Imports and dependencies**: Bring in necessary FRAME libraries and external modules. +- **Runtime configuration trait**: Specify types and constants for pallet-runtime interaction. +- **Runtime events**: Define signals that communicate state changes. +- **Runtime errors**: Define error types returned from dispatchable calls. +- **Runtime storage**: Declare on-chain storage items for your pallet's state. +- **Genesis configuration**: Set initial blockchain state. +- **Dispatchable functions (extrinsics)**: Create callable functions for user interactions. -## Create the Smart Contract +For additional macros beyond those covered here, refer to the [pallet_macros](https://paritytech.github.io/polkadot-sdk/master/frame_support/pallet_macros/index.html){target=\_blank} section of the Polkadot SDK Docs. -In this section, you'll build a simple storage contract step by step. This basic Storage contract is a great starting point for beginners. It introduces key concepts like state variables, functions, and events in a simple way, demonstrating how data is stored and updated on the blockchain. Later, you'll explore each component in more detail to understand what's happening behind the scenes. +## Create the Pallet Project -This contract will: +Begin by creating a new Rust library project for your custom pallet within the [Polkadot SDK Parachain Template](https://github.com/paritytech/polkadot-sdk-parachain-template){target=\_blank}: -- Store a number. -- Allow updating the stored number. -- Emit an event when the number changes. +1. Navigate to the root directory of your parachain template: -To build the smart contract, follow the steps below: + ```bash + cd polkadot-sdk-parachain-template + ``` -1. Create a new file named `Storage.sol`. +2. Navigate to the `pallets` directory: -2. Add the SPDX license identifier at the top of the file: + ```bash + cd pallets + ``` - ```solidity - // SPDX-License-Identifier: MIT +3. Create a new Rust library project: + + ```bash + cargo new --lib pallet-custom ``` - This line tells users and tools which license governs your code. The [MIT license](https://opensource.org/license/mit){target=\_blank} is commonly used for open-source projects. The Solidity compiler requires this line to avoid licensing-related warnings. +4. Enter the new project directory: -3. Specify the Solidity version: + ```bash + cd pallet-custom + ``` - ```solidity - pragma solidity ^0.8.28; +5. Verify the project structure. It should look like: + + ``` + pallet-custom/ + ├── Cargo.toml + └── src/ + └── lib.rs ``` - The caret `^` means "this version or any compatible newer version." This helps ensure your contract compiles correctly with the intended compiler features. +## Configure Dependencies -4. Create the contract structure: +To integrate your custom pallet into the Polkadot SDK-based runtime, configure the `Cargo.toml` file with the required dependencies. Since your pallet exists within the parachain template workspace, you'll use workspace inheritance to maintain version consistency. - ```solidity - contract Storage { - // Contract code will go here - } - ``` +1. Open `Cargo.toml` and replace its contents with: - This defines a contract named "Storage", similar to how you would define a class in other programming languages. + ```toml title="pallet-custom/Cargo.toml" + [package] + name = "pallet-custom" + description = "A custom counter pallet for demonstration purposes." + version = "0.1.0" + license = "Unlicense" + authors.workspace = true + homepage.workspace = true + repository.workspace = true + edition.workspace = true + publish = false -5. Add the state variables and event: + [package.metadata.docs.rs] + targets = ["x86_64-unknown-linux-gnu"] - ```solidity - contract Storage { - // State variable to store a number - uint256 private number; - - // Event to notify when the number changes - event NumberChanged(uint256 newNumber); - } - ``` + [dependencies] + codec = { features = ["derive"], workspace = true } + scale-info = { features = ["derive"], workspace = true } + frame = { features = ["experimental", "runtime"], workspace = true } - Here, you're defining: + [features] + default = ["std"] + std = [ + "codec/std", + "scale-info/std", + "frame/std", + ] + ``` - - A state variable named `number` of type `uint256` (unsigned integer with 256 bits), which is marked as `private` so it can only be accessed via functions within this contract. - - An event named `NumberChanged` that will be triggered whenever the number changes. The event includes the new value as data. + !!!note "Version Management" + The parachain template uses workspace inheritance to maintain consistent dependency versions across all packages. The actual versions are defined in the root `Cargo.toml` file, ensuring compatibility throughout the project. By using `workspace = true`, your pallet automatically inherits the correct versions. -6. Add the getter and setter functions: +2. The parachain template already includes `pallets/*` in the workspace members, so your new pallet is automatically recognized. Verify this by checking the root `Cargo.toml`: - ```solidity - // SPDX-License-Identifier: MIT - pragma solidity ^0.8.28; + ```toml title="Cargo.toml" + [workspace.members] + members = [ + "node", + "pallets/*", + "runtime", + ] + ``` - contract Storage { - // State variable to store our number - uint256 private number; +## Initialize the Pallet Structure - // Event to notify when the number changes - event NumberChanged(uint256 newNumber); +With dependencies configured, set up the basic scaffold that will hold your pallet's logic: - // Function to store a new number - function store(uint256 newNumber) public { - number = newNumber; - emit NumberChanged(newNumber); - } +1. Open `src/lib.rs` and delete all existing content. - // Function to retrieve the stored number - function retrieve() public view returns (uint256) { - return number; - } - } - ``` +2. Add the initial scaffold structure using the unified `frame` dependency: -??? code "Complete Storage.sol contract" + ```rust title="src/lib.rs" + #![cfg_attr(not(feature = "std"), no_std)] - ```solidity title="Storage.sol" - // SPDX-License-Identifier: MIT - pragma solidity ^0.8.28; + pub use pallet::*; - contract Storage { - // State variable to store our number - uint256 private number; + #[frame::pallet] + pub mod pallet { + use frame::prelude::*; - // Event to notify when the number changes - event NumberChanged(uint256 newNumber); + #[pallet::pallet] + pub struct Pallet(_); - // Function to store a new number - function store(uint256 newNumber) public { - number = newNumber; - emit NumberChanged(newNumber); + #[pallet::config] + pub trait Config: frame_system::Config { + // Configuration will be added here } - // Function to retrieve the stored number - function retrieve() public view returns (uint256) { - return number; + #[pallet::storage] + pub type CounterValue = StorageValue<_, u32, ValueQuery>; + + #[pallet::call] + impl Pallet { + // Dispatchable functions will be added here } } ``` -## Understanding the Code + This setup starts with a minimal scaffold without events and errors. These will be added in the following sections after the `Config` trait is correctly configured with the required `RuntimeEvent` type. -Let's break down the key components of the contract: +3. Verify it compiles using the following command: -- **State Variable** + ```bash + cargo build --package pallet-custom + ``` - - **`uint256 private number`**: A private variable that can only be accessed through the contract's functions. - - The `private` keyword prevents direct access from other contracts, but it's important to note that while other contracts cannot read this variable directly, the data itself is still visible on the blockchain and can be read by external tools or applications that interact with the blockchain. "Private" in Solidity doesn't mean the data is encrypted or truly hidden. - - State variables in Solidity are permanent storage on the blockchain, making them different from variables in traditional programming. Every change to a state variable requires a transaction and costs gas (the fee paid for blockchain operations). +## Configure the Pallet -- **Event** +The [`Config`](https://paritytech.github.io/polkadot-sdk/master/frame_system/pallet/trait.Config.html){target=\_blank} trait exposes configurable options and links your pallet to the runtime. All types and constants the pallet depends on must be declared here. These types are defined generically and become concrete when the pallet is instantiated at runtime. - - **`event NumberChanged(uint256 newNumber)`**: Emitted when the stored number changes. - - When triggered, events write data to the blockchain's log, which can be efficiently queried by applications. - - Unlike state variables, events cannot be read by smart contracts, only by external applications. - - Events are much more gas-efficient than storing data when you only need to notify external systems of changes. +Replace the [`#[pallet::config]`](https://paritytech.github.io/polkadot-sdk/master/frame_support/pallet_macros/attr.config.html){target=\_blank} section with: -- **Functions** +```rust title="src/lib.rs" +#[pallet::config] +pub trait Config: frame_system::Config { + /// The overarching runtime event type. + type RuntimeEvent: From> + IsType<::RuntimeEvent>; - - **`store(uint256 newNumber)`**: Updates the stored number and emits an event. - - This function changes the state of the contract and requires a transaction to execute. - - The `emit` keyword is used to trigger the defined event. + /// Maximum value the counter can reach. + #[pallet::constant] + type CounterMaxValue: Get; +} - - **`retrieve()`**: Returns the current stored number. - - The `view` keyword indicates that this function only reads data and doesn't modify the contract's state. - - View functions don't require a transaction and don't cost gas when called externally. +``` - For those new to Solidity, this naming pattern (getter/setter functions) is a common design pattern. Instead of directly accessing state variables, the convention is to use functions to control access and add additional logic if needed. +Key configuration elements include the following: -This basic contract serves as a foundation for learning smart contract development. Real-world contracts often require additional security considerations, more complex logic, and thorough testing before deployment. +- **[`RuntimeEvent`](https://paritytech.github.io/polkadot-sdk/master/frame_system/pallet/trait.Config.html#associatedtype.RuntimeEvent){target=\_blank}**: Required for the pallet to emit events that the runtime can process. +- **`CounterMaxValue`**: A constant that sets an upper limit on counter values, configurable per runtime. -For more detailed information about Solidity types, functions, and best practices, refer to the [Solidity documentation](https://docs.soliditylang.org/en/latest/){target=\_blank} or this [beginner's guide to Solidity](https://www.tutorialspoint.com/solidity/index.htm){target=\_blank}. +## Define Events -## Where to Go Next +Events inform external entities (dApps, explorers, users) about significant runtime changes. Event details are included in the node's metadata, making them accessible to external tools. +The [`#[pallet::generate_deposit]`](https://paritytech.github.io/polkadot-sdk/master/frame_support/pallet_macros/attr.generate_deposit.html){target=\_blank} macro automatically generates a `deposit_event` function that converts your pallet's events into the `RuntimeEvent` type and deposits them via [`frame_system::Pallet::deposit_event`](https://paritytech.github.io/polkadot-sdk/master/frame_system/pallet/struct.Pallet.html#method.deposit_event){target=\_blank}. -
+Add the [`#[pallet::event]`](https://paritytech.github.io/polkadot-sdk/master/frame_support/pallet_macros/attr.event.html){target=\_blank} section after the `Config` trait: -- Tutorial __Test and Deploy with Hardhat__ +```rust title="src/lib.rs" +#[pallet::event] +#[pallet::generate_deposit(pub(super) fn deposit_event)] +pub enum Event { + /// Counter value was explicitly set. [new_value] + CounterValueSet { + new_value: u32, + }, + /// Counter was incremented. [new_value, who, amount] + CounterIncremented { + new_value: u32, + who: T::AccountId, + amount: u32, + }, + /// Counter was decremented. [new_value, who, amount] + CounterDecremented { + new_value: u32, + who: T::AccountId, + amount: u32, + }, +} - --- +``` - Learn how to test and deploy the smart contract you created by using Hardhat. +## Define Errors - [:octicons-arrow-right-24: Get Started](/tutorials/smart-contracts/launch-your-first-project/test-and-deploy-with-hardhat/) +Errors indicate when and why a call fails. Use informative names and descriptions, as error documentation is included in the node's metadata. -
+Error types must implement the [`TypeInfo`](https://paritytech.github.io/polkadot-sdk/master/frame_support/pallet_prelude/trait.TypeInfo.html){target=\_blank} trait, and runtime errors can be up to 4 bytes in size. +Add the [`#[pallet::error]`](https://paritytech.github.io/polkadot-sdk/master/frame_support/pallet_macros/attr.error.html){target=\_blank} section after the events: ---- - -Page Title: Cryptography - -- Source (raw): https://raw.githubusercontent.com/polkadot-developers/polkadot-docs/master/.ai/pages/reference-parachains-cryptography.md -- Canonical (HTML): https://docs.polkadot.com/reference/parachains/cryptography/ -- Summary: A concise guide to cryptography in blockchain, covering hash functions, encryption types, digital signatures, and elliptic curve applications. +```rust title="src/lib.rs" +#[pallet::error] +pub enum Error { + /// The counter value has not been set yet. + NoneValue, + /// Arithmetic operation would cause overflow. + Overflow, + /// Arithmetic operation would cause underflow. + Underflow, + /// The counter value would exceed the maximum allowed value. + CounterMaxValueExceeded, +} -# Cryptography +``` -## Introduction +## Add Storage Items -Cryptography forms the backbone of blockchain technology, providing the mathematical verifiability crucial for consensus systems, data integrity, and user security. While a deep understanding of the underlying mathematical processes isn't necessary for most blockchain developers, grasping the fundamental applications of cryptography is essential. This page comprehensively overviews cryptographic implementations used across Polkadot SDK-based chains and the broader blockchain ecosystem. +Storage items persist state on-chain. This pallet uses two storage items: -## Hash Functions +- **`CounterValue`**: Stores the current counter value. +- **`UserInteractions`**: Tracks interaction counts per user account. -Hash functions are fundamental to blockchain technology, creating a unique digital fingerprint for any piece of data, including simple text, images, or any other form of file. They map input data of any size to a fixed-size output (typically 32 bytes) using complex mathematical operations. Hashing is used to verify data integrity, create digital signatures, and provide a secure way to store passwords. This form of mapping is known as the ["pigeonhole principle,"](https://en.wikipedia.org/wiki/Pigeonhole_principle){target=\_blank} it is primarily implemented to efficiently and verifiably identify data from large sets. +The initial scaffold already includes the `CounterValue` storage item. Now add the `UserInteractions` storage map after it: -### Key Properties of Hash Functions +```rust title="src/lib.rs" +/// Tracks the number of interactions per user. +#[pallet::storage] +pub type UserInteractions = StorageMap<_, Blake2_128Concat, T::AccountId, u32, ValueQuery>; +``` -- **Deterministic**: The same input always produces the same output. -- **Quick computation**: It's easy to calculate the hash value for any given input. -- **Pre-image resistance**: It's infeasible to generate the input data from its hash. -- **Small changes in input yield large changes in output**: Known as the ["avalanche effect"](https://en.wikipedia.org/wiki/Avalanche_effect){target=\_blank}. -- **Collision resistance**: The probabilities are extremely low to find two different inputs with the same hash. +Your storage section should now look like this: -### Blake2 +```rust title="src/lib.rs" +/// The current value of the counter. +#[pallet::storage] +pub type CounterValue = StorageValue<_, u32, ValueQuery>; -The Polkadot SDK utilizes Blake2, a state-of-the-art hashing method that offers: +/// Tracks the number of interactions per user. +#[pallet::storage] +pub type UserInteractions = StorageMap<_, Blake2_128Concat, T::AccountId, u32, ValueQuery>; +``` -- Equal or greater security compared to [SHA-2](https://en.wikipedia.org/wiki/SHA-2){target=\_blank}. -- Significantly faster performance than other algorithms. +For more storage types and patterns, explore the [Polkadot SDK storage documentation](https://paritytech.github.io/polkadot-sdk/master/frame_support/storage/types/index.html){target=\_blank}. -These properties make Blake2 ideal for blockchain systems, reducing sync times for new nodes and lowering the resources required for validation. For detailed technical specifications about Blake2, see the [official Blake2 paper](https://www.blake2.net/blake2.pdf){target=\_blank}. +## Configure Genesis State -## Types of Cryptography +Genesis configuration allows you to set the initial state of your pallet when the blockchain first starts and is essential for both production networks and testing environments. It is beneficial for: -There are two different ways that cryptographic algorithms are implemented: symmetric cryptography and asymmetric cryptography. +- Setting initial parameter values. +- Pre-allocating resources or accounts. +- Establishing starting conditions for testing. +- Configuring network-specific initial state. -### Symmetric Cryptography +Add the [`#[pallet::genesis_config]`](https://paritytech.github.io/polkadot-sdk/master/frame_support/pallet_macros/attr.genesis_config.html){target=\_blank} and [`#[pallet::genesis_build]`](https://paritytech.github.io/polkadot-sdk/master/frame_support/pallet_macros/attr.genesis_build.html){target=\_blank} sections after your storage items: -Symmetric encryption is a branch of cryptography that isn't based on one-way functions, unlike asymmetric cryptography. It uses the same cryptographic key to encrypt plain text and decrypt the resulting ciphertext. +```rust title="src/lib.rs" +#[pallet::genesis_config] +#[derive(DefaultNoBound)] +pub struct GenesisConfig { + /// Initial value for the counter + pub initial_counter_value: u32, + /// Pre-populated user interactions + pub initial_user_interactions: Vec<(T::AccountId, u32)>, +} -Symmetric cryptography is a type of encryption that has been used throughout history, such as the Enigma Cipher and the Caesar Cipher. It is still widely used today and can be found in Web2 and Web3 applications alike. There is only one single key, and a recipient must also have access to it to access the contained information. +#[pallet::genesis_build] +impl BuildGenesisConfig for GenesisConfig { + fn build(&self) { + // Set the initial counter value + CounterValue::::put(self.initial_counter_value); -#### Advantages {: #symmetric-advantages } + // Set initial user interactions + for (account, count) in &self.initial_user_interactions { + UserInteractions::::insert(account, count); + } + } +} -- Fast and efficient for large amounts of data. -- Requires less computational power. +``` -#### Disadvantages {: #symmetric-disadvantages } +Genesis configuration components include the following: -- Key distribution can be challenging. -- Scalability issues in systems with many users. +- **`GenesisConfig` struct**: Defines what can be configured at genesis. +- **`#[derive(DefaultNoBound)]`**: Provides sensible defaults (empty vec and 0 for the counter). +- **`BuildGenesisConfig` implementation**: Executes the logic to set initial storage values. +- **`build()` method**: Called once when the blockchain initializes. -### Asymmetric Cryptography +## Implement Dispatchable Functions -Asymmetric encryption is a type of cryptography that uses two different keys, known as a keypair: a public key, used to encrypt plain text, and a private counterpart, used to decrypt the ciphertext. +Dispatchable functions (extrinsics) allow users to interact with your pallet and trigger state changes. Each function must: -The public key encrypts a fixed-length message that can only be decrypted with the recipient's private key and, sometimes, a set password. The public key can be used to cryptographically verify that the corresponding private key was used to create a piece of data without compromising the private key, such as with digital signatures. This has obvious implications for identity, ownership, and properties and is used in many different protocols across Web2 and Web3. +- Return a [`DispatchResult`](https://paritytech.github.io/polkadot-sdk/master/frame_support/dispatch/type.DispatchResult.html){target=\_blank}. +- Be annotated with a weight (computational cost). +- Have an explicit call index for backward compatibility. -#### Advantages {: #asymmetric-advantages } +Replace the [`#[pallet::call]`](https://paritytech.github.io/polkadot-sdk/master/frame_support/pallet_macros/attr.call.html){target=\_blank} section with: -- Solves the key distribution problem. -- Enables digital signatures and secure key exchange. +```rust title="src/lib.rs" +#[pallet::call] +impl Pallet { + /// Set the counter to a specific value. Root origin only. + #[pallet::call_index(0)] + #[pallet::weight(0)] + pub fn set_counter_value(origin: OriginFor, new_value: u32) -> DispatchResult { + // Ensure the caller is root + ensure_root(origin)?; -#### Disadvantages {: #asymmetric-disadvantages } + // Validate the new value doesn't exceed the maximum + ensure!(new_value <= T::CounterMaxValue::get(), Error::::CounterMaxValueExceeded); -- Slower than symmetric encryption. -- Requires more computational resources. + // Update storage + CounterValue::::put(new_value); -### Trade-offs and Compromises + // Emit event + Self::deposit_event(Event::CounterValueSet { new_value }); -Symmetric cryptography is faster and requires fewer bits in the key to achieve the same level of security that asymmetric cryptography provides. However, it requires a shared secret before communication can occur, which poses issues to its integrity and a potential compromise point. On the other hand, asymmetric cryptography doesn't require the secret to be shared ahead of time, allowing for far better end-user security. + Ok(()) + } -Hybrid symmetric and asymmetric cryptography is often used to overcome the engineering issues of asymmetric cryptography, as it is slower and requires more bits in the key to achieve the same level of security. It encrypts a key and then uses the comparatively lightweight symmetric cipher to do the "heavy lifting" with the message. + /// Increment the counter by a specified amount. + #[pallet::call_index(1)] + #[pallet::weight(0)] + pub fn increment(origin: OriginFor, amount: u32) -> DispatchResult { + // Ensure the caller is signed + let who = ensure_signed(origin)?; -## Digital Signatures + // Get current counter value + let current_value = CounterValue::::get(); -Digital signatures are a way of verifying the authenticity of a document or message using asymmetric keypairs. They are used to ensure that a sender or signer's document or message hasn't been tampered with in transit, and for recipients to verify that the data is accurate and from the expected sender. + // Check for overflow + let new_value = current_value.checked_add(amount).ok_or(Error::::Overflow)?; -Signing digital signatures only requires a low-level understanding of mathematics and cryptography. For a conceptual example -- when signing a check, it is expected that it cannot be cashed multiple times. This isn't a feature of the signature system but rather the check serialization system. The bank will check that the serial number on the check hasn't already been used. Digital signatures essentially combine these two concepts, allowing the signature to provide the serialization via a unique cryptographic fingerprint that cannot be reproduced. + // Ensure new value doesn't exceed maximum + ensure!(new_value <= T::CounterMaxValue::get(), Error::::CounterMaxValueExceeded); -Unlike pen-and-paper signatures, knowledge of a digital signature cannot be used to create other signatures. Digital signatures are often used in bureaucratic processes, as they are more secure than simply scanning in a signature and pasting it onto a document. + // Update counter storage + CounterValue::::put(new_value); -Polkadot SDK provides multiple different cryptographic schemes and is generic so that it can support anything that implements the [`Pair` trait](https://paritytech.github.io/polkadot-sdk/master/sp_core/crypto/trait.Pair.html){target=\_blank}. + // Track user interaction + UserInteractions::::mutate(&who, |count| { + *count = count.saturating_add(1); + }); -### Example of Creating a Digital Signature + // Emit event + Self::deposit_event(Event::CounterIncremented { + new_value, + who, + amount, + }); -The process of creating and verifying a digital signature involves several steps: + Ok(()) + } -1. The sender creates a hash of the message. -2. The hash is encrypted using the sender's private key, creating the signature. -3. The message and signature are sent to the recipient. -4. The recipient decrypts the signature using the sender's public key. -5. The recipient hashes the received message and compares it to the decrypted hash. + /// Decrement the counter by a specified amount. + #[pallet::call_index(2)] + #[pallet::weight(0)] + pub fn decrement(origin: OriginFor, amount: u32) -> DispatchResult { + // Ensure the caller is signed + let who = ensure_signed(origin)?; -If the hashes match, the signature is valid, confirming the message's integrity and the sender's identity. + // Get current counter value + let current_value = CounterValue::::get(); -## Elliptic Curve + // Check for underflow + let new_value = current_value.checked_sub(amount).ok_or(Error::::Underflow)?; -Blockchain technology requires the ability to have multiple keys creating a signature for block proposal and validation. To this end, Elliptic Curve Digital Signature Algorithm (ECDSA) and Schnorr signatures are two of the most commonly used methods. While ECDSA is a far simpler implementation, Schnorr signatures are more efficient when it comes to multi-signatures. + // Update counter storage + CounterValue::::put(new_value); -Schnorr signatures bring some noticeable features over the ECDSA/EdDSA schemes: + // Track user interaction + UserInteractions::::mutate(&who, |count| { + *count = count.saturating_add(1); + }); -- It is better for hierarchical deterministic key derivations. -- It allows for native multi-signature through [signature aggregation](https://bitcoincore.org/en/2017/03/23/schnorr-signature-aggregation/){target=\_blank}. -- It is generally more resistant to misuse. + // Emit event + Self::deposit_event(Event::CounterDecremented { + new_value, + who, + amount, + }); -One sacrifice that is made when using Schnorr signatures over ECDSA is that both require 64 bytes, but only ECDSA signatures communicate their public key. + Ok(()) + } +} -### Various Implementations +``` -- **[ECDSA](https://en.wikipedia.org/wiki/Elliptic_Curve_Digital_Signature_Algorithm){target=\_blank}**: Polkadot SDK provides an ECDSA signature scheme using the [secp256k1](https://en.bitcoin.it/wiki/Secp256k1){target=\_blank} curve. This is the same cryptographic algorithm used to secure [Bitcoin](https://en.wikipedia.org/wiki/Bitcoin){target=\_blank} and [Ethereum](https://en.wikipedia.org/wiki/Ethereum){target=\_blank}. +### Dispatchable Function Details -- **[Ed25519](https://en.wikipedia.org/wiki/EdDSA#Ed25519){target=\_blank}**: An EdDSA signature scheme using [Curve25519](https://en.wikipedia.org/wiki/Curve25519){target=\_blank}. It is carefully engineered at several levels of design and implementation to achieve very high speeds without compromising security. +???+ interface "`set_counter_value`" -- **[SR25519](https://research.web3.foundation/Polkadot/security/keys/accounts-more){target=\_blank}**: Based on the same underlying curve as Ed25519. However, it uses Schnorr signatures instead of the EdDSA scheme. + - **Access**: Root origin only (privileged operations). + - **Purpose**: Set counter to a specific value. + - **Validations**: New value must not exceed `CounterMaxValue`. + - **State changes**: Updates `CounterValue` storage. + - **Events**: Emits `CounterValueSet`. +??? interface "`increment`" ---- + - **Access**: Any signed account. + - **Purpose**: Increase counter by specified amount. + - **Validations**: Checks for overflow and max value compliance. + - **State changes**: Updates `CounterValue` and `UserInteractions`. + - **Events**: Emits `CounterIncremented`. -Page Title: Data Encoding +??? interface "`decrement`" -- Source (raw): https://raw.githubusercontent.com/polkadot-developers/polkadot-docs/master/.ai/pages/reference-parachains-data-encoding.md -- Canonical (HTML): https://docs.polkadot.com/reference/parachains/data-encoding/ -- Summary: SCALE codec enables fast, efficient data encoding, ideal for resource-constrained environments like Wasm, supporting custom types and compact encoding. + - **Access**: Any signed account. + - **Purpose**: Decrease counter by specified amount. + - **Validations**: Checks for underflow. + - **State changes**: Updates `CounterValue` and `UserInteractions`. + - **Events**: Emits `CounterDecremented`. -# Data Encoding +## Verify Pallet Compilation -## Introduction +Before proceeding, ensure your pallet compiles without errors by running the following command: -The Polkadot SDK uses a lightweight and efficient encoding/decoding mechanism to optimize data transmission across the network. This mechanism, known as the _SCALE_ codec, is used for serializing and deserializing data. +```bash +cargo build --package pallet-custom +``` -The SCALE codec enables communication between the runtime and the outer node. This mechanism is designed for high-performance, copy-free data encoding and decoding in resource-constrained environments like the Polkadot SDK [Wasm runtime](/develop/parachains/deployment/build-deterministic-runtime/#introduction){target=\_blank}. +If you encounter errors, carefully review the code against this guide. Once the build completes successfully, your custom pallet is ready for integration. -It is not self-describing, meaning the decoding context must fully know the encoded data types. +??? code "Complete Pallet Implementation" + + ```rust title="src/lib.rs" + #![cfg_attr(not(feature = "std"), no_std)] -Parity's libraries utilize the [`parity-scale-codec`](https://github.com/paritytech/parity-scale-codec){target=\_blank} crate (a Rust implementation of the SCALE codec) to handle encoding and decoding for interactions between RPCs and the runtime. + pub use pallet::*; -The `codec` mechanism is ideal for Polkadot SDK-based chains because: + #[frame::pallet] + pub mod pallet { + use frame::prelude::*; -- It is lightweight compared to generic serialization frameworks like [`serde`](https://serde.rs/){target=\_blank}, which add unnecessary bulk to binaries. -- It doesn’t rely on Rust’s `libstd`, making it compatible with `no_std` environments like Wasm runtime. -- It integrates seamlessly with Rust, allowing easy derivation of encoding and decoding logic for new types using `#[derive(Encode, Decode)]`. + #[pallet::pallet] + pub struct Pallet(_); -Defining a custom encoding scheme in the Polkadot SDK-based chains, rather than using an existing Rust codec library, is crucial for enabling cross-platform and multi-language support. + #[pallet::config] + pub trait Config: frame_system::Config { + type RuntimeEvent: From> + IsType<::RuntimeEvent>; -## SCALE Codec + #[pallet::constant] + type CounterMaxValue: Get; + } -The codec is implemented using the following traits: + #[pallet::event] + #[pallet::generate_deposit(pub(super) fn deposit_event)] + pub enum Event { + CounterValueSet { + new_value: u32, + }, + CounterIncremented { + new_value: u32, + who: T::AccountId, + amount: u32, + }, + CounterDecremented { + new_value: u32, + who: T::AccountId, + amount: u32, + }, + } -- [`Encode`](#encode) -- [`Decode`](#decode) -- [`CompactAs`](#compactas) -- [`HasCompact`](#hascompact) -- [`EncodeLike`](#encodelike) + #[pallet::error] + pub enum Error { + NoneValue, + Overflow, + Underflow, + CounterMaxValueExceeded, + } -### Encode + #[pallet::storage] + pub type CounterValue = StorageValue<_, u32, ValueQuery>; -The [`Encode`](https://docs.rs/parity-scale-codec/latest/parity_scale_codec/trait.Encode.html){target=\_blank} trait handles data encoding into SCALE format and includes the following key functions: + #[pallet::storage] + pub type UserInteractions = StorageMap< + _, + Blake2_128Concat, + T::AccountId, + u32, + ValueQuery + >; -- **`size_hint(&self) -> usize`**: Estimates the number of bytes required for encoding to prevent multiple memory allocations. This should be inexpensive and avoid complex operations. Optional if the size isn’t known. -- **`encode_to(&self, dest: &mut T)`**: Encodes the data, appending it to a destination buffer. -- **`encode(&self) -> Vec`**: Encodes the data and returns it as a byte vector. -- **`using_encoded R>(&self, f: F) -> R`**: Encodes the data and passes it to a closure, returning the result. -- **`encoded_size(&self) -> usize`**: Calculates the encoded size. Should be used when the encoded data isn’t required. + #[pallet::genesis_config] + #[derive(DefaultNoBound)] + pub struct GenesisConfig { + pub initial_counter_value: u32, + pub initial_user_interactions: Vec<(T::AccountId, u32)>, + } -!!!tip - For best performance, value types should override `using_encoded`, and allocating types should override `encode_to`. It's recommended to implement `size_hint` for all types where possible. + #[pallet::genesis_build] + impl BuildGenesisConfig for GenesisConfig { + fn build(&self) { + CounterValue::::put(self.initial_counter_value); + for (account, count) in &self.initial_user_interactions { + UserInteractions::::insert(account, count); + } + } + } -### Decode + #[pallet::call] + impl Pallet { + #[pallet::call_index(0)] + #[pallet::weight(0)] + pub fn set_counter_value(origin: OriginFor, new_value: u32) -> DispatchResult { + ensure_root(origin)?; + ensure!(new_value <= T::CounterMaxValue::get(), Error::::CounterMaxValueExceeded); + CounterValue::::put(new_value); + Self::deposit_event(Event::CounterValueSet { new_value }); + Ok(()) + } -The [`Decode`](https://docs.rs/parity-scale-codec/latest/parity_scale_codec/trait.Decode.html){target=\_blank} trait handles decoding SCALE-encoded data back into the appropriate types: + #[pallet::call_index(1)] + #[pallet::weight(0)] + pub fn increment(origin: OriginFor, amount: u32) -> DispatchResult { + let who = ensure_signed(origin)?; + let current_value = CounterValue::::get(); + let new_value = current_value.checked_add(amount).ok_or(Error::::Overflow)?; + ensure!(new_value <= T::CounterMaxValue::get(), Error::::CounterMaxValueExceeded); + CounterValue::::put(new_value); + UserInteractions::::mutate(&who, |count| { + *count = count.saturating_add(1); + }); + Self::deposit_event(Event::CounterIncremented { new_value, who, amount }); + Ok(()) + } -- **`fn decode(value: &mut I) -> Result`**: Decodes data from the SCALE format, returning an error if decoding fails. + #[pallet::call_index(2)] + #[pallet::weight(0)] + pub fn decrement(origin: OriginFor, amount: u32) -> DispatchResult { + let who = ensure_signed(origin)?; + let current_value = CounterValue::::get(); + let new_value = current_value.checked_sub(amount).ok_or(Error::::Underflow)?; + CounterValue::::put(new_value); + UserInteractions::::mutate(&who, |count| { + *count = count.saturating_add(1); + }); + Self::deposit_event(Event::CounterDecremented { new_value, who, amount }); + Ok(()) + } + } + } -### CompactAs + ``` -The [`CompactAs`](https://docs.rs/parity-scale-codec/latest/parity_scale_codec/trait.CompactAs.html){target=\_blank} trait wraps custom types for compact encoding: +## Add the Pallet to Your Runtime -- **`encode_as(&self) -> &Self::As`**: Encodes the type as a compact type. -- **`decode_from(_: Self::As) -> Result`**: decodes from a compact encoded type. +Now that your custom pallet is complete, you can integrate it into the parachain runtime. -### HasCompact +### Add Runtime Dependency -The [`HasCompact`](https://docs.rs/parity-scale-codec/latest/parity_scale_codec/trait.HasCompact.html){target=\_blank} trait indicates a type supports compact encoding. +1. In the `runtime/Cargo.toml`, add your custom pallet to the `[dependencies]` section: -### EncodeLike + ```toml title="runtime/Cargo.toml" + [dependencies] + # Local dependencies + pallet-custom = { path = "../pallets/pallet-custom", default-features = false } + + # Other dependencies + ``` -The [`EncodeLike`](https://docs.rs/parity-scale-codec/latest/parity_scale_codec/trait.EncodeLike.html){target=\_blank} trait is used to ensure multiple types that encode similarly are accepted by the same function. When using `derive`, it is automatically implemented. +2. Enable the `std` feature by adding it to the `[features]` section: -### Data Types + ```toml title="runtime/Cargo.toml" + [features] + default = ["std"] + std = [ + "codec/std", + "pallet-custom/std", + # ... other features + ] + ``` -The table below outlines how the Rust implementation of the Parity SCALE codec encodes different data types. +### Implement the Config Trait -| Type | Description | Example SCALE Decoded Value | SCALE Encoded Value | -|-------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------|-------------------------------------------------------------------------| -| Boolean | Boolean values are encoded using the least significant bit of a single byte. | `false` / `true` | `0x00` / `0x01` | -| Compact/general integers | A "compact" or general integer encoding is sufficient for encoding large integers (up to 2^536) and is more efficient at encoding most values than the fixed-width version. | `unsigned integer 0` / `unsigned integer 1` / `unsigned integer 42` / `unsigned integer 69` / `unsigned integer 65535` / `BigInt(100000000000000)` | `0x00` / `0x04` / `0xa8` / `0x1501` / `0xfeff0300` / `0x0b00407a10f35a` | -| Enumerations (tagged-unions) | A fixed number of variants, each mutually exclusive and potentially implying a further value or series of values. Encoded as the first byte identifying the index of the variant that the value is. Any further bytes are used to encode any data that the variant implies. Thus, no more than 256 variants are supported. | `Int(42)` and `Bool(true)` where `enum IntOrBool { Int(u8), Bool(bool) }` | `0x002a` and `0x0101` | -| Fixed-width integers | Basic integers are encoded using a fixed-width little-endian (LE) format. | `signed 8-bit integer 69` / `unsigned 16-bit integer 42` / `unsigned 32-bit integer 16777215` | `0x45` / `0x2a00` / `0xffffff00` | -| Options | One or zero values of a particular type. | `Some` / `None` | `0x01` followed by the encoded value / `0x00` | -| Results | Results are commonly used enumerations which indicate whether certain operations were successful or unsuccessful. | `Ok(42)` / `Err(false)` | `0x002a` / `0x0100` | -| Strings | Strings are Vectors of bytes (Vec) containing a valid UTF8 sequence. | | | -| Structs | For structures, the values are named, but that is irrelevant for the encoding (names are ignored - only order matters). | `SortedVecAsc::from([3, 5, 2, 8])` | `[3, 2, 5, 8] ` | -| Tuples | A fixed-size series of values, each with a possibly different but predetermined and fixed type. This is simply the concatenation of each encoded value. | Tuple of compact unsigned integer and boolean: `(3, false)` | `0x0c00` | -| Vectors (lists, series, sets) | A collection of same-typed values is encoded, prefixed with a compact encoding of the number of items, followed by each item's encoding concatenated in turn. | Vector of unsigned `16`-bit integers: `[4, 8, 15, 16, 23, 42]` | `0x18040008000f00100017002a00` | +At the end of the `runtime/src/configs/mod.rs` file, add the implementation: -## Encode and Decode Rust Trait Implementations +```rust title="runtime/src/configs/mod.rs" +/// Configure the custom counter pallet +impl pallet_custom::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type CounterMaxValue = ConstU32<1000>; +} +``` -Here's how the `Encode` and `Decode` traits are implemented: +This configuration: +- Links the pallet's events to the runtime's event system. +- Sets a maximum counter value of 1000 using [`ConstU32`](https://paritytech.github.io/polkadot-sdk/master/frame_support/traits/struct.ConstU32.html){target=\_blank}. -```rust -use parity_scale_codec::{Encode, Decode}; +### Add to Runtime Construct -[derive(Debug, PartialEq, Encode, Decode)] -enum EnumType { - #[codec(index = 15)] - A, - B(u32, u64), - C { - a: u32, - b: u64, - }, -} +In the `runtime/src/lib.rs` file, locate the [`#[frame_support::runtime]`](https://paritytech.github.io/polkadot-sdk/master/frame_support/attr.runtime.html){target=\_blank} section and add your pallet with a unique `pallet_index`: -let a = EnumType::A; -let b = EnumType::B(1, 2); -let c = EnumType::C { a: 1, b: 2 }; +```rust title="runtime/src/lib.rs" +#[frame_support::runtime] +mod runtime { + #[runtime::runtime] + #[runtime::derive( + RuntimeCall, + RuntimeEvent, + RuntimeError, + RuntimeOrigin, + RuntimeTask, + RuntimeFreezeReason, + RuntimeHoldReason, + RuntimeSlashReason, + RuntimeLockId, + RuntimeViewFunction + )] + pub struct Runtime; -a.using_encoded(|ref slice| { - assert_eq!(slice, &b"\x0f"); -}); + #[runtime::pallet_index(0)] + pub type System = frame_system; -b.using_encoded(|ref slice| { - assert_eq!(slice, &b"\x01\x01\0\0\0\x02\0\0\0\0\0\0\0"); -}); + // ... other pallets -c.using_encoded(|ref slice| { - assert_eq!(slice, &b"\x02\x01\0\0\0\x02\0\0\0\0\0\0\0"); -}); + #[runtime::pallet_index(51)] + pub type CustomPallet = pallet_custom; +} +``` -let mut da: &[u8] = b"\x0f"; -assert_eq!(EnumType::decode(&mut da).ok(), Some(a)); +!!!warning + Each pallet must have a unique index. Duplicate indices will cause compilation errors. Choose an index that doesn't conflict with existing pallets. -let mut db: &[u8] = b"\x01\x01\0\0\0\x02\0\0\0\0\0\0\0"; -assert_eq!(EnumType::decode(&mut db).ok(), Some(b)); +### Configure Genesis for Your Runtime -let mut dc: &[u8] = b"\x02\x01\0\0\0\x02\0\0\0\0\0\0\0"; -assert_eq!(EnumType::decode(&mut dc).ok(), Some(c)); +To set initial values for your pallet when the chain starts, you'll need to configure the genesis in your chain specification. Genesis configuration is typically done in the `node/src/chain_spec.rs` file or when generating the chain specification. -let mut dz: &[u8] = &[0]; -assert_eq!(EnumType::decode(&mut dz).ok(), None); -``` +For development and testing, you can use the default values provided by the `#[derive(DefaultNoBound)]` macro. For production networks, you'll want to explicitly set these values in your chain specification. -## SCALE Codec Libraries +### Verify Runtime Compilation -Several SCALE codec implementations are available in various languages. Here's a list of them: +Compile the runtime to ensure everything is configured correctly: -- **AssemblyScript**: [`LimeChain/as-scale-codec`](https://github.com/LimeChain/as-scale-codec){target=\_blank} -- **C**: [`MatthewDarnell/cScale`](https://github.com/MatthewDarnell/cScale){target=\_blank} -- **C++**: [`qdrvm/scale-codec-cpp`](https://github.com/qdrvm/scale-codec-cpp){target=\_blank} -- **JavaScript**: [`polkadot-js/api`](https://github.com/polkadot-js/api){target=\_blank} -- **Dart**: [`leonardocustodio/polkadart`](https://github.com/leonardocustodio/polkadart){target=\_blank} -- **Haskell**: [`airalab/hs-web3`](https://github.com/airalab/hs-web3/tree/master/packages/scale){target=\_blank} -- **Golang**: [`itering/scale.go`](https://github.com/itering/scale.go){target=\_blank} -- **Java**: [`splix/polkaj`](https://github.com/splix/polkaj){target=\_blank} -- **Python**: [`polkascan/py-scale-codec`](https://github.com/polkascan/py-scale-codec){target=\_blank} -- **Ruby**: [` wuminzhe/scale_rb`](https://github.com/wuminzhe/scale_rb){target=\_blank} -- **TypeScript**: [`parity-scale-codec-ts`](https://github.com/tjjfvi/subshape){target=\_blank}, [`scale-ts`](https://github.com/unstoppablejs/unstoppablejs/tree/main/packages/scale-ts#scale-ts){target=\_blank}, [`soramitsu/scale-codec-js-library`](https://github.com/soramitsu/scale-codec-js-library){target=\_blank}, [`subsquid/scale-codec`](https://github.com/subsquid/squid-sdk/tree/master/substrate/scale-codec){target=\_blank} +```bash +cargo build --release +``` +This command validates all pallet configurations and prepares the build for deployment. ---- +## Run Your Chain Locally -Page Title: Deploy an ERC-20 to Polkadot Hub +Launch your parachain locally to test the new pallet functionality using the [Polkadot Omni Node](https://crates.io/crates/polkadot-omni-node){target=\_blank}. -- Source (raw): https://raw.githubusercontent.com/polkadot-developers/polkadot-docs/master/.ai/pages/smart-contracts-cookbook-smart-contracts-deploy-erc20-erc20-remix.md -- Canonical (HTML): https://docs.polkadot.com/smart-contracts/cookbook/smart-contracts/deploy-erc20/erc20-remix/ -- Summary: Deploy an ERC-20 token contract on Polkadot Hub. This guide covers contract creation, compilation, deployment, and interaction via the Remix IDE. +### Generate a Chain Specification -# Deploy an ERC-20 to Polkadot Hub +Create a chain specification file with the updated runtime: -## Introduction +```bash +chain-spec-builder create -t development \ +--relay-chain paseo \ +--para-id 1000 \ +--runtime ./target/release/wbuild/parachain-template-runtime/parachain_template_runtime.compact.compressed.wasm \ +named-preset development +``` -[ERC-20](https://eips.ethereum.org/EIPS/eip-20){target=\_blank} tokens are fungible tokens commonly used for creating cryptocurrencies, governance tokens, and staking mechanisms. Polkadot Hub enables easy token deployment with Ethereum-compatible smart contracts and tools via the EVM backend. +This command generates a `chain_spec.json` that includes your custom pallet. -This tutorial covers deploying an ERC-20 contract on the Polkadot Hub TestNet using [Remix IDE](https://remix.ethereum.org/){target=\_blank}, a web-based development tool. The ERC-20 contract can be retrieved from OpenZeppelin's [GitHub repository](https://github.com/OpenZeppelin/openzeppelin-contracts/tree/v5.4.0/contracts/token/ERC20){target=\_blank} or their [Contract Wizard](https://wizard.openzeppelin.com/){target=\_blank}. +### Start the Parachain Node -## Prerequisites +Launch the parachain: -Before starting, make sure you have: +```bash +polkadot-omni-node --chain ./chain_spec.json --dev +``` -- An EVM-compatible wallet [connected to Polkadot Hub](/smart-contracts/integrations/wallets){target=\_blank}. This example utilizes [MetaMask](https://metamask.io/){target=\_blank}. -- A funded account with tokens for transaction fees. This example will deploy the contract to the Polkadot TestNet, so you'll [need some TestNet tokens](/smart-contracts/faucet/#get-test-tokens){target=\_blank} from the [Polkadot Faucet](https://faucet.polkadot.io/?parachain=1111){target=\_blank}. -- Basic understanding of Solidity and fungible tokens. +Verify the node starts successfully and begins producing blocks. -## Create Your Contract +## Interact with Your Pallet -To create the ERC-20 contract, you can follow the steps below: +Use the Polkadot.js Apps interface to test your pallet: -1. Navigate to the [Polkadot Remix IDE](https://remix.polkadot.io){target=\_blank}. -2. Click in the **Create new file** button under the **contracts** folder, and name your contract as `MyToken.sol`. +1. Navigate to [Polkadot.js Apps](https://polkadot.js.org/apps/?rpc=ws%3A%2F%2F127.0.0.1%3A9944#/extrinsics){target=\_blank}. - ![](/images/smart-contracts/cookbook/smart-contracts/deploy-erc20/erc20-remix-1.webp) +2. Ensure you're connected to your local node at `ws://127.0.0.1:9944`. -3. Now, paste the following ERC-20 contract code into the editor: +3. Go to **Developer** > **Extrinsics**. - ```solidity title="MyToken.sol" - // SPDX-License-Identifier: MIT - // Compatible with OpenZeppelin Contracts ^5.4.0 - pragma solidity ^0.8.27; - - import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; - import {ERC20Permit} from "@openzeppelin/contracts/token/ERC20/extensions/ERC20Permit.sol"; - import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol"; - - contract MyToken is ERC20, Ownable, ERC20Permit { - constructor(address initialOwner) - ERC20("MyToken", "MTK") - Ownable(initialOwner) - ERC20Permit("MyToken") - {} +4. Locate **customPallet** in the pallet dropdown. - function mint(address to, uint256 amount) public onlyOwner { - _mint(to, amount); - } - } - ``` +5. You should see the available extrinsics: - The key components of the code above are: + - **`increment(amount)`**: Increase the counter by a specified amount. + - **`decrement(amount)`**: Decrease the counter by a specified amount. + - **`setCounterValue(newValue)`**: Set counter to a specific value (requires sudo/root). - - Contract imports: +![](/images/parachains/customize-runtime/pallet-development/create-a-pallet/create-a-pallet-01.webp) - - **[`ERC20.sol`](https://github.com/OpenZeppelin/openzeppelin-contracts/tree/v5.4.0/contracts/token/ERC20/ERC20.sol){target=\_blank}**: The base contract for fungible tokens, implementing core functionality like transfers, approvals, and balance tracking. - - **[`ERC20Permit.sol`](https://github.com/OpenZeppelin/openzeppelin-contracts/tree/v5.4.0/contracts/token/ERC20/extensions/ERC20Permit.sol){target=\_blank}**: [EIP-2612](https://eips.ethereum.org/EIPS/eip-2612){target=\_blank} extension for ERC-20 that adds the [permit function](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20Permit-permit-address-address-uint256-uint256-uint8-bytes32-bytes32-){target=\_blank}, allowing approvals via off-chain signatures (no on-chain tx from the holder). Manages nonces and EIP-712 domain separator and updates allowances when a valid signature is presented. - - **[`Ownable.sol`](https://github.com/OpenZeppelin/openzeppelin-contracts/tree/v5.4.0/contracts/access/Ownable.sol){target=\_blank}**: Provides basic authorization control, ensuring only the contract owner can mint new tokens. - - - Constructor parameters: +## Key Takeaways - - **`initialOwner`**: Sets the address that will have administrative rights over the contract. - - **`"MyToken"`**: The full name of your token. - - **`"MTK"`**: The symbol representing your token in wallets and exchanges. +You've successfully created and integrated a custom pallet into a Polkadot SDK-based runtime. You have now successfully: - - Key functions: +- Defined runtime-specific types and constants via the `Config` trait. +- Implemented on-chain state using `StorageValue` and `StorageMap`. +- Created signals to communicate state changes to external systems. +- Established clear error handling with descriptive error types. +- Configured initial blockchain state for both production and testing. +- Built callable functions with proper validation and access control. +- Added the pallet to a runtime and tested it locally. - - **`mint(address to, uint256 amount)`**: Allows the contract owner to create new tokens for any address. The amount should include 18 decimals (e.g., 1 token = 1000000000000000000). - - Inherited [Standard ERC-20](https://ethereum.org/en/developers/docs/standards/tokens/erc-20/){target=\_blank} functions: - - **`transfer(address recipient, uint256 amount)`**: Sends a specified amount of tokens to another address. - - **`approve(address spender, uint256 amount)`**: Grants permission for another address to spend a specific number of tokens on behalf of the token owner. - - **`transferFrom(address sender, address recipient, uint256 amount)`**: Transfers tokens from one address to another, if previously approved. - - **`balanceOf(address account)`**: Returns the token balance of a specific address. - - **`allowance(address owner, address spender)`**: Checks how many tokens an address is allowed to spend on behalf of another address. +These components form the foundation for developing sophisticated blockchain logic in Polkadot SDK-based chains. - !!! tip - Use the [OpenZeppelin Contracts Wizard](https://wizard.openzeppelin.com/){target=\_blank} to generate customized smart contracts quickly. Simply configure your contract, copy the generated code, and paste it into the Remix IDE for deployment. Below is an example of an ERC-20 token contract created with it: +## Where to Go Next - ![Screenshot of the OpenZeppelin Contracts Wizard showing an ERC-20 contract configuration.](/images/smart-contracts/cookbook/smart-contracts/deploy-erc20/erc20-remix-2.webp) - +
-## Compile +- Guide __Mock Your Runtime__ -The compilation transforms your Solidity source code into bytecode that can be deployed on the blockchain. During this process, the compiler checks your contract for syntax errors, ensures type safety, and generates the machine-readable instructions needed for blockchain execution. + --- -To compile your contract, ensure you have it opened in the Remix IDE Editor, and follow the instructions below: + Learn to create a mock runtime environment for testing your pallet in isolation before integration. -1. Select the **Solidity Compiler** plugin from the left panel. -2. Click the **Compile MyToken.sol** button. -3. If the compilation succeeded, you'll see a green checkmark indicating success in the **Solidity Compiler** icon. + [:octicons-arrow-right-24: Continue](/parachains/customize-runtime/pallet-development/mock-runtime/) -![](/images/smart-contracts/cookbook/smart-contracts/deploy-erc20/erc20-remix-3.gif) +
-## Deploy -Deployment is the process of publishing your compiled smart contract to the blockchain, making it permanently available for interaction. During deployment, you'll create a new instance of your contract on the blockchain, which involves: +--- -1. Select the **Deploy & Run Transactions** plugin from the left panel. -2. Configure the deployment settings: - 1. From the **ENVIRONMENT** dropdown, select **Injected Provider - MetaMask** (check the [Deploying Contracts](/smart-contracts/dev-environments/remix/deploy-a-contract/){target=\_blank} section of the Remix IDE guide for more details). - 2. (Optional) From the **ACCOUNT** dropdown, select the acccount you want to use for the deploy. +Page Title: Create a Smart Contract -3. Configure the contract parameters: - 1. Enter the address that will own the deployed token contract. - 2. Click the **Deploy** button to initiate the deployment. +- Source (raw): https://raw.githubusercontent.com/polkadot-developers/polkadot-docs/master/.ai/pages/tutorials-smart-contracts-launch-your-first-project-create-contracts.md +- Canonical (HTML): https://docs.polkadot.com/tutorials/smart-contracts/launch-your-first-project/create-contracts/ +- Summary: Learn how to write a basic smart contract using just a text editor. This guide covers creating and preparing a contract for deployment on Polkadot Hub. -4. **MetaMask will pop up**: Review the transaction details. Click **Confirm** to deploy your contract. -5. If the deployment process succeeded, you will see the transaction details in the terminal, including the contract address and deployment transaction hash. +# Create a Smart Contract -![](/images/smart-contracts/cookbook/smart-contracts/deploy-erc20/erc20-remix-4.gif) +!!! smartcontract "PolkaVM Preview Release" + PolkaVM smart contracts with Ethereum compatibility are in **early-stage development and may be unstable or incomplete**. +## Introduction -## Interact with Your Contract +Creating [smart contracts](/smart-contracts/get-started/){target=\_blank} is fundamental to blockchain development. While many frameworks and tools are available, understanding how to write a contract from scratch with just a text editor is essential knowledge. -Once deployed, you can interact with your contract through Remix. Find your contract under **Deployed/Unpinned Contracts**, and click it to expand the available methods. In this example, you'll mint some tokens to a given address: +This tutorial will guide you through creating a basic smart contract that can be used with other tutorials for deployment and integration on Polkadot Hub. To understand how smart contracts work in Polkadot Hub, check the [Smart Contract Basics](/polkadot-protocol/smart-contract-basics/){target=\_blank} guide for more information. -1. Expand the **mint** function: - 1. Enter the recipient address and the amount (remember to add 18 zeros for 1 whole token). - 2. Click **transact**. +## Prerequisites -2. Click **Approve** to confirm the transaction in the MetaMask popup. +Before starting, make sure you have: -3. If the transaction succeeds, you will see a green check mark in the terminal. +- A text editor of your choice ([VS Code](https://code.visualstudio.com/){target=\_blank}, [Sublime Text](https://www.sublimetext.com/){target=\_blank}, etc.). +- Basic understanding of programming concepts. +- Familiarity with the Solidity programming language syntax. For further references, check the official [Solidity documentation](https://docs.soliditylang.org/en/latest/){target=\_blank}. -4. You can also call the **balanceOf** function by passing the address of the **mint** call to confirm the new balance. +## Understanding Smart Contract Structure -![](/images/smart-contracts/cookbook/smart-contracts/deploy-erc20/erc20-remix-5.gif) +Let's explore these components before building the contract: +- **[SPDX license identifier](https://docs.soliditylang.org/en/v0.6.8/layout-of-source-files.html){target=\_blank}**: A standardized way to declare the license under which your code is released. This helps with legal compliance and is required by the Solidity compiler to avoid warnings. +- **Pragma directive**: Specifies which version of Solidity compiler should be used for your contract. +- **Contract declaration**: Similar to a class in object-oriented programming, it defines the boundaries of your smart contract. +- **State variables**: Data stored directly in the contract that persists between function calls. These represent the contract's "state" on the blockchain. +- **Functions**: Executable code that can read or modify the contract's state variables. +- **Events**: Notification mechanisms that applications can subscribe to in order to track blockchain changes. -Other standard functions you can use: +## Create the Smart Contract -- **`transfer(address to, uint256 amount)`**: Send tokens to another address. -- **`approve(address spender, uint256 amount)`**: Allow another address to spend your tokens. +In this section, you'll build a simple storage contract step by step. This basic Storage contract is a great starting point for beginners. It introduces key concepts like state variables, functions, and events in a simple way, demonstrating how data is stored and updated on the blockchain. Later, you'll explore each component in more detail to understand what's happening behind the scenes. -Feel free to explore and interact with the contract's other functions using the same approach: select the method, provide any required parameters, and confirm the transaction in MetaMask when needed. +This contract will: -## Where to Go Next +- Store a number. +- Allow updating the stored number. +- Emit an event when the number changes. -
+To build the smart contract, follow the steps below: -- Guide __Deploy an NFT with Remix__ +1. Create a new file named `Storage.sol`. - --- +2. Add the SPDX license identifier at the top of the file: - Walk through deploying an ERC-721 Non-Fungible Token (NFT) using OpenZeppelin's battle-tested NFT implementation and Remix. + ```solidity + // SPDX-License-Identifier: MIT + ``` - [:octicons-arrow-right-24: Get Started](/smart-contracts/cookbook/smart-contracts/deploy-nft/remix/) + This line tells users and tools which license governs your code. The [MIT license](https://opensource.org/license/mit){target=\_blank} is commonly used for open-source projects. The Solidity compiler requires this line to avoid licensing-related warnings. -
+3. Specify the Solidity version: + ```solidity + pragma solidity ^0.8.28; + ``` ---- + The caret `^` means "this version or any compatible newer version." This helps ensure your contract compiles correctly with the intended compiler features. -Page Title: Deploy an ERC-20 to Polkadot Hub +4. Create the contract structure: -- Source (raw): https://raw.githubusercontent.com/polkadot-developers/polkadot-docs/master/.ai/pages/smart-contracts-cookbook-smart-contracts-deploy-erc20.md -- Canonical (HTML): https://docs.polkadot.com/smart-contracts/cookbook/smart-contracts/deploy-erc20/ -- Summary: Deploy an ERC-20 token on Polkadot Hub using PolkaVM. This guide covers contract creation, compilation, deployment, and interaction via Polkadot Remix IDE. + ```solidity + contract Storage { + // Contract code will go here + } + ``` -# Deploy an ERC-20 to Polkadot Hub + This defines a contract named "Storage", similar to how you would define a class in other programming languages. -!!! smartcontract "PolkaVM Preview Release" - PolkaVM smart contracts with Ethereum compatibility are in **early-stage development and may be unstable or incomplete**. -## Introduction +5. Add the state variables and event: -[ERC-20](https://eips.ethereum.org/EIPS/eip-20){target=\_blank} tokens are fungible tokens commonly used for creating cryptocurrencies, governance tokens, and staking mechanisms. Polkadot Hub enables easy token deployment with Ethereum-compatible smart contracts via PolkaVM. + ```solidity + contract Storage { + // State variable to store a number + uint256 private number; + + // Event to notify when the number changes + event NumberChanged(uint256 newNumber); + } + ``` -This tutorial covers deploying an ERC-20 contract on the Polkadot Hub TestNet using [Polkadot Remix IDE](https://remix.polkadot.io){target=\_blank}, a web-based development tool. [OpenZeppelin's ERC-20 contracts](https://github.com/OpenZeppelin/openzeppelin-contracts/tree/v5.4.0/contracts/token/ERC20){target=\_blank} are used for security and compliance. + Here, you're defining: -## Prerequisites + - A state variable named `number` of type `uint256` (unsigned integer with 256 bits), which is marked as `private` so it can only be accessed via functions within this contract. + - An event named `NumberChanged` that will be triggered whenever the number changes. The event includes the new value as data. -Before starting, make sure you have: +6. Add the getter and setter functions: -- [MetaMask](https://metamask.io/){target=\_blank} installed and connected to Polkadot Hub. For detailed instructions, see the [Connect Your Wallet](/smart-contracts/integrations/wallets){target=\_blank} section. -- A funded account with some PAS tokens (you can get them from the [Polkadot Faucet](https://faucet.polkadot.io/?parachain=1111){target=\_blank}). To learn how to get test tokens, check out the [Test Tokens](/smart-contracts/connect/#test-tokens){target=\_blank} section. -- Basic understanding of Solidity and fungible tokens. + ```solidity + // SPDX-License-Identifier: MIT + pragma solidity ^0.8.28; -## Create the ERC-20 Contract + contract Storage { + // State variable to store our number + uint256 private number; -To create the ERC-20 contract, you can follow the steps below: + // Event to notify when the number changes + event NumberChanged(uint256 newNumber); -1. Navigate to the [Polkadot Remix IDE](https://remix.polkadot.io){target=\_blank}. -2. Click in the **Create new file** button under the **contracts** folder, and name your contract as `MyToken.sol`. + // Function to store a new number + function store(uint256 newNumber) public { + number = newNumber; + emit NumberChanged(newNumber); + } - ![](/images/smart-contracts/cookbook/smart-contracts/deploy-erc20/deploy-erc20-1.webp) + // Function to retrieve the stored number + function retrieve() public view returns (uint256) { + return number; + } + } + ``` -3. Now, paste the following ERC-20 contract code into the editor: +??? code "Complete Storage.sol contract" - ```solidity title="MyToken.sol" + ```solidity title="Storage.sol" // SPDX-License-Identifier: MIT - // Compatible with OpenZeppelin Contracts ^5.0.0 - pragma solidity ^0.8.22; + pragma solidity ^0.8.28; - import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; - import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol"; + contract Storage { + // State variable to store our number + uint256 private number; - contract MyToken is ERC20, Ownable { - constructor(address initialOwner) - ERC20("MyToken", "MTK") - Ownable(initialOwner) - {} + // Event to notify when the number changes + event NumberChanged(uint256 newNumber); - function mint(address to, uint256 amount) public onlyOwner { - _mint(to, amount); + // Function to store a new number + function store(uint256 newNumber) public { + number = newNumber; + emit NumberChanged(newNumber); + } + + // Function to retrieve the stored number + function retrieve() public view returns (uint256) { + return number; } } ``` - The key components of the code above are: +## Understanding the Code - - Contract imports: +Let's break down the key components of the contract: - - **[`ERC20.sol`](https://github.com/OpenZeppelin/openzeppelin-contracts/tree/v5.4.0/contracts/token/ERC20/ERC20.sol){target=\_blank}**: The base contract for fungible tokens, implementing core functionality like transfers, approvals, and balance tracking. - - **[`Ownable.sol`](https://github.com/OpenZeppelin/openzeppelin-contracts/tree/v5.4.0/contracts/access/Ownable.sol){target=\_blank}**: Provides basic authorization control, ensuring only the contract owner can mint new tokens. - - - Constructor parameters: +- **State Variable** - - **`initialOwner`**: Sets the address that will have administrative rights over the contract. - - **`"MyToken"`**: The full name of your token. - - **`"MTK"`**: The symbol representing your token in wallets and exchanges. + - **`uint256 private number`**: A private variable that can only be accessed through the contract's functions. + - The `private` keyword prevents direct access from other contracts, but it's important to note that while other contracts cannot read this variable directly, the data itself is still visible on the blockchain and can be read by external tools or applications that interact with the blockchain. "Private" in Solidity doesn't mean the data is encrypted or truly hidden. + - State variables in Solidity are permanent storage on the blockchain, making them different from variables in traditional programming. Every change to a state variable requires a transaction and costs gas (the fee paid for blockchain operations). - - Key functions: +- **Event** - - **`mint(address to, uint256 amount)`**: Allows the contract owner to create new tokens for any address. The amount should include 18 decimals (e.g., 1 token = 1000000000000000000). - - Inherited [Standard ERC-20](https://ethereum.org/en/developers/docs/standards/tokens/erc-20/){target=\_blank} functions: - - **`transfer(address recipient, uint256 amount)`**: Sends a specified amount of tokens to another address. - - **`approve(address spender, uint256 amount)`**: Grants permission for another address to spend a specific number of tokens on behalf of the token owner. - - **`transferFrom(address sender, address recipient, uint256 amount)`**: Transfers tokens from one address to another, if previously approved. - - **`balanceOf(address account)`**: Returns the token balance of a specific address. - - **`allowance(address owner, address spender)`**: Checks how many tokens an address is allowed to spend on behalf of another address. + - **`event NumberChanged(uint256 newNumber)`**: Emitted when the stored number changes. + - When triggered, events write data to the blockchain's log, which can be efficiently queried by applications. + - Unlike state variables, events cannot be read by smart contracts, only by external applications. + - Events are much more gas-efficient than storing data when you only need to notify external systems of changes. - !!! tip - Use the [OpenZeppelin Contracts Wizard](https://wizard.openzeppelin.com/){target=\_blank} to quickly generate customized smart contracts. Simply configure your contract, copy the generated code, and paste it into Polkadot Remix IDE for deployment. Below is an example of an ERC-20 token contract created with it: +- **Functions** - ![Screenshot of the OpenZeppelin Contracts Wizard showing an ERC-20 contract configuration.](/images/smart-contracts/cookbook/smart-contracts/deploy-erc20/deploy-erc20-2.webp) - + - **`store(uint256 newNumber)`**: Updates the stored number and emits an event. + - This function changes the state of the contract and requires a transaction to execute. + - The `emit` keyword is used to trigger the defined event. -## Compile the Contract + - **`retrieve()`**: Returns the current stored number. + - The `view` keyword indicates that this function only reads data and doesn't modify the contract's state. + - View functions don't require a transaction and don't cost gas when called externally. -The compilation transforms your Solidity source code into bytecode that can be deployed on the blockchain. During this process, the compiler checks your contract for syntax errors, ensures type safety, and generates the machine-readable instructions needed for blockchain execution. To compile your contract, follow the instructions below: + For those new to Solidity, this naming pattern (getter/setter functions) is a common design pattern. Instead of directly accessing state variables, the convention is to use functions to control access and add additional logic if needed. -1. Select the **Solidity Compiler** plugin from the left panel. +This basic contract serves as a foundation for learning smart contract development. Real-world contracts often require additional security considerations, more complex logic, and thorough testing before deployment. - ![](/images/smart-contracts/cookbook/smart-contracts/deploy-erc20/deploy-erc20-3.webp) +For more detailed information about Solidity types, functions, and best practices, refer to the [Solidity documentation](https://docs.soliditylang.org/en/latest/){target=\_blank} or this [beginner's guide to Solidity](https://www.tutorialspoint.com/solidity/index.htm){target=\_blank}. -2. Click the **Compile MyToken.sol** button. +## Where to Go Next - ![](/images/smart-contracts/cookbook/smart-contracts/deploy-erc20/deploy-erc20-4.webp) -3. If the compilation succeeded, you'll see a green checkmark indicating success in the **Solidity Compiler** icon. +
- ![](/images/smart-contracts/cookbook/smart-contracts/deploy-erc20/deploy-erc20-5.webp) +- Tutorial __Test and Deploy with Hardhat__ -## Deploy the Contract + --- -Deployment is the process of publishing your compiled smart contract to the blockchain, making it permanently available for interaction. During deployment, you'll create a new instance of your contract on the blockchain, which involves: + Learn how to test and deploy the smart contract you created by using Hardhat. -1. Select the **Deploy & Run Transactions** plugin from the left panel. + [:octicons-arrow-right-24: Get Started](/tutorials/smart-contracts/launch-your-first-project/test-and-deploy-with-hardhat/) - ![](/images/smart-contracts/cookbook/smart-contracts/deploy-erc20/deploy-erc20-6.webp) +
-2. Configure the deployment settings. - 1. From the **ENVIRONMENT** dropdown, select **Injected Provider - Talisman** (check the [Deploying Contracts](/smart-contracts/dev-environments/remix/deploy-a-contract/){target=\_blank} section of the Remix IDE guide for more details). - 2. From the **ACCOUNT** dropdown, select the account you want to use for the deploy. - ![](/images/smart-contracts/cookbook/smart-contracts/deploy-erc20/deploy-erc20-7.webp) +--- -3. Configure the contract parameters: +Page Title: Cryptography - 1. Enter the address that will own the deployed token contract. - 2. Click the **Deploy** button to initiate the deployment. +- Source (raw): https://raw.githubusercontent.com/polkadot-developers/polkadot-docs/master/.ai/pages/reference-parachains-cryptography.md +- Canonical (HTML): https://docs.polkadot.com/reference/parachains/cryptography/ +- Summary: A concise guide to cryptography in blockchain, covering hash functions, encryption types, digital signatures, and elliptic curve applications. - ![](/images/smart-contracts/cookbook/smart-contracts/deploy-erc20/deploy-erc20-8.webp) +# Cryptography -4. **Talisman will pop up**: Review the transaction details. Click **Approve** to deploy your contract. +## Introduction - ![](/images/smart-contracts/cookbook/smart-contracts/deploy-erc20/deploy-erc20-9.webp){: .browser-extension} +Cryptography forms the backbone of blockchain technology, providing the mathematical verifiability crucial for consensus systems, data integrity, and user security. While a deep understanding of the underlying mathematical processes isn't necessary for most blockchain developers, grasping the fundamental applications of cryptography is essential. This page comprehensively overviews cryptographic implementations used across Polkadot SDK-based chains and the broader blockchain ecosystem. - If the deployment process succeeded, you will see the transaction details in the terminal, including the contract address and deployment transaction hash: +## Hash Functions - ![](/images/smart-contracts/cookbook/smart-contracts/deploy-erc20/deploy-erc20-10.webp) +Hash functions are fundamental to blockchain technology, creating a unique digital fingerprint for any piece of data, including simple text, images, or any other form of file. They map input data of any size to a fixed-size output (typically 32 bytes) using complex mathematical operations. Hashing is used to verify data integrity, create digital signatures, and provide a secure way to store passwords. This form of mapping is known as the ["pigeonhole principle,"](https://en.wikipedia.org/wiki/Pigeonhole_principle){target=\_blank} it is primarily implemented to efficiently and verifiably identify data from large sets. -## Interact with Your ERC-20 Contract +### Key Properties of Hash Functions -Once deployed, you can interact with your contract through Remix: +- **Deterministic**: The same input always produces the same output. +- **Quick computation**: It's easy to calculate the hash value for any given input. +- **Pre-image resistance**: It's infeasible to generate the input data from its hash. +- **Small changes in input yield large changes in output**: Known as the ["avalanche effect"](https://en.wikipedia.org/wiki/Avalanche_effect){target=\_blank}. +- **Collision resistance**: The probabilities are extremely low to find two different inputs with the same hash. -1. Find your contract under **Deployed/Unpinned Contracts**, and click it to expand the available methods. +### Blake2 - ![](/images/smart-contracts/cookbook/smart-contracts/deploy-erc20/deploy-erc20-11.webp) +The Polkadot SDK utilizes Blake2, a state-of-the-art hashing method that offers: -2. To mint new tokens: +- Equal or greater security compared to [SHA-2](https://en.wikipedia.org/wiki/SHA-2){target=\_blank}. +- Significantly faster performance than other algorithms. - 1. Click in the contract to expand its associated methods. - 2. Expand the **mint** function. - 3. Enter: - - The recipient address. - - The amount (remember to add 18 zeros for 1 whole token). - 4. Click **Transact**. +These properties make Blake2 ideal for blockchain systems, reducing sync times for new nodes and lowering the resources required for validation. For detailed technical specifications about Blake2, see the [official Blake2 paper](https://www.blake2.net/blake2.pdf){target=\_blank}. - ![](/images/smart-contracts/cookbook/smart-contracts/deploy-erc20/deploy-erc20-12.webp) +## Types of Cryptography -3. Click **Approve** to confirm the transaction in the Talisman popup. +There are two different ways that cryptographic algorithms are implemented: symmetric cryptography and asymmetric cryptography. - ![](/images/smart-contracts/cookbook/smart-contracts/deploy-erc20/deploy-erc20-13.webp){: .browser-extension} +### Symmetric Cryptography - If the transaction succeeds, you will see the following output in the terminal: +Symmetric encryption is a branch of cryptography that isn't based on one-way functions, unlike asymmetric cryptography. It uses the same cryptographic key to encrypt plain text and decrypt the resulting ciphertext. - ![](/images/smart-contracts/cookbook/smart-contracts/deploy-erc20/deploy-erc20-14.webp) +Symmetric cryptography is a type of encryption that has been used throughout history, such as the Enigma Cipher and the Caesar Cipher. It is still widely used today and can be found in Web2 and Web3 applications alike. There is only one single key, and a recipient must also have access to it to access the contained information. -Other common functions you can use: +#### Advantages {: #symmetric-advantages } -- **`balanceOf(address)`**: Check token balance of any address. -- **`transfer(address to, uint256 amount)`**: Send tokens to another address. -- **`approve(address spender, uint256 amount)`**: Allow another address to spend your tokens. +- Fast and efficient for large amounts of data. +- Requires less computational power. -Feel free to explore and interact with the contract's other functions using the same approach - selecting the method, providing any required parameters, and confirming the transaction through Talisman when needed. +#### Disadvantages {: #symmetric-disadvantages } +- Key distribution can be challenging. +- Scalability issues in systems with many users. ---- +### Asymmetric Cryptography -Page Title: Deploy an NFT to Polkadot Hub with Ethers.js +Asymmetric encryption is a type of cryptography that uses two different keys, known as a keypair: a public key, used to encrypt plain text, and a private counterpart, used to decrypt the ciphertext. -- Source (raw): https://raw.githubusercontent.com/polkadot-developers/polkadot-docs/master/.ai/pages/smart-contracts-cookbook-smart-contracts-deploy-nft-ethers.md -- Canonical (HTML): https://docs.polkadot.com/smart-contracts/cookbook/smart-contracts/deploy-nft/ethers/ -- Summary: Learn how to deploy an ERC-721 NFT contract to Polkadot Hub using Ethers.js, giving you complete programmatic control over the deployment process. +The public key encrypts a fixed-length message that can only be decrypted with the recipient's private key and, sometimes, a set password. The public key can be used to cryptographically verify that the corresponding private key was used to create a piece of data without compromising the private key, such as with digital signatures. This has obvious implications for identity, ownership, and properties and is used in many different protocols across Web2 and Web3. -# Deploy an NFT with Ethers.js +#### Advantages {: #asymmetric-advantages } -## Introduction +- Solves the key distribution problem. +- Enables digital signatures and secure key exchange. -Non-Fungible Tokens (NFTs) represent unique digital assets commonly used for digital art, collectibles, gaming, and identity verification. +#### Disadvantages {: #asymmetric-disadvantages } -This guide demonstrates how to deploy an [ERC-721](https://eips.ethereum.org/EIPS/eip-721){target=\_blank} NFT contract to [Polkadot Hub](/smart-contracts/overview/#smart-contract-development){target=\_blank}. You'll use [OpenZeppelin's battle-tested NFT implementation](https://github.com/OpenZeppelin/openzeppelin-contracts){target=\_blank} and [Ethers.js](https://docs.ethers.org/v6/){target=\_blank}, a lightweight approach for deploying contracts in pure JavaScript. This method is ideal if you want programmatic control over the deployment process or need to integrate contract deployment into existing applications. +- Slower than symmetric encryption. +- Requires more computational resources. -## Prerequisites +### Trade-offs and Compromises -- Basic understanding of Solidity programming and NFT standards. -- Node.js v22.13.1 or later. -- Test tokens for gas fees (available from the [Polkadot faucet](https://faucet.polkadot.io/){target=\_blank}). See the [step-by-step instructions](/smart-contracts/faucet/#get-test-tokens){target=\_blank}. -- A wallet with a private key for signing transactions. +Symmetric cryptography is faster and requires fewer bits in the key to achieve the same level of security that asymmetric cryptography provides. However, it requires a shared secret before communication can occur, which poses issues to its integrity and a potential compromise point. On the other hand, asymmetric cryptography doesn't require the secret to be shared ahead of time, allowing for far better end-user security. -## Set Up Your Project +Hybrid symmetric and asymmetric cryptography is often used to overcome the engineering issues of asymmetric cryptography, as it is slower and requires more bits in the key to achieve the same level of security. It encrypts a key and then uses the comparatively lightweight symmetric cipher to do the "heavy lifting" with the message. -First, initialize your project and install dependencies: +## Digital Signatures -```bash -mkdir ethers-nft-deployment -cd ethers-nft-deployment -npm init -y -npm install ethers@6.15.0 solc@0.8.30 @openzeppelin/contracts@5.0.0 -``` +Digital signatures are a way of verifying the authenticity of a document or message using asymmetric keypairs. They are used to ensure that a sender or signer's document or message hasn't been tampered with in transit, and for recipients to verify that the data is accurate and from the expected sender. -## Create Your Contract +Signing digital signatures only requires a low-level understanding of mathematics and cryptography. For a conceptual example -- when signing a check, it is expected that it cannot be cashed multiple times. This isn't a feature of the signature system but rather the check serialization system. The bank will check that the serial number on the check hasn't already been used. Digital signatures essentially combine these two concepts, allowing the signature to provide the serialization via a unique cryptographic fingerprint that cannot be reproduced. -Create an NFT contract in `contracts/MyNFT.sol`: +Unlike pen-and-paper signatures, knowledge of a digital signature cannot be used to create other signatures. Digital signatures are often used in bureaucratic processes, as they are more secure than simply scanning in a signature and pasting it onto a document. -```solidity title="contracts/MyNFT.sol" -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.20; +Polkadot SDK provides multiple different cryptographic schemes and is generic so that it can support anything that implements the [`Pair` trait](https://paritytech.github.io/polkadot-sdk/master/sp_core/crypto/trait.Pair.html){target=\_blank}. -import "@openzeppelin/contracts/token/ERC721/ERC721.sol"; -import "@openzeppelin/contracts/access/Ownable.sol"; +### Example of Creating a Digital Signature -contract MyNFT is ERC721, Ownable { - uint256 private _nextTokenId; +The process of creating and verifying a digital signature involves several steps: - constructor(address initialOwner) - ERC721("MyToken", "MTK") - Ownable(initialOwner) - {} +1. The sender creates a hash of the message. +2. The hash is encrypted using the sender's private key, creating the signature. +3. The message and signature are sent to the recipient. +4. The recipient decrypts the signature using the sender's public key. +5. The recipient hashes the received message and compares it to the decrypted hash. - function safeMint(address to) public onlyOwner { - uint256 tokenId = _nextTokenId++; - _safeMint(to, tokenId); - } -} -``` +If the hashes match, the signature is valid, confirming the message's integrity and the sender's identity. -## Compile +## Elliptic Curve -Create a compilation script `compile.js`: +Blockchain technology requires the ability to have multiple keys creating a signature for block proposal and validation. To this end, Elliptic Curve Digital Signature Algorithm (ECDSA) and Schnorr signatures are two of the most commonly used methods. While ECDSA is a far simpler implementation, Schnorr signatures are more efficient when it comes to multi-signatures. -```javascript title="compile.js" -const fs = require('fs'); -const path = require('path'); -const solc = require('solc'); +Schnorr signatures bring some noticeable features over the ECDSA/EdDSA schemes: -const contractPath = path.join(__dirname, 'contracts', 'MyNFT.sol'); -const contractSource = fs.readFileSync(contractPath, 'utf8'); +- It is better for hierarchical deterministic key derivations. +- It allows for native multi-signature through [signature aggregation](https://bitcoincore.org/en/2017/03/23/schnorr-signature-aggregation/){target=\_blank}. +- It is generally more resistant to misuse. -function findImports(importPath) { - try { - const nodePath = path.join(__dirname, 'node_modules', importPath); - const contents = fs.readFileSync(nodePath, 'utf8'); - return { contents }; - } catch (error) { - return { error: 'File not found' }; - } -} +One sacrifice that is made when using Schnorr signatures over ECDSA is that both require 64 bytes, but only ECDSA signatures communicate their public key. -const input = { - language: 'Solidity', - sources: { - 'MyNFT.sol': { - content: contractSource - } - }, - settings: { - outputSelection: { - '*': { - '*': ['abi', 'evm.bytecode'] - } - }, - optimizer: { - enabled: true, - runs: 200 - } - } -}; +### Various Implementations -console.log('Compiling contract...'); +- **[ECDSA](https://en.wikipedia.org/wiki/Elliptic_Curve_Digital_Signature_Algorithm){target=\_blank}**: Polkadot SDK provides an ECDSA signature scheme using the [secp256k1](https://en.bitcoin.it/wiki/Secp256k1){target=\_blank} curve. This is the same cryptographic algorithm used to secure [Bitcoin](https://en.wikipedia.org/wiki/Bitcoin){target=\_blank} and [Ethereum](https://en.wikipedia.org/wiki/Ethereum){target=\_blank}. -const output = JSON.parse(solc.compile(JSON.stringify(input), { import: findImports })); +- **[Ed25519](https://en.wikipedia.org/wiki/EdDSA#Ed25519){target=\_blank}**: An EdDSA signature scheme using [Curve25519](https://en.wikipedia.org/wiki/Curve25519){target=\_blank}. It is carefully engineered at several levels of design and implementation to achieve very high speeds without compromising security. -if (output.errors) { - output.errors.forEach(error => { - console.error(error.formattedMessage); - }); - - const hasErrors = output.errors.some(error => error.severity === 'error'); - if (hasErrors) { - process.exit(1); - } -} +- **[SR25519](https://research.web3.foundation/Polkadot/security/keys/accounts-more){target=\_blank}**: Based on the same underlying curve as Ed25519. However, it uses Schnorr signatures instead of the EdDSA scheme. -const contractName = 'MyNFT'; -const contract = output.contracts['MyNFT.sol'][contractName]; -if (!contract) { - console.error('Contract not found in compilation output'); - process.exit(1); -} +--- -const buildPath = path.join(__dirname, 'build'); -if (!fs.existsSync(buildPath)) { - fs.mkdirSync(buildPath); -} +Page Title: Data Encoding -const abiPath = path.join(buildPath, `${contractName}_abi.json`); -fs.writeFileSync(abiPath, JSON.stringify(contract.abi, null, 2)); -console.log(`ABI saved to ${abiPath}`); +- Source (raw): https://raw.githubusercontent.com/polkadot-developers/polkadot-docs/master/.ai/pages/reference-parachains-data-encoding.md +- Canonical (HTML): https://docs.polkadot.com/reference/parachains/data-encoding/ +- Summary: SCALE codec enables fast, efficient data encoding, ideal for resource-constrained environments like Wasm, supporting custom types and compact encoding. -const bytecodePath = path.join(buildPath, `${contractName}_bytecode.txt`); -fs.writeFileSync(bytecodePath, contract.evm.bytecode.object); -console.log(`Bytecode saved to ${bytecodePath}`); +# Data Encoding -const artifactPath = path.join(buildPath, `${contractName}.json`); -const artifact = { - contractName: contractName, - abi: contract.abi, - bytecode: '0x' + contract.evm.bytecode.object -}; -fs.writeFileSync(artifactPath, JSON.stringify(artifact, null, 2)); -console.log(`Complete artifact saved to ${artifactPath}`); +## Introduction -console.log('\nCompilation successful!'); -``` +The Polkadot SDK uses a lightweight and efficient encoding/decoding mechanism to optimize data transmission across the network. This mechanism, known as the _SCALE_ codec, is used for serializing and deserializing data. -Run the compilation: +The SCALE codec enables communication between the runtime and the outer node. This mechanism is designed for high-performance, copy-free data encoding and decoding in resource-constrained environments like the Polkadot SDK [Wasm runtime](/develop/parachains/deployment/build-deterministic-runtime/#introduction){target=\_blank}. -```bash -node compile.js -``` +It is not self-describing, meaning the decoding context must fully know the encoded data types. -## Deploy +Parity's libraries utilize the [`parity-scale-codec`](https://github.com/paritytech/parity-scale-codec){target=\_blank} crate (a Rust implementation of the SCALE codec) to handle encoding and decoding for interactions between RPCs and the runtime. -Create a deployment script `deploy.js`: +The `codec` mechanism is ideal for Polkadot SDK-based chains because: -```javascript title="deploy.js" -const { ethers } = require('ethers'); -const fs = require('fs'); -const path = require('path'); +- It is lightweight compared to generic serialization frameworks like [`serde`](https://serde.rs/){target=\_blank}, which add unnecessary bulk to binaries. +- It doesn’t rely on Rust’s `libstd`, making it compatible with `no_std` environments like Wasm runtime. +- It integrates seamlessly with Rust, allowing easy derivation of encoding and decoding logic for new types using `#[derive(Encode, Decode)]`. -const providerConfig = { - rpc: 'https://testnet-passet-hub-eth-rpc.polkadot.io', - chainId: 420420422, - name: 'polkadot-hub-testnet', -}; +Defining a custom encoding scheme in the Polkadot SDK-based chains, rather than using an existing Rust codec library, is crucial for enabling cross-platform and multi-language support. -const mnemonic = 'INSERT_MNEMONIC'; -const initialOwner = 'INSERT_OWNER_ADDRESS'; +## SCALE Codec -async function deployContract(contractName, mnemonic, initialOwner, providerConfig) { - try { - console.log(`\nStarting deployment of ${contractName}...`); - - const artifactPath = path.join(__dirname, 'build', `${contractName}.json`); - if (!fs.existsSync(artifactPath)) { - throw new Error(`Contract artifact not found at ${artifactPath}. Please run compile.js first.`); - } - - const artifact = JSON.parse(fs.readFileSync(artifactPath, 'utf8')); - - console.log(`Connecting to ${providerConfig.name}...`); - const provider = new ethers.JsonRpcProvider(providerConfig.rpc, { - chainId: providerConfig.chainId, - name: providerConfig.name - }); - - const wallet = ethers.Wallet.fromPhrase(mnemonic); - const signer = wallet.connect(provider); - - console.log(`Deploying from address: ${signer.address}`); - - const balance = await provider.getBalance(signer.address); - console.log(`Account balance: ${ethers.formatEther(balance)} ETH`); - - if (balance === 0n) { - throw new Error('Insufficient balance for deployment'); - } - - const factory = new ethers.ContractFactory(artifact.abi, artifact.bytecode, signer); - - console.log(`\nDeploying contract with initialOwner: ${initialOwner}...`); - const contract = await factory.deploy(initialOwner); - - console.log(`Waiting for deployment transaction: ${contract.target}...`); - await contract.waitForDeployment(); - - const contractAddress = await contract.getAddress(); - - console.log(`\n${contractName} deployed successfully!`); - console.log(`Contract address: ${contractAddress}`); - console.log(`Transaction hash: ${contract.deploymentTransaction().hash}`); - - const deploymentInfo = { - contractName: contractName, - address: contractAddress, - deployer: signer.address, - initialOwner: initialOwner, - network: providerConfig.name, - chainId: providerConfig.chainId, - transactionHash: contract.deploymentTransaction().hash, - deployedAt: new Date().toISOString() - }; - - const deploymentPath = path.join(__dirname, 'build', `${contractName}_deployment.json`); - fs.writeFileSync(deploymentPath, JSON.stringify(deploymentInfo, null, 2)); - console.log(`Deployment info saved to ${deploymentPath}`); - - return contract; - - } catch (error) { - console.error(`\nDeployment failed: ${error.message}`); - throw error; - } -} +The codec is implemented using the following traits: -deployContract('MyNFT', mnemonic, initialOwner, providerConfig) - .then(() => { - console.log('\nDeployment completed successfully!'); - process.exit(0); - }) - .catch((error) => { - console.error('\nDeployment error:', error); - process.exit(1); - }); +- [`Encode`](#encode) +- [`Decode`](#decode) +- [`CompactAs`](#compactas) +- [`HasCompact`](#hascompact) +- [`EncodeLike`](#encodelike) -``` +### Encode -Replace the `INSERT_MNEMONIC` and `INSERT_OWNER_ADDRESS` placeholders with your actual mnemonic and desired owner address. +The [`Encode`](https://docs.rs/parity-scale-codec/latest/parity_scale_codec/trait.Encode.html){target=\_blank} trait handles data encoding into SCALE format and includes the following key functions: -!!! warning - Never embed private keys, mnemonic phrases, or security-sensitive credentials directly into your JavaScript, TypeScript, or any front-end/client-side files. +- **`size_hint(&self) -> usize`**: Estimates the number of bytes required for encoding to prevent multiple memory allocations. This should be inexpensive and avoid complex operations. Optional if the size isn’t known. +- **`encode_to(&self, dest: &mut T)`**: Encodes the data, appending it to a destination buffer. +- **`encode(&self) -> Vec`**: Encodes the data and returns it as a byte vector. +- **`using_encoded R>(&self, f: F) -> R`**: Encodes the data and passes it to a closure, returning the result. +- **`encoded_size(&self) -> usize`**: Calculates the encoded size. Should be used when the encoded data isn’t required. -Execute the deployment: +!!!tip + For best performance, value types should override `using_encoded`, and allocating types should override `encode_to`. It's recommended to implement `size_hint` for all types where possible. -```bash -node deploy.js -``` +### Decode -## Where to Go Next +The [`Decode`](https://docs.rs/parity-scale-codec/latest/parity_scale_codec/trait.Decode.html){target=\_blank} trait handles decoding SCALE-encoded data back into the appropriate types: -
+- **`fn decode(value: &mut I) -> Result`**: Decodes data from the SCALE format, returning an error if decoding fails. -- Guide __Deploy an ERC-20__ +### CompactAs - --- +The [`CompactAs`](https://docs.rs/parity-scale-codec/latest/parity_scale_codec/trait.CompactAs.html){target=\_blank} trait wraps custom types for compact encoding: - Walk through deploying a fully-functional ERC-20 to the Polkadot Hub using Ethers.js. +- **`encode_as(&self) -> &Self::As`**: Encodes the type as a compact type. +- **`decode_from(_: Self::As) -> Result`**: decodes from a compact encoded type. - [:octicons-arrow-right-24: Get Started](/smart-contracts/cookbook/smart-contracts/deploy-erc20/ethers/) +### HasCompact -
+The [`HasCompact`](https://docs.rs/parity-scale-codec/latest/parity_scale_codec/trait.HasCompact.html){target=\_blank} trait indicates a type supports compact encoding. +### EncodeLike ---- +The [`EncodeLike`](https://docs.rs/parity-scale-codec/latest/parity_scale_codec/trait.EncodeLike.html){target=\_blank} trait is used to ensure multiple types that encode similarly are accepted by the same function. When using `derive`, it is automatically implemented. -Page Title: Deploy an NFT to Polkadot Hub with Foundry +### Data Types -- Source (raw): https://raw.githubusercontent.com/polkadot-developers/polkadot-docs/master/.ai/pages/smart-contracts-cookbook-smart-contracts-deploy-nft-foundry.md -- Canonical (HTML): https://docs.polkadot.com/smart-contracts/cookbook/smart-contracts/deploy-nft/foundry/ -- Summary: Learn how to deploy an ERC-721 NFT contract to Polkadot Hub using Foundry, a Rust toolkit with high-performance compilation. +The table below outlines how the Rust implementation of the Parity SCALE codec encodes different data types. -# Deploy an NFT with Foundry +| Type | Description | Example SCALE Decoded Value | SCALE Encoded Value | +|-------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------|-------------------------------------------------------------------------| +| Boolean | Boolean values are encoded using the least significant bit of a single byte. | `false` / `true` | `0x00` / `0x01` | +| Compact/general integers | A "compact" or general integer encoding is sufficient for encoding large integers (up to 2^536) and is more efficient at encoding most values than the fixed-width version. | `unsigned integer 0` / `unsigned integer 1` / `unsigned integer 42` / `unsigned integer 69` / `unsigned integer 65535` / `BigInt(100000000000000)` | `0x00` / `0x04` / `0xa8` / `0x1501` / `0xfeff0300` / `0x0b00407a10f35a` | +| Enumerations (tagged-unions) | A fixed number of variants, each mutually exclusive and potentially implying a further value or series of values. Encoded as the first byte identifying the index of the variant that the value is. Any further bytes are used to encode any data that the variant implies. Thus, no more than 256 variants are supported. | `Int(42)` and `Bool(true)` where `enum IntOrBool { Int(u8), Bool(bool) }` | `0x002a` and `0x0101` | +| Fixed-width integers | Basic integers are encoded using a fixed-width little-endian (LE) format. | `signed 8-bit integer 69` / `unsigned 16-bit integer 42` / `unsigned 32-bit integer 16777215` | `0x45` / `0x2a00` / `0xffffff00` | +| Options | One or zero values of a particular type. | `Some` / `None` | `0x01` followed by the encoded value / `0x00` | +| Results | Results are commonly used enumerations which indicate whether certain operations were successful or unsuccessful. | `Ok(42)` / `Err(false)` | `0x002a` / `0x0100` | +| Strings | Strings are Vectors of bytes (Vec) containing a valid UTF8 sequence. | | | +| Structs | For structures, the values are named, but that is irrelevant for the encoding (names are ignored - only order matters). | `SortedVecAsc::from([3, 5, 2, 8])` | `[3, 2, 5, 8] ` | +| Tuples | A fixed-size series of values, each with a possibly different but predetermined and fixed type. This is simply the concatenation of each encoded value. | Tuple of compact unsigned integer and boolean: `(3, false)` | `0x0c00` | +| Vectors (lists, series, sets) | A collection of same-typed values is encoded, prefixed with a compact encoding of the number of items, followed by each item's encoding concatenated in turn. | Vector of unsigned `16`-bit integers: `[4, 8, 15, 16, 23, 42]` | `0x18040008000f00100017002a00` | -## Introduction +## Encode and Decode Rust Trait Implementations -Non-Fungible Tokens (NFTs) represent unique digital assets commonly used for digital art, collectibles, gaming, and identity verification. +Here's how the `Encode` and `Decode` traits are implemented: -This guide demonstrates how to deploy an [ERC-721](https://eips.ethereum.org/EIPS/eip-721){target=\_blank} NFT contract to [Polkadot Hub](/smart-contracts/overview/#smart-contract-development){target=\_blank}. It showcases a secure approach using [OpenZeppelin's battle-tested NFT implementation](https://github.com/OpenZeppelin/openzeppelin-contracts){target=\_blank} and the [Foundry](https://getfoundry.sh/){target=\_blank} toolchain. Foundry, a fast, Rust-written toolkit, ensures high-performance compilation and is fully compatible with the Hub’s EVM environment via standard Solidity compilation. -## Prerequisites +```rust +use parity_scale_codec::{Encode, Decode}; -- Basic understanding of Solidity programming and NFT standards. -- Test tokens for gas fees (available from the [Polkadot faucet](https://faucet.polkadot.io/){target=\_blank}). See the [step-by-step instructions](/smart-contracts/faucet/#get-test-tokens){target=\_blank}. -- A wallet with a private key for signing transactions. +[derive(Debug, PartialEq, Encode, Decode)] +enum EnumType { + #[codec(index = 15)] + A, + B(u32, u64), + C { + a: u32, + b: u64, + }, +} -## Set Up Your Project +let a = EnumType::A; +let b = EnumType::B(1, 2); +let c = EnumType::C { a: 1, b: 2 }; -To get started, take the following steps: +a.using_encoded(|ref slice| { + assert_eq!(slice, &b"\x0f"); +}); -1. Install Foundry: +b.using_encoded(|ref slice| { + assert_eq!(slice, &b"\x01\x01\0\0\0\x02\0\0\0\0\0\0\0"); +}); - ```bash - curl -L https://foundry.paradigm.xyz | bash - foundryup - ``` +c.using_encoded(|ref slice| { + assert_eq!(slice, &b"\x02\x01\0\0\0\x02\0\0\0\0\0\0\0"); +}); -2. Initialize your project: +let mut da: &[u8] = b"\x0f"; +assert_eq!(EnumType::decode(&mut da).ok(), Some(a)); - ```bash - forge init foundry-nft-deployment - cd foundry-nft-deployment - ``` +let mut db: &[u8] = b"\x01\x01\0\0\0\x02\0\0\0\0\0\0\0"; +assert_eq!(EnumType::decode(&mut db).ok(), Some(b)); -3. Install OpenZeppelin contracts: +let mut dc: &[u8] = b"\x02\x01\0\0\0\x02\0\0\0\0\0\0\0"; +assert_eq!(EnumType::decode(&mut dc).ok(), Some(c)); - ```bash - forge install OpenZeppelin/openzeppelin-contracts - ``` +let mut dz: &[u8] = &[0]; +assert_eq!(EnumType::decode(&mut dz).ok(), None); +``` -## Configure Foundry +## SCALE Codec Libraries -Edit `foundry.toml`: +Several SCALE codec implementations are available in various languages. Here's a list of them: -```toml title="foundry.toml" -[profile.default] -src = "src" -out = "out" -libs = ["lib"] -remappings = ['@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/'] +- **AssemblyScript**: [`LimeChain/as-scale-codec`](https://github.com/LimeChain/as-scale-codec){target=\_blank} +- **C**: [`MatthewDarnell/cScale`](https://github.com/MatthewDarnell/cScale){target=\_blank} +- **C++**: [`qdrvm/scale-codec-cpp`](https://github.com/qdrvm/scale-codec-cpp){target=\_blank} +- **JavaScript**: [`polkadot-js/api`](https://github.com/polkadot-js/api){target=\_blank} +- **Dart**: [`leonardocustodio/polkadart`](https://github.com/leonardocustodio/polkadart){target=\_blank} +- **Haskell**: [`airalab/hs-web3`](https://github.com/airalab/hs-web3/tree/master/packages/scale){target=\_blank} +- **Golang**: [`itering/scale.go`](https://github.com/itering/scale.go){target=\_blank} +- **Java**: [`splix/polkaj`](https://github.com/splix/polkaj){target=\_blank} +- **Python**: [`polkascan/py-scale-codec`](https://github.com/polkascan/py-scale-codec){target=\_blank} +- **Ruby**: [` wuminzhe/scale_rb`](https://github.com/wuminzhe/scale_rb){target=\_blank} +- **TypeScript**: [`parity-scale-codec-ts`](https://github.com/tjjfvi/subshape){target=\_blank}, [`scale-ts`](https://github.com/unstoppablejs/unstoppablejs/tree/main/packages/scale-ts#scale-ts){target=\_blank}, [`soramitsu/scale-codec-js-library`](https://github.com/soramitsu/scale-codec-js-library){target=\_blank}, [`subsquid/scale-codec`](https://github.com/subsquid/squid-sdk/tree/master/substrate/scale-codec){target=\_blank} -[rpc_endpoints] -polkadot_hub_testnet = "https://testnet-passet-hub-eth-rpc.polkadot.io" -``` -## Create Your Contract +--- -Create `src/MyNFT.sol`: +Page Title: Deploy an ERC-20 to Polkadot Hub -```solidity title="src/MyNFT.sol" -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.20; +- Source (raw): https://raw.githubusercontent.com/polkadot-developers/polkadot-docs/master/.ai/pages/smart-contracts-cookbook-smart-contracts-deploy-erc20-erc20-remix.md +- Canonical (HTML): https://docs.polkadot.com/smart-contracts/cookbook/smart-contracts/deploy-erc20/erc20-remix/ +- Summary: Deploy an ERC-20 token contract on Polkadot Hub. This guide covers contract creation, compilation, deployment, and interaction via the Remix IDE. -import "@openzeppelin/contracts/token/ERC721/ERC721.sol"; -import "@openzeppelin/contracts/access/Ownable.sol"; +# Deploy an ERC-20 to Polkadot Hub -contract MyNFT is ERC721, Ownable { - uint256 private _nextTokenId; +## Introduction - constructor(address initialOwner) - ERC721("MyToken", "MTK") - Ownable(initialOwner) - {} +[ERC-20](https://eips.ethereum.org/EIPS/eip-20){target=\_blank} tokens are fungible tokens commonly used for creating cryptocurrencies, governance tokens, and staking mechanisms. Polkadot Hub enables easy token deployment with Ethereum-compatible smart contracts and tools via the EVM backend. - function safeMint(address to) public onlyOwner { - uint256 tokenId = _nextTokenId++; - _safeMint(to, tokenId); - } -} -``` +This tutorial covers deploying an ERC-20 contract on the Polkadot Hub TestNet using [Remix IDE](https://remix.ethereum.org/){target=\_blank}, a web-based development tool. The ERC-20 contract can be retrieved from OpenZeppelin's [GitHub repository](https://github.com/OpenZeppelin/openzeppelin-contracts/tree/v5.4.0/contracts/token/ERC20){target=\_blank} or their [Contract Wizard](https://wizard.openzeppelin.com/){target=\_blank}. -## Compile +## Prerequisites -```bash -forge build -``` +Before starting, make sure you have: -Verify the compilation by inspecting the bytecode: +- An EVM-compatible wallet [connected to Polkadot Hub](/smart-contracts/integrations/wallets){target=\_blank}. This example utilizes [MetaMask](https://metamask.io/){target=\_blank}. +- A funded account with tokens for transaction fees. This example will deploy the contract to the Polkadot TestNet, so you'll [need some TestNet tokens](/smart-contracts/faucet/#get-test-tokens){target=\_blank} from the [Polkadot Faucet](https://faucet.polkadot.io/?parachain=1111){target=\_blank}. +- Basic understanding of Solidity and fungible tokens. -```bash -forge inspect MyNFT bytecode -``` +## Create Your Contract -## Deploy +To create the ERC-20 contract, you can follow the steps below: -Deploy to Polkadot Hub TestNet: +1. Navigate to the [Polkadot Remix IDE](https://remix.polkadot.io){target=\_blank}. +2. Click in the **Create new file** button under the **contracts** folder, and name your contract as `MyToken.sol`. -```bash -forge create MyNFT \ - --rpc-url polkadot_hub_testnet \ - --private-key YOUR_PRIVATE_KEY \ - --constructor-args YOUR_OWNER_ADDRESS \ - --broadcast -``` + ![](/images/smart-contracts/cookbook/smart-contracts/deploy-erc20/erc20-remix-1.webp) -Replace `YOUR_PRIVATE_KEY` with your private key and `YOUR_OWNER_ADDRESS` with the address that will own the NFT contract. +3. Now, paste the following ERC-20 contract code into the editor: -## Where to Go Next + ```solidity title="MyToken.sol" + // SPDX-License-Identifier: MIT + // Compatible with OpenZeppelin Contracts ^5.4.0 + pragma solidity ^0.8.27; -
+ import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; + import {ERC20Permit} from "@openzeppelin/contracts/token/ERC20/extensions/ERC20Permit.sol"; + import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol"; -- Guide __Verify Your Contract__ + contract MyToken is ERC20, Ownable, ERC20Permit { + constructor(address initialOwner) + ERC20("MyToken", "MTK") + Ownable(initialOwner) + ERC20Permit("MyToken") + {} - --- + function mint(address to, uint256 amount) public onlyOwner { + _mint(to, amount); + } + } + ``` - Now that you've deployed an NFT contract, learn how to verify it with Foundry. + The key components of the code above are: - [:octicons-arrow-right-24: Get Started](/smart-contracts/dev-environments/foundry/verify-a-contract/) + - Contract imports: -- Guide __Deploy an ERC-20__ + - **[`ERC20.sol`](https://github.com/OpenZeppelin/openzeppelin-contracts/tree/v5.4.0/contracts/token/ERC20/ERC20.sol){target=\_blank}**: The base contract for fungible tokens, implementing core functionality like transfers, approvals, and balance tracking. + - **[`ERC20Permit.sol`](https://github.com/OpenZeppelin/openzeppelin-contracts/tree/v5.4.0/contracts/token/ERC20/extensions/ERC20Permit.sol){target=\_blank}**: [EIP-2612](https://eips.ethereum.org/EIPS/eip-2612){target=\_blank} extension for ERC-20 that adds the [permit function](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20#ERC20Permit-permit-address-address-uint256-uint256-uint8-bytes32-bytes32-){target=\_blank}, allowing approvals via off-chain signatures (no on-chain tx from the holder). Manages nonces and EIP-712 domain separator and updates allowances when a valid signature is presented. + - **[`Ownable.sol`](https://github.com/OpenZeppelin/openzeppelin-contracts/tree/v5.4.0/contracts/access/Ownable.sol){target=\_blank}**: Provides basic authorization control, ensuring only the contract owner can mint new tokens. + + - Constructor parameters: - --- + - **`initialOwner`**: Sets the address that will have administrative rights over the contract. + - **`"MyToken"`**: The full name of your token. + - **`"MTK"`**: The symbol representing your token in wallets and exchanges. - Walk through deploying a fully-functional ERC-20 to the Polkadot Hub using Foundry. + - Key functions: - [:octicons-arrow-right-24: Get Started](/smart-contracts/cookbook/smart-contracts/deploy-erc20/foundry/) + - **`mint(address to, uint256 amount)`**: Allows the contract owner to create new tokens for any address. The amount should include 18 decimals (e.g., 1 token = 1000000000000000000). + - Inherited [Standard ERC-20](https://ethereum.org/en/developers/docs/standards/tokens/erc-20/){target=\_blank} functions: + - **`transfer(address recipient, uint256 amount)`**: Sends a specified amount of tokens to another address. + - **`approve(address spender, uint256 amount)`**: Grants permission for another address to spend a specific number of tokens on behalf of the token owner. + - **`transferFrom(address sender, address recipient, uint256 amount)`**: Transfers tokens from one address to another, if previously approved. + - **`balanceOf(address account)`**: Returns the token balance of a specific address. + - **`allowance(address owner, address spender)`**: Checks how many tokens an address is allowed to spend on behalf of another address. -
+ !!! tip + Use the [OpenZeppelin Contracts Wizard](https://wizard.openzeppelin.com/){target=\_blank} to generate customized smart contracts quickly. Simply configure your contract, copy the generated code, and paste it into the Remix IDE for deployment. Below is an example of an ERC-20 token contract created with it: + ![Screenshot of the OpenZeppelin Contracts Wizard showing an ERC-20 contract configuration.](/images/smart-contracts/cookbook/smart-contracts/deploy-erc20/erc20-remix-2.webp) + ---- +## Compile -Page Title: Deploy an NFT to Polkadot Hub with Hardhat +The compilation transforms your Solidity source code into bytecode that can be deployed on the blockchain. During this process, the compiler checks your contract for syntax errors, ensures type safety, and generates the machine-readable instructions needed for blockchain execution. -- Source (raw): https://raw.githubusercontent.com/polkadot-developers/polkadot-docs/master/.ai/pages/smart-contracts-cookbook-smart-contracts-deploy-nft-hardhat.md -- Canonical (HTML): https://docs.polkadot.com/smart-contracts/cookbook/smart-contracts/deploy-nft/hardhat/ -- Summary: Learn how to deploy an ERC-721 NFT contract to Polkadot Hub with Hardhat, a comprehenive development environment with built-in deployment capabilities. +To compile your contract, ensure you have it opened in the Remix IDE Editor, and follow the instructions below: -# Deploy an NFT with Hardhat +1. Select the **Solidity Compiler** plugin from the left panel. +2. Click the **Compile MyToken.sol** button. +3. If the compilation succeeded, you'll see a green checkmark indicating success in the **Solidity Compiler** icon. -## Introduction +![](/images/smart-contracts/cookbook/smart-contracts/deploy-erc20/erc20-remix-3.gif) -Non-Fungible Tokens (NFTs) represent unique digital assets commonly used for digital art, collectibles, gaming, and identity verification. +## Deploy -This guide demonstrates how to deploy an [ERC-721](https://eips.ethereum.org/EIPS/eip-721){target=\_blank} NFT contract to [Polkadot Hub](/smart-contracts/overview/#smart-contract-development){target=\_blank}. You'll use [OpenZeppelin's battle-tested NFT implementation](https://github.com/OpenZeppelin/openzeppelin-contracts){target=\_blank} and [Hardhat](https://hardhat.org/docs/getting-started){target=\_blank}, a comprehensive development environment with built-in testing, debugging, and deployment capabilities. Hardhat uses standard Solidity compilation to generate EVM bytecode, making it fully compatible with Polkadot Hub's EVM environment. +Deployment is the process of publishing your compiled smart contract to the blockchain, making it permanently available for interaction. During deployment, you'll create a new instance of your contract on the blockchain, which involves: -## Prerequisites +1. Select the **Deploy & Run Transactions** plugin from the left panel. +2. Configure the deployment settings: + 1. From the **ENVIRONMENT** dropdown, select **Injected Provider - MetaMask** (check the [Deploying Contracts](/smart-contracts/dev-environments/remix/deploy-a-contract/){target=\_blank} section of the Remix IDE guide for more details). + 2. (Optional) From the **ACCOUNT** dropdown, select the acccount you want to use for the deploy. -- Basic understanding of Solidity programming and NFT standards. -- Node.js v22.13.1 or later. -- Test tokens for gas fees (available from the [Polkadot faucet](https://faucet.polkadot.io/){target=\_blank}). See the [step-by-step instructions](/smart-contracts/faucet/#get-test-tokens){target=\_blank}. -- A wallet with a private key for signing transactions. +3. Configure the contract parameters: + 1. Enter the address that will own the deployed token contract. + 2. Click the **Deploy** button to initiate the deployment. -## Set Up Your Project +4. **MetaMask will pop up**: Review the transaction details. Click **Confirm** to deploy your contract. +5. If the deployment process succeeded, you will see the transaction details in the terminal, including the contract address and deployment transaction hash. -Take the following steps to get started: +![](/images/smart-contracts/cookbook/smart-contracts/deploy-erc20/erc20-remix-4.gif) -1. Initialize your Hardhat project: +## Interact with Your Contract - ```bash - mkdir hardhat-nft-deployment - cd hardhat-nft-deployment - npx hardhat --init - ``` +Once deployed, you can interact with your contract through Remix. Find your contract under **Deployed/Unpinned Contracts**, and click it to expand the available methods. In this example, you'll mint some tokens to a given address: -2. Install OpenZeppelin contracts: +1. Expand the **mint** function: + 1. Enter the recipient address and the amount (remember to add 18 zeros for 1 whole token). + 2. Click **transact**. - ```bash - npm install @openzeppelin/contracts - ``` +2. Click **Approve** to confirm the transaction in the MetaMask popup. -## Configure Hardhat +3. If the transaction succeeds, you will see a green check mark in the terminal. -Edit `hardhat.config.ts`: +4. You can also call the **balanceOf** function by passing the address of the **mint** call to confirm the new balance. -```typescript title="hardhat.config.ts" -import type { HardhatUserConfig } from 'hardhat/config'; +![](/images/smart-contracts/cookbook/smart-contracts/deploy-erc20/erc20-remix-5.gif) -import hardhatToolboxViemPlugin from '@nomicfoundation/hardhat-toolbox-viem'; -import { configVariable } from 'hardhat/config'; -const config: HardhatUserConfig = { - plugins: [hardhatToolboxViemPlugin], - solidity: { - profiles: { - default: { - version: '0.8.28', - }, - production: { - version: '0.8.28', - settings: { - optimizer: { - enabled: true, - runs: 200, - }, - }, - }, - }, - }, - networks: { - hardhatMainnet: { - type: 'edr-simulated', - chainType: 'l1', - }, - hardhatOp: { - type: 'edr-simulated', - chainType: 'op', - }, - sepolia: { - type: 'http', - chainType: 'l1', - url: configVariable('SEPOLIA_RPC_URL'), - accounts: [configVariable('SEPOLIA_PRIVATE_KEY')], - }, - polkadotHubTestnet: { - type: 'http', - url: 'https://testnet-passet-hub-eth-rpc.polkadot.io', - chainId: 420420422, - accounts: [configVariable('PRIVATE_KEY')], - }, - }, -}; +Other standard functions you can use: -export default config; -``` +- **`transfer(address to, uint256 amount)`**: Send tokens to another address. +- **`approve(address spender, uint256 amount)`**: Allow another address to spend your tokens. -!!! tip - Learn how to use Hardhat's [Config Variables](https://hardhat.org/docs/learn-more/configuration-variables){target=\_blank} to handle your private keys in a secure way. +Feel free to explore and interact with the contract's other functions using the same approach: select the method, provide any required parameters, and confirm the transaction in MetaMask when needed. -## Create Your Contract +## Where to Go Next -Create `contracts/MyNFT.sol`: +
-```solidity title="contracts/MyNFT.sol" -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.20; +- Guide __Deploy an NFT with Remix__ -import "@openzeppelin/contracts/token/ERC721/ERC721.sol"; -import "@openzeppelin/contracts/access/Ownable.sol"; + --- -contract MyNFT is ERC721, Ownable { - uint256 private _nextTokenId; + Walk through deploying an ERC-721 Non-Fungible Token (NFT) using OpenZeppelin's battle-tested NFT implementation and Remix. - constructor(address initialOwner) - ERC721("MyToken", "MTK") - Ownable(initialOwner) - {} + [:octicons-arrow-right-24: Get Started](/smart-contracts/cookbook/smart-contracts/deploy-nft/remix/) - function safeMint(address to) public onlyOwner { - uint256 tokenId = _nextTokenId++; - _safeMint(to, tokenId); - } -} -``` +
-## Compile -```bash -npx hardhat compile -``` +--- -## Set Up Deployment +Page Title: Deploy an ERC-20 to Polkadot Hub -Create a deployment module in `ignition/modules/MyNFT.ts`: +- Source (raw): https://raw.githubusercontent.com/polkadot-developers/polkadot-docs/master/.ai/pages/smart-contracts-cookbook-smart-contracts-deploy-erc20.md +- Canonical (HTML): https://docs.polkadot.com/smart-contracts/cookbook/smart-contracts/deploy-erc20/ +- Summary: Deploy an ERC-20 token on Polkadot Hub using PolkaVM. This guide covers contract creation, compilation, deployment, and interaction via Polkadot Remix IDE. -```typescript title="ignition/modules/MyNFT.ts" -import { buildModule } from '@nomicfoundation/hardhat-ignition/modules'; +# Deploy an ERC-20 to Polkadot Hub -export default buildModule('MyNFTModule', (m) => { - const initialOwner = m.getParameter('initialOwner', 'INSERT_OWNER_ADDRESS'); - const myNFT = m.contract('MyNFT', [initialOwner]); - return { myNFT }; -}); -``` +!!! smartcontract "PolkaVM Preview Release" + PolkaVM smart contracts with Ethereum compatibility are in **early-stage development and may be unstable or incomplete**. +## Introduction -Replace `INSERT_OWNER_ADDRESS` with your desired owner address. +[ERC-20](https://eips.ethereum.org/EIPS/eip-20){target=\_blank} tokens are fungible tokens commonly used for creating cryptocurrencies, governance tokens, and staking mechanisms. Polkadot Hub enables easy token deployment with Ethereum-compatible smart contracts via PolkaVM. -## Deploy - -Deploy to Polkadot Hub TestNet: - -```bash -npx hardhat ignition deploy ignition/modules/MyNFT.ts --network polkadotHubTestnet -``` +This tutorial covers deploying an ERC-20 contract on the Polkadot Hub TestNet using [Polkadot Remix IDE](https://remix.polkadot.io){target=\_blank}, a web-based development tool. [OpenZeppelin's ERC-20 contracts](https://github.com/OpenZeppelin/openzeppelin-contracts/tree/v5.4.0/contracts/token/ERC20){target=\_blank} are used for security and compliance. -## Where to Go Next +## Prerequisites -
+Before starting, make sure you have: -- Guide __Verify Your Contract__ +- [MetaMask](https://metamask.io/){target=\_blank} installed and connected to Polkadot Hub. For detailed instructions, see the [Connect Your Wallet](/smart-contracts/integrations/wallets){target=\_blank} section. +- A funded account with some PAS tokens (you can get them from the [Polkadot Faucet](https://faucet.polkadot.io/?parachain=1111){target=\_blank}). To learn how to get test tokens, check out the [Test Tokens](/smart-contracts/connect/#test-tokens){target=\_blank} section. +- Basic understanding of Solidity and fungible tokens. - --- +## Create the ERC-20 Contract - Now that you've deployed an NFT contract, learn how to verify it with Hardhat. +To create the ERC-20 contract, you can follow the steps below: - [:octicons-arrow-right-24: Get Started](/smart-contracts/dev-environments/hardhat/verify-a-contract/) +1. Navigate to the [Polkadot Remix IDE](https://remix.polkadot.io){target=\_blank}. +2. Click in the **Create new file** button under the **contracts** folder, and name your contract as `MyToken.sol`. + ![](/images/smart-contracts/cookbook/smart-contracts/deploy-erc20/deploy-erc20-1.webp) -- Guide __Deploy an ERC-20__ +3. Now, paste the following ERC-20 contract code into the editor: - --- + ```solidity title="MyToken.sol" + // SPDX-License-Identifier: MIT + // Compatible with OpenZeppelin Contracts ^5.0.0 + pragma solidity ^0.8.22; - Walk through deploying a fully-functional ERC-20 to the Polkadot Hub using Hardhat. + import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; + import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol"; - [:octicons-arrow-right-24: Get Started](/smart-contracts/cookbook/smart-contracts/deploy-erc20/hardhat/) + contract MyToken is ERC20, Ownable { + constructor(address initialOwner) + ERC20("MyToken", "MTK") + Ownable(initialOwner) + {} -
+ function mint(address to, uint256 amount) public onlyOwner { + _mint(to, amount); + } + } + ``` + The key components of the code above are: ---- + - Contract imports: -Page Title: Deploy an NFT to Polkadot Hub with Remix + - **[`ERC20.sol`](https://github.com/OpenZeppelin/openzeppelin-contracts/tree/v5.4.0/contracts/token/ERC20/ERC20.sol){target=\_blank}**: The base contract for fungible tokens, implementing core functionality like transfers, approvals, and balance tracking. + - **[`Ownable.sol`](https://github.com/OpenZeppelin/openzeppelin-contracts/tree/v5.4.0/contracts/access/Ownable.sol){target=\_blank}**: Provides basic authorization control, ensuring only the contract owner can mint new tokens. + + - Constructor parameters: -- Source (raw): https://raw.githubusercontent.com/polkadot-developers/polkadot-docs/master/.ai/pages/smart-contracts-cookbook-smart-contracts-deploy-nft-remix.md -- Canonical (HTML): https://docs.polkadot.com/smart-contracts/cookbook/smart-contracts/deploy-nft/remix/ -- Summary: Learn how to deploy an ERC-721 NFT contract to Polkadot Hub using Remix, a browser-based IDE for quick prototyping and learning. + - **`initialOwner`**: Sets the address that will have administrative rights over the contract. + - **`"MyToken"`**: The full name of your token. + - **`"MTK"`**: The symbol representing your token in wallets and exchanges. -# Deploy an NFT with Remix + - Key functions: -## Introduction + - **`mint(address to, uint256 amount)`**: Allows the contract owner to create new tokens for any address. The amount should include 18 decimals (e.g., 1 token = 1000000000000000000). + - Inherited [Standard ERC-20](https://ethereum.org/en/developers/docs/standards/tokens/erc-20/){target=\_blank} functions: + - **`transfer(address recipient, uint256 amount)`**: Sends a specified amount of tokens to another address. + - **`approve(address spender, uint256 amount)`**: Grants permission for another address to spend a specific number of tokens on behalf of the token owner. + - **`transferFrom(address sender, address recipient, uint256 amount)`**: Transfers tokens from one address to another, if previously approved. + - **`balanceOf(address account)`**: Returns the token balance of a specific address. + - **`allowance(address owner, address spender)`**: Checks how many tokens an address is allowed to spend on behalf of another address. -Non-Fungible Tokens (NFTs) represent unique digital assets commonly used for digital art, collectibles, gaming, and identity verification. + !!! tip + Use the [OpenZeppelin Contracts Wizard](https://wizard.openzeppelin.com/){target=\_blank} to quickly generate customized smart contracts. Simply configure your contract, copy the generated code, and paste it into Polkadot Remix IDE for deployment. Below is an example of an ERC-20 token contract created with it: -This guide demonstrates how to deploy an [ERC-721](https://eips.ethereum.org/EIPS/eip-721){target=\_blank} NFT contract to [Polkadot Hub](/smart-contracts/overview/#smart-contract-development){target=\_blank}. You'll use [OpenZeppelin's battle-tested NFT implementation](https://github.com/OpenZeppelin/openzeppelin-contracts){target=\_blank} and [Remix](https://remix.ethereum.org/){target=\_blank}, a visual, browser-based environment perfect for rapid prototyping and learning. It requires no local installation and provides an intuitive interface for contract development. + ![Screenshot of the OpenZeppelin Contracts Wizard showing an ERC-20 contract configuration.](/images/smart-contracts/cookbook/smart-contracts/deploy-erc20/deploy-erc20-2.webp) + -## Prerequisites +## Compile the Contract -- Basic understanding of Solidity programming and NFT standards. -- Test tokens for gas fees (available from the [Polkadot faucet](https://faucet.polkadot.io/){target=\_blank}). See the [step-by-step instructions](/smart-contracts/faucet/#get-test-tokens){target=\_blank} -- A wallet with a private key for signing transactions. +The compilation transforms your Solidity source code into bytecode that can be deployed on the blockchain. During this process, the compiler checks your contract for syntax errors, ensures type safety, and generates the machine-readable instructions needed for blockchain execution. To compile your contract, follow the instructions below: -## Access Remix +1. Select the **Solidity Compiler** plugin from the left panel. -Navigate to [Remix](https://remix.ethereum.org/){target=\_blank} in your web browser. + ![](/images/smart-contracts/cookbook/smart-contracts/deploy-erc20/deploy-erc20-3.webp) -The interface will load with a default workspace containing sample contracts. In this interface, you can access a file explorer, edit your code, interact with various plugins for development, and use a terminal. +2. Click the **Compile MyToken.sol** button. -## Create Your Contract + ![](/images/smart-contracts/cookbook/smart-contracts/deploy-erc20/deploy-erc20-4.webp) -1. Create a new file `contracts/MyNFT.sol`. -2. Paste the following code: +3. If the compilation succeeded, you'll see a green checkmark indicating success in the **Solidity Compiler** icon. - ```solidity title="contracts/MyNFT.sol" - // SPDX-License-Identifier: MIT - pragma solidity ^0.8.20; + ![](/images/smart-contracts/cookbook/smart-contracts/deploy-erc20/deploy-erc20-5.webp) - import "@openzeppelin/contracts/token/ERC721/ERC721.sol"; - import "@openzeppelin/contracts/access/Ownable.sol"; +## Deploy the Contract - contract MyNFT is ERC721, Ownable { - uint256 private _nextTokenId; +Deployment is the process of publishing your compiled smart contract to the blockchain, making it permanently available for interaction. During deployment, you'll create a new instance of your contract on the blockchain, which involves: - constructor(address initialOwner) - ERC721("MyToken", "MTK") - Ownable(initialOwner) - {} +1. Select the **Deploy & Run Transactions** plugin from the left panel. - function safeMint(address to) public onlyOwner { - uint256 tokenId = _nextTokenId++; - _safeMint(to, tokenId); - } - } - ``` + ![](/images/smart-contracts/cookbook/smart-contracts/deploy-erc20/deploy-erc20-6.webp) -![](/images/smart-contracts/cookbook/smart-contracts/deploy-nft/remix/remix-01.webp) +2. Configure the deployment settings. + 1. From the **ENVIRONMENT** dropdown, select **Injected Provider - Talisman** (check the [Deploying Contracts](/smart-contracts/dev-environments/remix/deploy-a-contract/){target=\_blank} section of the Remix IDE guide for more details). + 2. From the **ACCOUNT** dropdown, select the account you want to use for the deploy. -## Compile + ![](/images/smart-contracts/cookbook/smart-contracts/deploy-erc20/deploy-erc20-7.webp) -1. Navigate to the **Solidity Compiler** tab (third icon in the left sidebar). -2. Click **Compile MyNFT.sol** or press `Ctrl+S`. +3. Configure the contract parameters: -![](/images/smart-contracts/cookbook/smart-contracts/deploy-nft/remix/remix-02.webp) + 1. Enter the address that will own the deployed token contract. + 2. Click the **Deploy** button to initiate the deployment. -Compilation errors and warnings appear in the terminal panel at the bottom of the screen. + ![](/images/smart-contracts/cookbook/smart-contracts/deploy-erc20/deploy-erc20-8.webp) -## Deploy +4. **Talisman will pop up**: Review the transaction details. Click **Approve** to deploy your contract. -1. Navigate to the **Deploy & Run Transactions** tab. -2. Click the **Environment** dropdown, select **Browser Extension**, and click on **Injected Provider - MetaMask**. + ![](/images/smart-contracts/cookbook/smart-contracts/deploy-erc20/deploy-erc20-9.webp){: .browser-extension} - ![](/images/smart-contracts/cookbook/smart-contracts/deploy-nft/remix/remix-03.webp) + If the deployment process succeeded, you will see the transaction details in the terminal, including the contract address and deployment transaction hash: -3. In the deploy section, enter the initial owner address in the constructor parameter field. -4. Click **Deploy**. + ![](/images/smart-contracts/cookbook/smart-contracts/deploy-erc20/deploy-erc20-10.webp) - ![](/images/smart-contracts/cookbook/smart-contracts/deploy-nft/remix/remix-04.webp) +## Interact with Your ERC-20 Contract -5. Approve the transaction in your MetaMask wallet. +Once deployed, you can interact with your contract through Remix: -Your deployed contract will appear in the **Deployed Contracts** section, ready for interaction. +1. Find your contract under **Deployed/Unpinned Contracts**, and click it to expand the available methods. -## Where to Go Next + ![](/images/smart-contracts/cookbook/smart-contracts/deploy-erc20/deploy-erc20-11.webp) -
+2. To mint new tokens: -- Guide __Verify Your Contract__ + 1. Click in the contract to expand its associated methods. + 2. Expand the **mint** function. + 3. Enter: + - The recipient address. + - The amount (remember to add 18 zeros for 1 whole token). + 4. Click **Transact**. - --- + ![](/images/smart-contracts/cookbook/smart-contracts/deploy-erc20/deploy-erc20-12.webp) - Now that you've deployed an NFT contract, learn how to verify it with Remix. +3. Click **Approve** to confirm the transaction in the Talisman popup. - [:octicons-arrow-right-24: Get Started](/smart-contracts/dev-environments/remix/verify-a-contract/) + ![](/images/smart-contracts/cookbook/smart-contracts/deploy-erc20/deploy-erc20-13.webp){: .browser-extension} -- Guide __Deploy an ERC-20__ + If the transaction succeeds, you will see the following output in the terminal: - --- + ![](/images/smart-contracts/cookbook/smart-contracts/deploy-erc20/deploy-erc20-14.webp) - Walk through deploying a fully-functional ERC-20 to the Polkadot Hub using Remix. +Other common functions you can use: - [:octicons-arrow-right-24: Get Started](/smart-contracts/cookbook/smart-contracts/deploy-erc20/remix/) +- **`balanceOf(address)`**: Check token balance of any address. +- **`transfer(address to, uint256 amount)`**: Send tokens to another address. +- **`approve(address spender, uint256 amount)`**: Allow another address to spend your tokens. -
+Feel free to explore and interact with the contract's other functions using the same approach - selecting the method, providing any required parameters, and confirming the transaction through Talisman when needed. --- -Page Title: Deploy on Paseo TestNet +Page Title: Deploy an NFT to Polkadot Hub with Ethers.js -- Source (raw): https://raw.githubusercontent.com/polkadot-developers/polkadot-docs/master/.ai/pages/tutorials-polkadot-sdk-parachains-zero-to-hero-deploy-to-testnet.md -- Canonical (HTML): https://docs.polkadot.com/tutorials/polkadot-sdk/parachains/zero-to-hero/deploy-to-testnet/ -- Summary: This guide walks you through the journey of deploying your Polkadot SDK blockchain on Paseo, detailing each step to a successful TestNet deployment. +- Source (raw): https://raw.githubusercontent.com/polkadot-developers/polkadot-docs/master/.ai/pages/smart-contracts-cookbook-smart-contracts-deploy-nft-ethers.md +- Canonical (HTML): https://docs.polkadot.com/smart-contracts/cookbook/smart-contracts/deploy-nft/ethers/ +- Summary: Learn how to deploy an ERC-721 NFT contract to Polkadot Hub using Ethers.js, giving you complete programmatic control over the deployment process. -# Deploy on Paseo TestNet +# Deploy an NFT with Ethers.js ## Introduction -Previously, you learned how to [build and run a blockchain locally](/parachains/customize-runtime/pallet-development/add-pallet-to-runtime/){target=\_blank}. Now, you'll take the next step towards a production-like environment by deploying your parachain to a public test network. - -This tutorial guides you through deploying a parachain on the Paseo network, a public TestNet that provides a more realistic blockchain ecosystem. While public testnets have a higher barrier to entry compared to private networks, they are crucial for validating your parachain's functionality and preparing it for eventual mainnet deployment. - -## Get Started with an Account and Tokens - -To perform any action on Paseo, you need PAS tokens, which can be requested from the [Polkadot Faucet](https://faucet.polkadot.io/){target=\_blank}. To store the tokens, you must have access to a Substrate-compatible wallet. Go to the [Polkadot Wallets](https://polkadot.com/get-started/wallets/){target=\_blank} page on the Polkadot Wiki to view different options for a wallet, or use the [Polkadot.js browser extension](https://polkadot.js.org/extension/){target=\_blank}, which is suitable for development purposes. +Non-Fungible Tokens (NFTs) represent unique digital assets commonly used for digital art, collectibles, gaming, and identity verification. -!!!warning - Development keys and accounts should never hold assets of actual value and should not be used for production. +This guide demonstrates how to deploy an [ERC-721](https://eips.ethereum.org/EIPS/eip-721){target=\_blank} NFT contract to [Polkadot Hub](/smart-contracts/overview/#smart-contract-development){target=\_blank}. You'll use [OpenZeppelin's battle-tested NFT implementation](https://github.com/OpenZeppelin/openzeppelin-contracts){target=\_blank} and [Ethers.js](https://docs.ethers.org/v6/){target=\_blank}, a lightweight approach for deploying contracts in pure JavaScript. This method is ideal if you want programmatic control over the deployment process or need to integrate contract deployment into existing applications. -The [Polkadot.js Apps](https://polkadot.js.org/apps/){target=\_blank} interface can be used to get you started for testing purposes. +## Prerequisites -To prepare an account, follow these steps: +- Basic understanding of Solidity programming and NFT standards. +- Node.js v22.13.1 or later. +- Test tokens for gas fees (available from the [Polkadot faucet](https://faucet.polkadot.io/){target=\_blank}). See the [step-by-step instructions](/smart-contracts/faucet/#get-test-tokens){target=\_blank}. +- A wallet with a private key for signing transactions. -1. Open the [Polkadot.js Apps: Paseo](https://polkadot.js.org/apps/?rpc=wss://paseo.dotters.network#/explorer){target=\_blank} interface and connect to the Paseo network. Alternatively use this link to connect directly to Paseo. +## Set Up Your Project - ![](/images/tutorials/polkadot-sdk/parachains/zero-to-hero/deploy-to-testnet/deploy-to-testnet-1.webp) +First, initialize your project and install dependencies: -2. Navigate to the **Accounts** section: +```bash +mkdir ethers-nft-deployment +cd ethers-nft-deployment +npm init -y +npm install ethers@6.15.0 solc@0.8.30 @openzeppelin/contracts@5.0.0 +``` - 1. Click on the **Accounts** tab in the top menu. - 2. Select the **Accounts** option from the dropdown menu. - - ![](/images/tutorials/polkadot-sdk/parachains/zero-to-hero/deploy-to-testnet/deploy-to-testnet-2.webp) +## Create Your Contract -3. Copy the address of the account you want to use for the parachain deployment. +Create an NFT contract in `contracts/MyNFT.sol`: - ![](/images/tutorials/polkadot-sdk/parachains/zero-to-hero/deploy-to-testnet/deploy-to-testnet-3.webp) +```solidity title="contracts/MyNFT.sol" +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.20; -4. Visit the [Polkadot Faucet](https://faucet.polkadot.io){target=\_blank} and paste the copied address in the input field. Ensure that the network is set to Paseo and click on the **Get some PASs** button. +import "@openzeppelin/contracts/token/ERC721/ERC721.sol"; +import "@openzeppelin/contracts/access/Ownable.sol"; - ![](/images/tutorials/polkadot-sdk/parachains/zero-to-hero/deploy-to-testnet/deploy-to-testnet-4.webp) +contract MyNFT is ERC721, Ownable { + uint256 private _nextTokenId; - After a few seconds, you will receive 5000 PAS tokens in your account. + constructor(address initialOwner) + ERC721("MyToken", "MTK") + Ownable(initialOwner) + {} -## Reserve a Parachain Identifier + function safeMint(address to) public onlyOwner { + uint256 tokenId = _nextTokenId++; + _safeMint(to, tokenId); + } +} +``` -You must reserve a parachain identifier (ID) before registering your parachain on Paseo. You'll be assigned the next available identifier. +## Compile -To reserve a parachain identifier, follow these steps: +Create a compilation script `compile.js`: -1. Navigate to the **Parachains** section: +```javascript title="compile.js" +const fs = require('fs'); +const path = require('path'); +const solc = require('solc'); - 1. Click on the **Network** tab in the top menu. - 2. Select the **Parachains** option from the dropdown menu. +const contractPath = path.join(__dirname, 'contracts', 'MyNFT.sol'); +const contractSource = fs.readFileSync(contractPath, 'utf8'); - ![](/images/tutorials/polkadot-sdk/parachains/zero-to-hero/deploy-to-testnet/deploy-to-testnet-5.webp) +function findImports(importPath) { + try { + const nodePath = path.join(__dirname, 'node_modules', importPath); + const contents = fs.readFileSync(nodePath, 'utf8'); + return { contents }; + } catch (error) { + return { error: 'File not found' }; + } +} -2. Register a ParaId: +const input = { + language: 'Solidity', + sources: { + 'MyNFT.sol': { + content: contractSource + } + }, + settings: { + outputSelection: { + '*': { + '*': ['abi', 'evm.bytecode'] + } + }, + optimizer: { + enabled: true, + runs: 200 + } + } +}; - 1. Select the **Parathreads** tab. - 2. Click on the **+ ParaId** button. +console.log('Compiling contract...'); - ![](/images/tutorials/polkadot-sdk/parachains/zero-to-hero/deploy-to-testnet/deploy-to-testnet-6.webp) +const output = JSON.parse(solc.compile(JSON.stringify(input), { import: findImports })); -3. Review the transaction and click on the **+ Submit** button. +if (output.errors) { + output.errors.forEach(error => { + console.error(error.formattedMessage); + }); + + const hasErrors = output.errors.some(error => error.severity === 'error'); + if (hasErrors) { + process.exit(1); + } +} - ![](/images/tutorials/polkadot-sdk/parachains/zero-to-hero/deploy-to-testnet/deploy-to-testnet-7.webp) +const contractName = 'MyNFT'; +const contract = output.contracts['MyNFT.sol'][contractName]; - For this case, the next available parachain identifier is `4508`. +if (!contract) { + console.error('Contract not found in compilation output'); + process.exit(1); +} -4. After submitting the transaction, you can navigate to the **Explorer** tab and check the list of recent events for successful `registrar.Reserved`. +const buildPath = path.join(__dirname, 'build'); +if (!fs.existsSync(buildPath)) { + fs.mkdirSync(buildPath); +} - ![](/images/tutorials/polkadot-sdk/parachains/zero-to-hero/deploy-to-testnet/deploy-to-testnet-8.webp) +const abiPath = path.join(buildPath, `${contractName}_abi.json`); +fs.writeFileSync(abiPath, JSON.stringify(contract.abi, null, 2)); +console.log(`ABI saved to ${abiPath}`); -## Generate Customs Keys for Your Collator +const bytecodePath = path.join(buildPath, `${contractName}_bytecode.txt`); +fs.writeFileSync(bytecodePath, contract.evm.bytecode.object); +console.log(`Bytecode saved to ${bytecodePath}`); -To securely deploy your parachain, it is essential to generate custom keys specifically for your collators (block producers). You should generate two sets of keys for each collator: +const artifactPath = path.join(buildPath, `${contractName}.json`); +const artifact = { + contractName: contractName, + abi: contract.abi, + bytecode: '0x' + contract.evm.bytecode.object +}; +fs.writeFileSync(artifactPath, JSON.stringify(artifact, null, 2)); +console.log(`Complete artifact saved to ${artifactPath}`); -- **Account keys**: Used to interact with the network and manage funds. These should be protected carefully and should never exist on the filesystem of the collator node. +console.log('\nCompilation successful!'); +``` -- **Session keys**: Used in block production to identify your node and its blocks on the network. These keys are stored in the parachain keystore and function as disposable "hot wallet" keys. If these keys are leaked, someone could impersonate your node, which could result in the slashing of your funds. To minimize these risks, rotating your session keys frequently is essential. Treat them with the same level of caution as you would a hot wallet to ensure the security of your node. +Run the compilation: -To perform this step, you can use [subkey](https://docs.rs/crate/subkey/latest){target=\_blank}, a command-line tool for generating and managing keys: +```bash +node compile.js +``` + +## Deploy + +Create a deployment script `deploy.js`: + +```javascript title="deploy.js" +const { ethers } = require('ethers'); +const fs = require('fs'); +const path = require('path'); + +const providerConfig = { + rpc: 'https://testnet-passet-hub-eth-rpc.polkadot.io', + chainId: 420420422, + name: 'polkadot-hub-testnet', +}; + +const mnemonic = 'INSERT_MNEMONIC'; +const initialOwner = 'INSERT_OWNER_ADDRESS'; + +async function deployContract(contractName, mnemonic, initialOwner, providerConfig) { + try { + console.log(`\nStarting deployment of ${contractName}...`); + + const artifactPath = path.join(__dirname, 'build', `${contractName}.json`); + if (!fs.existsSync(artifactPath)) { + throw new Error(`Contract artifact not found at ${artifactPath}. Please run compile.js first.`); + } + + const artifact = JSON.parse(fs.readFileSync(artifactPath, 'utf8')); + + console.log(`Connecting to ${providerConfig.name}...`); + const provider = new ethers.JsonRpcProvider(providerConfig.rpc, { + chainId: providerConfig.chainId, + name: providerConfig.name + }); + + const wallet = ethers.Wallet.fromPhrase(mnemonic); + const signer = wallet.connect(provider); + + console.log(`Deploying from address: ${signer.address}`); + + const balance = await provider.getBalance(signer.address); + console.log(`Account balance: ${ethers.formatEther(balance)} ETH`); + + if (balance === 0n) { + throw new Error('Insufficient balance for deployment'); + } + + const factory = new ethers.ContractFactory(artifact.abi, artifact.bytecode, signer); + + console.log(`\nDeploying contract with initialOwner: ${initialOwner}...`); + const contract = await factory.deploy(initialOwner); + + console.log(`Waiting for deployment transaction: ${contract.target}...`); + await contract.waitForDeployment(); + + const contractAddress = await contract.getAddress(); + + console.log(`\n${contractName} deployed successfully!`); + console.log(`Contract address: ${contractAddress}`); + console.log(`Transaction hash: ${contract.deploymentTransaction().hash}`); + + const deploymentInfo = { + contractName: contractName, + address: contractAddress, + deployer: signer.address, + initialOwner: initialOwner, + network: providerConfig.name, + chainId: providerConfig.chainId, + transactionHash: contract.deploymentTransaction().hash, + deployedAt: new Date().toISOString() + }; + + const deploymentPath = path.join(__dirname, 'build', `${contractName}_deployment.json`); + fs.writeFileSync(deploymentPath, JSON.stringify(deploymentInfo, null, 2)); + console.log(`Deployment info saved to ${deploymentPath}`); + + return contract; + + } catch (error) { + console.error(`\nDeployment failed: ${error.message}`); + throw error; + } +} + +deployContract('MyNFT', mnemonic, initialOwner, providerConfig) + .then(() => { + console.log('\nDeployment completed successfully!'); + process.exit(0); + }) + .catch((error) => { + console.error('\nDeployment error:', error); + process.exit(1); + }); + +``` + +Replace the `INSERT_MNEMONIC` and `INSERT_OWNER_ADDRESS` placeholders with your actual mnemonic and desired owner address. + +!!! warning + Never embed private keys, mnemonic phrases, or security-sensitive credentials directly into your JavaScript, TypeScript, or any front-end/client-side files. + +Execute the deployment: ```bash -docker run -it parity/subkey:latest generate --scheme sr25519 +node deploy.js ``` -The output should look similar to the following: +## Where to Go Next + +
+ +- Guide __Deploy an ERC-20__ + + --- + + Walk through deploying a fully-functional ERC-20 to the Polkadot Hub using Ethers.js. + + [:octicons-arrow-right-24: Get Started](/smart-contracts/cookbook/smart-contracts/deploy-erc20/ethers/) -
- docker run -it parity/subkey:latest generate --scheme sr25519 -
Secret phrase: lemon play remain picture leopard frog mad bridge hire hazard best buddy
Network ID: substrate
Secret seed: 0xb748b501de061bae1fcab1c0b814255979d74d9637b84e06414a57a1a149c004
Public key (hex): 0xf4ec62ec6e70a3c0f8dcbe0531e2b1b8916cf16d30635bbe9232f6ed3f0bf422
Account ID: 0xf4ec62ec6e70a3c0f8dcbe0531e2b1b8916cf16d30635bbe9232f6ed3f0bf422
Public key (SS58): 5HbqmBBJ5ALUzho7tw1k1jEgKBJM7dNsQwrtfSfUskT1a3oe
SS58 Address: 5HbqmBBJ5ALUzho7tw1k1jEgKBJM7dNsQwrtfSfUskT1a3oe
-Ensure that this command is executed twice to generate the keys for both the account and session keys. Save them for future reference. -## Generate the Chain Specification +--- -Polkadot SDK-based blockchains are defined by a file called the [chain specification](/develop/parachains/deployment/generate-chain-specs/){target=\_blank}, or chain spec for short. There are two types of chain spec files: +Page Title: Deploy an NFT to Polkadot Hub with Foundry -- **Plain chain spec**: A human-readable JSON file that can be modified to suit your parachain's requirements. It serves as a template for initial configuration and includes human-readable keys and structures. -- **Raw chain spec**: A binary-encoded file used to start your parachain node. This file is generated from the plain chain spec and contains the encoded information necessary for the parachain node to synchronize with the blockchain network. It ensures compatibility across different runtime versions by providing data in a format directly interpretable by the node's runtime, regardless of upgrades since the chain's genesis. +- Source (raw): https://raw.githubusercontent.com/polkadot-developers/polkadot-docs/master/.ai/pages/smart-contracts-cookbook-smart-contracts-deploy-nft-foundry.md +- Canonical (HTML): https://docs.polkadot.com/smart-contracts/cookbook/smart-contracts/deploy-nft/foundry/ +- Summary: Learn how to deploy an ERC-721 NFT contract to Polkadot Hub using Foundry, a Rust toolkit with high-performance compilation. -The chain spec file is only required during the initial blockchain creation (genesis). You do not need to generate a new chain spec when performing runtime upgrades after your chain is already running. +# Deploy an NFT with Foundry -The files required to register a parachain must specify the correct relay chain to connect to and the parachain identifier you have been assigned. To make these changes, you must build and modify the chain specification file for your parachain. In this tutorial, the relay chain is `paseo`, and the parachain identifier is `4508`. +## Introduction -To define your chain specification: +Non-Fungible Tokens (NFTs) represent unique digital assets commonly used for digital art, collectibles, gaming, and identity verification. -1. Generate the plain chain specification for the parachain template node by running the following command. Make sure to use the `*.compact.compressed.wasm` version of your compiled runtime when generating your chain specification, and replace `INSERT_PARA_ID` with the ID you obtained in the [Reserve a Parachain Identifier](#reserve-a-parachain-identifier) section: +This guide demonstrates how to deploy an [ERC-721](https://eips.ethereum.org/EIPS/eip-721){target=\_blank} NFT contract to [Polkadot Hub](/smart-contracts/overview/#smart-contract-development){target=\_blank}. It showcases a secure approach using [OpenZeppelin's battle-tested NFT implementation](https://github.com/OpenZeppelin/openzeppelin-contracts){target=\_blank} and the [Foundry](https://getfoundry.sh/){target=\_blank} toolchain. Foundry, a fast, Rust-written toolkit, ensures high-performance compilation and is fully compatible with the Hub’s EVM environment via standard Solidity compilation. + +## Prerequisites + +- Basic understanding of Solidity programming and NFT standards. +- Test tokens for gas fees (available from the [Polkadot faucet](https://faucet.polkadot.io/){target=\_blank}). See the [step-by-step instructions](/smart-contracts/faucet/#get-test-tokens){target=\_blank}. +- A wallet with a private key for signing transactions. + +## Set Up Your Project + +To get started, take the following steps: + +1. Install Foundry: ```bash - chain-spec-builder \ - --chain-spec-path ./plain_chain_spec.json \ - create \ - --relay-chain paseo \ - --para-id INSERT_PARA_ID \ - --runtime target/release/wbuild/parachain-template-runtime/parachain_template_runtime.compact.compressed.wasm \ - named-preset local_testnet + curl -L https://foundry.paradigm.xyz | bash + foundryup ``` -2. Edit the `plain_chain_spec.json` file: - - - Update the `name`, `id`, and `protocolId` fields to unique values for your parachain. - - Change `para_id` and `parachainInfo.parachainId` fields to the parachain ID you obtained previously. Make sure to use a number without quotes. - - Modify the `balances` field to specify the initial balances for your accounts in SS58 format. - - Insert the account IDs and session keys in SS58 format generated for your collators in the `collatorSelection.invulnerables` and `session.keys` fields. - - Modify the `sudo` value to specify the account that will have sudo access to the parachain. - - ```json - { - "bootNodes": [], - "chainType": "Live", - "codeSubstitutes": {}, - "genesis": { - "runtimeGenesis": { - "code": "0x...", - "patch": { - "aura": { - "authorities": [] - }, - "auraExt": {}, - "balances": { - "balances": [["INSERT_SUDO_ACCOUNT", 1152921504606846976]] - }, - "collatorSelection": { - "candidacyBond": 16000000000, - "desiredCandidates": 0, - "invulnerables": ["INSERT_ACCOUNT_ID_COLLATOR_1"] - }, - "parachainInfo": { - "parachainId": "INSERT_PARA_ID" - }, - "parachainSystem": {}, - "polkadotXcm": { - "safeXcmVersion": 4 - }, - "session": { - "keys": [ - [ - "INSERT_ACCOUNT_ID_COLLATOR_1", - "INSERT_ACCOUNT_ID_COLLATOR_1", - { - "aura": "INSERT_SESSION_KEY_COLLATOR_1" - } - ] - ], - "nonAuthorityKeys": [] - }, - "sudo": { - "key": "INSERT_SUDO_ACCOUNT" - }, - "system": {}, - "transactionPayment": { - "multiplier": "1000000000000000000" - } - } - } - }, - "id": "INSERT_ID", - "name": "INSERT_NAME", - "para_id": "INSERT_PARA_ID", - "properties": { - "tokenDecimals": 12, - "tokenSymbol": "UNIT" - }, - "protocolId": "INSERT_PROTOCOL_ID", - "relay_chain": "paseo", - "telemetryEndpoints": null - } +2. Initialize your project: + ```bash + forge init foundry-nft-deployment + cd foundry-nft-deployment ``` - For this tutorial, the `plain_chain_spec.json` file should look similar to the following. Take into account that the same account is being used for the collator and sudo, which must not be the case in a production environment: +3. Install OpenZeppelin contracts: - ??? code "View complete script" + ```bash + forge install OpenZeppelin/openzeppelin-contracts + ``` - ```json title="plain_chain_spec.json" - { - "bootNodes": [], - "chainType": "Live", - "codeSubstitutes": {}, - "genesis": { - "runtimeGenesis": { - "code": "0x...", - "patch": { - "aura": { - "authorities": [] - }, - "auraExt": {}, - "balances": { - "balances": [ - [ - "5F9Zteceg3Q4ywi63AxQNVb2b2r5caFSqjQxBkCrux6j8ZpS", - 1152921504606846976 - ] - ] - }, - "collatorSelection": { - "candidacyBond": 16000000000, - "desiredCandidates": 0, - "invulnerables": [ - "5F9Zteceg3Q4ywi63AxQNVb2b2r5caFSqjQxBkCrux6j8ZpS" - ] - }, - "parachainInfo": { - "parachainId": 4508 - }, - "parachainSystem": {}, - "polkadotXcm": { - "safeXcmVersion": 4 - }, - "session": { - "keys": [ - [ - "5F9Zteceg3Q4ywi63AxQNVb2b2r5caFSqjQxBkCrux6j8ZpS", - "5F9Zteceg3Q4ywi63AxQNVb2b2r5caFSqjQxBkCrux6j8ZpS", - { - "aura": "5GcAKNdYcw5ybb2kAnta8WVFyiQbGJ5od3aH9MsgYDmVcrhJ" - } - ] - ], - "nonAuthorityKeys": [] - }, - "sudo": { - "key": "5F9Zteceg3Q4ywi63AxQNVb2b2r5caFSqjQxBkCrux6j8ZpS" - }, - "system": {}, - "transactionPayment": { - "multiplier": "1000000000000000000" - } - } - } - }, - "id": "custom", - "name": "Custom", - "para_id": 4508, - "properties": { - "tokenDecimals": 12, - "tokenSymbol": "UNIT" - }, - "protocolId": null, - "relay_chain": "paseo", - "telemetryEndpoints": null - } +## Configure Foundry - ``` +Edit `foundry.toml`: -3. Save your changes and close the plain text chain specification file. +```toml title="foundry.toml" +[profile.default] +src = "src" +out = "out" +libs = ["lib"] +remappings = ['@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/'] -4. Convert the modified plain chain specification file to a raw chain specification file: +[rpc_endpoints] +polkadot_hub_testnet = "https://testnet-passet-hub-eth-rpc.polkadot.io" +``` - ```bash - chain-spec-builder \ - --chain-spec-path ./raw_chain_spec.json \ - convert-to-raw plain_chain_spec.json - ``` +## Create Your Contract - You should now see your chain specification containing SCALE-encoded hex values versus plain text. +Create `src/MyNFT.sol`: +```solidity title="src/MyNFT.sol" +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.20; -!!!note "`para_id` Considerations" +import "@openzeppelin/contracts/token/ERC721/ERC721.sol"; +import "@openzeppelin/contracts/access/Ownable.sol"; - The `para_id` field in JSON chain specifications, added through the [`chain-spec-builder`](https://paritytech.github.io/polkadot-sdk/master/staging_chain_spec_builder/index.html){target=\_blank} command, is used by nodes for configuration purposes. Beginning with Polkadot SDK release `stable2509`, runtimes can optionally implement the [`cumulus_primitives_core::GetParachainInfo`](https://paritytech.github.io/polkadot-sdk/master/cumulus_primitives_core/trait.GetParachainInfo.html){target=\_blank} trait as an alternative method for parachain identification. +contract MyNFT is ERC721, Ownable { + uint256 private _nextTokenId; - However, the `para_id` field will remain supported in chain specifications for backwards compatibility. This ensures that nodes can still sync from genesis or from runtime states that existed before the `GetParachainInfo` runtime API was introduced. + constructor(address initialOwner) + ERC721("MyToken", "MTK") + Ownable(initialOwner) + {} - For guidance on performing runtime upgrades to implement the `GetParachainInfo` trait, refer to the [runtime upgrade tutorial](/tutorials/polkadot-sdk/parachains/zero-to-hero/runtime-upgrade/){target=\_blank}. + function safeMint(address to) public onlyOwner { + uint256 tokenId = _nextTokenId++; + _safeMint(to, tokenId); + } +} +``` -## Export Required Files +## Compile -To prepare the parachain collator to be registered on Paseo, follow these steps: +```bash +forge build +``` -1. Export the Wasm runtime for the parachain by running the following command: +Verify the compilation by inspecting the bytecode: - ```bash - polkadot-omni-node export-genesis-wasm \ - --chain raw_chain_spec.json para-wasm - ``` +```bash +forge inspect MyNFT bytecode +``` -2. Export the genesis state for the parachain by running the following command: +## Deploy - ```bash - polkadot-omni-node export-genesis-head \ - --chain raw_chain_spec.json para-state - ``` +Deploy to Polkadot Hub TestNet: -## Register a Parathread +```bash +forge create MyNFT \ + --rpc-url polkadot_hub_testnet \ + --private-key YOUR_PRIVATE_KEY \ + --constructor-args YOUR_OWNER_ADDRESS \ + --broadcast +``` -Once you have the genesis state and runtime, you can now register these with your parachain ID. +Replace `YOUR_PRIVATE_KEY` with your private key and `YOUR_OWNER_ADDRESS` with the address that will own the NFT contract. -1. Go to the [Parachains > Parathreads](https://polkadot.js.org/apps/#/parachains/parathreads){target=\_blank} tab, and select **+ Parathread**. - -2. You should see fields to place your runtime Wasm and genesis state respectively, along with the parachain ID. Select your parachain ID, and upload `para-wasm` in the **code** field and `para-state` in the **initial state** field. +## Where to Go Next - ![](/images/tutorials/polkadot-sdk/parachains/zero-to-hero/deploy-to-testnet/deploy-to-testnet-9.webp) - -3. Confirm your details and **+ Submit** button, where there should be a new Parathread with your parachain ID and an active **Deregister** button. +
- ![](/images/tutorials/polkadot-sdk/parachains/zero-to-hero/deploy-to-testnet/deploy-to-testnet-10.webp) +- Guide __Verify Your Contract__ -Your parachain's runtime logic and genesis are now part of the relay chain. The next step is to ensure you are able to run a collator to produce blocks for your parachain. + --- -!!!note - You may need to wait several hours for your parachain to onboard. Until it has onboarded, you will be unable to purchase coretime, and therefore will not be able to perform transactions on your network. + Now that you've deployed an NFT contract, learn how to verify it with Foundry. -## Start the Collator Node + [:octicons-arrow-right-24: Get Started](/smart-contracts/dev-environments/foundry/verify-a-contract/) -Before starting a collator, you need to generate a node key. This key is responsible for communicating with other nodes over Libp2p: +- Guide __Deploy an ERC-20__ -```bash -polkadot-omni-node key generate-node-key \ ---base-path data \ ---chain raw_chain_spec.json -``` + --- -After running the command, you should see the following output, indicating the base path now has a suitable node key: + Walk through deploying a fully-functional ERC-20 to the Polkadot Hub using Foundry. + + [:octicons-arrow-right-24: Get Started](/smart-contracts/cookbook/smart-contracts/deploy-erc20/foundry/) -
- polkadot-omni-node key generate-node-key --base-path data --chain raw_chain_spec.json -
- Generating key in "/data/chains/custom/network/secret_ed25519" - 12D3KooWKGW964eG4fAwsNMFdckbj3GwhpmSGFU9dd8LFAVAa4EE
-You must have the ports for the collator publicly accessible and discoverable to enable parachain nodes to peer with Paseo validator nodes to produce blocks. You can specify the ports with the `--port` command-line option. You can start the collator with a command similar to the following: -```bash -polkadot-omni-node --collator \ ---chain raw_chain_spec.json \ ---base-path data \ ---port 40333 \ ---rpc-port 8845 \ ---force-authoring \ ---node-key-file ./data/chains/custom/network/secret_ed25519 \ --- \ ---sync warp \ ---chain paseo \ ---port 50343 \ ---rpc-port 9988 -``` +--- -In this example, the first `--port` setting specifies the port for the collator node, and the second `--port` specifies the embedded relay chain node port. The first `--rpc-port` setting specifies the port you can connect to the collator. The second `--rpc-port` specifies the port for connecting to the embedded relay chain. +Page Title: Deploy an NFT to Polkadot Hub with Hardhat -Before proceeding, ensure that the collator node is running. Then, open a new terminal and insert your generated session key into the collator keystore by running the following command. Use the same port specified in the `--rpc-port` parameter when starting the collator node (`8845` in this example) to connect to it. Replace `INSERT_SECRET_PHRASE` and `INSERT_PUBLIC_KEY_HEX_FORMAT` with the values from the session key you generated in the [Generate Customs Keys for Your Collator](#generate-customs-keys-for-your-collator) section: +- Source (raw): https://raw.githubusercontent.com/polkadot-developers/polkadot-docs/master/.ai/pages/smart-contracts-cookbook-smart-contracts-deploy-nft-hardhat.md +- Canonical (HTML): https://docs.polkadot.com/smart-contracts/cookbook/smart-contracts/deploy-nft/hardhat/ +- Summary: Learn how to deploy an ERC-721 NFT contract to Polkadot Hub with Hardhat, a comprehenive development environment with built-in deployment capabilities. -```bash -curl -H "Content-Type: application/json" \ ---data '{ - "jsonrpc":"2.0", - "method":"author_insertKey", - "params":[ - "aura", - "INSERT_SECRET_PHRASE", - "INSERT_PUBLIC_KEY_HEX_FORMAT" - ], - "id":1 -}' \ -http://localhost:8845 -``` +# Deploy an NFT with Hardhat -If successful, you should see the following response: +## Introduction -```json -{"jsonrpc":"2.0","result":null,"id":1} -``` +Non-Fungible Tokens (NFTs) represent unique digital assets commonly used for digital art, collectibles, gaming, and identity verification. -Once your collator is synced with the Paseo relay chain, and your parathread finished onboarding, it will be ready to start producing blocks. This process may take some time. +This guide demonstrates how to deploy an [ERC-721](https://eips.ethereum.org/EIPS/eip-721){target=\_blank} NFT contract to [Polkadot Hub](/smart-contracts/overview/#smart-contract-development){target=\_blank}. You'll use [OpenZeppelin's battle-tested NFT implementation](https://github.com/OpenZeppelin/openzeppelin-contracts){target=\_blank} and [Hardhat](https://hardhat.org/docs/getting-started){target=\_blank}, a comprehensive development environment with built-in testing, debugging, and deployment capabilities. Hardhat uses standard Solidity compilation to generate EVM bytecode, making it fully compatible with Polkadot Hub's EVM environment. -## Producing Blocks +## Prerequisites -With your parachain collator operational, the next step is acquiring coretime. This is essential for ensuring your parachain's security through the relay chain. [Agile Coretime](https://wiki.polkadot.com/learn/learn-agile-coretime/){target=\_blank} enhances Polkadot's resource management, offering developers greater economic adaptability. Once you have configured your parachain, you can follow two paths: +- Basic understanding of Solidity programming and NFT standards. +- Node.js v22.13.1 or later. +- Test tokens for gas fees (available from the [Polkadot faucet](https://faucet.polkadot.io/){target=\_blank}). See the [step-by-step instructions](/smart-contracts/faucet/#get-test-tokens){target=\_blank}. +- A wallet with a private key for signing transactions. -- Bulk coretime is purchased via the Broker pallet on the respective coretime system parachain. You can purchase bulk coretime on the coretime chain and assign the purchased core to the registered `ParaID`. -- On-demand coretime is ordered via the `OnDemandAssignment` pallet, which is located on the respective relay chain. +## Set Up Your Project -Once coretime is correctly assigned to your parachain, whether bulk or on-demand, blocks should be produced (provided your collator is running). +Take the following steps to get started: -For more information on coretime, refer to the [Coretime](/polkadot-protocol/architecture/system-chains/coretime/){target=\_blank} documentation. +1. Initialize your Hardhat project: -## Where to Go Next + ```bash + mkdir hardhat-nft-deployment + cd hardhat-nft-deployment + npx hardhat --init + ``` -
+2. Install OpenZeppelin contracts: -- Tutorial __Obtain Coretime__ + ```bash + npm install @openzeppelin/contracts + ``` - --- +## Configure Hardhat - Get coretime for block production now! Follow this guide to explore on-demand and bulk options for seamless and efficient operations. +Edit `hardhat.config.ts`: - [:octicons-arrow-right-24: Get Started](/tutorials/polkadot-sdk/parachains/zero-to-hero/obtain-coretime/) +```typescript title="hardhat.config.ts" +import type { HardhatUserConfig } from 'hardhat/config'; -
+import hardhatToolboxViemPlugin from '@nomicfoundation/hardhat-toolbox-viem'; +import { configVariable } from 'hardhat/config'; +const config: HardhatUserConfig = { + plugins: [hardhatToolboxViemPlugin], + solidity: { + profiles: { + default: { + version: '0.8.28', + }, + production: { + version: '0.8.28', + settings: { + optimizer: { + enabled: true, + runs: 200, + }, + }, + }, + }, + }, + networks: { + hardhatMainnet: { + type: 'edr-simulated', + chainType: 'l1', + }, + hardhatOp: { + type: 'edr-simulated', + chainType: 'op', + }, + sepolia: { + type: 'http', + chainType: 'l1', + url: configVariable('SEPOLIA_RPC_URL'), + accounts: [configVariable('SEPOLIA_PRIVATE_KEY')], + }, + polkadotHubTestnet: { + type: 'http', + url: 'https://testnet-passet-hub-eth-rpc.polkadot.io', + chainId: 420420422, + accounts: [configVariable('PRIVATE_KEY')], + }, + }, +}; ---- +export default config; +``` -Page Title: Deploy on Polkadot +!!! tip + Learn how to use Hardhat's [Config Variables](https://hardhat.org/docs/learn-more/configuration-variables){target=\_blank} to handle your private keys in a secure way. -- Source (raw): https://raw.githubusercontent.com/polkadot-developers/polkadot-docs/master/.ai/pages/parachains-launch-a-parachain-deploy-to-polkadot.md -- Canonical (HTML): https://docs.polkadot.com/parachains/launch-a-parachain/deploy-to-polkadot/ -- Summary: This guide walks you through the journey of deploying your Polkadot SDK parachain on the Polkadot TestNet, detailing each step to a successful deployment. +## Create Your Contract -# Deploy on Polkadot +Create `contracts/MyNFT.sol`: -## Introduction +```solidity title="contracts/MyNFT.sol" +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.20; -Previously, you learned how to [choose and set up a parachain template](/parachains/launch-a-parachain/choose-a-template/){target=\_blank}. Now, you'll take the next step towards a production-like environment by deploying your parachain to the Polkadot TestNet. Deploying to a TestNet is a crucial step for validating your parachain's functionality and preparing it for eventual MainNet deployment. +import "@openzeppelin/contracts/token/ERC721/ERC721.sol"; +import "@openzeppelin/contracts/access/Ownable.sol"; -## Get Started with an Account and Tokens +contract MyNFT is ERC721, Ownable { + uint256 private _nextTokenId; -To perform any action on the Polkadot TestNet, you need PAS tokens, which can be requested from the [Polkadot Faucet](https://faucet.polkadot.io/?parachain=0){target=\_blank}. To store the tokens, you must have access to a Polkadot-SDK-compatible wallet. Go to the [Polkadot Wallets](https://polkadot.com/get-started/wallets/){target=\_blank} page to view different options for a Polkadot wallet, or use the [Polkadot.js browser extension](https://polkadot.js.org/extension/){target=\_blank}, which is suitable for development purposes. + constructor(address initialOwner) + ERC721("MyToken", "MTK") + Ownable(initialOwner) + {} -!!!warning - Development keys and accounts should never hold assets of actual value and should not be used for production. + function safeMint(address to) public onlyOwner { + uint256 tokenId = _nextTokenId++; + _safeMint(to, tokenId); + } +} +``` -The [Polkadot.js Apps](https://polkadot.js.org/apps/){target=\_blank} interface can be used to get you started for testing purposes. +## Compile -To prepare an account, follow these steps: +```bash +npx hardhat compile +``` -1. Open the [Polkadot.js Apps: Paseo](https://polkadot.js.org/apps/?rpc=wss://paseo.dotters.network#/explorer){target=\_blank} interface and connect to the Polkadot TestNet (Paseo). +## Set Up Deployment - ![](/images/parachains/launch-a-parachain/deploy-to-polkadot/deploy-to-polkadot-1.webp) +Create a deployment module in `ignition/modules/MyNFT.ts`: -2. Navigate to the **Accounts** section: +```typescript title="ignition/modules/MyNFT.ts" +import { buildModule } from '@nomicfoundation/hardhat-ignition/modules'; - 1. Click on the **Accounts** tab in the top menu. - 2. Select the **Accounts** option from the dropdown menu. - - ![](/images/parachains/launch-a-parachain/deploy-to-polkadot/deploy-to-polkadot-2.webp) +export default buildModule('MyNFTModule', (m) => { + const initialOwner = m.getParameter('initialOwner', 'INSERT_OWNER_ADDRESS'); + const myNFT = m.contract('MyNFT', [initialOwner]); + return { myNFT }; +}); +``` -3. Copy the address of the account you want to use for the parachain deployment. +Replace `INSERT_OWNER_ADDRESS` with your desired owner address. - ![](/images/parachains/launch-a-parachain/deploy-to-polkadot/deploy-to-polkadot-3.webp) +## Deploy -4. Visit the [Polkadot Faucet](https://faucet.polkadot.io/?parachain=0){target=\_blank} and paste the copied address in the input field. Ensure that the network is set to Paseo and click on the **Get some PASs** button. +Deploy to Polkadot Hub TestNet: - ![](/images/parachains/launch-a-parachain/deploy-to-polkadot/deploy-to-polkadot-4.webp) +```bash +npx hardhat ignition deploy ignition/modules/MyNFT.ts --network polkadotHubTestnet +``` - After a few seconds, you will receive 5000 PAS tokens in your account. +## Where to Go Next -## Reserve a Parachain Identifier +
-You must reserve a parachain identifier (ID) before registering your parachain on Paseo. You'll be assigned the next available identifier. +- Guide __Verify Your Contract__ -To reserve a parachain identifier, follow these steps: + --- -1. Navigate to the **Parachains** section: + Now that you've deployed an NFT contract, learn how to verify it with Hardhat. - 1. Click on the **Network** tab in the top menu. - 2. Select the **Parachains** option from the dropdown menu. + [:octicons-arrow-right-24: Get Started](/smart-contracts/dev-environments/hardhat/verify-a-contract/) - ![](/images/parachains/launch-a-parachain/deploy-to-polkadot/deploy-to-polkadot-5.webp) -2. Register a ParaId: +- Guide __Deploy an ERC-20__ - 1. Select the **Parathreads** tab. - 2. Click on the **+ ParaId** button. + --- - ![](/images/parachains/launch-a-parachain/deploy-to-polkadot/deploy-to-polkadot-6.webp) + Walk through deploying a fully-functional ERC-20 to the Polkadot Hub using Hardhat. -3. Review the transaction and click on the **+ Submit** button. + [:octicons-arrow-right-24: Get Started](/smart-contracts/cookbook/smart-contracts/deploy-erc20/hardhat/) - ![](/images/parachains/launch-a-parachain/deploy-to-polkadot/deploy-to-polkadot-7.webp) +
- For this case, the next available parachain identifier is `4508`. -4. After submitting the transaction, you can navigate to the **Explorer** tab and check the list of recent events for successful `registrar.Reserved`. +--- - ![](/images/parachains/launch-a-parachain/deploy-to-polkadot/deploy-to-polkadot-8.webp) +Page Title: Deploy an NFT to Polkadot Hub with Remix -## Generate Custom Keys for Your Collators +- Source (raw): https://raw.githubusercontent.com/polkadot-developers/polkadot-docs/master/.ai/pages/smart-contracts-cookbook-smart-contracts-deploy-nft-remix.md +- Canonical (HTML): https://docs.polkadot.com/smart-contracts/cookbook/smart-contracts/deploy-nft/remix/ +- Summary: Learn how to deploy an ERC-721 NFT contract to Polkadot Hub using Remix, a browser-based IDE for quick prototyping and learning. -To securely deploy your parachain, it is essential to generate custom keys specifically for your [collators](/reference/glossary/#collator){target=\_blank} (block producers). You should generate two sets of keys for each collator: +# Deploy an NFT with Remix -- **Account keys**: Used to interact with the network and manage funds. These should be protected carefully and should never exist on the filesystem of the collator node. +## Introduction -- **Session keys**: Used in block production to identify your node and its blocks on the network. These keys are stored in the parachain keystore and function as disposable "hot wallet" keys. If these keys are leaked, someone could impersonate your node, which could result in the slashing of your funds. To minimize these risks, rotating your session keys frequently is essential. Treat them with the same level of caution as you would a hot wallet to ensure the security of your node. +Non-Fungible Tokens (NFTs) represent unique digital assets commonly used for digital art, collectibles, gaming, and identity verification. -To perform this step, you can use [subkey](https://docs.rs/crate/subkey/latest){target=\_blank}, a command-line tool for generating and managing keys: +This guide demonstrates how to deploy an [ERC-721](https://eips.ethereum.org/EIPS/eip-721){target=\_blank} NFT contract to [Polkadot Hub](/smart-contracts/overview/#smart-contract-development){target=\_blank}. You'll use [OpenZeppelin's battle-tested NFT implementation](https://github.com/OpenZeppelin/openzeppelin-contracts){target=\_blank} and [Remix](https://remix.ethereum.org/){target=\_blank}, a visual, browser-based environment perfect for rapid prototyping and learning. It requires no local installation and provides an intuitive interface for contract development. -```bash -docker run -it parity/subkey:latest generate --scheme sr25519 -``` +## Prerequisites -The output should look similar to the following: +- Basic understanding of Solidity programming and NFT standards. +- Test tokens for gas fees (available from the [Polkadot faucet](https://faucet.polkadot.io/){target=\_blank}). See the [step-by-step instructions](/smart-contracts/faucet/#get-test-tokens){target=\_blank} +- A wallet with a private key for signing transactions. +## Access Remix -Ensure that this command is executed twice to generate the keys for both the account and session keys. Save them for future reference. +Navigate to [Remix](https://remix.ethereum.org/){target=\_blank} in your web browser. -## Generate the Chain Specification +The interface will load with a default workspace containing sample contracts. In this interface, you can access a file explorer, edit your code, interact with various plugins for development, and use a terminal. -Polkadot SDK-based parachains are defined by a file called the [chain specification](/reference/glossary/#chain-specification){target=\_blank}, or chain spec for short. There are two types of chain spec files: +## Create Your Contract -- **Plain chain spec**: A human-readable JSON file that can be modified to suit your parachain's requirements. It serves as a template for initial configuration and includes human-readable keys and structures. -- **Raw chain spec**: A binary-encoded file used to start your parachain node. This file is generated from the plain chain spec and contains the encoded information necessary for the parachain node to synchronize with the blockchain network. It ensures compatibility across different runtime versions by providing data in a format directly interpretable by the node's runtime, regardless of upgrades since the chain's genesis. +1. Create a new file `contracts/MyNFT.sol`. +2. Paste the following code: -The chain spec file is only required during the initial blockchain creation (genesis). You do not need to generate a new chain spec when performing runtime upgrades after your chain is already running. + ```solidity title="contracts/MyNFT.sol" + // SPDX-License-Identifier: MIT + pragma solidity ^0.8.20; -The files required to register a parachain must specify the correct relay chain to connect to and the parachain identifier you have been assigned. To make these changes, you must build and modify the chain specification file for your parachain. In this tutorial, the relay chain is `paseo`, and the parachain identifier is `4508`. + import "@openzeppelin/contracts/token/ERC721/ERC721.sol"; + import "@openzeppelin/contracts/access/Ownable.sol"; -To define your chain specification: + contract MyNFT is ERC721, Ownable { + uint256 private _nextTokenId; -1. Generate the plain chain specification for the parachain template node by running the following command. Make sure to use the `*.compact.compressed.wasm` version of your compiled runtime when generating your chain specification, and replace `INSERT_PARA_ID` with the ID you obtained in the [Reserve a Parachain Identifier](#reserve-a-parachain-identifier) section: + constructor(address initialOwner) + ERC721("MyToken", "MTK") + Ownable(initialOwner) + {} - ```bash - chain-spec-builder \ - --chain-spec-path ./plain_chain_spec.json \ - create \ - --relay-chain paseo \ - --para-id INSERT_PARA_ID \ - --runtime target/release/wbuild/parachain-template-runtime/parachain_template_runtime.compact.compressed.wasm \ - named-preset local_testnet - ``` - -2. Edit the `plain_chain_spec.json` file: - - - Update the `name`, `id`, and `protocolId` fields to unique values for your parachain. - - Change `para_id` and `parachainInfo.parachainId` fields to the parachain ID you obtained previously. Make sure to use a number without quotes. - - Modify the `balances` field to specify the initial balances for your accounts in SS58 format. - - Insert the account IDs and session keys in SS58 format generated for your collators in the `collatorSelection.invulnerables` and `session.keys` fields. - - Modify the `sudo` value to specify the account that will have sudo access to the parachain. - - ```json - + function safeMint(address to) public onlyOwner { + uint256 tokenId = _nextTokenId++; + _safeMint(to, tokenId); + } + } ``` - For this tutorial, the `plain_chain_spec.json` file should look similar to the following. Take into account that the same account is being used for the collator and sudo, which must not be the case in a production environment: +![](/images/smart-contracts/cookbook/smart-contracts/deploy-nft/remix/remix-01.webp) - ??? code "View complete script" +## Compile - ```json title="plain_chain_spec.json" - - ``` +1. Navigate to the **Solidity Compiler** tab (third icon in the left sidebar). +2. Click **Compile MyNFT.sol** or press `Ctrl+S`. -3. Save your changes and close the plain text chain specification file. +![](/images/smart-contracts/cookbook/smart-contracts/deploy-nft/remix/remix-02.webp) -4. Convert the modified plain chain specification file to a raw chain specification file: +Compilation errors and warnings appear in the terminal panel at the bottom of the screen. - ```bash - chain-spec-builder \ - --chain-spec-path ./raw_chain_spec.json \ - convert-to-raw plain_chain_spec.json - ``` +## Deploy - You should now see your chain specification containing SCALE-encoded hex values versus plain text. +1. Navigate to the **Deploy & Run Transactions** tab. +2. Click the **Environment** dropdown, select **Browser Extension**, and click on **Injected Provider - MetaMask**. + ![](/images/smart-contracts/cookbook/smart-contracts/deploy-nft/remix/remix-03.webp) -!!!note "`para_id` Considerations" +3. In the deploy section, enter the initial owner address in the constructor parameter field. +4. Click **Deploy**. - The `para_id` field in JSON chain specifications, added through the [`chain-spec-builder`](https://paritytech.github.io/polkadot-sdk/master/staging_chain_spec_builder/index.html){target=\_blank} command, is used by nodes for configuration purposes. Beginning with Polkadot SDK release `stable2509`, runtimes can optionally implement the [`cumulus_primitives_core::GetParachainInfo`](https://paritytech.github.io/polkadot-sdk/master/cumulus_primitives_core/trait.GetParachainInfo.html){target=\_blank} trait as an alternative method for parachain identification. + ![](/images/smart-contracts/cookbook/smart-contracts/deploy-nft/remix/remix-04.webp) - However, the `para_id` field will remain supported in chain specifications for backwards compatibility. This ensures that nodes can still sync from genesis or from runtime states that existed before the `GetParachainInfo` runtime API was introduced. +5. Approve the transaction in your MetaMask wallet. -## Export Required Files +Your deployed contract will appear in the **Deployed Contracts** section, ready for interaction. -To prepare the parachain collator to be registered on Paseo, follow these steps: +## Where to Go Next -1. Export the Wasm runtime for the parachain by running the following command: +
- ```bash - polkadot-omni-node export-genesis-wasm \ - --chain raw_chain_spec.json para-wasm - ``` +- Guide __Verify Your Contract__ -2. Export the genesis state for the parachain by running the following command: + --- - ```bash - polkadot-omni-node export-genesis-head \ - --chain raw_chain_spec.json para-state - ``` + Now that you've deployed an NFT contract, learn how to verify it with Remix. -## Register a Parathread + [:octicons-arrow-right-24: Get Started](/smart-contracts/dev-environments/remix/verify-a-contract/) -Once you have the genesis state and runtime, you can now register these with your parachain ID. +- Guide __Deploy an ERC-20__ -1. Go to the [Parachains > Parathreads](https://polkadot.js.org/apps/#/parachains/parathreads){target=\_blank} tab, and select **+ Parathread**. - -2. You should see fields to place your runtime Wasm and genesis state respectively, along with the parachain ID. Select your parachain ID, and upload `para-wasm` in the **code** field and `para-state` in the **initial state** field. + --- - ![](/images/parachains/launch-a-parachain/deploy-to-polkadot/deploy-to-polkadot-9.webp) - -3. Confirm your details and **+ Submit** button, where there should be a new Parathread with your parachain ID and an active **Deregister** button. + Walk through deploying a fully-functional ERC-20 to the Polkadot Hub using Remix. - ![](/images/parachains/launch-a-parachain/deploy-to-polkadot/deploy-to-polkadot-10.webp) + [:octicons-arrow-right-24: Get Started](/smart-contracts/cookbook/smart-contracts/deploy-erc20/remix/) -Your parachain's runtime logic and genesis are now part of the relay chain. The next step is to ensure you are able to run a collator to produce blocks for your parachain. +
-!!!note - You may need to wait several hours for your parachain to onboard. Until it has onboarded, you will be unable to purchase coretime, and therefore will not be able to perform transactions on your network. -## Start the Collator Node +--- -Before starting a collator, you need to generate a node key. This key is responsible for communicating with other nodes over Libp2p: +Page Title: Deploy on Paseo TestNet -```bash -polkadot-omni-node key generate-node-key \ ---base-path data \ ---chain raw_chain_spec.json -``` +- Source (raw): https://raw.githubusercontent.com/polkadot-developers/polkadot-docs/master/.ai/pages/tutorials-polkadot-sdk-parachains-zero-to-hero-deploy-to-testnet.md +- Canonical (HTML): https://docs.polkadot.com/tutorials/polkadot-sdk/parachains/zero-to-hero/deploy-to-testnet/ +- Summary: This guide walks you through the journey of deploying your Polkadot SDK blockchain on Paseo, detailing each step to a successful TestNet deployment. -After running the command, you should see the following output, indicating the base path now has a suitable node key: +# Deploy on Paseo TestNet +## Introduction -You must have the ports for the collator publicly accessible and discoverable to enable parachain nodes to peer with Paseo validator nodes to produce blocks. You can specify the ports with the `--port` command-line option. You can start the collator with a command similar to the following: +Previously, you learned how to [build and run a blockchain locally](/parachains/customize-runtime/pallet-development/add-pallet-to-runtime/){target=\_blank}. Now, you'll take the next step towards a production-like environment by deploying your parachain to a public test network. -```bash -polkadot-omni-node --collator \ ---chain raw_chain_spec.json \ ---base-path data \ ---port 40333 \ ---rpc-port 8845 \ ---force-authoring \ ---node-key-file ./data/chains/custom/network/secret_ed25519 \ --- \ ---sync warp \ ---chain paseo \ ---port 50343 \ ---rpc-port 9988 -``` +This tutorial guides you through deploying a parachain on the Paseo network, a public TestNet that provides a more realistic blockchain ecosystem. While public testnets have a higher barrier to entry compared to private networks, they are crucial for validating your parachain's functionality and preparing it for eventual mainnet deployment. -In this example, the first `--port` setting specifies the port for the collator node, and the second `--port` specifies the embedded relay chain node port. The first `--rpc-port` setting specifies the port you can connect to the collator. The second `--rpc-port` specifies the port for connecting to the embedded relay chain. +## Get Started with an Account and Tokens -Before proceeding, ensure that the collator node is running. Then, open a new terminal and insert your generated session key into the collator keystore by running the following command. Use the same port specified in the `--rpc-port` parameter when starting the collator node (`8845` in this example) to connect to it. Replace `INSERT_SECRET_PHRASE` and `INSERT_PUBLIC_KEY_HEX_FORMAT` with the values from the session key you generated in the [Generate Custom Keys for Your Collators](#generate-custom-keys-for-your-collators) section: +To perform any action on Paseo, you need PAS tokens, which can be requested from the [Polkadot Faucet](https://faucet.polkadot.io/){target=\_blank}. To store the tokens, you must have access to a Substrate-compatible wallet. Go to the [Polkadot Wallets](https://polkadot.com/get-started/wallets/){target=\_blank} page on the Polkadot Wiki to view different options for a wallet, or use the [Polkadot.js browser extension](https://polkadot.js.org/extension/){target=\_blank}, which is suitable for development purposes. -```bash -curl -H "Content-Type: application/json" \ ---data '{ - "jsonrpc":"2.0", - "method":"author_insertKey", - "params":[ - "aura", - "INSERT_SECRET_PHRASE", - "INSERT_PUBLIC_KEY_HEX_FORMAT" - ], - "id":1 -}' \ -http://localhost:8845 -``` +!!!warning + Development keys and accounts should never hold assets of actual value and should not be used for production. -If successful, you should see the following response: +The [Polkadot.js Apps](https://polkadot.js.org/apps/){target=\_blank} interface can be used to get you started for testing purposes. -```json -{"jsonrpc":"2.0","result":null,"id":1} -``` +To prepare an account, follow these steps: -Once your collator is synced with the Paseo relay chain, and your parathread finished onboarding, it will be ready to start producing blocks. This process may take some time. +1. Open the [Polkadot.js Apps: Paseo](https://polkadot.js.org/apps/?rpc=wss://paseo.dotters.network#/explorer){target=\_blank} interface and connect to the Paseo network. Alternatively use this link to connect directly to Paseo. -## Producing Blocks + ![](/images/tutorials/polkadot-sdk/parachains/zero-to-hero/deploy-to-testnet/deploy-to-testnet-1.webp) -With your parachain collator operational, the next step is acquiring coretime. This is essential for ensuring your parachain's security through the relay chain. [Agile Coretime](https://wiki.polkadot.com/learn/learn-agile-coretime/){target=\_blank} enhances Polkadot's resource management, offering developers greater economic adaptability. Once you have configured your parachain, you can follow two paths: +2. Navigate to the **Accounts** section: -- Bulk coretime is purchased via the Broker pallet on the respective coretime system parachain. You can purchase bulk coretime on the coretime chain and assign the purchased core to the registered `ParaID`. -- On-demand coretime is ordered via the [`OnDemand`](https://paritytech.github.io/polkadot-sdk/master/polkadot_runtime_parachains/on_demand/index.html){target=\_blank} pallet, which is located on the respective relay chain. + 1. Click on the **Accounts** tab in the top menu. + 2. Select the **Accounts** option from the dropdown menu. + + ![](/images/tutorials/polkadot-sdk/parachains/zero-to-hero/deploy-to-testnet/deploy-to-testnet-2.webp) -Once coretime is correctly assigned to your parachain, whether bulk or on-demand, blocks should be produced (provided your collator is running). +3. Copy the address of the account you want to use for the parachain deployment. + ![](/images/tutorials/polkadot-sdk/parachains/zero-to-hero/deploy-to-testnet/deploy-to-testnet-3.webp) ---- +4. Visit the [Polkadot Faucet](https://faucet.polkadot.io){target=\_blank} and paste the copied address in the input field. Ensure that the network is set to Paseo and click on the **Get some PASs** button. -Page Title: E2E Testing with Moonwall + ![](/images/tutorials/polkadot-sdk/parachains/zero-to-hero/deploy-to-testnet/deploy-to-testnet-4.webp) -- Source (raw): https://raw.githubusercontent.com/polkadot-developers/polkadot-docs/master/.ai/pages/reference-tools-moonwall.md -- Canonical (HTML): https://docs.polkadot.com/reference/tools/moonwall/ -- Summary: Enhance blockchain end-to-end testing with Moonwall's standardized environment setup, comprehensive configuration management, and simple network interactions. + After a few seconds, you will receive 5000 PAS tokens in your account. -# E2E Testing with Moonwall +## Reserve a Parachain Identifier -## Introduction +You must reserve a parachain identifier (ID) before registering your parachain on Paseo. You'll be assigned the next available identifier. -Moonwall is an end-to-end testing framework designed explicitly for Polkadot SDK-based blockchain networks. It addresses one of the most significant challenges in blockchain development: managing complex test environments and network configurations. +To reserve a parachain identifier, follow these steps: -Moonwall consolidates this complexity by providing the following: +1. Navigate to the **Parachains** section: -- A centralized configuration management system that explicitly defines all network parameters. -- A standardized approach to environment setup across different Substrate-based chains. -- Built-in utilities for common testing scenarios and network interactions. + 1. Click on the **Network** tab in the top menu. + 2. Select the **Parachains** option from the dropdown menu. -Developers can focus on writing meaningful tests rather than managing infrastructure complexities or searching through documentation for configuration options. + ![](/images/tutorials/polkadot-sdk/parachains/zero-to-hero/deploy-to-testnet/deploy-to-testnet-5.webp) -## Prerequisites +2. Register a ParaId: -Before you begin, ensure you have the following installed: + 1. Select the **Parathreads** tab. + 2. Click on the **+ ParaId** button. -- [Node.js](https://nodejs.org/en/){target=\_blank} (version 20.10 or higher). -- A package manager such as [npm](https://www.npmjs.com/){target=\_blank}, [yarn](https://yarnpkg.com/){target=\_blank}, or [pnpm](https://pnpm.io/){target=\_blank}. + ![](/images/tutorials/polkadot-sdk/parachains/zero-to-hero/deploy-to-testnet/deploy-to-testnet-6.webp) -## Install Moonwall +3. Review the transaction and click on the **+ Submit** button. -Moonwall can be installed globally for system-wide access or locally within specific projects. This section covers both installation methods. + ![](/images/tutorials/polkadot-sdk/parachains/zero-to-hero/deploy-to-testnet/deploy-to-testnet-7.webp) -!!! tip - This documentation corresponds to Moonwall version `5.15.0`. To avoid compatibility issues with the documented features, ensure you're using the matching version. + For this case, the next available parachain identifier is `4508`. -### Global Installation +4. After submitting the transaction, you can navigate to the **Explorer** tab and check the list of recent events for successful `registrar.Reserved`. -Global installation provides system-wide access to the Moonwall CLI, making it ideal for developers working across multiple blockchain projects. Install it by running one of the following commands: + ![](/images/tutorials/polkadot-sdk/parachains/zero-to-hero/deploy-to-testnet/deploy-to-testnet-8.webp) -=== "npm" +## Generate Customs Keys for Your Collator - ```bash - npm install -g @moonwall/cli@5.15.0 - ``` +To securely deploy your parachain, it is essential to generate custom keys specifically for your collators (block producers). You should generate two sets of keys for each collator: -=== "pnpm" +- **Account keys**: Used to interact with the network and manage funds. These should be protected carefully and should never exist on the filesystem of the collator node. - ```bash - pnpm -g install @moonwall/cli@5.15.0 - ``` +- **Session keys**: Used in block production to identify your node and its blocks on the network. These keys are stored in the parachain keystore and function as disposable "hot wallet" keys. If these keys are leaked, someone could impersonate your node, which could result in the slashing of your funds. To minimize these risks, rotating your session keys frequently is essential. Treat them with the same level of caution as you would a hot wallet to ensure the security of your node. -=== "yarn" +To perform this step, you can use [subkey](https://docs.rs/crate/subkey/latest){target=\_blank}, a command-line tool for generating and managing keys: - ```bash - yarn global add @moonwall/cli@5.15.0 - ``` +```bash +docker run -it parity/subkey:latest generate --scheme sr25519 +``` -Now, you can run the `moonwall` command from your terminal. +The output should look similar to the following: -### Local Installation +
+ docker run -it parity/subkey:latest generate --scheme sr25519 +
Secret phrase: lemon play remain picture leopard frog mad bridge hire hazard best buddy
Network ID: substrate
Secret seed: 0xb748b501de061bae1fcab1c0b814255979d74d9637b84e06414a57a1a149c004
Public key (hex): 0xf4ec62ec6e70a3c0f8dcbe0531e2b1b8916cf16d30635bbe9232f6ed3f0bf422
Account ID: 0xf4ec62ec6e70a3c0f8dcbe0531e2b1b8916cf16d30635bbe9232f6ed3f0bf422
Public key (SS58): 5HbqmBBJ5ALUzho7tw1k1jEgKBJM7dNsQwrtfSfUskT1a3oe
SS58 Address: 5HbqmBBJ5ALUzho7tw1k1jEgKBJM7dNsQwrtfSfUskT1a3oe
+
-Local installation is recommended for better dependency management and version control within a specific project. First, initialize your project: +Ensure that this command is executed twice to generate the keys for both the account and session keys. Save them for future reference. -```bash -mkdir my-moonwall-project -cd my-moonwall-project -npm init -y -``` +## Generate the Chain Specification -Then, install it as a local dependency: +Polkadot SDK-based blockchains are defined by a file called the [chain specification](/develop/parachains/deployment/generate-chain-specs/){target=\_blank}, or chain spec for short. There are two types of chain spec files: -=== "npm" +- **Plain chain spec**: A human-readable JSON file that can be modified to suit your parachain's requirements. It serves as a template for initial configuration and includes human-readable keys and structures. +- **Raw chain spec**: A binary-encoded file used to start your parachain node. This file is generated from the plain chain spec and contains the encoded information necessary for the parachain node to synchronize with the blockchain network. It ensures compatibility across different runtime versions by providing data in a format directly interpretable by the node's runtime, regardless of upgrades since the chain's genesis. - ```bash - npm install @moonwall/cli@5.15.0 - ``` +The chain spec file is only required during the initial blockchain creation (genesis). You do not need to generate a new chain spec when performing runtime upgrades after your chain is already running. -=== "pnpm" +The files required to register a parachain must specify the correct relay chain to connect to and the parachain identifier you have been assigned. To make these changes, you must build and modify the chain specification file for your parachain. In this tutorial, the relay chain is `paseo`, and the parachain identifier is `4508`. - ```bash - pnpm install @moonwall/cli@5.15.0 - ``` +To define your chain specification: -=== "yarn" +1. Generate the plain chain specification for the parachain template node by running the following command. Make sure to use the `*.compact.compressed.wasm` version of your compiled runtime when generating your chain specification, and replace `INSERT_PARA_ID` with the ID you obtained in the [Reserve a Parachain Identifier](#reserve-a-parachain-identifier) section: ```bash - yarn add @moonwall/cli@5.15.0 + chain-spec-builder \ + --chain-spec-path ./plain_chain_spec.json \ + create \ + --relay-chain paseo \ + --para-id INSERT_PARA_ID \ + --runtime target/release/wbuild/parachain-template-runtime/parachain_template_runtime.compact.compressed.wasm \ + named-preset local_testnet ``` -## Initialize Moonwall +2. Edit the `plain_chain_spec.json` file: -The `moonwall init` command launches an interactive wizard to create your configuration file: + - Update the `name`, `id`, and `protocolId` fields to unique values for your parachain. + - Change `para_id` and `parachainInfo.parachainId` fields to the parachain ID you obtained previously. Make sure to use a number without quotes. + - Modify the `balances` field to specify the initial balances for your accounts in SS58 format. + - Insert the account IDs and session keys in SS58 format generated for your collators in the `collatorSelection.invulnerables` and `session.keys` fields. + - Modify the `sudo` value to specify the account that will have sudo access to the parachain. + + ```json + { + "bootNodes": [], + "chainType": "Live", + "codeSubstitutes": {}, + "genesis": { + "runtimeGenesis": { + "code": "0x...", + "patch": { + "aura": { + "authorities": [] + }, + "auraExt": {}, + "balances": { + "balances": [["INSERT_SUDO_ACCOUNT", 1152921504606846976]] + }, + "collatorSelection": { + "candidacyBond": 16000000000, + "desiredCandidates": 0, + "invulnerables": ["INSERT_ACCOUNT_ID_COLLATOR_1"] + }, + "parachainInfo": { + "parachainId": "INSERT_PARA_ID" + }, + "parachainSystem": {}, + "polkadotXcm": { + "safeXcmVersion": 4 + }, + "session": { + "keys": [ + [ + "INSERT_ACCOUNT_ID_COLLATOR_1", + "INSERT_ACCOUNT_ID_COLLATOR_1", + { + "aura": "INSERT_SESSION_KEY_COLLATOR_1" + } + ] + ], + "nonAuthorityKeys": [] + }, + "sudo": { + "key": "INSERT_SUDO_ACCOUNT" + }, + "system": {}, + "transactionPayment": { + "multiplier": "1000000000000000000" + } + } + } + }, + "id": "INSERT_ID", + "name": "INSERT_NAME", + "para_id": "INSERT_PARA_ID", + "properties": { + "tokenDecimals": 12, + "tokenSymbol": "UNIT" + }, + "protocolId": "INSERT_PROTOCOL_ID", + "relay_chain": "paseo", + "telemetryEndpoints": null + } -```bash -moonwall init -``` + ``` -During setup, you will see prompts for the following parameters: + For this tutorial, the `plain_chain_spec.json` file should look similar to the following. Take into account that the same account is being used for the collator and sudo, which must not be the case in a production environment: -- **`label`**: Identifies your test configuration. -- **`global timeout`**: Maximum time (ms) for test execution. -- **`environment name`**: Name for your testing environment. -- **`network foundation`**: Type of blockchain environment to use. -- **`tests directory`**: Location of your test files. + ??? code "View complete script" -Select `Enter` to accept defaults or input custom values. You should see something like this: + ```json title="plain_chain_spec.json" + { + "bootNodes": [], + "chainType": "Live", + "codeSubstitutes": {}, + "genesis": { + "runtimeGenesis": { + "code": "0x...", + "patch": { + "aura": { + "authorities": [] + }, + "auraExt": {}, + "balances": { + "balances": [ + [ + "5F9Zteceg3Q4ywi63AxQNVb2b2r5caFSqjQxBkCrux6j8ZpS", + 1152921504606846976 + ] + ] + }, + "collatorSelection": { + "candidacyBond": 16000000000, + "desiredCandidates": 0, + "invulnerables": [ + "5F9Zteceg3Q4ywi63AxQNVb2b2r5caFSqjQxBkCrux6j8ZpS" + ] + }, + "parachainInfo": { + "parachainId": 4508 + }, + "parachainSystem": {}, + "polkadotXcm": { + "safeXcmVersion": 4 + }, + "session": { + "keys": [ + [ + "5F9Zteceg3Q4ywi63AxQNVb2b2r5caFSqjQxBkCrux6j8ZpS", + "5F9Zteceg3Q4ywi63AxQNVb2b2r5caFSqjQxBkCrux6j8ZpS", + { + "aura": "5GcAKNdYcw5ybb2kAnta8WVFyiQbGJ5od3aH9MsgYDmVcrhJ" + } + ] + ], + "nonAuthorityKeys": [] + }, + "sudo": { + "key": "5F9Zteceg3Q4ywi63AxQNVb2b2r5caFSqjQxBkCrux6j8ZpS" + }, + "system": {}, + "transactionPayment": { + "multiplier": "1000000000000000000" + } + } + } + }, + "id": "custom", + "name": "Custom", + "para_id": 4508, + "properties": { + "tokenDecimals": 12, + "tokenSymbol": "UNIT" + }, + "protocolId": null, + "relay_chain": "paseo", + "telemetryEndpoints": null + } -
- moonwall init - ✔ Provide a label for the config file moonwall_config - ✔ Provide a global timeout value 30000 - ✔ Provide a name for this environment default_env - ✔ What type of network foundation is this? dev - ✔ Provide the path for where tests for this environment are kept tests/ - ? Would you like to generate this config? (no to restart from beginning) (Y/n) -
+ ``` -The wizard generates a `moonwall.config` file: +3. Save your changes and close the plain text chain specification file. -```json -{ - "label": "moonwall_config", - "defaultTestTimeout": 30000, - "environments": [ - { - "name": "default_env", - "testFileDir": ["tests/"], - "foundation": { - "type": "dev" - } - } - ] -} +4. Convert the modified plain chain specification file to a raw chain specification file: -``` + ```bash + chain-spec-builder \ + --chain-spec-path ./raw_chain_spec.json \ + convert-to-raw plain_chain_spec.json + ``` -The default configuration requires specific details about your blockchain node and test requirements: + You should now see your chain specification containing SCALE-encoded hex values versus plain text. -- The `foundation` object defines how your test blockchain node will be launched and managed. The dev foundation, which runs a local node binary, is used for local development. - For more information about available options, check the [Foundations](https://moonsong-labs.github.io/moonwall/guide/intro/foundations.html){target=\_blank} section. +!!!note "`para_id` Considerations" -- The `connections` array specifies how your tests will interact with the blockchain node. This typically includes provider configuration and endpoint details. + The `para_id` field in JSON chain specifications, added through the [`chain-spec-builder`](https://paritytech.github.io/polkadot-sdk/master/staging_chain_spec_builder/index.html){target=\_blank} command, is used by nodes for configuration purposes. Beginning with Polkadot SDK release `stable2509`, runtimes can optionally implement the [`cumulus_primitives_core::GetParachainInfo`](https://paritytech.github.io/polkadot-sdk/master/cumulus_primitives_core/trait.GetParachainInfo.html){target=\_blank} trait as an alternative method for parachain identification. - A provider is a tool that allows you or your application to connect to a blockchain network and simplifies the low-level details of the process. A provider handles submitting transactions, reading state, and more. For more information on available providers, check the [Providers supported](https://moonsong-labs.github.io/moonwall/guide/intro/providers.html#providers-supported){target=\_blank} page in the Moonwall documentation. + However, the `para_id` field will remain supported in chain specifications for backwards compatibility. This ensures that nodes can still sync from genesis or from runtime states that existed before the `GetParachainInfo` runtime API was introduced. -Here's a complete configuration example for testing a local node using Polkadot.js as a provider: + For guidance on performing runtime upgrades to implement the `GetParachainInfo` trait, refer to the [runtime upgrade tutorial](/tutorials/polkadot-sdk/parachains/zero-to-hero/runtime-upgrade/){target=\_blank}. -```json -{ - "label": "moonwall_config", - "defaultTestTimeout": 30000, - "environments": [ - { - "name": "default_env", - "testFileDir": ["tests/"], - "foundation": { - "launchSpec": [ - { - "binPath": "./node-template", - "newRpcBehaviour": true, - "ports": { "rpcPort": 9944 } - } - ], - "type": "dev" - }, - "connections": [ - { - "name": "myconnection", - "type": "polkadotJs", - "endpoints": ["ws://127.0.0.1:9944"] - } - ] - } - ] -} +## Export Required Files -``` +To prepare the parachain collator to be registered on Paseo, follow these steps: -## Writing Tests +1. Export the Wasm runtime for the parachain by running the following command: -Moonwall uses the [`describeSuite`](https://github.com/Moonsong-Labs/moonwall/blob/7568048c52e9f7844f38fb4796ae9e1b9205fdaa/packages/cli/src/lib/runnerContext.ts#L65){target=\_blank} function to define test suites, like using [Mocha](https://mochajs.org/){target=\_blank}. Each test suite requires the following: + ```bash + polkadot-omni-node export-genesis-wasm \ + --chain raw_chain_spec.json para-wasm + ``` -- **`id`**: Unique identifier for the suite. -- **`title`**: Descriptive name for the suite. -- **`foundationMethods`**: Specifies the testing environment (e.g., `dev` for local node testing). -- **`testCases`**: A callback function that houses the individual test cases of this suite. +2. Export the genesis state for the parachain by running the following command: -The following example shows how to test a balance transfer between two accounts: + ```bash + polkadot-omni-node export-genesis-head \ + --chain raw_chain_spec.json para-state + ``` -```ts -import '@polkadot/api-augment'; -import { describeSuite, expect } from '@moonwall/cli'; -import { Keyring } from '@polkadot/api'; +## Register a Parathread -describeSuite({ - id: 'D1', - title: 'Demo suite', - foundationMethods: 'dev', - testCases: ({ it, context, log }) => { - it({ - id: 'T1', - title: 'Test Case', - test: async () => { - // Set up polkadot.js API and testing accounts - let api = context.polkadotJs(); - let alice = new Keyring({ type: 'sr25519' }).addFromUri('//Alice'); - let charlie = new Keyring({ type: 'sr25519' }).addFromUri('//Charlie'); +Once you have the genesis state and runtime, you can now register these with your parachain ID. - // Query Charlie's account balance before transfer - const balanceBefore = (await api.query.system.account(charlie.address)) - .data.free; +1. Go to the [Parachains > Parathreads](https://polkadot.js.org/apps/#/parachains/parathreads){target=\_blank} tab, and select **+ Parathread**. + +2. You should see fields to place your runtime Wasm and genesis state respectively, along with the parachain ID. Select your parachain ID, and upload `para-wasm` in the **code** field and `para-state` in the **initial state** field. - // Before transfer, Charlie's account balance should be 0 - expect(balanceBefore.toString()).toEqual('0'); - log('Balance before: ' + balanceBefore.toString()); + ![](/images/tutorials/polkadot-sdk/parachains/zero-to-hero/deploy-to-testnet/deploy-to-testnet-9.webp) + +3. Confirm your details and **+ Submit** button, where there should be a new Parathread with your parachain ID and an active **Deregister** button. - // Transfer from Alice to Charlie - const amount = 1000000000000000; - await api.tx.balances - .transferAllowDeath(charlie.address, amount) - .signAndSend(alice); + ![](/images/tutorials/polkadot-sdk/parachains/zero-to-hero/deploy-to-testnet/deploy-to-testnet-10.webp) - // Wait for the transaction to be included in a block. - // This is necessary because the balance is not updated immediately. - // Block time is 6 seconds. - await new Promise((resolve) => setTimeout(resolve, 6000)); +Your parachain's runtime logic and genesis are now part of the relay chain. The next step is to ensure you are able to run a collator to produce blocks for your parachain. - // Query Charlie's account balance after transfer - const balanceAfter = (await api.query.system.account(charlie.address)) - .data.free; +!!!note + You may need to wait several hours for your parachain to onboard. Until it has onboarded, you will be unable to purchase coretime, and therefore will not be able to perform transactions on your network. - // After transfer, Charlie's account balance should be 1000000000000000 - expect(balanceAfter.toString()).toEqual(amount.toString()); - log('Balance after: ' + balanceAfter.toString()); - }, - }); - }, -}); +## Start the Collator Node -``` +Before starting a collator, you need to generate a node key. This key is responsible for communicating with other nodes over Libp2p: -This test demonstrates several key concepts: +```bash +polkadot-omni-node key generate-node-key \ +--base-path data \ +--chain raw_chain_spec.json +``` -- Initializing the Polkadot.js API through Moonwall's context and setting up test accounts. -- Querying on-chain state. -- Executing transactions. -- Waiting for block inclusion. -- Verifying results using assertions. +After running the command, you should see the following output, indicating the base path now has a suitable node key: -## Running the Tests +
+ polkadot-omni-node key generate-node-key --base-path data --chain raw_chain_spec.json +
+ Generating key in "/data/chains/custom/network/secret_ed25519" + 12D3KooWKGW964eG4fAwsNMFdckbj3GwhpmSGFU9dd8LFAVAa4EE +
-Execute your tests using the `test` Moonwall CLI command. For the default environment setup run: +You must have the ports for the collator publicly accessible and discoverable to enable parachain nodes to peer with Paseo validator nodes to produce blocks. You can specify the ports with the `--port` command-line option. You can start the collator with a command similar to the following: ```bash -moonwall test default_env -c moonwall.config +polkadot-omni-node --collator \ +--chain raw_chain_spec.json \ +--base-path data \ +--port 40333 \ +--rpc-port 8845 \ +--force-authoring \ +--node-key-file ./data/chains/custom/network/secret_ed25519 \ +-- \ +--sync warp \ +--chain paseo \ +--port 50343 \ +--rpc-port 9988 ``` -The test runner will output detailed results showing: +In this example, the first `--port` setting specifies the port for the collator node, and the second `--port` specifies the embedded relay chain node port. The first `--rpc-port` setting specifies the port you can connect to the collator. The second `--rpc-port` specifies the port for connecting to the embedded relay chain. -- Test suite execution status. -- Individual test case results. -- Execution time. -- Detailed logs and error messages (if any). +Before proceeding, ensure that the collator node is running. Then, open a new terminal and insert your generated session key into the collator keystore by running the following command. Use the same port specified in the `--rpc-port` parameter when starting the collator node (`8845` in this example) to connect to it. Replace `INSERT_SECRET_PHRASE` and `INSERT_PUBLIC_KEY_HEX_FORMAT` with the values from the session key you generated in the [Generate Customs Keys for Your Collator](#generate-customs-keys-for-your-collator) section: -Example output: -
- moonwall test default_env -c moonwall.config - stdout | tests/test1.ts > 🗃️ D1 Demo suite > 📁 D1T1 Test Case - 2025-01-21T19:27:55.624Z test:default_env Balance before: 0 - - stdout | tests/test1.ts > 🗃️ D1 Demo suite > 📁 D1T1 Test Case - 2025-01-21T19:28:01.637Z test:default_env Balance after: 1000000000000000 - - ✓ default_env tests/test1.ts (1 test) 6443ms - ✓ 🗃️ D1 Demo suite > 📁 D1T1 Test Case 6028ms - - Test Files 1 passed (1) - Tests 1 passed (1) - Start at 16:27:53 - Duration 7.95s (transform 72ms, setup 0ms, collect 1.31s, tests 6.44s, environment 0ms, prepare 46ms) - - ✅ All tests passed -
+```bash +curl -H "Content-Type: application/json" \ +--data '{ + "jsonrpc":"2.0", + "method":"author_insertKey", + "params":[ + "aura", + "INSERT_SECRET_PHRASE", + "INSERT_PUBLIC_KEY_HEX_FORMAT" + ], + "id":1 +}' \ +http://localhost:8845 +``` -## Where to Go Next +If successful, you should see the following response: -For a comprehensive guide to Moonwall's full capabilities, available configurations, and advanced usage, see the official [Moonwall](https://moonsong-labs.github.io/moonwall/){target=\_blank} documentation. +```json +{"jsonrpc":"2.0","result":null,"id":1} +``` +Once your collator is synced with the Paseo relay chain, and your parathread finished onboarding, it will be ready to start producing blocks. This process may take some time. ---- +## Producing Blocks -Page Title: EVM vs PolkaVM +With your parachain collator operational, the next step is acquiring coretime. This is essential for ensuring your parachain's security through the relay chain. [Agile Coretime](https://wiki.polkadot.com/learn/learn-agile-coretime/){target=\_blank} enhances Polkadot's resource management, offering developers greater economic adaptability. Once you have configured your parachain, you can follow two paths: -- Source (raw): https://raw.githubusercontent.com/polkadot-developers/polkadot-docs/master/.ai/pages/polkadot-protocol-smart-contract-basics-evm-vs-polkavm.md -- Canonical (HTML): https://docs.polkadot.com/polkadot-protocol/smart-contract-basics/evm-vs-polkavm/ -- Summary: Compares EVM and PolkaVM, highlighting key architectural differences, gas models, memory management, and account handling while ensuring Solidity compatibility. +- Bulk coretime is purchased via the Broker pallet on the respective coretime system parachain. You can purchase bulk coretime on the coretime chain and assign the purchased core to the registered `ParaID`. +- On-demand coretime is ordered via the `OnDemandAssignment` pallet, which is located on the respective relay chain. -# EVM vs PolkaVM +Once coretime is correctly assigned to your parachain, whether bulk or on-demand, blocks should be produced (provided your collator is running). -!!! smartcontract "PolkaVM Preview Release" - PolkaVM smart contracts with Ethereum compatibility are in **early-stage development and may be unstable or incomplete**. -## Introduction +For more information on coretime, refer to the [Coretime](/polkadot-protocol/architecture/system-chains/coretime/){target=\_blank} documentation. -While [PolkaVM](/smart-contracts/for-eth-devs/dual-vm-stack/){target=\_blank} strives for maximum Ethereum compatibility, several fundamental design decisions create necessary divergences from the [EVM](https://ethereum.org/en/developers/docs/evm/){target=\_blank}. These differences represent trade-offs that enhance performance and resource management while maintaining accessibility for Solidity developers. +## Where to Go Next -## Core Virtual Machine Architecture +
-The most significant departure from Ethereum comes from PolkaVM's foundation itself. Rather than implementing the EVM, PolkaVM utilizes a RISC-V instruction set. For most Solidity developers, this architectural change remains transparent thanks to the [Revive compiler's](https://github.com/paritytech/revive){target=\_blank} complete Solidity support, including inline assembler functionality. +- Tutorial __Obtain Coretime__ -```mermaid -graph TD - subgraph "Ethereum Path" - EthCompile["Standard Solidity Compiler"] --> EVM_Bytecode["EVM Bytecode"] - EVM_Bytecode --> EVM["Stack-based EVM"] - EVM --> EthExecution["Contract Execution"] - end + --- - subgraph "PolkaVM Path" - ReviveCompile["Revive Compiler"] --> RISCV_Bytecode["RISC-V Format Bytecode"] - RISCV_Bytecode --> PolkaVM["RISC-V Based PolkaVM"] - PolkaVM --> PolkaExecution["Contract Execution"] - end + Get coretime for block production now! Follow this guide to explore on-demand and bulk options for seamless and efficient operations. - EthExecution -.-> DifferencesNote["Key Differences: - - Instruction Set Architecture - - Bytecode Format - - Runtime Behavior"] - PolkaExecution -.-> DifferencesNote -``` + [:octicons-arrow-right-24: Get Started](/tutorials/polkadot-sdk/parachains/zero-to-hero/obtain-coretime/) -However, this architectural difference becomes relevant in specific scenarios. Tools that attempt to download and inspect contract bytecode will fail, as they expect EVM bytecode rather than PolkaVM's RISC-V format. Most applications typically pass bytecode as an opaque blob, making this a non-issue for standard use cases. +
-This primarily affects contracts using [`EXTCODECOPY`](https://www.evm.codes/?fork=cancun#3c){target=\_blank} to manipulate code at runtime. A contract encounters problems specifically when it uses `EXTCODECOPY` to copy contract code into memory and then attempts to mutate it. This pattern is not possible in standard Solidity and requires dropping down to YUL assembly. An example would be a factory contract written in assembly that constructs and instantiates new contracts by generating code at runtime. Such contracts are rare in practice. -PolkaVM offers an elegant alternative through its [on-chain constructors](https://paritytech.github.io/polkadot-sdk/master/pallet_revive/pallet/struct.Pallet.html#method.bare_instantiate){target=\_blank}, enabling contract instantiation without runtime code modification, making this pattern unnecessary. This architectural difference also impacts how contract deployment works more broadly, as discussed in the [Contract Deployment](#contract-deployment) section. +--- -### High-Level Architecture Comparison +Page Title: Deploy on Polkadot -| Feature | Ethereum Virtual Machine (EVM) | PolkaVM | -|:-----------------------------:|:------------------------------------------------------------------------------------:|:------------------------------------------------------:| -| **Instruction Set** | Stack-based architecture | RISC-V instruction set | -| **Bytecode Format** | EVM bytecode | RISC-V format | -| **Contract Size Limit** | 24KB code size limit | Contract-specific memory limits | -| **Compiler** | Solidity Compiler | Revive Compiler | -| **Inline Assembly** | Supported | Supported with the compatibility layer | -| **Code Introspection** | Supported via [`EXTCODECOPY`](https://www.evm.codes/?fork=cancun#3c){target=\_blank} | Limited support, alternative via on-chain constructors | -| **Resource Metering** | Single gas metric | Multi-dimensional | -| **Runtime Code Modification** | Supported | Limited, with alternatives | -| **Contract Instantiation** | Standard deployment | On-chain constructors for flexible instantiation | +- Source (raw): https://raw.githubusercontent.com/polkadot-developers/polkadot-docs/master/.ai/pages/parachains-launch-a-parachain-deploy-to-polkadot.md +- Canonical (HTML): https://docs.polkadot.com/parachains/launch-a-parachain/deploy-to-polkadot/ +- Summary: This guide walks you through the journey of deploying your Polkadot SDK parachain on the Polkadot TestNet, detailing each step to a successful deployment. -## Gas Model +# Deploy on Polkadot -Ethereum's resource model relies on a single metric: [gas](https://ethereum.org/en/developers/docs/gas/#what-is-gas){target=\_blank}, which serves as the universal unit for measuring computational costs. Each operation on the network consumes a specific amount of gas. Most platforms aiming for Ethereum compatibility typically adopt identical gas values to ensure seamless integration. +## Introduction -The significant changes to Ethereum's gas model will be outlined in the following sections. +Previously, you learned how to [choose and set up a parachain template](/parachains/launch-a-parachain/choose-a-template/){target=\_blank}. Now, you'll take the next step towards a production-like environment by deploying your parachain to the Polkadot TestNet. Deploying to a TestNet is a crucial step for validating your parachain's functionality and preparing it for eventual MainNet deployment. -### Dynamic Gas Value Scaling +## Get Started with an Account and Tokens -Instead of adhering to Ethereum's fixed gas values, PolkaVM implements benchmark-based pricing that better reflects its improved execution performance. This makes instructions cheaper relative to I/O-bound operations but requires developers to avoid hardcoding gas values, particularly in cross-contract calls. +To perform any action on the Polkadot TestNet, you need PAS tokens, which can be requested from the [Polkadot Faucet](https://faucet.polkadot.io/?parachain=0){target=\_blank}. To store the tokens, you must have access to a Polkadot-SDK-compatible wallet. Go to the [Polkadot Wallets](https://polkadot.com/get-started/wallets/){target=\_blank} page to view different options for a Polkadot wallet, or use the [Polkadot.js browser extension](https://polkadot.js.org/extension/){target=\_blank}, which is suitable for development purposes. -### Multi-Dimensional Resource Metering +!!!warning + Development keys and accounts should never hold assets of actual value and should not be used for production. -Moving beyond Ethereum's single gas metric, PolkaVM meters three distinct resources: +The [Polkadot.js Apps](https://polkadot.js.org/apps/){target=\_blank} interface can be used to get you started for testing purposes. -- **`ref_time`**: Equivalent to traditional gas, measuring computation time. -- **`proof_size`**: Tracks state proof size for validator verification. -- **`storage_deposit`**: Manages state bloat through a deposit system. +To prepare an account, follow these steps: -All three resources can be limited at the transaction level, just like gas on Ethereum. The [Ethereum RPC proxy](https://github.com/paritytech/polkadot-sdk/tree/master/substrate/frame/revive/rpc){target=\_blank} maps all three dimensions into the single gas dimension, ensuring everything behaves as expected for users. +1. Open the [Polkadot.js Apps: Paseo](https://polkadot.js.org/apps/?rpc=wss://paseo.dotters.network#/explorer){target=\_blank} interface and connect to the Polkadot TestNet (Paseo). -These resources can also be limited when making cross-contract calls, which is essential for security when interacting with untrusted contracts. However, Solidity only allows specifying `gas_limit` for cross-contract calls. The `gas_limit` is most similar to Polkadots `ref_time_limit`, but the Revive compiler doesn't supply any imposed `gas_limit` for cross-contract calls for two key reasons: + ![](/images/parachains/launch-a-parachain/deploy-to-polkadot/deploy-to-polkadot-1.webp) -- **Semantic differences**: `gas_limit` and `ref_time_limit` are not semantically identical; blindly passing EVM gas as `ref_time_limit` can lead to unexpected behavior. -- **Incomplete protection**: The other two resources (`proof_size` and `storage_deposit`) would remain uncapped anyway, making it insufficient to prevent malicious callees from performing DOS attacks. +2. Navigate to the **Accounts** section: -When resources are "uncapped" in cross-contract calls, they remain constrained by transaction-specified limits, preventing abuse of the transaction signer. + 1. Click on the **Accounts** tab in the top menu. + 2. Select the **Accounts** option from the dropdown menu. + + ![](/images/parachains/launch-a-parachain/deploy-to-polkadot/deploy-to-polkadot-2.webp) -!!! note - The runtime will provide a special precompile, allowing cross-contract calls with limits specified for all weight dimensions in the future. +3. Copy the address of the account you want to use for the parachain deployment. -All gas-related opcodes like [`GAS`](https://www.evm.codes/?fork=cancun#5a){target=\_blank} or [`GAS_LIMIT`](https://www.evm.codes/?fork=cancun#45){target=\_blank} return only the `ref_time` value as it's the closest match to traditional gas. Extended APIs will be provided through precompiles to make full use of all resources, including cross-contract calls with all three resources specified. + ![](/images/parachains/launch-a-parachain/deploy-to-polkadot/deploy-to-polkadot-3.webp) -## Memory Management +4. Visit the [Polkadot Faucet](https://faucet.polkadot.io/?parachain=0){target=\_blank} and paste the copied address in the input field. Ensure that the network is set to Paseo and click on the **Get some PASs** button. -The EVM and the PolkaVM take fundamentally different approaches to memory constraints: + ![](/images/parachains/launch-a-parachain/deploy-to-polkadot/deploy-to-polkadot-4.webp) -| Feature | Ethereum Virtual Machine (EVM) | PolkaVM | -|:------------------------:|:-----------------------------------------:|:----------------------------------------------:| -| **Memory Constraints** | Indirect control via gas costs | Hard memory limits per contract | -| **Cost Model** | Increasing gas curve with allocation size | Fixed costs separated from execution gas | -| **Memory Limits** | Soft limits through prohibitive gas costs | Hard fixed limits per contract | -| **Pricing Efficiency** | Potential overcharging for memory | More efficient through separation of concerns | -| **Contract Nesting** | Limited by available gas | Limited by constant memory per contract | -| **Memory Metering** | Dynamic based on total allocation | Static limits per contract instance | -| **Future Improvements** | Incremental gas cost updates | Potential dynamic metering for deeper nesting | -| **Cross-Contract Calls** | Handled through gas forwarding | Requires careful boundary limit implementation | + After a few seconds, you will receive 5000 PAS tokens in your account. -The architecture establishes a constant memory limit per contract, which is the basis for calculating maximum contract nesting depth. This calculation assumes worst-case memory usage for each nested contract, resulting in a straightforward but conservative limit that operates independently of actual memory consumption. Future iterations may introduce dynamic memory metering, allowing deeper nesting depths for contracts with smaller memory footprints. However, such an enhancement would require careful implementation of cross-contract boundary limits before API stabilization, as it would introduce an additional resource metric to the system. +## Reserve a Parachain Identifier -### Current Memory Limits +You must reserve a parachain identifier (ID) before registering your parachain on Paseo. You'll be assigned the next available identifier. -The following table depicts memory-related limits at the time of writing: +To reserve a parachain identifier, follow these steps: -| Limit | Maximum | -|:------------------------------------------:|:---------------:| -| Call stack depth | 5 | -| Event topics | 4 | -| Event data payload size (including topics) | 416 bytes | -| Storage value size | 416 bytes | -| Transient storage variables | 128 uint values | -| Immutable variables | 16 uint values | -| Contract code blob size | ~100 kilobytes | - -!!! note - Limits might be increased in the future. To guarantee existing contracts work as expected, limits will never be decreased. - -## Account Management - Existential Deposit +1. Navigate to the **Parachains** section: -Ethereum and Polkadot handle account persistence differently, affecting state management and contract interactions: + 1. Click on the **Network** tab in the top menu. + 2. Select the **Parachains** option from the dropdown menu. -### Account Management Comparison + ![](/images/parachains/launch-a-parachain/deploy-to-polkadot/deploy-to-polkadot-5.webp) -| Feature | Ethereum Approach | PolkaVM/Polkadot Approach | -|:-------------------------:|:-----------------------------------------------------:|:------------------------------------------------------:| -| **Account Persistence** | Accounts persist indefinitely, even with zero balance | Requires existential deposit (ED) to maintain account | -| **Minimum Balance** | None | ED required | -| **Account Deletion** | Accounts remain in state | Accounts below ED are automatically deleted | -| **Contract Accounts** | Exist indefinitely | Must maintain ED | -| **Balance Reporting** | Reports full balance | Reports ED-adjusted balance via Ethereum RPC | -| **New Account Transfers** | Standard transfer | Includes ED automatically with extra fee cost | -| **Contract-to-Contract** | Direct transfers | ED drawn from transaction signer, not sending contract | -| **State Management** | Potential bloat from zero-balance accounts | Optimized with auto-deletion of dust accounts | +2. Register a ParaId: -This difference introduces potential compatibility challenges for Ethereum-based contracts and tools, particularly wallets. To mitigate this, PolkaVM implements several transparent adjustments: + 1. Select the **Parathreads** tab. + 2. Click on the **+ ParaId** button. -- Balance queries via Ethereum RPC automatically deduct the ED, ensuring reported balances match spendable amounts. -- Account balance checks through EVM opcodes reflect the ED-adjusted balance. -- Transfers to new accounts automatically include the ED (`x + ED`), with the extra cost incorporated into transaction fees. -- Contract-to-contract transfers handle ED requirements by: - - Drawing ED from the transaction signer instead of the sending contract. - - Keeping transfer amounts transparent for contract logic. - - Treating ED like other storage deposit costs. + ![](/images/parachains/launch-a-parachain/deploy-to-polkadot/deploy-to-polkadot-6.webp) -This approach ensures that Ethereum contracts work without modifications while maintaining Polkadot's optimized state management. +3. Review the transaction and click on the **+ Submit** button. -## Contract Deployment + ![](/images/parachains/launch-a-parachain/deploy-to-polkadot/deploy-to-polkadot-7.webp) -For most users deploying contracts (like ERC-20 tokens), contract deployment works seamlessly without requiring special steps. However, when using advanced patterns like factory contracts that dynamically create other contracts at runtime, you'll need to understand PolkaVM's unique deployment model. + For this case, the next available parachain identifier is `4508`. -In the PolkaVM, contract deployment follows a fundamentally different model from EVM. The EVM allows contracts to be deployed with a single transaction, where the contract code is bundled with the deployment transaction. In contrast, PolkaVM has a different process for contract instantiation. +4. After submitting the transaction, you can navigate to the **Explorer** tab and check the list of recent events for successful `registrar.Reserved`. -- **Code must be pre-uploaded**: Unlike EVM, where contract code is bundled within the deploying contract, PolkaVM requires all contract bytecode to be uploaded to the chain before instantiation. -- **Factory pattern limitations**: The common EVM pattern, where contracts dynamically create other contracts, will fail with a `CodeNotFound` error unless the dependent contract code was previously uploaded. -- **Separate upload and instantiation**: This creates a two-step process where developers must first upload all contract code, then instantiate relationships between contracts. + ![](/images/parachains/launch-a-parachain/deploy-to-polkadot/deploy-to-polkadot-8.webp) -This architecture impacts several common EVM patterns and requires developers to adapt their deployment strategies accordingly. _Factory contracts must be modified to work with pre-uploaded code rather than embedding bytecode_, and runtime code generation is not supported due to PolkaVM's RISC-V bytecode format. The specific behavior of contract creation opcodes is detailed in the [YUL IR Translation](#yul-function-translation-differences) section. +## Generate Custom Keys for Your Collators -When migrating EVM projects to PolkaVM, developers should identify all contracts that will be instantiated at runtime and ensure they are pre-uploaded to the chain before any instantiation attempts. +To securely deploy your parachain, it is essential to generate custom keys specifically for your [collators](/reference/glossary/#collator){target=\_blank} (block producers). You should generate two sets of keys for each collator: -## Solidity and YUL IR Translation Incompatibilities +- **Account keys**: Used to interact with the network and manage funds. These should be protected carefully and should never exist on the filesystem of the collator node. -While PolkaVM maintains high-level compatibility with Solidity, several low-level differences exist in the translation of YUL IR and specific Solidity constructs. These differences are particularly relevant for developers working with assembly code or utilizing advanced contract patterns. +- **Session keys**: Used in block production to identify your node and its blocks on the network. These keys are stored in the parachain keystore and function as disposable "hot wallet" keys. If these keys are leaked, someone could impersonate your node, which could result in the slashing of your funds. To minimize these risks, rotating your session keys frequently is essential. Treat them with the same level of caution as you would a hot wallet to ensure the security of your node. -### Contract Code Structure +To perform this step, you can use [subkey](https://docs.rs/crate/subkey/latest){target=\_blank}, a command-line tool for generating and managing keys: -PolkaVM's contract runtime does not differentiate between runtime code and deploy (constructor) code. Instead, both are emitted into a single PolkaVM contract code blob and live on-chain. Therefore, in EVM terminology, the deploy code equals the runtime code. For most standard Solidity contracts, this is transparent. However, if you are analyzing raw bytecode or building tools that expect separate deploy and runtime sections, you'll need to adjust for this unified structure. +```bash +docker run -it parity/subkey:latest generate --scheme sr25519 +``` -In the constructor code, the `codesize` instruction returns the call data size instead of the actual code blob size, which differs from standard EVM behavior. Developers might consider that the constructor logic uses `codesize` to inspect the deployed contract's size (e.g., for self-validation or specific deployment patterns); this will return an incorrect value on PolkaVM. Re-evaluate such logic or use alternative methods to achieve your goal. +The output should look similar to the following: -### Solidity-Specific Differences -Solidity constructs behave differently under PolkaVM: +Ensure that this command is executed twice to generate the keys for both the account and session keys. Save them for future reference. -- **`address.creationCode`**: Returns the bytecode keccak256 hash instead of the actual creation code, reflecting PolkaVM's hash-based code referencing system. - - If your contract relies on `address.creationCode` to verify or interact with the full raw bytecode of a newly deployed contract, this will not work as expected. You will receive a hash, not the code itself. This typically affects highly specialized factory contracts or introspection tools. +## Generate the Chain Specification -### YUL Function Translation Differences +Polkadot SDK-based parachains are defined by a file called the [chain specification](/reference/glossary/#chain-specification){target=\_blank}, or chain spec for short. There are two types of chain spec files: -The following YUL functions exhibit notable behavioral differences in PolkaVM: +- **Plain chain spec**: A human-readable JSON file that can be modified to suit your parachain's requirements. It serves as a template for initial configuration and includes human-readable keys and structures. +- **Raw chain spec**: A binary-encoded file used to start your parachain node. This file is generated from the plain chain spec and contains the encoded information necessary for the parachain node to synchronize with the blockchain network. It ensures compatibility across different runtime versions by providing data in a format directly interpretable by the node's runtime, regardless of upgrades since the chain's genesis. -- Memory operations: +The chain spec file is only required during the initial blockchain creation (genesis). You do not need to generate a new chain spec when performing runtime upgrades after your chain is already running. - - **`mload`, `mstore`, `msize`, `mcopy`**: PolkaVM preserves memory layout but implements several constraints. +The files required to register a parachain must specify the correct relay chain to connect to and the parachain identifier you have been assigned. To make these changes, you must build and modify the chain specification file for your parachain. In this tutorial, the relay chain is `paseo`, and the parachain identifier is `4508`. - - EVM linear heap memory is emulated using a fixed 64KB byte buffer, limiting maximum contract memory usage. - - Accessing memory offsets larger than the buffer size traps the contract with an `OutOfBound` error. - - Compiler optimizations may eliminate unused memory operations, potentially causing `msize` to differ from EVM behavior. +To define your chain specification: - For Solidity developers, the compiler generally handles memory efficiently within this 64KB limit. However, if you are writing low-level YUL assembly and perform direct memory manipulations, you must respect the 64KB buffer limit. Attempting to access memory outside this range will cause your transaction to revert. Be aware that `msize` might not always reflect the exact EVM behavior if compiler optimizations occur. +1. Generate the plain chain specification for the parachain template node by running the following command. Make sure to use the `*.compact.compressed.wasm` version of your compiled runtime when generating your chain specification, and replace `INSERT_PARA_ID` with the ID you obtained in the [Reserve a Parachain Identifier](#reserve-a-parachain-identifier) section: -- Call data operations: + ```bash + chain-spec-builder \ + --chain-spec-path ./plain_chain_spec.json \ + create \ + --relay-chain paseo \ + --para-id INSERT_PARA_ID \ + --runtime target/release/wbuild/parachain-template-runtime/parachain_template_runtime.compact.compressed.wasm \ + named-preset local_testnet + ``` - - **`calldataload`, `calldatacopy`**: In constructor code, the offset parameter is ignored and these functions always return `0`, diverging from EVM behavior where call data represents constructor arguments. +2. Edit the `plain_chain_spec.json` file: - - If your constructor logic in YUL assembly attempts to read constructor arguments using `calldataload` or `calldatacopy` with specific offsets, this will not yield the expected constructor arguments. Instead, these functions will return `zeroed` values. Standard Solidity constructors are handled correctly by the compiler, but manual YUL assembly for constructor argument parsing will need adjustment. + - Update the `name`, `id`, and `protocolId` fields to unique values for your parachain. + - Change `para_id` and `parachainInfo.parachainId` fields to the parachain ID you obtained previously. Make sure to use a number without quotes. + - Modify the `balances` field to specify the initial balances for your accounts in SS58 format. + - Insert the account IDs and session keys in SS58 format generated for your collators in the `collatorSelection.invulnerables` and `session.keys` fields. + - Modify the `sudo` value to specify the account that will have sudo access to the parachain. + + ```json + + ``` -- Code operations: + For this tutorial, the `plain_chain_spec.json` file should look similar to the following. Take into account that the same account is being used for the collator and sudo, which must not be the case in a production environment: - - **`codecopy`**: Only supported within constructor code, reflecting PolkaVM's different approach to code handling and the unified code blob structure. + ??? code "View complete script" - - If your contracts use `codecopy` (e.g., for self-modifying code or inspecting other contract's runtime bytecode) outside of the constructor, this will not be supported and will likely result in a compile-time error or runtime trap. This implies that patterns like dynamically generating or modifying contract code at runtime are not directly feasible with `codecopy` on PolkaVM. + ```json title="plain_chain_spec.json" + + ``` -- Control flow: +3. Save your changes and close the plain text chain specification file. - - **`invalid`**: Traps the contract execution but does not consume remaining gas, unlike EVM where it consumes all available gas. +4. Convert the modified plain chain specification file to a raw chain specification file: - - While `invalid` still reverts the transaction, the difference in gas consumption could subtly affect very specific error handling or gas accounting patterns that rely on `invalid` to consume all remaining gas. For most error scenarios, `revert()` is the standard and recommended practice. + ```bash + chain-spec-builder \ + --chain-spec-path ./raw_chain_spec.json \ + convert-to-raw plain_chain_spec.json + ``` -- Cross-contract calls: + You should now see your chain specification containing SCALE-encoded hex values versus plain text. - - **`call`, `delegatecall`, `staticall`**: These functions ignore supplied gas limits and forward all remaining resources due to PolkaVM's multi-dimensional resource model. This creates important security implications: - - Contract authors must implement reentrancy protection since gas stipends don't provide protection. - - The compiler detects `address payable.{send,transfer}` patterns and disables call reentrancy as a protective heuristic. - - Using `address payable.{send,transfer}` is already deprecated; PolkaVM will provide dedicated precompiles for safe balance transfers. +!!!note "`para_id` Considerations" - The traditional EVM pattern of limiting gas in cross-contract calls (especially with the 2300 gas stipend for send/transfer) does not provide reentrancy protection on PolkaVM. Developers must explicitly implement reentrancy guards (e.g., using a reentrancy lock mutex) in their Solidity code when making external calls to untrusted contracts. Relying on gas limits alone for reentrancy prevention is unsafe and will lead to vulnerabilities on PolkaVM. + The `para_id` field in JSON chain specifications, added through the [`chain-spec-builder`](https://paritytech.github.io/polkadot-sdk/master/staging_chain_spec_builder/index.html){target=\_blank} command, is used by nodes for configuration purposes. Beginning with Polkadot SDK release `stable2509`, runtimes can optionally implement the [`cumulus_primitives_core::GetParachainInfo`](https://paritytech.github.io/polkadot-sdk/master/cumulus_primitives_core/trait.GetParachainInfo.html){target=\_blank} trait as an alternative method for parachain identification. - !!! warning - The 2300 gas stipend that is provided by solc for address payable.{send, transfer} calls offers no reentrancy protection in PolkaVM. While the compiler attempts to detect and mitigate this pattern, developers should avoid these deprecated functions. + However, the `para_id` field will remain supported in chain specifications for backwards compatibility. This ensures that nodes can still sync from genesis or from runtime states that existed before the `GetParachainInfo` runtime API was introduced. -- Contract creation: +## Export Required Files - - **`create`, `create2`**: Contract instantiation works fundamentally differently in PolkaVM. Instead of supplying deploy code concatenated with constructor arguments, the runtime expects: +To prepare the parachain collator to be registered on Paseo, follow these steps: - 1. A buffer containing the code hash to deploy. - 2. The constructor arguments buffer. +1. Export the Wasm runtime for the parachain by running the following command: - PolkaVM translates `dataoffset` and `datasize` instructions to handle contract hashes instead of contract code, enabling seamless use of the `new` keyword in Solidity. However, this translation may fail for contracts creating other contracts within `assembly` blocks. + ```bash + polkadot-omni-node export-genesis-wasm \ + --chain raw_chain_spec.json para-wasm + ``` - If you use the Solidity `new` keyword to deploy contracts, the Revive compiler handles this transparently. However, if you are creating contracts manually in YUL assembly using `create` or `create2` opcodes, you must provide the code hash of the contract to be deployed, not its raw bytecode. Attempting to pass raw bytecode will fail. This fundamentally changes how manual contract creation is performed in assembly. +2. Export the genesis state for the parachain by running the following command: - !!! warning - Avoid using `create` family opcodes for manual deployment crafting in `assembly` blocks. This pattern is discouraged due to translation complexity and offers no gas savings benefits in PolkaVM. + ```bash + polkadot-omni-node export-genesis-head \ + --chain raw_chain_spec.json para-state + ``` -- Data operations: +## Register a Parathread - - **`dataoffset`**: Returns the contract hash instead of code offset, aligning with PolkaVM's hash-based code referencing. - - **`datasize`**: Returns the constant contract hash size (32 bytes) rather than variable code size. +Once you have the genesis state and runtime, you can now register these with your parachain ID. - These changes are primarily relevant for low-level YUL assembly developers who are trying to inspect or manipulate contract code directly. `dataoffset` will provide a hash, not a memory offset to the code, and `datasize` will always be 32 bytes (the size of a hash). This reinforces that direct manipulation of contract bytecode at runtime, as might be done in some EVM patterns, is not supported. +1. Go to the [Parachains > Parathreads](https://polkadot.js.org/apps/#/parachains/parathreads){target=\_blank} tab, and select **+ Parathread**. + +2. You should see fields to place your runtime Wasm and genesis state respectively, along with the parachain ID. Select your parachain ID, and upload `para-wasm` in the **code** field and `para-state` in the **initial state** field. -- Resource queries: + ![](/images/parachains/launch-a-parachain/deploy-to-polkadot/deploy-to-polkadot-9.webp) + +3. Confirm your details and **+ Submit** button, where there should be a new Parathread with your parachain ID and an active **Deregister** button. - - **`gas`, `gaslimit`**: Return only the `ref_time` component of PolkaVM's multi-dimensional weight system, providing the closest analog to traditional gas measurements. + ![](/images/parachains/launch-a-parachain/deploy-to-polkadot/deploy-to-polkadot-10.webp) - - While `gas` and `gaslimit` still provide a useful metric, consider that they represent `ref_time` (computation time) only. If your contract logic depends on precise knowledge of other resource costs (like `proof_size` or `storage_deposit`), you won't get that information from these opcodes. You'll need to use future precompiles for full multi-dimensional resource queries. +Your parachain's runtime logic and genesis are now part of the relay chain. The next step is to ensure you are able to run a collator to produce blocks for your parachain. -- Blockchain state: +!!!note + You may need to wait several hours for your parachain to onboard. Until it has onboarded, you will be unable to purchase coretime, and therefore will not be able to perform transactions on your network. - - **`prevrandao`, `difficulty`**: Both translate to a constant value of `2500000000000000`, as PolkaVM doesn't implement Ethereum's difficulty adjustment or randomness mechanisms. +## Start the Collator Node - - If your Solidity contract relies on `block.difficulty` (or its equivalent YUL opcode `difficulty`) for randomness generation or any logic tied to Ethereum's proof-of-work difficulty, this will not provide true randomness on PolkaVM. The value will always be constant. Developers needing on-chain randomness should utilize Polkadot's native randomness sources or dedicated VRF (Verifiable Random Function) solutions if available. +Before starting a collator, you need to generate a node key. This key is responsible for communicating with other nodes over Libp2p: -### Unsupported Operations +```bash +polkadot-omni-node key generate-node-key \ +--base-path data \ +--chain raw_chain_spec.json +``` -Several EVM operations are not supported in PolkaVM and produce compile-time errors: +After running the command, you should see the following output, indicating the base path now has a suitable node key: -- **`pc`, `extcodecopy`**: These operations are EVM-specific and have no equivalent functionality in PolkaVM's RISC-V architecture. - - Any Solidity contracts that utilize inline assembly to interact with `pc` (program counter) or `extcodecopy` will fail to compile or behave unexpectedly. This means patterns involving introspection of the current execution location or copying external contract bytecode at runtime are not supported. +You must have the ports for the collator publicly accessible and discoverable to enable parachain nodes to peer with Paseo validator nodes to produce blocks. You can specify the ports with the `--port` command-line option. You can start the collator with a command similar to the following: -- **`blobhash`, `blobbasefee`**: Related to Ethereum's rollup model and blob data handling, these operations are unnecessary given Polkadot's superior rollup architecture. +```bash +polkadot-omni-node --collator \ +--chain raw_chain_spec.json \ +--base-path data \ +--port 40333 \ +--rpc-port 8845 \ +--force-authoring \ +--node-key-file ./data/chains/custom/network/secret_ed25519 \ +-- \ +--sync warp \ +--chain paseo \ +--port 50343 \ +--rpc-port 9988 +``` - - If you are porting contracts designed for Ethereum's EIP-4844 (proto-danksharding) and rely on these blob-related opcodes, they will not be available on PolkaVM. +In this example, the first `--port` setting specifies the port for the collator node, and the second `--port` specifies the embedded relay chain node port. The first `--rpc-port` setting specifies the port you can connect to the collator. The second `--rpc-port` specifies the port for connecting to the embedded relay chain. -- **`extcodecopy`, `selfdestruct`**: These deprecated operations are not supported and generate compile-time errors. +Before proceeding, ensure that the collator node is running. Then, open a new terminal and insert your generated session key into the collator keystore by running the following command. Use the same port specified in the `--rpc-port` parameter when starting the collator node (`8845` in this example) to connect to it. Replace `INSERT_SECRET_PHRASE` and `INSERT_PUBLIC_KEY_HEX_FORMAT` with the values from the session key you generated in the [Generate Custom Keys for Your Collators](#generate-custom-keys-for-your-collators) section: - - The `selfdestruct` opcode, which allowed contracts to remove themselves from the blockchain, is not supported. Contracts cannot be self-destroyed on PolkaVM. This affects contract upgradeability patterns that rely on self-destruction and redeployment. Similarly, `extcodecopy` is unsupported, impacting contracts that intend to inspect or copy the bytecode of other deployed contracts. +```bash +curl -H "Content-Type: application/json" \ +--data '{ + "jsonrpc":"2.0", + "method":"author_insertKey", + "params":[ + "aura", + "INSERT_SECRET_PHRASE", + "INSERT_PUBLIC_KEY_HEX_FORMAT" + ], + "id":1 +}' \ +http://localhost:8845 +``` -### Compilation Pipeline Considerations +If successful, you should see the following response: -PolkaVM processes YUL IR exclusively, meaning all contracts exhibit behavior consistent with Solidity's `via-ir` compilation mode. Developers familiar with the legacy compilation pipeline should expect [IR-based codegen behavior](https://docs.soliditylang.org/en/latest/ir-breaking-changes.html){target=\_blank} when working with PolkaVM contracts. +```json +{"jsonrpc":"2.0","result":null,"id":1} +``` -If you've previously worked with older Solidity compilers that did not use the `via-ir` pipeline by default, you might observe subtle differences in compiled bytecode size or gas usage. It's recommended to familiarize yourself with Solidity's IR-based codegen behavior, as this is the standard for PolkaVM. +Once your collator is synced with the Paseo relay chain, and your parathread finished onboarding, it will be ready to start producing blocks. This process may take some time. -### Memory Pointer Limitations +## Producing Blocks -YUL functions accepting memory buffer offset pointers or size arguments are limited by PolkaVM's 32-bit pointer size. Supplying values above `2^32-1` will trap the contract immediately. The Solidity compiler typically generates valid memory references, making this primarily a concern for low-level assembly code. +With your parachain collator operational, the next step is acquiring coretime. This is essential for ensuring your parachain's security through the relay chain. [Agile Coretime](https://wiki.polkadot.com/learn/learn-agile-coretime/){target=\_blank} enhances Polkadot's resource management, offering developers greater economic adaptability. Once you have configured your parachain, you can follow two paths: -For standard Solidity development, this limitation is unlikely to be hit as the compiler handles memory addresses correctly within typical contract sizes. However, if you are writing extremely large contracts using YUL assembly that manually and extensively manipulate memory addresses, ensure that your memory offsets and sizes do not exceed PolkaVM's **fixed 64KB memory limit per contract**. While the YUL functions might accept 32-bit pointers (up to 2^32-1), attempting to access memory beyond the allocated 64KB buffer will trap the contract immediately. +- Bulk coretime is purchased via the Broker pallet on the respective coretime system parachain. You can purchase bulk coretime on the coretime chain and assign the purchased core to the registered `ParaID`. +- On-demand coretime is ordered via the [`OnDemand`](https://paritytech.github.io/polkadot-sdk/master/polkadot_runtime_parachains/on_demand/index.html){target=\_blank} pallet, which is located on the respective relay chain. -These incompatibilities reflect the fundamental architectural differences between EVM and PolkaVM while maintaining high-level Solidity compatibility. Most developers using standard Solidity patterns will encounter no issues, but those working with assembly code or advanced contract patterns should carefully review these differences during migration. +Once coretime is correctly assigned to your parachain, whether bulk or on-demand, blocks should be produced (provided your collator is running). --- -Page Title: Fork a Chain with Chopsticks +Page Title: Dual Virtual Machine Stack -- Source (raw): https://raw.githubusercontent.com/polkadot-developers/polkadot-docs/master/.ai/pages/tutorials-polkadot-sdk-testing-fork-live-chains.md -- Canonical (HTML): https://docs.polkadot.com/tutorials/polkadot-sdk/testing/fork-live-chains/ -- Summary: Learn how to fork live Polkadot SDK chains with Chopsticks. Configure forks, replay blocks, test XCM, and interact programmatically or via UI. +- Source (raw): https://raw.githubusercontent.com/polkadot-developers/polkadot-docs/master/.ai/pages/smart-contracts-for-eth-devs-dual-vm-stack.md +- Canonical (HTML): https://docs.polkadot.com/smart-contracts/for-eth-devs/dual-vm-stack/ +- Summary: Compare Polkadot’s dual smart contract VMs—REVM for EVM compatibility and PolkaVM for RISC-V performance, flexibility, and efficiency. -# Fork a Chain with Chopsticks +# Dual Virtual Machine Stack +!!! smartcontract "PolkaVM Preview Release" + PolkaVM smart contracts with Ethereum compatibility are in **early-stage development and may be unstable or incomplete**. ## Introduction -Chopsticks is an innovative tool that simplifies the process of forking live Polkadot SDK chains. This guide provides step-by-step instructions to configure and fork chains, enabling developers to: +Polkadot's smart contract platform supports two distinct virtual machine (VM) architectures, providing developers with flexibility in selecting the optimal execution backend for their specific needs. This approach strikes a balance between immediate Ethereum compatibility and long-term innovation, enabling developers to deploy either unmodified (Ethereum Virtual Machine) EVM contracts using Rust Ethereum Virtual Machine (REVM) or optimize for higher performance using PolkaVM (PVM). -- Replay blocks for state analysis. -- Test cross-chain messaging (XCM). -- Simulate blockchain environments for debugging and experimentation. +Both VM options share common infrastructure, including RPC interfaces, tooling support, and precompiles. The following sections compare architectures and guide you in selecting the best VM for your project's needs. -With support for both configuration files and CLI commands, Chopsticks offers flexibility for diverse development workflows. Whether you're testing locally or exploring complex blockchain scenarios, Chopsticks empowers developers to gain deeper insights and accelerate application development. +## Migrate from EVM -Chopsticks uses the [Smoldot](https://github.com/smol-dot/smoldot){target=\_blank} light client, which does not support calls made through the Ethereum JSON-RPC. As a result, you can't fork your chain using Chopsticks and then interact with it using tools like MetaMask. +The [REVM backend](https://github.com/bluealloy/revm){target=\_blank} integrates a complete Rust implementation of the EVM, enabling Solidity contracts to run unchanged on Polkadot's smart contract platform. -For additional support and information, please reach out through [GitHub Issues](https://github.com/AcalaNetwork/chopsticks/issues){target=\_blank}. +REVM allows developers to use their existing Ethereum tooling and infrastructure to build on Polkadot. Choose REVM to: + +- Migrate existing Ethereum contracts without modifications. +- Retain exact EVM behavior for audit tools. +- Use developer tools that rely upon inspecting EVM bytecode. +- Prioritize rapid deployment over optimization. +- Work with established Ethereum infrastructure and tooling to build on Polkadot. + +REVM enables Ethereum developers to seamlessly migrate to Polkadot, achieving performance and fee improvements without modifying their existing contracts or developer tooling stack. + +## Upgrade to PolkaVM + +[**PolkaVM**](https://github.com/paritytech/polkavm){target=\_blank} is a custom virtual machine optimized for performance with [RISC-V-based](https://en.wikipedia.org/wiki/RISC-V){target=\_blank} architecture, supporting Solidity and additional high-performance languages. It serves as the core execution environment, integrated directly within the runtime. Choose the PolkaVM for: + +- An efficient interpreter for immediate code execution. +- A planned [Just In Time (JIT)](https://en.wikipedia.org/wiki/Just-in-time_compilation){target=\_blank} compiler for optimized performance. +- Dual-mode execution capability, allowing selection of the most appropriate backend for specific workloads. +- Optimized performance for short-running contract calls through the interpreter. + +The interpreter remains particularly beneficial for contracts with minimal code execution, as it enables immediate code execution through lazy interpretation. + +## Architecture + +The following key components of PolkaVM work together to enable Ethereum compatibility on Polkadot-based chains. + +### Revive Pallet + +[**`pallet_revive`**](https://paritytech.github.io/polkadot-sdk/master/pallet_revive/index.html){target=\_blank} is a runtime module that executes smart contracts by adding extrinsics, runtime APIs, and logic to convert Ethereum-style transactions into formats compatible with Polkadot SDK-based blockchains. It processes Ethereum-style transactions through the following workflow: + +```mermaid +sequenceDiagram + participant User as User/dApp + participant Proxy as Ethereum JSON RPC Proxy + participant Chain as Blockchain Node + participant Pallet as pallet_revive + + User->>Proxy: Submit Ethereum Transaction + Proxy->>Chain: Repackage as Polkadot Compatible Transaction + Chain->>Pallet: Process Transaction + Pallet->>Pallet: Decode Ethereum Transaction + Pallet->>Pallet: Execute Contract via PolkaVM + Pallet->>Chain: Return Results + Chain->>Proxy: Forward Results + Proxy->>User: Return Ethereum-compatible Response +``` + +This proxy-based approach eliminates the need for node binary modifications, maintaining compatibility across different client implementations. Preserving the original Ethereum transaction payload simplifies the adaptation of existing tools, which can continue processing familiar transaction formats. + +### PolkaVM Design Fundamentals + +PolkaVM differs from the EVM in two key ways that make it faster, more hardware-efficient, and easier to extend: + +- **Register-based design**: Instead of a stack machine, PolkaVM uses a RISC-V–style register model. This design: + + - Uses a fixed set of registers to pass arguments, not an infinite stack. + - Maps cleanly to real hardware like x86-64. + - Simplifies compilation and boosts runtime efficiency. + - Enables tighter control over register allocation and performance tuning. + +- **64-bit word size**: PolkaVM runs on a native 64-bit word size, aligning directly with modern CPUs. This design: + + - Executes arithmetic operations with direct hardware support. + - Maintains compatibility with Solidity’s 256-bit types via YUL translation. + - Accelerates computation-heavy workloads through native word alignment. + - Integrates easily with low-level, performance-focused components. + +## Where To Go Next + +
+ +- Learn __Contract Deployment__ + + --- + + Learn how REVM and PVM compare for compiling and deploying smart contracts. + + [:octicons-arrow-right-24: Reference](/smart-contracts/for-eth-devs/contract-deployment/) + +
+ + +--- + +Page Title: E2E Testing with Moonwall + +- Source (raw): https://raw.githubusercontent.com/polkadot-developers/polkadot-docs/master/.ai/pages/reference-tools-moonwall.md +- Canonical (HTML): https://docs.polkadot.com/reference/tools/moonwall/ +- Summary: Enhance blockchain end-to-end testing with Moonwall's standardized environment setup, comprehensive configuration management, and simple network interactions. + +# E2E Testing with Moonwall + +## Introduction + +Moonwall is an end-to-end testing framework designed explicitly for Polkadot SDK-based blockchain networks. It addresses one of the most significant challenges in blockchain development: managing complex test environments and network configurations. + +Moonwall consolidates this complexity by providing the following: + +- A centralized configuration management system that explicitly defines all network parameters. +- A standardized approach to environment setup across different Substrate-based chains. +- Built-in utilities for common testing scenarios and network interactions. + +Developers can focus on writing meaningful tests rather than managing infrastructure complexities or searching through documentation for configuration options. ## Prerequisites -To follow this tutorial, ensure you have completed the following: +Before you begin, ensure you have the following installed: -- **Installed Chopsticks**: If you still need to do so, see the [Install Chopsticks](/parachains/testing/#install-chopsticks){target=\_blank} instructions for assistance. -- **Reviewed [Configure Chopsticks](/parachains/testing/#configure-chopsticks){target=\_blank}**: You should understand how forked chains are configured. +- [Node.js](https://nodejs.org/en/){target=\_blank} (version 20.10 or higher). +- A package manager such as [npm](https://www.npmjs.com/){target=\_blank}, [yarn](https://yarnpkg.com/){target=\_blank}, or [pnpm](https://pnpm.io/){target=\_blank}. -## Configuration File +## Install Moonwall -To run Chopsticks using a configuration file, utilize the `--config` flag. You can use a raw GitHub URL, a path to a local file, or simply the chain's name. The following commands all look different but they use the `polkadot` configuration in the same way: +Moonwall can be installed globally for system-wide access or locally within specific projects. This section covers both installation methods. -=== "GitHub URL" +!!! tip + This documentation corresponds to Moonwall version `5.15.0`. To avoid compatibility issues with the documented features, ensure you're using the matching version. - ```bash - npx @acala-network/chopsticks \ - --config=https://raw.githubusercontent.com/AcalaNetwork/chopsticks/master/configs/polkadot.yml - ``` +### Global Installation -=== "Local File Path" +Global installation provides system-wide access to the Moonwall CLI, making it ideal for developers working across multiple blockchain projects. Install it by running one of the following commands: + +=== "npm" ```bash - npx @acala-network/chopsticks --config=configs/polkadot.yml + npm install -g @moonwall/cli@5.15.0 ``` -=== "Chain Name" +=== "pnpm" ```bash - npx @acala-network/chopsticks --config=polkadot + pnpm -g install @moonwall/cli@5.15.0 ``` -Regardless of which method you choose from the preceding examples, you'll see an output similar to the following: +=== "yarn" -
- npx @acala-network/chopsticks --config=polkadot -
- [18:38:26.155] INFO: Loading config file https://raw.githubusercontent.com/AcalaNetwork/chopsticks/master/configs/polkadot.yml - app: "chopsticks" - chopsticks::executor TRACE: Calling Metadata_metadata - chopsticks::executor TRACE: Completed Metadata_metadata - [18:38:28.186] INFO: Polkadot RPC listening on port 8000 - app: "chopsticks" -
+ ```bash + yarn global add @moonwall/cli@5.15.0 + ``` -If using a file path, make sure you've downloaded the [Polkadot configuration file](https://github.com/AcalaNetwork/chopsticks/blob/master/configs/polkadot.yml){target=\_blank}, or have created your own. +Now, you can run the `moonwall` command from your terminal. -## Create a Fork +### Local Installation -Once you've configured Chopsticks, use the following command to fork Polkadot at block 100: +Local installation is recommended for better dependency management and version control within a specific project. First, initialize your project: ```bash -npx @acala-network/chopsticks \ ---endpoint wss://polkadot-rpc.dwellir.com \ ---block 100 +mkdir my-moonwall-project +cd my-moonwall-project +npm init -y ``` -If the fork is successful, you will see output similar to the following: - -
- npx @acala-network/chopsticks \ --endpoint wss://polkadot-rpc.dwellir.com \ --block 100 -
- [19:12:21.023] INFO: Polkadot RPC listening on port 8000 - app: "chopsticks" -
- -Access the running Chopsticks fork using the default address. +Then, install it as a local dependency: -```bash -ws://localhost:8000 -``` +=== "npm" -## Interact with a Fork + ```bash + npm install @moonwall/cli@5.15.0 + ``` -You can interact with the forked chain using various [libraries](/develop/toolkit/#libraries){target=\_blank} such as [Polkadot.js](https://polkadot.js.org/docs/){target=\_blank} and its user interface, [Polkadot.js Apps](https://polkadot.js.org/apps/#/explorer){target=\_blank}. +=== "pnpm" -### Use Polkadot.js Apps + ```bash + pnpm install @moonwall/cli@5.15.0 + ``` -To interact with Chopsticks via the hosted user interface, visit [Polkadot.js Apps](https://polkadot.js.org/apps/#/explorer){target=\_blank} and follow these steps: +=== "yarn" -1. Select the network icon in the top left corner. + ```bash + yarn add @moonwall/cli@5.15.0 + ``` - ![](/images/tutorials/polkadot-sdk/testing/fork-live-chains/chopsticks-1.webp) +## Initialize Moonwall -2. Scroll to the bottom and select **Development**. -3. Choose **Custom**. -4. Enter `ws://localhost:8000` in the input field. -5. Select the **Switch** button. +The `moonwall init` command launches an interactive wizard to create your configuration file: - ![](/images/tutorials/polkadot-sdk/testing/fork-live-chains/chopsticks-2.webp) +```bash +moonwall init +``` -You should now be connected to your local fork and can interact with it as you would with a real chain. +During setup, you will see prompts for the following parameters: -### Use Polkadot.js Library +- **`label`**: Identifies your test configuration. +- **`global timeout`**: Maximum time (ms) for test execution. +- **`environment name`**: Name for your testing environment. +- **`network foundation`**: Type of blockchain environment to use. +- **`tests directory`**: Location of your test files. -For programmatic interaction, you can use the Polkadot.js library. The following is a basic example: +Select `Enter` to accept defaults or input custom values. You should see something like this: -```js -import { ApiPromise, WsProvider } from '@polkadot/api'; +
+ moonwall init + ✔ Provide a label for the config file moonwall_config + ✔ Provide a global timeout value 30000 + ✔ Provide a name for this environment default_env + ✔ What type of network foundation is this? dev + ✔ Provide the path for where tests for this environment are kept tests/ + ? Would you like to generate this config? (no to restart from beginning) (Y/n) +
-async function connectToFork() { - const wsProvider = new WsProvider('ws://localhost:8000'); - const api = await ApiPromise.create({ provider: wsProvider }); - await api.isReady; +The wizard generates a `moonwall.config` file: - // Now you can use 'api' to interact with your fork - console.log(`Connected to chain: ${await api.rpc.system.chain()}`); +```json +{ + "label": "moonwall_config", + "defaultTestTimeout": 30000, + "environments": [ + { + "name": "default_env", + "testFileDir": ["tests/"], + "foundation": { + "type": "dev" + } + } + ] } -connectToFork(); - ``` -## Replay Blocks +The default configuration requires specific details about your blockchain node and test requirements: -Chopsticks allows you to replay specific blocks from a chain, which is useful for debugging and analyzing state changes. You can use the parameters in the [Configuration](/parachains/testing/#configure-chopsticks){target=\_blank} section to set up the chain configuration, and then use the run-block subcommand with the following additional options: +- The `foundation` object defines how your test blockchain node will be launched and managed. The dev foundation, which runs a local node binary, is used for local development. -- **`output-path`**: Path to print output. -- **`html`**: Generate HTML with storage diff. -- **`open`**: Open generated HTML. + For more information about available options, check the [Foundations](https://moonsong-labs.github.io/moonwall/guide/intro/foundations.html){target=\_blank} section. -For example, the command to replay block 1000 from Polkadot and save the output to a JSON file would be as follows: +- The `connections` array specifies how your tests will interact with the blockchain node. This typically includes provider configuration and endpoint details. -```bash -npx @acala-network/chopsticks run-block \ ---endpoint wss://polkadot-rpc.dwellir.com \ ---output-path ./polkadot-output.json \ ---block 1000 -``` + A provider is a tool that allows you or your application to connect to a blockchain network and simplifies the low-level details of the process. A provider handles submitting transactions, reading state, and more. For more information on available providers, check the [Providers supported](https://moonsong-labs.github.io/moonwall/guide/intro/providers.html#providers-supported){target=\_blank} page in the Moonwall documentation. -??? code "polkadot-output.json" +Here's a complete configuration example for testing a local node using Polkadot.js as a provider: - ```json - { - "Call": { - "result": "0xba754e7478944d07a1f7e914422b4d973b0855abeb6f81138fdca35beb474b44a10f6fc59a4d90c3b78e38fac100fc6adc6f9e69a07565ec8abce6165bd0d24078cc7bf34f450a2cc7faacc1fa1e244b959f0ed65437f44208876e1e5eefbf8dd34c040642414245b501030100000083e2cc0f00000000d889565422338aa58c0fd8ebac32234149c7ce1f22ac2447a02ef059b58d4430ca96ba18fbf27d06fe92ec86d8b348ef42f6d34435c791b952018d0a82cae40decfe5faf56203d88fdedee7b25f04b63f41f23da88c76c876db5c264dad2f70c", - "storageDiff": [ - [ - "0x0b76934f4cc08dee01012d059e1b83eebbd108c4899964f707fdaffb82636065", - "0x00" - ], - [ - "0x1cb6f36e027abb2091cfb5110ab5087f0323475657e0890fbdbf66fb24b4649e", - null - ], - [ - "0x1cb6f36e027abb2091cfb5110ab5087f06155b3cd9a8c9e5e9a23fd5dc13a5ed", - "0x83e2cc0f00000000" - ], - [ - "0x1cb6f36e027abb2091cfb5110ab5087ffa92de910a7ce2bd58e99729c69727c1", - null - ], - [ - "0x26aa394eea5630e07c48ae0c9558cef702a5c1b19ab7a04f536c519aca4983ac", - null - ], - [ - "0x26aa394eea5630e07c48ae0c9558cef70a98fdbe9ce6c55837576c60c7af3850", - "0x02000000" - ], - [ - "0x26aa394eea5630e07c48ae0c9558cef734abf5cb34d6244378cddbf18e849d96", - "0xc03b86ae010000000000000000000000" - ], - [ - "0x26aa394eea5630e07c48ae0c9558cef780d41e5e16056765bc8461851072c9d7", - "0x080000000000000080e36a09000000000200000001000000000000ca9a3b00000000020000" - ], - [ - "0x26aa394eea5630e07c48ae0c9558cef78a42f33323cb5ced3b44dd825fda9fcc", - null - ], - [ - "0x26aa394eea5630e07c48ae0c9558cef799e7f93fc6a98f0874fd057f111c4d2d", - null - ], - [ - "0x26aa394eea5630e07c48ae0c9558cef7a44704b568d21667356a5a050c118746d366e7fe86e06375e7030000", - "0xba754e7478944d07a1f7e914422b4d973b0855abeb6f81138fdca35beb474b44" - ], - [ - "0x26aa394eea5630e07c48ae0c9558cef7a86da5a932684f199539836fcb8c886f", - null - ], - [ - "0x26aa394eea5630e07c48ae0c9558cef7b06c3320c6ac196d813442e270868d63", - null - ], - [ - "0x26aa394eea5630e07c48ae0c9558cef7bdc0bd303e9855813aa8a30d4efc5112", - null - ], - [ - "0x26aa394eea5630e07c48ae0c9558cef7df1daeb8986837f21cc5d17596bb78d15153cb1f00942ff401000000", - null - ], - [ - "0x26aa394eea5630e07c48ae0c9558cef7df1daeb8986837f21cc5d17596bb78d1b4def25cfda6ef3a00000000", - null - ], - [ - "0x26aa394eea5630e07c48ae0c9558cef7ff553b5a9862a516939d82b3d3d8661a", - null - ], - [ - "0x2b06af9719ac64d755623cda8ddd9b94b1c371ded9e9c565e89ba783c4d5f5f9b4def25cfda6ef3a000000006f3d6b177c8acbd8dc9974cdb3cebfac4d31333c30865ff66c35c1bf898df5c5dd2924d3280e7201", - "0x9b000000" - ], - ["0x3a65787472696e7369635f696e646578", null], - [ - "0x3f1467a096bcd71a5b6a0c8155e208103f2edf3bdf381debe331ab7446addfdc", - "0x550057381efedcffffffffffffffffff" - ], - [ - "0x3fba98689ebed1138735e0e7a5a790ab0f41321f75df7ea5127be2db4983c8b2", - "0x00" - ], - [ - "0x3fba98689ebed1138735e0e7a5a790ab21a5051453bd3ae7ed269190f4653f3b", - "0x080000" - ], - [ - "0x3fba98689ebed1138735e0e7a5a790abb984cfb497221deefcefb70073dcaac1", - "0x00" - ], - [ - "0x5f3e4907f716ac89b6347d15ececedca80cc6574281671b299c1727d7ac68cabb4def25cfda6ef3a00000000", - "0x204e0000183887050ecff59f58658b3df63a16d03a00f92890f1517f48c2f6ccd215e5450e380e00005809fd84af6483070acbb92378e3498dbc02fb47f8e97f006bb83f60d7b2b15d980d000082104c22c383925323bf209d771dec6e1388285abe22c22d50de968467e0bb6ce00b000088ee494d719d68a18aade04903839ea37b6be99552ceceb530674b237afa9166480d0000dc9974cdb3cebfac4d31333c30865ff66c35c1bf898df5c5dd2924d3280e72011c0c0000e240d12c7ad07bb0e7785ee6837095ddeebb7aef84d6ed7ea87da197805b343a0c0d0000" - ], - [ - "0xae394d879ddf7f99595bc0dd36e355b5bbd108c4899964f707fdaffb82636065", - null - ], - [ - "0xbd2a529379475088d3e29a918cd478721a39ec767bd5269111e6492a1675702a", - "0x4501407565175cfbb5dca18a71e2433f838a3d946ef532c7bff041685db1a7c13d74252fffe343a960ef84b15187ea0276687d8cb3168aeea5202ea6d651cb646517102b81ff629ee6122430db98f2cadf09db7f298b49589b265dae833900f24baa8fb358d87e12f3e9f7986a9bf920c2fb48ce29886199646d2d12c6472952519463e80b411adef7e422a1595f1c1af4b5dd9b30996fba31fa6a30bd94d2022d6b35c8bc5a8a51161d47980bf4873e01d15afc364f8939a6ce5a09454ab7f2dd53bf4ee59f2c418e85aa6eb764ad218d0097fb656900c3bdd859771858f87bf7f06fc9b6db154e65d50d28e8b2374898f4f519517cd0bedc05814e0f5297dc04beb307b296a93cc14d53afb122769dfd402166568d8912a4dff9c2b1d4b6b34d811b40e5f3763e5f3ab5cd1da60d75c0ff3c12bcef3639f5f792a85709a29b752ffd1233c2ccae88ed3364843e2fa92bdb49021ee36b36c7cdc91b3e9ad32b9216082b6a2728fccd191a5cd43896f7e98460859ca59afbf7c7d93cd48da96866f983f5ff8e9ace6f47ee3e6c6edb074f578efbfb0907673ebca82a7e1805bc5c01cd2fa5a563777feeb84181654b7b738847c8e48d4f575c435ad798aec01631e03cf30fe94016752b5f087f05adf1713910767b7b0e6521013be5370776471191641c282fdfe7b7ccf3b2b100a83085cd3af2b0ad4ab3479448e71fc44ff987ec3a26be48161974b507fb3bc8ad23838f2d0c54c9685de67dc6256e71e739e9802d0e6e3b456f6dca75600bc04a19b3cc1605784f46595bfb10d5e077ce9602ae3820436166aa1905a7686b31a32d6809686462bc9591c0bc82d9e49825e5c68352d76f1ac6e527d8ac02db3213815080afad4c2ecb95b0386e3e9ab13d4f538771dac70d3059bd75a33d0b9b581ec33bb16d0e944355d4718daccb35553012adfcdacb1c5200a2aec3756f6ad5a2beffd30018c439c1b0c4c0f86dbf19d0ad59b1c9efb7fe90906febdb9001af1e7e15101089c1ab648b199a40794d30fe387894db25e614b23e833291a604d07eec2ade461b9b139d51f9b7e88475f16d6d23de6fe7831cc1dbba0da5efb22e3b26cd2732f45a2f9a5d52b6d6eaa38782357d9ae374132d647ef60816d5c98e6959f8858cfa674c8b0d340a8f607a68398a91b3a965585cc91e46d600b1310b8f59c65b7c19e9d14864a83c4ad6fa4ba1f75bba754e7478944d07a1f7e914422b4d973b0855abeb6f81138fdca35beb474b44c7736fc3ab2969878810153aa3c93fc08c99c478ed1bb57f647d3eb02f25cee122c70424643f4b106a7643acaa630a5c4ac39364c3cb14453055170c01b44e8b1ef007c7727494411958932ae8b3e0f80d67eec8e94dd2ff7bbe8c9e51ba7e27d50bd9f52cbaf9742edecb6c8af1aaf3e7c31542f7d946b52e0c37d194b3dd13c3fddd39db0749755c7044b3db1143a027ad428345d930afcefc0d03c3a0217147900bdea1f5830d826f7e75ecd1c4e2bc8fd7de3b35c6409acae1b2215e9e4fd7e360d6825dc712cbf9d87ae0fd4b349b624d19254e74331d66a39657da81e73d7b13adc1e5efa8efd65aa32c1a0a0315913166a590ae551c395c476116156cf9d872fd863893edb41774f33438161f9b973e3043f819d087ba18a0f1965e189012496b691f342f7618fa9db74e8089d4486c8bd1993efd30ff119976f5cc0558e29b417115f60fd8897e13b6de1a48fbeee38ed812fd267ae25bffea0caa71c09309899b34235676d5573a8c3cf994a3d7f0a5dbd57ab614c6caf2afa2e1a860c6307d6d9341884f1b16ef22945863335bb4af56e5ef5e239a55dbd449a4d4d3555c8a3ec5bd3260f88cabca88385fe57920d2d2dfc5d70812a8934af5691da5b91206e29df60065a94a0a8178d118f1f7baf768d934337f570f5ec68427506391f51ab4802c666cc1749a84b5773b948fcbe460534ed0e8d48a15c149d27d67deb8ea637c4cc28240ee829c386366a0b1d6a275763100da95374e46528a0adefd4510c38c77871e66aeda6b6bfd629d32af9b2fad36d392a1de23a683b7afd13d1e3d45dad97c740106a71ee308d8d0f94f6771164158c6cd3715e72ccfbc49a9cc49f21ead8a3c5795d64e95c15348c6bf8571478650192e52e96dd58f95ec2c0fb4f2ccc05b0ab749197db8d6d1c6de07d6e8cb2620d5c308881d1059b50ffef3947c273eaed7e56c73848e0809c4bd93619edd9fd08c8c5c88d5f230a55d2c6a354e5dd94440e7b5bf99326cf4a112fe843e7efdea56e97af845761d98f40ed2447bd04a424976fcf0fe0a0c72b97619f85cf431fe4c3aa6b3a4f61df8bc1179c11e77783bfedb7d374bd1668d0969333cb518bd20add8329462f2c9a9f04d150d60413fdd27271586405fd85048481fc2ae25b6826cb2c947e4231dc7b9a0d02a9a03f88460bced3fef5d78f732684bd218a1954a4acfc237d79ccf397913ab6864cd8a07e275b82a8a72520624738368d1c5f7e0eaa2b445cf6159f2081d3483618f7fc7b16ec4e6e4d67ab5541bcda0ca1af40efd77ef8653e223191448631a8108c5e50e340cd405767ecf932c1015aa8856b834143dc81fa0e8b9d1d8c32278fca390f2ff08181df0b74e2d13c9b7b1d85543416a0dae3a77530b9cd1366213fcf3cd12a9cd3ae0a006d6b29b5ffc5cdc1ab24343e2ab882abfd719892fca5bf2134731332c5d3bef6c6e4013d84a853cb03d972146b655f0f8541bcd36c3c0c8a775bb606edfe50d07a5047fd0fe01eb125e83673930bc89e91609fd6dfe97132679374d3de4a0b3db8d3f76f31bed53e247da591401d508d65f9ee01d3511ee70e3644f3ab5d333ca7dbf737fe75217b4582d50d98b5d59098ea11627b7ed3e3e6ee3012eadd326cf74ec77192e98619427eb0591e949bf314db0fb932ed8be58258fb4f08e0ccd2cd18b997fb5cf50c90d5df66a9f3bb203bd22061956128b800e0157528d45c7f7208c65d0592ad846a711fa3c5601d81bb318a45cc1313b122d4361a7d7a954645b04667ff3f81d3366109772a41f66ece09eb93130abe04f2a51bb30e767dd37ec6ee6a342a4969b8b342f841193f4f6a9f0fac4611bc31b6cab1d25262feb31db0b8889b6f8d78be23f033994f2d3e18e00f3b0218101e1a7082782aa3680efc8502e1536c30c8c336b06ae936e2bcf9bbfb20dd514ed2867c03d4f44954867c97db35677d30760f37622b85089cc5d182a89e29ab0c6b9ef18138b16ab91d59c2312884172afa4874e6989172014168d3ed8db3d9522d6cbd631d581d166787c93209bec845d112e0cbd825f6df8b64363411270921837cfb2f9e7f2e74cdb9cd0d2b02058e5efd9583e2651239654b887ea36ce9537c392fc5dfca8c5a0facbe95b87dfc4232f229bd12e67937d32b7ffae2e837687d2d292c08ff6194a2256b17254748857c7e3c871c3fff380115e6f7faf435a430edf9f8a589f6711720cfc5cec6c8d0d94886a39bb9ac6c50b2e8ef6cf860415192ca4c1c3aaa97d36394021a62164d5a63975bcd84b8e6d74f361c17101e3808b4d8c31d1ee1a5cf3a2feda1ca2c0fd5a50edc9d95e09fb5158c9f9b0eb5e2c90a47deb0459cea593201ae7597e2e9245aa5848680f546256f3" - ], - [ - "0xd57bce545fb382c34570e5dfbf338f5e326d21bc67a4b34023d577585d72bfd7", - null - ], - [ - "0xd57bce545fb382c34570e5dfbf338f5ea36180b5cfb9f6541f8849df92a6ec93", - "0x00" - ], - [ - "0xd57bce545fb382c34570e5dfbf338f5ebddf84c5eb23e6f53af725880d8ffe90", - null - ], - [ - "0xd5c41b52a371aa36c9254ce34324f2a53b996bb988ea8ee15bad3ffd2f68dbda", - "0x00" - ], - [ - "0xf0c365c3cf59d671eb72da0e7a4113c49f1f0515f462cdcf84e0f1d6045dfcbb", - "0x50defc5172010000" - ], - [ - "0xf0c365c3cf59d671eb72da0e7a4113c4bbd108c4899964f707fdaffb82636065", - null - ], - [ - "0xf68f425cf5645aacb2ae59b51baed90420d49a14a763e1cbc887acd097f92014", - "0x9501800300008203000082030000840300008503000086030000870300008703000089030000890300008b0300008b0300008d0300008d0300008f0300008f0300009103000092030000920300009403000094030000960300009603000098030000990300009a0300009b0300009b0300009d0300009d0300009f0300009f030000a1030000a2030000a3030000a4030000a5030000a6030000a6030000a8030000a8030000aa030000ab030000ac030000ad030000ae030000af030000b0030000b1030000b1030000b3030000b3030000b5030000b6030000b7030000b8030000b9030000ba030000ba030000bc030000bc030000be030000be030000c0030000c1030000c2030000c2030000c4030000c5030000c5030000c7030000c7030000c9030000c9030000cb030000cc030000cd030000ce030000cf030000d0030000d0030000d2030000d2030000d4030000d4030000d6030000d7030000d8030000d9030000da030000db030000db030000dd030000dd030000df030000e0030000e1030000e2030000e3030000e4030000e4030000" - ], - [ - "0xf68f425cf5645aacb2ae59b51baed9049b58374218f48eaf5bc23b7b3e7cf08a", - "0xb3030000" +```json +{ + "label": "moonwall_config", + "defaultTestTimeout": 30000, + "environments": [ + { + "name": "default_env", + "testFileDir": ["tests/"], + "foundation": { + "launchSpec": [ + { + "binPath": "./node-template", + "newRpcBehaviour": true, + "ports": { "rpcPort": 9944 } + } ], - [ - "0xf68f425cf5645aacb2ae59b51baed904b97380ce5f4e70fbf9d6b5866eb59527", - "0x9501800300008203000082030000840300008503000086030000870300008703000089030000890300008b0300008b0300008d0300008d0300008f0300008f0300009103000092030000920300009403000094030000960300009603000098030000990300009a0300009b0300009b0300009d0300009d0300009f0300009f030000a1030000a2030000a3030000a4030000a5030000a6030000a6030000a8030000a8030000aa030000ab030000ac030000ad030000ae030000af030000b0030000b1030000b1030000b3030000b3030000b5030000b6030000b7030000b8030000b9030000ba030000ba030000bc030000bc030000be030000be030000c0030000c1030000c2030000c2030000c4030000c5030000c5030000c7030000c7030000c9030000c9030000cb030000cc030000cd030000ce030000cf030000d0030000d0030000d2030000d2030000d4030000d4030000d6030000d7030000d8030000d9030000da030000db030000db030000dd030000dd030000df030000e0030000e1030000e2030000e3030000e4030000e4030000" - ] - ], - "offchainStorageDiff": [], - "runtimeLogs": [] + "type": "dev" + }, + "connections": [ + { + "name": "myconnection", + "type": "polkadotJs", + "endpoints": ["ws://127.0.0.1:9944"] + } + ] } - } + ] +} - ``` +``` -## XCM Testing +## Writing Tests -To test XCM (Cross-Consensus Messaging) messages between networks, you can fork multiple parachains and a relay chain locally using Chopsticks. +Moonwall uses the [`describeSuite`](https://github.com/Moonsong-Labs/moonwall/blob/7568048c52e9f7844f38fb4796ae9e1b9205fdaa/packages/cli/src/lib/runnerContext.ts#L65){target=\_blank} function to define test suites, like using [Mocha](https://mochajs.org/){target=\_blank}. Each test suite requires the following: -- **`relaychain`**: Relay chain config file. -- **`parachain`**: Parachain config file. +- **`id`**: Unique identifier for the suite. +- **`title`**: Descriptive name for the suite. +- **`foundationMethods`**: Specifies the testing environment (e.g., `dev` for local node testing). +- **`testCases`**: A callback function that houses the individual test cases of this suite. -For example, to fork Moonbeam, Astar, and Polkadot enabling XCM between them, you can use the following command: +The following example shows how to test a balance transfer between two accounts: + +```ts +import '@polkadot/api-augment'; +import { describeSuite, expect } from '@moonwall/cli'; +import { Keyring } from '@polkadot/api'; + +describeSuite({ + id: 'D1', + title: 'Demo suite', + foundationMethods: 'dev', + testCases: ({ it, context, log }) => { + it({ + id: 'T1', + title: 'Test Case', + test: async () => { + // Set up polkadot.js API and testing accounts + let api = context.polkadotJs(); + let alice = new Keyring({ type: 'sr25519' }).addFromUri('//Alice'); + let charlie = new Keyring({ type: 'sr25519' }).addFromUri('//Charlie'); + + // Query Charlie's account balance before transfer + const balanceBefore = (await api.query.system.account(charlie.address)) + .data.free; + + // Before transfer, Charlie's account balance should be 0 + expect(balanceBefore.toString()).toEqual('0'); + log('Balance before: ' + balanceBefore.toString()); + + // Transfer from Alice to Charlie + const amount = 1000000000000000; + await api.tx.balances + .transferAllowDeath(charlie.address, amount) + .signAndSend(alice); + + // Wait for the transaction to be included in a block. + // This is necessary because the balance is not updated immediately. + // Block time is 6 seconds. + await new Promise((resolve) => setTimeout(resolve, 6000)); + + // Query Charlie's account balance after transfer + const balanceAfter = (await api.query.system.account(charlie.address)) + .data.free; + + // After transfer, Charlie's account balance should be 1000000000000000 + expect(balanceAfter.toString()).toEqual(amount.toString()); + log('Balance after: ' + balanceAfter.toString()); + }, + }); + }, +}); + +``` + +This test demonstrates several key concepts: + +- Initializing the Polkadot.js API through Moonwall's context and setting up test accounts. +- Querying on-chain state. +- Executing transactions. +- Waiting for block inclusion. +- Verifying results using assertions. + +## Running the Tests + +Execute your tests using the `test` Moonwall CLI command. For the default environment setup run: ```bash -npx @acala-network/chopsticks xcm \ ---r polkadot \ ---p moonbeam \ ---p astar +moonwall test default_env -c moonwall.config ``` -After running it, you should see output similar to the following: +The test runner will output detailed results showing: +- Test suite execution status. +- Individual test case results. +- Execution time. +- Detailed logs and error messages (if any). + +Example output:
- npx @acala-network/chopsticks xcm \ - --r polkadot \ - --p moonbeam \ - --p astar -
- [13:46:07.901] INFO: Loading config file https://raw.githubusercontent.com/AcalaNetwork/chopsticks/master/configs/moonbeam.yml - app: "chopsticks" - [13:46:12.631] INFO: Moonbeam RPC listening on port 8000 - app: "chopsticks" - [13:46:12.632] INFO: Loading config file https://raw.githubusercontent.com/AcalaNetwork/chopsticks/master/configs/astar.yml - app: "chopsticks" - chopsticks::executor TRACE: Calling Metadata_metadata - chopsticks::executor TRACE: Completed Metadata_metadata - [13:46:23.669] INFO: Astar RPC listening on port 8001 - app: "chopsticks" - [13:46:25.144] INFO (xcm): Connected parachains [2004,2006] - app: "chopsticks" - [13:46:25.144] INFO: Loading config file https://raw.githubusercontent.com/AcalaNetwork/chopsticks/master/configs/polkadot.yml - app: "chopsticks" - chopsticks::executor TRACE: Calling Metadata_metadata - chopsticks::executor TRACE: Completed Metadata_metadata - [13:46:53.320] INFO: Polkadot RPC listening on port 8002 - app: "chopsticks" - [13:46:54.038] INFO (xcm): Connected relaychain 'Polkadot' with parachain 'Moonbeam' - app: "chopsticks" - [13:46:55.028] INFO (xcm): Connected relaychain 'Polkadot' with parachain 'Astar' - app: "chopsticks" + moonwall test default_env -c moonwall.config + stdout | tests/test1.ts > 🗃️ D1 Demo suite > 📁 D1T1 Test Case + 2025-01-21T19:27:55.624Z test:default_env Balance before: 0 + + stdout | tests/test1.ts > 🗃️ D1 Demo suite > 📁 D1T1 Test Case + 2025-01-21T19:28:01.637Z test:default_env Balance after: 1000000000000000 + + ✓ default_env tests/test1.ts (1 test) 6443ms + ✓ 🗃️ D1 Demo suite > 📁 D1T1 Test Case 6028ms + + Test Files 1 passed (1) + Tests 1 passed (1) + Start at 16:27:53 + Duration 7.95s (transform 72ms, setup 0ms, collect 1.31s, tests 6.44s, environment 0ms, prepare 46ms) + + ✅ All tests passed
-Now you can interact with your forked chains using the ports specified in the output. +## Where to Go Next + +For a comprehensive guide to Moonwall's full capabilities, available configurations, and advanced usage, see the official [Moonwall](https://moonsong-labs.github.io/moonwall/){target=\_blank} documentation. --- -Page Title: Generate Chain Specs +Page Title: EVM vs PolkaVM -- Source (raw): https://raw.githubusercontent.com/polkadot-developers/polkadot-docs/master/.ai/pages/develop-parachains-deployment-generate-chain-specs.md -- Canonical (HTML): https://docs.polkadot.com/develop/parachains/deployment/generate-chain-specs/ -- Summary: Describes the role of the chain specification in a network, how to specify its parameters when starting a node, and how to customize and distribute it. +- Source (raw): https://raw.githubusercontent.com/polkadot-developers/polkadot-docs/master/.ai/pages/polkadot-protocol-smart-contract-basics-evm-vs-polkavm.md +- Canonical (HTML): https://docs.polkadot.com/polkadot-protocol/smart-contract-basics/evm-vs-polkavm/ +- Summary: Compares EVM and PolkaVM, highlighting key architectural differences, gas models, memory management, and account handling while ensuring Solidity compatibility. -# Generate Chain Specs +# EVM vs PolkaVM +!!! smartcontract "PolkaVM Preview Release" + PolkaVM smart contracts with Ethereum compatibility are in **early-stage development and may be unstable or incomplete**. ## Introduction -A chain specification collects information that describes a Polkadot SDK-based network. A chain specification is a crucial parameter when starting a node, providing the genesis configurations, bootnodes, and other parameters relating to that particular network. It identifies the network a blockchain node connects to, the other nodes it initially communicates with, and the initial state that nodes must agree on to produce blocks. - -The chain specification is defined using the [`ChainSpec`](https://paritytech.github.io/polkadot-sdk/master/sc_chain_spec/struct.GenericChainSpec.html){target=\_blank} struct. This struct separates the information required for a chain into two parts: - -- **Client specification**: Contains information the _node_ uses to communicate with network participants and send data to telemetry endpoints. Many of these chain specification settings can be overridden by command-line options when starting a node or can be changed after the blockchain has started. - -- **Initial genesis state**: Agreed upon by all nodes in the network. It must be set when the blockchain is first started and cannot be changed after that without starting a whole new blockchain. - -## Node Settings Customization - -For the node, the chain specification controls information such as: - -- The bootnodes the node will communicate with. -- The server endpoints for the node to send telemetry data to. -- The human and machine-readable names for the network the node will connect to. - -The chain specification can be customized to include additional information. For example, you can configure the node to connect to specific blocks at specific heights to prevent long-range attacks when syncing a new node from genesis. +While [PolkaVM](/smart-contracts/for-eth-devs/dual-vm-stack/){target=\_blank} strives for maximum Ethereum compatibility, several fundamental design decisions create necessary divergences from the [EVM](https://ethereum.org/en/developers/docs/evm/){target=\_blank}. These differences represent trade-offs that enhance performance and resource management while maintaining accessibility for Solidity developers. -Note that you can customize node settings after genesis. However, nodes only add peers that use the same [`protocolId`](https://paritytech.github.io/polkadot-sdk/master/sc_service/struct.GenericChainSpec.html#method.protocol_id){target=_blank}. +## Core Virtual Machine Architecture -## Genesis Configuration Customization +The most significant departure from Ethereum comes from PolkaVM's foundation itself. Rather than implementing the EVM, PolkaVM utilizes a RISC-V instruction set. For most Solidity developers, this architectural change remains transparent thanks to the [Revive compiler's](https://github.com/paritytech/revive){target=\_blank} complete Solidity support, including inline assembler functionality. -All nodes in the network must agree on the genesis state before they can agree on any subsequent blocks. The information configured in the genesis portion of a chain specification is used to create a genesis block. When you start the first node, it takes effect and cannot be overridden with command-line options. However, you can configure some information in the genesis section of a chain specification. For example, you can customize it to include information such as: +```mermaid +graph TD + subgraph "Ethereum Path" + EthCompile["Standard Solidity Compiler"] --> EVM_Bytecode["EVM Bytecode"] + EVM_Bytecode --> EVM["Stack-based EVM"] + EVM --> EthExecution["Contract Execution"] + end -- Initial account balances. -- Accounts that are initially part of a governance council. -- The account that controls the `sudo` key. -- Any other genesis state for a pallet. + subgraph "PolkaVM Path" + ReviveCompile["Revive Compiler"] --> RISCV_Bytecode["RISC-V Format Bytecode"] + RISCV_Bytecode --> PolkaVM["RISC-V Based PolkaVM"] + PolkaVM --> PolkaExecution["Contract Execution"] + end -Nodes also require the compiled Wasm to execute the runtime logic on the chain, so the initial runtime must also be supplied in the chain specification. For a more detailed look at customizing the genesis chain specification, be sure to check out the [Polkadot SDK Docs](https://paritytech.github.io/polkadot-sdk/master/polkadot_sdk_docs/reference_docs/chain_spec_genesis/index.html){target=_blank}. + EthExecution -.-> DifferencesNote["Key Differences: + - Instruction Set Architecture + - Bytecode Format + - Runtime Behavior"] + PolkaExecution -.-> DifferencesNote +``` -## Declaring Storage Items for a Runtime +However, this architectural difference becomes relevant in specific scenarios. Tools that attempt to download and inspect contract bytecode will fail, as they expect EVM bytecode rather than PolkaVM's RISC-V format. Most applications typically pass bytecode as an opaque blob, making this a non-issue for standard use cases. -A runtime usually requires some storage items to be configured at genesis. This includes the initial state for pallets, for example, how much balance specific accounts have, or which account will have sudo permissions. +This primarily affects contracts using [`EXTCODECOPY`](https://www.evm.codes/?fork=cancun#3c){target=\_blank} to manipulate code at runtime. A contract encounters problems specifically when it uses `EXTCODECOPY` to copy contract code into memory and then attempts to mutate it. This pattern is not possible in standard Solidity and requires dropping down to YUL assembly. An example would be a factory contract written in assembly that constructs and instantiates new contracts by generating code at runtime. Such contracts are rare in practice. -These storage values are configured in the genesis portion of the chain specification. You can create a [patch](https://paritytech.github.io/polkadot-sdk/master/sc_chain_spec/index.html#chain-spec-formats){target=_blank} file and ingest it using the [`chain-spec-builder`](https://paritytech.github.io/polkadot-sdk/master/staging_chain_spec_builder/index.html){target=_blank} utility, that is explained in the [Creating a Custom Chain Specification](#creating-a-custom-chain-specification) section. +PolkaVM offers an elegant alternative through its [on-chain constructors](https://paritytech.github.io/polkadot-sdk/master/pallet_revive/pallet/struct.Pallet.html#method.bare_instantiate){target=\_blank}, enabling contract instantiation without runtime code modification, making this pattern unnecessary. This architectural difference also impacts how contract deployment works more broadly, as discussed in the [Contract Deployment](#contract-deployment) section. -## Chain Specification JSON Format +### High-Level Architecture Comparison -Users generally work with the JSON format of the chain specification. Internally, the chain specification is embedded in the [`GenericChainSpec`](https://paritytech.github.io/polkadot-sdk/master/sc_chain_spec/struct.GenericChainSpec.html){target=\_blank} struct, with specific properties accessible through the [`ChainSpec`](https://paritytech.github.io/polkadot-sdk/master/sc_chain_spec/trait.ChainSpec.html){target=\_blank} struct. The chain specification includes the following keys: +| Feature | Ethereum Virtual Machine (EVM) | PolkaVM | +|:-----------------------------:|:------------------------------------------------------------------------------------:|:------------------------------------------------------:| +| **Instruction Set** | Stack-based architecture | RISC-V instruction set | +| **Bytecode Format** | EVM bytecode | RISC-V format | +| **Contract Size Limit** | 24KB code size limit | Contract-specific memory limits | +| **Compiler** | Solidity Compiler | Revive Compiler | +| **Inline Assembly** | Supported | Supported with the compatibility layer | +| **Code Introspection** | Supported via [`EXTCODECOPY`](https://www.evm.codes/?fork=cancun#3c){target=\_blank} | Limited support, alternative via on-chain constructors | +| **Resource Metering** | Single gas metric | Multi-dimensional | +| **Runtime Code Modification** | Supported | Limited, with alternatives | +| **Contract Instantiation** | Standard deployment | On-chain constructors for flexible instantiation | -- **`name`**: The human-readable name for the network. -- **`id`**: The machine-readable identifier for the network. -- **`chainType`**: The type of chain to start (refer to [`ChainType`](https://paritytech.github.io/polkadot-sdk/master/sc_chain_spec/enum.ChainType.html){target=\_blank} for more details). -- **`bootNodes`**: A list of multiaddresses belonging to the chain's boot nodes. -- **`telemetryEndpoints`**: An optional list of multiaddresses for telemetry endpoints with verbosity levels ranging from 0 to 9 (0 being the lowest verbosity). -- **`protocolId`**: The optional protocol identifier for the network. -- **`forkId`**: An optional fork ID that should typically be left empty; it can be used to signal a fork at the network level when two chains share the same genesis hash. -- **`properties`**: Custom properties provided as a key-value JSON object. -- **`codeSubstitutes`**: An optional mapping of block numbers to Wasm code. -- **`genesis`**: The genesis configuration for the chain. +## Gas Model -For example, the following JSON shows a basic chain specification file: +Ethereum's resource model relies on a single metric: [gas](https://ethereum.org/en/developers/docs/gas/#what-is-gas){target=\_blank}, which serves as the universal unit for measuring computational costs. Each operation on the network consumes a specific amount of gas. Most platforms aiming for Ethereum compatibility typically adopt identical gas values to ensure seamless integration. -```json -{ - "name": "chainName", - "id": "chainId", - "chainType": "Local", - "bootNodes": [], - "telemetryEndpoints": null, - "protocolId": null, - "properties": null, - "codeSubstitutes": {}, - "genesis": { - "code": "0x..." - } -} +The significant changes to Ethereum's gas model will be outlined in the following sections. -``` +### Dynamic Gas Value Scaling -## Creating a Custom Chain Specification +Instead of adhering to Ethereum's fixed gas values, PolkaVM implements benchmark-based pricing that better reflects its improved execution performance. This makes instructions cheaper relative to I/O-bound operations but requires developers to avoid hardcoding gas values, particularly in cross-contract calls. -To create a custom chain specification, you can use the [`chain-spec-builder`](https://paritytech.github.io/polkadot-sdk/master/staging_chain_spec_builder/index.html){target=\_blank} tool. This is a CLI tool that is used to generate chain specifications from the runtime of a node. To install the tool, run the following command: +### Multi-Dimensional Resource Metering -```bash -cargo install --git https://github.com/paritytech/polkadot-sdk --force staging-chain-spec-builder -``` +Moving beyond Ethereum's single gas metric, PolkaVM meters three distinct resources: -To verify the installation, run the following: +- **`ref_time`**: Equivalent to traditional gas, measuring computation time. +- **`proof_size`**: Tracks state proof size for validator verification. +- **`storage_deposit`**: Manages state bloat through a deposit system. -```bash -chain-spec-builder --help -``` +All three resources can be limited at the transaction level, just like gas on Ethereum. The [Ethereum RPC proxy](https://github.com/paritytech/polkadot-sdk/tree/master/substrate/frame/revive/rpc){target=\_blank} maps all three dimensions into the single gas dimension, ensuring everything behaves as expected for users. -### Plain Chain Specifications +These resources can also be limited when making cross-contract calls, which is essential for security when interacting with untrusted contracts. However, Solidity only allows specifying `gas_limit` for cross-contract calls. The `gas_limit` is most similar to Polkadots `ref_time_limit`, but the Revive compiler doesn't supply any imposed `gas_limit` for cross-contract calls for two key reasons: -To create a plain chain specification, first ensure that the runtime has been compiled and is available at the specified path. Next, you can use the following utility within your project: +- **Semantic differences**: `gas_limit` and `ref_time_limit` are not semantically identical; blindly passing EVM gas as `ref_time_limit` can lead to unexpected behavior. +- **Incomplete protection**: The other two resources (`proof_size` and `storage_deposit`) would remain uncapped anyway, making it insufficient to prevent malicious callees from performing DOS attacks. -```bash -chain-spec-builder create -r INSERT_RUNTIME_WASM_PATH INSERT_COMMAND -``` +When resources are "uncapped" in cross-contract calls, they remain constrained by transaction-specified limits, preventing abuse of the transaction signer. -Replace `INSERT_RUNTIME_WASM_PATH` with the path to the runtime Wasm file and `INSERT_COMMAND` with the command to insert the runtime into the chain specification. +!!! note + The runtime will provide a special precompile, allowing cross-contract calls with limits specified for all weight dimensions in the future. -The available commands are: +All gas-related opcodes like [`GAS`](https://www.evm.codes/?fork=cancun#5a){target=\_blank} or [`GAS_LIMIT`](https://www.evm.codes/?fork=cancun#45){target=\_blank} return only the `ref_time` value as it's the closest match to traditional gas. Extended APIs will be provided through precompiles to make full use of all resources, including cross-contract calls with all three resources specified. -- **`patch`**: Overwrites the runtime's default genesis config with the provided patch. You can check the following [patch file](https://github.com/paritytech/polkadot-sdk/blob/polkadot-stable2506-2/substrate/bin/utils/chain-spec-builder/tests/input/patch.json){target=\_blank} as a reference. -- **`full`**: Build the genesis config for runtime using the JSON file. No defaults will be used. As a reference, you can check the following [full file](https://github.com/paritytech/polkadot-sdk/blob/polkadot-stable2506-2/substrate/bin/utils/chain-spec-builder/tests/input/full.json){target=\_blank}. -- **`default`**: Gets the default genesis config for the runtime and uses it in `ChainSpec`. Please note that the default genesis config may not be valid. For some runtimes, initial values should be added there (e.g., session keys, BABE epoch). -- **`named-preset`**: Uses named preset provided by the runtime to build the chain spec. +## Memory Management -### Raw Chain Specifications +The EVM and the PolkaVM take fundamentally different approaches to memory constraints: -With runtime upgrades, the blockchain's runtime can be upgraded with newer business logic. Chain specifications contain information structured in a way that the node's runtime can understand. For example, consider this excerpt of a common entry for a chain specification: +| Feature | Ethereum Virtual Machine (EVM) | PolkaVM | +|:------------------------:|:-----------------------------------------:|:----------------------------------------------:| +| **Memory Constraints** | Indirect control via gas costs | Hard memory limits per contract | +| **Cost Model** | Increasing gas curve with allocation size | Fixed costs separated from execution gas | +| **Memory Limits** | Soft limits through prohibitive gas costs | Hard fixed limits per contract | +| **Pricing Efficiency** | Potential overcharging for memory | More efficient through separation of concerns | +| **Contract Nesting** | Limited by available gas | Limited by constant memory per contract | +| **Memory Metering** | Dynamic based on total allocation | Static limits per contract instance | +| **Future Improvements** | Incremental gas cost updates | Potential dynamic metering for deeper nesting | +| **Cross-Contract Calls** | Handled through gas forwarding | Requires careful boundary limit implementation | -```json -"sudo": { - "key": "5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY" -} -``` +The architecture establishes a constant memory limit per contract, which is the basis for calculating maximum contract nesting depth. This calculation assumes worst-case memory usage for each nested contract, resulting in a straightforward but conservative limit that operates independently of actual memory consumption. Future iterations may introduce dynamic memory metering, allowing deeper nesting depths for contracts with smaller memory footprints. However, such an enhancement would require careful implementation of cross-contract boundary limits before API stabilization, as it would introduce an additional resource metric to the system. -In the plain chain spec JSON file, the keys and associated values are in a human-readable format, which can be used to initialize the genesis storage. When the chain specification is loaded, the runtime converts these readable values into storage items within the trie. However, for long-lived networks like testnets or production chains, using the raw format for storage initialization is preferred. This avoids the need for conversion by the runtime and ensures that storage items remain consistent, even when runtime upgrades occur. +### Current Memory Limits -To enable a node with an upgraded runtime to synchronize with a chain from genesis, the plain chain specification is encoded in a raw format. The raw format allows the distribution of chain specifications that all nodes can use to synchronize the chain even after runtime upgrades. +The following table depicts memory-related limits at the time of writing: -To convert a plain chain specification to a raw chain specification, you can use the following utility: +| Limit | Maximum | +|:------------------------------------------:|:---------------:| +| Call stack depth | 5 | +| Event topics | 4 | +| Event data payload size (including topics) | 416 bytes | +| Storage value size | 416 bytes | +| Transient storage variables | 128 uint values | +| Immutable variables | 16 uint values | +| Contract code blob size | ~100 kilobytes | -```bash -chain-spec-builder convert-to-raw chain_spec.json -``` +!!! note + Limits might be increased in the future. To guarantee existing contracts work as expected, limits will never be decreased. -After the conversion to the raw format, the `sudo key` snippet looks like this: +## Account Management - Existential Deposit -```json -"0x50a63a871aced22e88ee6466fe5aa5d9": "0xd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d", -``` +Ethereum and Polkadot handle account persistence differently, affecting state management and contract interactions: -The raw chain specification can be used to initialize the genesis storage for a node. +### Account Management Comparison -## Generate Custom Keys for Your Collator +| Feature | Ethereum Approach | PolkaVM/Polkadot Approach | +|:-------------------------:|:-----------------------------------------------------:|:------------------------------------------------------:| +| **Account Persistence** | Accounts persist indefinitely, even with zero balance | Requires existential deposit (ED) to maintain account | +| **Minimum Balance** | None | ED required | +| **Account Deletion** | Accounts remain in state | Accounts below ED are automatically deleted | +| **Contract Accounts** | Exist indefinitely | Must maintain ED | +| **Balance Reporting** | Reports full balance | Reports ED-adjusted balance via Ethereum RPC | +| **New Account Transfers** | Standard transfer | Includes ED automatically with extra fee cost | +| **Contract-to-Contract** | Direct transfers | ED drawn from transaction signer, not sending contract | +| **State Management** | Potential bloat from zero-balance accounts | Optimized with auto-deletion of dust accounts | -To securely deploy your parachain, you must generate custom cryptographic keys for your collators (block producers). Each collator requires two distinct sets of keys with different security requirements and operational purposes. +This difference introduces potential compatibility challenges for Ethereum-based contracts and tools, particularly wallets. To mitigate this, PolkaVM implements several transparent adjustments: -- **Account keys**: Serve as the primary identity and financial controller for your collator. These keys are used to interact with the network and manage funds. They should be treated as cold storage and must never exist on the filesystem of the collator node. Secure offline backup is essential. +- Balance queries via Ethereum RPC automatically deduct the ED, ensuring reported balances match spendable amounts. +- Account balance checks through EVM opcodes reflect the ED-adjusted balance. +- Transfers to new accounts automatically include the ED (`x + ED`), with the extra cost incorporated into transaction fees. +- Contract-to-contract transfers handle ED requirements by: + - Drawing ED from the transaction signer instead of the sending contract. + - Keeping transfer amounts transparent for contract logic. + - Treating ED like other storage deposit costs. -- **Session keys**: Handle block production operations to identify your node and sign blocks on the network. These keys are stored in the parachain keystore and function as operational "hot wallet" keys. If compromised, an attacker could impersonate your node, potentially resulting in slashing of your funds. To minimize these risks, implement regular session key rotation and treat them with the same caution as hot wallet keys. +This approach ensures that Ethereum contracts work without modifications while maintaining Polkadot's optimized state management. -To perform this step, you can use [Subkey](https://docs.rs/crate/subkey/latest){target=\_blank}, a command-line tool for generating and managing keys: +## Contract Deployment -```bash -docker run -it parity/subkey:latest generate --scheme sr25519 -``` +For most users deploying contracts (like ERC-20 tokens), contract deployment works seamlessly without requiring special steps. However, when using advanced patterns like factory contracts that dynamically create other contracts at runtime, you'll need to understand PolkaVM's unique deployment model. -The output should look similar to the following: +In the PolkaVM, contract deployment follows a fundamentally different model from EVM. The EVM allows contracts to be deployed with a single transaction, where the contract code is bundled with the deployment transaction. In contrast, PolkaVM has a different process for contract instantiation. -
- docker run -it parity/subkey:latest generate --scheme sr25519 -
Secret phrase: lemon play remain picture leopard frog mad bridge hire hazard best buddy
Network ID: substrate
Secret seed: 0xb748b501de061bae1fcab1c0b814255979d74d9637b84e06414a57a1a149c004
Public key (hex): 0xf4ec62ec6e70a3c0f8dcbe0531e2b1b8916cf16d30635bbe9232f6ed3f0bf422
Account ID: 0xf4ec62ec6e70a3c0f8dcbe0531e2b1b8916cf16d30635bbe9232f6ed3f0bf422
Public key (SS58): 5HbqmBBJ5ALUzho7tw1k1jEgKBJM7dNsQwrtfSfUskT1a3oe
SS58 Address: 5HbqmBBJ5ALUzho7tw1k1jEgKBJM7dNsQwrtfSfUskT1a3oe
-
+- **Code must be pre-uploaded**: Unlike EVM, where contract code is bundled within the deploying contract, PolkaVM requires all contract bytecode to be uploaded to the chain before instantiation. +- **Factory pattern limitations**: The common EVM pattern, where contracts dynamically create other contracts, will fail with a `CodeNotFound` error unless the dependent contract code was previously uploaded. +- **Separate upload and instantiation**: This creates a two-step process where developers must first upload all contract code, then instantiate relationships between contracts. -Ensure that this command is executed twice to generate the keys for both the account and session keys. Save them for future reference. +This architecture impacts several common EVM patterns and requires developers to adapt their deployment strategies accordingly. _Factory contracts must be modified to work with pre-uploaded code rather than embedding bytecode_, and runtime code generation is not supported due to PolkaVM's RISC-V bytecode format. The specific behavior of contract creation opcodes is detailed in the [YUL IR Translation](#yul-function-translation-differences) section. -After generating the plain chain specification, you need to edit this file by inserting the account IDs and session keys in SS58 format generated for your collators in the `collatorSelection.invulnerables` and `session.keys` fields. +When migrating EVM projects to PolkaVM, developers should identify all contracts that will be instantiated at runtime and ensure they are pre-uploaded to the chain before any instantiation attempts. -### Add Invulnerables +## Solidity and YUL IR Translation Incompatibilities -In the `collatorSelection.invulnerables` array, add the SS58 addresses (account keys) of your collators. These addresses will be automatically included in the active collator set: +While PolkaVM maintains high-level compatibility with Solidity, several low-level differences exist in the translation of YUL IR and specific Solidity constructs. These differences are particularly relevant for developers working with assembly code or utilizing advanced contract patterns. -```json - "collatorSelection": { - "candidacyBond": 16000000000, - "desiredCandidates": 0, - "invulnerables": [ - "INSERT_ACCOUNT_ID_COLLATOR_1", - "INSERT_ACCOUNT_ID_COLLATOR_2", - "INSERT_ACCOUNT_ID_COLLATOR_3" - ] - } -``` +### Contract Code Structure -- **`candidacyBond`**: Minimum stake required for collator candidates (in Planck units). -- **`desiredCandidates`**: Number of candidates beyond invulnerables (set to 0 for invulnerables-only). -- **`invulnerables`**: Use the SS58 addresses from your generated account keys as collators. +PolkaVM's contract runtime does not differentiate between runtime code and deploy (constructor) code. Instead, both are emitted into a single PolkaVM contract code blob and live on-chain. Therefore, in EVM terminology, the deploy code equals the runtime code. For most standard Solidity contracts, this is transparent. However, if you are analyzing raw bytecode or building tools that expect separate deploy and runtime sections, you'll need to adjust for this unified structure. -### Add Session Keys +In the constructor code, the `codesize` instruction returns the call data size instead of the actual code blob size, which differs from standard EVM behavior. Developers might consider that the constructor logic uses `codesize` to inspect the deployed contract's size (e.g., for self-validation or specific deployment patterns); this will return an incorrect value on PolkaVM. Re-evaluate such logic or use alternative methods to achieve your goal. -For each invulnerable collator, add a corresponding entry in the `session.keys` array. This maps each collator's account ID to their session keys: +### Solidity-Specific Differences -```json - "session": { - "keys": [ - [ - "INSERT_ACCOUNT_ID_COLLATOR_1", - "INSERT_ACCOUNT_ID_COLLATOR_1", - { - "aura": "INSERT_SESSION_KEY_COLLATOR_1" - } - ], - [ - "INSERT_ACCOUNT_ID_COLLATOR_2", - "INSERT_ACCOUNT_ID_COLLATOR_2", - { - "aura": "INSERT_SESSION_KEY_COLLATOR_2" - } - ], - [ - "INSERT_ACCOUNT_ID_COLLATOR_3", - "INSERT_ACCOUNT_ID_COLLATOR_3", - { - "aura": "INSERT_SESSION_KEY_COLLATOR_3" - } - ] - ], - "nonAuthorityKeys": [] - } -``` +Solidity constructs behave differently under PolkaVM: -## Where to Go Next +- **`address.creationCode`**: Returns the bytecode keccak256 hash instead of the actual creation code, reflecting PolkaVM's hash-based code referencing system. + - If your contract relies on `address.creationCode` to verify or interact with the full raw bytecode of a newly deployed contract, this will not work as expected. You will receive a hash, not the code itself. This typically affects highly specialized factory contracts or introspection tools. -After generating a chain specification, you can use it to initialize the genesis storage for a node. Refer to the following guides to learn how to proceed with the deployment of your blockchain: +### YUL Function Translation Differences -
+The following YUL functions exhibit notable behavioral differences in PolkaVM: -- Guide __Obtain Coretime__ +- Memory operations: - --- + - **`mload`, `mstore`, `msize`, `mcopy`**: PolkaVM preserves memory layout but implements several constraints. - Learn how to obtain the necessary coretime configuration to synchronize your blockchain’s timestamping and enhance its performance. + - EVM linear heap memory is emulated using a fixed 64KB byte buffer, limiting maximum contract memory usage. + - Accessing memory offsets larger than the buffer size traps the contract with an `OutOfBound` error. + - Compiler optimizations may eliminate unused memory operations, potentially causing `msize` to differ from EVM behavior. - [:octicons-arrow-right-24: Reference](/parachains/launch-a-parachain/obtain-coretime/) + For Solidity developers, the compiler generally handles memory efficiently within this 64KB limit. However, if you are writing low-level YUL assembly and perform direct memory manipulations, you must respect the 64KB buffer limit. Attempting to access memory outside this range will cause your transaction to revert. Be aware that `msize` might not always reflect the exact EVM behavior if compiler optimizations occur. -- Guide __Deployment__ +- Call data operations: - --- + - **`calldataload`, `calldatacopy`**: In constructor code, the offset parameter is ignored and these functions always return `0`, diverging from EVM behavior where call data represents constructor arguments. - Explore the steps required to deploy your chain specification, ensuring a smooth launch of your network and proper node operation. + - If your constructor logic in YUL assembly attempts to read constructor arguments using `calldataload` or `calldatacopy` with specific offsets, this will not yield the expected constructor arguments. Instead, these functions will return `zeroed` values. Standard Solidity constructors are handled correctly by the compiler, but manual YUL assembly for constructor argument parsing will need adjustment. +- Code operations: - [:octicons-arrow-right-24: Reference](/develop/parachains/deployment/) + - **`codecopy`**: Only supported within constructor code, reflecting PolkaVM's different approach to code handling and the unified code blob structure. -- Guide __Maintenance__ + - If your contracts use `codecopy` (e.g., for self-modifying code or inspecting other contract's runtime bytecode) outside of the constructor, this will not be supported and will likely result in a compile-time error or runtime trap. This implies that patterns like dynamically generating or modifying contract code at runtime are not directly feasible with `codecopy` on PolkaVM. - --- +- Control flow: - Discover best practices for maintaining your blockchain post-deployment, including how to manage upgrades and monitor network health. + - **`invalid`**: Traps the contract execution but does not consume remaining gas, unlike EVM where it consumes all available gas. + - While `invalid` still reverts the transaction, the difference in gas consumption could subtly affect very specific error handling or gas accounting patterns that rely on `invalid` to consume all remaining gas. For most error scenarios, `revert()` is the standard and recommended practice. - [:octicons-arrow-right-24: Reference](/develop/parachains/maintenance/) +- Cross-contract calls: -
+ - **`call`, `delegatecall`, `staticall`**: These functions ignore supplied gas limits and forward all remaining resources due to PolkaVM's multi-dimensional resource model. This creates important security implications: + - Contract authors must implement reentrancy protection since gas stipends don't provide protection. + - The compiler detects `address payable.{send,transfer}` patterns and disables call reentrancy as a protective heuristic. + - Using `address payable.{send,transfer}` is already deprecated; PolkaVM will provide dedicated precompiles for safe balance transfers. ---- + The traditional EVM pattern of limiting gas in cross-contract calls (especially with the 2300 gas stipend for send/transfer) does not provide reentrancy protection on PolkaVM. Developers must explicitly implement reentrancy guards (e.g., using a reentrancy lock mutex) in their Solidity code when making external calls to untrusted contracts. Relying on gas limits alone for reentrancy prevention is unsafe and will lead to vulnerabilities on PolkaVM. -Page Title: Get Started + !!! warning + The 2300 gas stipend that is provided by solc for address payable.{send, transfer} calls offers no reentrancy protection in PolkaVM. While the compiler attempts to detect and mitigate this pattern, developers should avoid these deprecated functions. -- Source (raw): https://raw.githubusercontent.com/polkadot-developers/polkadot-docs/master/.ai/pages/parachains-testing-fork-a-parachain.md -- Canonical (HTML): https://docs.polkadot.com/parachains/testing/fork-a-parachain/ -- Summary: Simplify Polkadot SDK development with Chopsticks. Learn essential features, how to install Chopsticks, and how to configure local blockchain forks. +- Contract creation: -# Get Started + - **`create`, `create2`**: Contract instantiation works fundamentally differently in PolkaVM. Instead of supplying deploy code concatenated with constructor arguments, the runtime expects: -## Introduction + 1. A buffer containing the code hash to deploy. + 2. The constructor arguments buffer. -[Chopsticks](https://github.com/AcalaNetwork/chopsticks/){target=\_blank}, developed by the [Acala Foundation](https://github.com/AcalaNetwork){target=\_blank}, is a versatile tool tailored for developers working on Polkadot SDK-based blockchains. With Chopsticks, you can fork live chains locally, replay blocks to analyze extrinsics, and simulate complex scenarios like XCM interactions all without deploying to a live network. + PolkaVM translates `dataoffset` and `datasize` instructions to handle contract hashes instead of contract code, enabling seamless use of the `new` keyword in Solidity. However, this translation may fail for contracts creating other contracts within `assembly` blocks. -This guide walks you through installing Chopsticks and provides information on configuring a local blockchain fork. By streamlining testing and experimentation, Chopsticks empowers developers to innovate and accelerate their blockchain projects within the Polkadot ecosystem. + If you use the Solidity `new` keyword to deploy contracts, the Revive compiler handles this transparently. However, if you are creating contracts manually in YUL assembly using `create` or `create2` opcodes, you must provide the code hash of the contract to be deployed, not its raw bytecode. Attempting to pass raw bytecode will fail. This fundamentally changes how manual contract creation is performed in assembly. -For additional support and information, please reach out through [GitHub Issues](https://github.com/AcalaNetwork/chopsticks/issues){target=_blank}. + !!! warning + Avoid using `create` family opcodes for manual deployment crafting in `assembly` blocks. This pattern is discouraged due to translation complexity and offers no gas savings benefits in PolkaVM. -!!! warning - Chopsticks uses [Smoldot](https://github.com/smol-dot/smoldot){target=_blank} light client, which only supports the native Polkadot SDK API. Consequently, a Chopsticks-based fork doesn't support Ethereum JSON-RPC calls, meaning you cannot use it to fork your chain and connect Metamask. +- Data operations: -## Prerequisites + - **`dataoffset`**: Returns the contract hash instead of code offset, aligning with PolkaVM's hash-based code referencing. + - **`datasize`**: Returns the constant contract hash size (32 bytes) rather than variable code size. -Before you begin, ensure you have the following installed: + These changes are primarily relevant for low-level YUL assembly developers who are trying to inspect or manipulate contract code directly. `dataoffset` will provide a hash, not a memory offset to the code, and `datasize` will always be 32 bytes (the size of a hash). This reinforces that direct manipulation of contract bytecode at runtime, as might be done in some EVM patterns, is not supported. -- [Node.js](https://nodejs.org/en/){target=\_blank}. -- A package manager such as [npm](https://www.npmjs.com/){target=\_blank}, which should be installed with Node.js by default, or [Yarn](https://yarnpkg.com/){target=\_blank}. +- Resource queries: -## Install Chopsticks + - **`gas`, `gaslimit`**: Return only the `ref_time` component of PolkaVM's multi-dimensional weight system, providing the closest analog to traditional gas measurements. -You can install Chopsticks globally or locally in your project. Choose the option that best fits your development workflow. This documentation explains the features of Chopsticks version `1.2.2`. Make sure you're using the correct version to match these instructions. + - While `gas` and `gaslimit` still provide a useful metric, consider that they represent `ref_time` (computation time) only. If your contract logic depends on precise knowledge of other resource costs (like `proof_size` or `storage_deposit`), you won't get that information from these opcodes. You'll need to use future precompiles for full multi-dimensional resource queries. -### Global Installation +- Blockchain state: -To install Chopsticks globally, allowing you to use it across multiple projects, run: + - **`prevrandao`, `difficulty`**: Both translate to a constant value of `2500000000000000`, as PolkaVM doesn't implement Ethereum's difficulty adjustment or randomness mechanisms. -```bash -npm i -g @acala-network/chopsticks@1.2.2 -``` + - If your Solidity contract relies on `block.difficulty` (or its equivalent YUL opcode `difficulty`) for randomness generation or any logic tied to Ethereum's proof-of-work difficulty, this will not provide true randomness on PolkaVM. The value will always be constant. Developers needing on-chain randomness should utilize Polkadot's native randomness sources or dedicated VRF (Verifiable Random Function) solutions if available. -Now, you should be able to run the `chopsticks` command from your terminal. +### Unsupported Operations -### Local Installation +Several EVM operations are not supported in PolkaVM and produce compile-time errors: -To use Chopsticks in a specific project, first create a new directory and initialize a Node.js project: +- **`pc`, `extcodecopy`**: These operations are EVM-specific and have no equivalent functionality in PolkaVM's RISC-V architecture. -```bash -mkdir my-chopsticks-project -cd my-chopsticks-project -npm init -y -``` + - Any Solidity contracts that utilize inline assembly to interact with `pc` (program counter) or `extcodecopy` will fail to compile or behave unexpectedly. This means patterns involving introspection of the current execution location or copying external contract bytecode at runtime are not supported. -Then, install Chopsticks as a local dependency: +- **`blobhash`, `blobbasefee`**: Related to Ethereum's rollup model and blob data handling, these operations are unnecessary given Polkadot's superior rollup architecture. -```bash -npm i @acala-network/chopsticks@1.2.2 -``` + - If you are porting contracts designed for Ethereum's EIP-4844 (proto-danksharding) and rely on these blob-related opcodes, they will not be available on PolkaVM. -Finally, you can run Chopsticks using the `npx` command. To see all available options and commands, run it with the `--help` flag: +- **`extcodecopy`, `selfdestruct`**: These deprecated operations are not supported and generate compile-time errors. -```bash -npx @acala-network/chopsticks --help -``` + - The `selfdestruct` opcode, which allowed contracts to remove themselves from the blockchain, is not supported. Contracts cannot be self-destroyed on PolkaVM. This affects contract upgradeability patterns that rely on self-destruction and redeployment. Similarly, `extcodecopy` is unsupported, impacting contracts that intend to inspect or copy the bytecode of other deployed contracts. -## Configure Chopsticks +### Compilation Pipeline Considerations -To run Chopsticks, you need to configure some parameters. This can be set either through using a configuration file or the command line interface (CLI). The parameters that can be configured are as follows: +PolkaVM processes YUL IR exclusively, meaning all contracts exhibit behavior consistent with Solidity's `via-ir` compilation mode. Developers familiar with the legacy compilation pipeline should expect [IR-based codegen behavior](https://docs.soliditylang.org/en/latest/ir-breaking-changes.html){target=\_blank} when working with PolkaVM contracts. -- **`genesis`**: The link to a parachain's raw genesis file to build the fork from, instead of an endpoint. -- **`timestamp`**: Timestamp of the block to fork from. -- **`endpoint`**: The endpoint of the parachain to fork. -- **`block`**: Use to specify at which block hash or number to replay the fork. -- **`wasm-override`**: Path of the Wasm to use as the parachain runtime, instead of an endpoint's runtime. -- **`db`**: Path to the name of the file that stores or will store the parachain's database. -- **`config`**: Path or URL of the config file. -- **`port`**: The port to expose an endpoint on. -- **`build-block-mode`**: How blocks should be built in the fork: batch, manual, instant. -- **`import-storage`**: A pre-defined JSON/YAML storage path to override in the parachain's storage. -- **`allow-unresolved-imports`**: Whether to allow Wasm unresolved imports when using a Wasm to build the parachain. -- **`html`**: Include to generate storage diff preview between blocks. -- **`mock-signature-host`**: Mock signature host so that any signature starts with `0xdeadbeef` and filled by `0xcd` is considered valid. +If you've previously worked with older Solidity compilers that did not use the `via-ir` pipeline by default, you might observe subtle differences in compiled bytecode size or gas usage. It's recommended to familiarize yourself with Solidity's IR-based codegen behavior, as this is the standard for PolkaVM. -### Configuration File +### Memory Pointer Limitations -The Chopsticks source repository includes a collection of [YAML](https://yaml.org/){target=\_blank} files that can be used to set up various Polkadot SDK chains locally. You can download these configuration files from the [repository's `configs` folder](https://github.com/AcalaNetwork/chopsticks/tree/master/configs){target=\_blank}. +YUL functions accepting memory buffer offset pointers or size arguments are limited by PolkaVM's 32-bit pointer size. Supplying values above `2^32-1` will trap the contract immediately. The Solidity compiler typically generates valid memory references, making this primarily a concern for low-level assembly code. -An example of a configuration file for Polkadot is as follows: +For standard Solidity development, this limitation is unlikely to be hit as the compiler handles memory addresses correctly within typical contract sizes. However, if you are writing extremely large contracts using YUL assembly that manually and extensively manipulate memory addresses, ensure that your memory offsets and sizes do not exceed PolkaVM's **fixed 64KB memory limit per contract**. While the YUL functions might accept 32-bit pointers (up to 2^32-1), attempting to access memory beyond the allocated 64KB buffer will trap the contract immediately. -{% raw %} -```yaml -endpoint: - - wss://rpc.ibp.network/polkadot - - wss://polkadot-rpc.dwellir.com -mock-signature-host: true -block: ${env.POLKADOT_BLOCK_NUMBER} -db: ./db.sqlite -runtime-log-level: 5 +These incompatibilities reflect the fundamental architectural differences between EVM and PolkaVM while maintaining high-level Solidity compatibility. Most developers using standard Solidity patterns will encounter no issues, but those working with assembly code or advanced contract patterns should carefully review these differences during migration. -import-storage: - System: - Account: - - - - 5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY - - providers: 1 - data: - free: '10000000000000000000' - ParasDisputes: - $removePrefix: ['disputes'] # those can makes block building super slow -``` -{% endraw %} +--- -The configuration file allows you to modify the storage of the forked network by rewriting the pallet, state component and value that you want to change. For example, Polkadot's file rewrites Alice's `system.Account` storage so that the free balance is set to `10000000000000000000`. +Page Title: Fork a Chain with Chopsticks -### CLI Flags +- Source (raw): https://raw.githubusercontent.com/polkadot-developers/polkadot-docs/master/.ai/pages/tutorials-polkadot-sdk-testing-fork-live-chains.md +- Canonical (HTML): https://docs.polkadot.com/tutorials/polkadot-sdk/testing/fork-live-chains/ +- Summary: Learn how to fork live Polkadot SDK chains with Chopsticks. Configure forks, replay blocks, test XCM, and interact programmatically or via UI. -Alternatively, all settings (except for genesis and timestamp) can be configured via command-line flags, providing a comprehensive method to set up the environment. +# Fork a Chain with Chopsticks -## WebSocket Commands +## Introduction -Chopstick's internal WebSocket server has special endpoints that allow the manipulation of the local Polkadot SDK chain. +Chopsticks is an innovative tool that simplifies the process of forking live Polkadot SDK chains. This guide provides step-by-step instructions to configure and fork chains, enabling developers to: -These are the methods that can be invoked and their parameters: +- Replay blocks for state analysis. +- Test cross-chain messaging (XCM). +- Simulate blockchain environments for debugging and experimentation. -- **dev_newBlock** (newBlockParams): Generates one or more new blocks. +With support for both configuration files and CLI commands, Chopsticks offers flexibility for diverse development workflows. Whether you're testing locally or exploring complex blockchain scenarios, Chopsticks empowers developers to gain deeper insights and accelerate application development. - === "Parameters" +Chopsticks uses the [Smoldot](https://github.com/smol-dot/smoldot){target=\_blank} light client, which does not support calls made through the Ethereum JSON-RPC. As a result, you can't fork your chain using Chopsticks and then interact with it using tools like MetaMask. - - **`newBlockParams` ++"NewBlockParams"++**: The parameters to build the new block with. Where the `NewBlockParams` interface includes the following properties. +For additional support and information, please reach out through [GitHub Issues](https://github.com/AcalaNetwork/chopsticks/issues){target=\_blank}. - - **`count` ++"number"++**: The number of blocks to build. - - **`dmp` ++"{ msg: string, sentAt: number }[]"++**: The downward messages to include in the block. - - **`hrmp` ++"Record"++**: The horizontal messages to include in the block. - - **`to` ++"number"++**: The block number to build to. - - **`transactions` ++"string[]"++**: The transactions to include in the block. - - **`ump` ++"Record"++**: The upward messages to include in the block. - - **`unsafeBlockHeight` ++"number"++**: Build block using a specific block height (unsafe). +## Prerequisites - === "Example" +To follow this tutorial, ensure you have completed the following: - ```js - import { ApiPromise, WsProvider } from '@polkadot/api'; +- **Installed Chopsticks**: If you still need to do so, see the [Install Chopsticks](/parachains/testing/#install-chopsticks){target=\_blank} instructions for assistance. +- **Reviewed [Configure Chopsticks](/parachains/testing/#configure-chopsticks){target=\_blank}**: You should understand how forked chains are configured. - async function main() { - const wsProvider = new WsProvider('ws://localhost:8000'); - const api = await ApiPromise.create({ provider: wsProvider }); - await api.isReady; - await api.rpc('dev_newBlock', { count: 1 }); - } +## Configuration File - main(); +To run Chopsticks using a configuration file, utilize the `--config` flag. You can use a raw GitHub URL, a path to a local file, or simply the chain's name. The following commands all look different but they use the `polkadot` configuration in the same way: - ``` +=== "GitHub URL" -- **dev_setBlockBuildMode** (buildBlockMode): Sets block build mode. + ```bash + npx @acala-network/chopsticks \ + --config=https://raw.githubusercontent.com/AcalaNetwork/chopsticks/master/configs/polkadot.yml + ``` - === "Parameter" - - - **`buildBlockMode` ++"BuildBlockMode"++**: The build mode. Can be any of the following modes: +=== "Local File Path" - ```ts - export enum BuildBlockMode { - Batch = 'Batch', /** One block per batch (default) */ - Instant = 'Instant', /** One block per transaction */ - Manual = 'Manual', /** Only build when triggered */ - } - ``` - - === "Example" + ```bash + npx @acala-network/chopsticks --config=configs/polkadot.yml + ``` - ```js - import { ApiPromise, WsProvider } from '@polkadot/api'; +=== "Chain Name" - async function main() { - const wsProvider = new WsProvider('ws://localhost:8000'); - const api = await ApiPromise.create({ provider: wsProvider }); - await api.isReady; - await api.rpc('dev_setBlockBuildMode', 'Instant'); - } + ```bash + npx @acala-network/chopsticks --config=polkadot + ``` - main(); +Regardless of which method you choose from the preceding examples, you'll see an output similar to the following: - ``` +
+ npx @acala-network/chopsticks --config=polkadot +
+ [18:38:26.155] INFO: Loading config file https://raw.githubusercontent.com/AcalaNetwork/chopsticks/master/configs/polkadot.yml + app: "chopsticks" + chopsticks::executor TRACE: Calling Metadata_metadata + chopsticks::executor TRACE: Completed Metadata_metadata + [18:38:28.186] INFO: Polkadot RPC listening on port 8000 + app: "chopsticks" +
-- **dev_setHead** (hashOrNumber): Sets the head of the blockchain to a specific hash or number. +If using a file path, make sure you've downloaded the [Polkadot configuration file](https://github.com/AcalaNetwork/chopsticks/blob/master/configs/polkadot.yml){target=\_blank}, or have created your own. - === "Parameter" +## Create a Fork - - **`hashOrNumber` ++"string | number"++**: The block hash or number to set as head. +Once you've configured Chopsticks, use the following command to fork Polkadot at block 100: - === "Example" +```bash +npx @acala-network/chopsticks \ +--endpoint wss://polkadot-rpc.dwellir.com \ +--block 100 +``` - ```js - import { ApiPromise, WsProvider } from '@polkadot/api'; +If the fork is successful, you will see output similar to the following: - async function main() { - const wsProvider = new WsProvider('ws://localhost:8000'); - const api = await ApiPromise.create({ provider: wsProvider }); - await api.isReady; - await api.rpc('dev_setHead', 500); - } +
+ npx @acala-network/chopsticks \ --endpoint wss://polkadot-rpc.dwellir.com \ --block 100 +
+ [19:12:21.023] INFO: Polkadot RPC listening on port 8000 + app: "chopsticks" +
- main(); +Access the running Chopsticks fork using the default address. - ``` +```bash +ws://localhost:8000 +``` -- **dev_setRuntimeLogLevel** (runtimeLogLevel): Sets the runtime log level. +## Interact with a Fork - === "Parameter" +You can interact with the forked chain using various [libraries](/develop/toolkit/#libraries){target=\_blank} such as [Polkadot.js](https://polkadot.js.org/docs/){target=\_blank} and its user interface, [Polkadot.js Apps](https://polkadot.js.org/apps/#/explorer){target=\_blank}. - - **`runtimeLogLevel` ++"number"++**: The runtime log level to set. +### Use Polkadot.js Apps - === "Example" +To interact with Chopsticks via the hosted user interface, visit [Polkadot.js Apps](https://polkadot.js.org/apps/#/explorer){target=\_blank} and follow these steps: - ```js - import { ApiPromise, WsProvider } from '@polkadot/api'; +1. Select the network icon in the top left corner. - async function main() { - const wsProvider = new WsProvider('ws://localhost:8000'); - const api = await ApiPromise.create({ provider: wsProvider }); - await api.isReady; - await api.rpc('dev_setRuntimeLogLevel', 1); - } + ![](/images/tutorials/polkadot-sdk/testing/fork-live-chains/chopsticks-1.webp) - main(); +2. Scroll to the bottom and select **Development**. +3. Choose **Custom**. +4. Enter `ws://localhost:8000` in the input field. +5. Select the **Switch** button. - ``` + ![](/images/tutorials/polkadot-sdk/testing/fork-live-chains/chopsticks-2.webp) -- **dev_setStorage** (values, blockHash): Creates or overwrites the value of any storage. +You should now be connected to your local fork and can interact with it as you would with a real chain. - === "Parameters" +### Use Polkadot.js Library - - **`values` ++"object"++**: JSON object resembling the path to a storage value. - - **`blockHash` ++"string"++**: The block hash to set the storage value. +For programmatic interaction, you can use the Polkadot.js library. The following is a basic example: - === "Example" +```js +import { ApiPromise, WsProvider } from '@polkadot/api'; - ```js - import { ApiPromise, WsProvider } from '@polkadot/api'; +async function connectToFork() { + const wsProvider = new WsProvider('ws://localhost:8000'); + const api = await ApiPromise.create({ provider: wsProvider }); + await api.isReady; - import { Keyring } from '@polkadot/keyring'; - async function main() { - const wsProvider = new WsProvider('ws://localhost:8000'); - const api = await ApiPromise.create({ provider: wsProvider }); - await api.isReady; - const keyring = new Keyring({ type: 'ed25519' }); - const bob = keyring.addFromUri('//Bob'); - const storage = { - System: { - Account: [[[bob.address], { data: { free: 100000 }, nonce: 1 }]], - }, - }; - await api.rpc('dev_setStorage', storage); - } + // Now you can use 'api' to interact with your fork + console.log(`Connected to chain: ${await api.rpc.system.chain()}`); +} - main(); +connectToFork(); - ``` +``` -- **dev_timeTravel** (date): Sets the timestamp of the block to a specific date". +## Replay Blocks - === "Parameter" +Chopsticks allows you to replay specific blocks from a chain, which is useful for debugging and analyzing state changes. You can use the parameters in the [Configuration](/parachains/testing/#configure-chopsticks){target=\_blank} section to set up the chain configuration, and then use the run-block subcommand with the following additional options: - - **`date` ++"string"++**: Timestamp or date string to set. All future blocks will be sequentially created after this point in time. +- **`output-path`**: Path to print output. +- **`html`**: Generate HTML with storage diff. +- **`open`**: Open generated HTML. - === "Example" +For example, the command to replay block 1000 from Polkadot and save the output to a JSON file would be as follows: - ```js - import { ApiPromise, WsProvider } from '@polkadot/api'; +```bash +npx @acala-network/chopsticks run-block \ +--endpoint wss://polkadot-rpc.dwellir.com \ +--output-path ./polkadot-output.json \ +--block 1000 +``` - async function main() { - const wsProvider = new WsProvider('ws://localhost:8000'); - const api = await ApiPromise.create({ provider: wsProvider }); - await api.isReady; - await api.rpc('dev_timeTravel', '2030-08-15T00:00:00'); +??? code "polkadot-output.json" + + ```json + { + "Call": { + "result": "0xba754e7478944d07a1f7e914422b4d973b0855abeb6f81138fdca35beb474b44a10f6fc59a4d90c3b78e38fac100fc6adc6f9e69a07565ec8abce6165bd0d24078cc7bf34f450a2cc7faacc1fa1e244b959f0ed65437f44208876e1e5eefbf8dd34c040642414245b501030100000083e2cc0f00000000d889565422338aa58c0fd8ebac32234149c7ce1f22ac2447a02ef059b58d4430ca96ba18fbf27d06fe92ec86d8b348ef42f6d34435c791b952018d0a82cae40decfe5faf56203d88fdedee7b25f04b63f41f23da88c76c876db5c264dad2f70c", + "storageDiff": [ + [ + "0x0b76934f4cc08dee01012d059e1b83eebbd108c4899964f707fdaffb82636065", + "0x00" + ], + [ + "0x1cb6f36e027abb2091cfb5110ab5087f0323475657e0890fbdbf66fb24b4649e", + null + ], + [ + "0x1cb6f36e027abb2091cfb5110ab5087f06155b3cd9a8c9e5e9a23fd5dc13a5ed", + "0x83e2cc0f00000000" + ], + [ + "0x1cb6f36e027abb2091cfb5110ab5087ffa92de910a7ce2bd58e99729c69727c1", + null + ], + [ + "0x26aa394eea5630e07c48ae0c9558cef702a5c1b19ab7a04f536c519aca4983ac", + null + ], + [ + "0x26aa394eea5630e07c48ae0c9558cef70a98fdbe9ce6c55837576c60c7af3850", + "0x02000000" + ], + [ + "0x26aa394eea5630e07c48ae0c9558cef734abf5cb34d6244378cddbf18e849d96", + "0xc03b86ae010000000000000000000000" + ], + [ + "0x26aa394eea5630e07c48ae0c9558cef780d41e5e16056765bc8461851072c9d7", + "0x080000000000000080e36a09000000000200000001000000000000ca9a3b00000000020000" + ], + [ + "0x26aa394eea5630e07c48ae0c9558cef78a42f33323cb5ced3b44dd825fda9fcc", + null + ], + [ + "0x26aa394eea5630e07c48ae0c9558cef799e7f93fc6a98f0874fd057f111c4d2d", + null + ], + [ + "0x26aa394eea5630e07c48ae0c9558cef7a44704b568d21667356a5a050c118746d366e7fe86e06375e7030000", + "0xba754e7478944d07a1f7e914422b4d973b0855abeb6f81138fdca35beb474b44" + ], + [ + "0x26aa394eea5630e07c48ae0c9558cef7a86da5a932684f199539836fcb8c886f", + null + ], + [ + "0x26aa394eea5630e07c48ae0c9558cef7b06c3320c6ac196d813442e270868d63", + null + ], + [ + "0x26aa394eea5630e07c48ae0c9558cef7bdc0bd303e9855813aa8a30d4efc5112", + null + ], + [ + "0x26aa394eea5630e07c48ae0c9558cef7df1daeb8986837f21cc5d17596bb78d15153cb1f00942ff401000000", + null + ], + [ + "0x26aa394eea5630e07c48ae0c9558cef7df1daeb8986837f21cc5d17596bb78d1b4def25cfda6ef3a00000000", + null + ], + [ + "0x26aa394eea5630e07c48ae0c9558cef7ff553b5a9862a516939d82b3d3d8661a", + null + ], + [ + "0x2b06af9719ac64d755623cda8ddd9b94b1c371ded9e9c565e89ba783c4d5f5f9b4def25cfda6ef3a000000006f3d6b177c8acbd8dc9974cdb3cebfac4d31333c30865ff66c35c1bf898df5c5dd2924d3280e7201", + "0x9b000000" + ], + ["0x3a65787472696e7369635f696e646578", null], + [ + "0x3f1467a096bcd71a5b6a0c8155e208103f2edf3bdf381debe331ab7446addfdc", + "0x550057381efedcffffffffffffffffff" + ], + [ + "0x3fba98689ebed1138735e0e7a5a790ab0f41321f75df7ea5127be2db4983c8b2", + "0x00" + ], + [ + "0x3fba98689ebed1138735e0e7a5a790ab21a5051453bd3ae7ed269190f4653f3b", + "0x080000" + ], + [ + "0x3fba98689ebed1138735e0e7a5a790abb984cfb497221deefcefb70073dcaac1", + "0x00" + ], + [ + "0x5f3e4907f716ac89b6347d15ececedca80cc6574281671b299c1727d7ac68cabb4def25cfda6ef3a00000000", + "0x204e0000183887050ecff59f58658b3df63a16d03a00f92890f1517f48c2f6ccd215e5450e380e00005809fd84af6483070acbb92378e3498dbc02fb47f8e97f006bb83f60d7b2b15d980d000082104c22c383925323bf209d771dec6e1388285abe22c22d50de968467e0bb6ce00b000088ee494d719d68a18aade04903839ea37b6be99552ceceb530674b237afa9166480d0000dc9974cdb3cebfac4d31333c30865ff66c35c1bf898df5c5dd2924d3280e72011c0c0000e240d12c7ad07bb0e7785ee6837095ddeebb7aef84d6ed7ea87da197805b343a0c0d0000" + ], + [ + "0xae394d879ddf7f99595bc0dd36e355b5bbd108c4899964f707fdaffb82636065", + null + ], + [ + "0xbd2a529379475088d3e29a918cd478721a39ec767bd5269111e6492a1675702a", + "0x4501407565175cfbb5dca18a71e2433f838a3d946ef532c7bff041685db1a7c13d74252fffe343a960ef84b15187ea0276687d8cb3168aeea5202ea6d651cb646517102b81ff629ee6122430db98f2cadf09db7f298b49589b265dae833900f24baa8fb358d87e12f3e9f7986a9bf920c2fb48ce29886199646d2d12c6472952519463e80b411adef7e422a1595f1c1af4b5dd9b30996fba31fa6a30bd94d2022d6b35c8bc5a8a51161d47980bf4873e01d15afc364f8939a6ce5a09454ab7f2dd53bf4ee59f2c418e85aa6eb764ad218d0097fb656900c3bdd859771858f87bf7f06fc9b6db154e65d50d28e8b2374898f4f519517cd0bedc05814e0f5297dc04beb307b296a93cc14d53afb122769dfd402166568d8912a4dff9c2b1d4b6b34d811b40e5f3763e5f3ab5cd1da60d75c0ff3c12bcef3639f5f792a85709a29b752ffd1233c2ccae88ed3364843e2fa92bdb49021ee36b36c7cdc91b3e9ad32b9216082b6a2728fccd191a5cd43896f7e98460859ca59afbf7c7d93cd48da96866f983f5ff8e9ace6f47ee3e6c6edb074f578efbfb0907673ebca82a7e1805bc5c01cd2fa5a563777feeb84181654b7b738847c8e48d4f575c435ad798aec01631e03cf30fe94016752b5f087f05adf1713910767b7b0e6521013be5370776471191641c282fdfe7b7ccf3b2b100a83085cd3af2b0ad4ab3479448e71fc44ff987ec3a26be48161974b507fb3bc8ad23838f2d0c54c9685de67dc6256e71e739e9802d0e6e3b456f6dca75600bc04a19b3cc1605784f46595bfb10d5e077ce9602ae3820436166aa1905a7686b31a32d6809686462bc9591c0bc82d9e49825e5c68352d76f1ac6e527d8ac02db3213815080afad4c2ecb95b0386e3e9ab13d4f538771dac70d3059bd75a33d0b9b581ec33bb16d0e944355d4718daccb35553012adfcdacb1c5200a2aec3756f6ad5a2beffd30018c439c1b0c4c0f86dbf19d0ad59b1c9efb7fe90906febdb9001af1e7e15101089c1ab648b199a40794d30fe387894db25e614b23e833291a604d07eec2ade461b9b139d51f9b7e88475f16d6d23de6fe7831cc1dbba0da5efb22e3b26cd2732f45a2f9a5d52b6d6eaa38782357d9ae374132d647ef60816d5c98e6959f8858cfa674c8b0d340a8f607a68398a91b3a965585cc91e46d600b1310b8f59c65b7c19e9d14864a83c4ad6fa4ba1f75bba754e7478944d07a1f7e914422b4d973b0855abeb6f81138fdca35beb474b44c7736fc3ab2969878810153aa3c93fc08c99c478ed1bb57f647d3eb02f25cee122c70424643f4b106a7643acaa630a5c4ac39364c3cb14453055170c01b44e8b1ef007c7727494411958932ae8b3e0f80d67eec8e94dd2ff7bbe8c9e51ba7e27d50bd9f52cbaf9742edecb6c8af1aaf3e7c31542f7d946b52e0c37d194b3dd13c3fddd39db0749755c7044b3db1143a027ad428345d930afcefc0d03c3a0217147900bdea1f5830d826f7e75ecd1c4e2bc8fd7de3b35c6409acae1b2215e9e4fd7e360d6825dc712cbf9d87ae0fd4b349b624d19254e74331d66a39657da81e73d7b13adc1e5efa8efd65aa32c1a0a0315913166a590ae551c395c476116156cf9d872fd863893edb41774f33438161f9b973e3043f819d087ba18a0f1965e189012496b691f342f7618fa9db74e8089d4486c8bd1993efd30ff119976f5cc0558e29b417115f60fd8897e13b6de1a48fbeee38ed812fd267ae25bffea0caa71c09309899b34235676d5573a8c3cf994a3d7f0a5dbd57ab614c6caf2afa2e1a860c6307d6d9341884f1b16ef22945863335bb4af56e5ef5e239a55dbd449a4d4d3555c8a3ec5bd3260f88cabca88385fe57920d2d2dfc5d70812a8934af5691da5b91206e29df60065a94a0a8178d118f1f7baf768d934337f570f5ec68427506391f51ab4802c666cc1749a84b5773b948fcbe460534ed0e8d48a15c149d27d67deb8ea637c4cc28240ee829c386366a0b1d6a275763100da95374e46528a0adefd4510c38c77871e66aeda6b6bfd629d32af9b2fad36d392a1de23a683b7afd13d1e3d45dad97c740106a71ee308d8d0f94f6771164158c6cd3715e72ccfbc49a9cc49f21ead8a3c5795d64e95c15348c6bf8571478650192e52e96dd58f95ec2c0fb4f2ccc05b0ab749197db8d6d1c6de07d6e8cb2620d5c308881d1059b50ffef3947c273eaed7e56c73848e0809c4bd93619edd9fd08c8c5c88d5f230a55d2c6a354e5dd94440e7b5bf99326cf4a112fe843e7efdea56e97af845761d98f40ed2447bd04a424976fcf0fe0a0c72b97619f85cf431fe4c3aa6b3a4f61df8bc1179c11e77783bfedb7d374bd1668d0969333cb518bd20add8329462f2c9a9f04d150d60413fdd27271586405fd85048481fc2ae25b6826cb2c947e4231dc7b9a0d02a9a03f88460bced3fef5d78f732684bd218a1954a4acfc237d79ccf397913ab6864cd8a07e275b82a8a72520624738368d1c5f7e0eaa2b445cf6159f2081d3483618f7fc7b16ec4e6e4d67ab5541bcda0ca1af40efd77ef8653e223191448631a8108c5e50e340cd405767ecf932c1015aa8856b834143dc81fa0e8b9d1d8c32278fca390f2ff08181df0b74e2d13c9b7b1d85543416a0dae3a77530b9cd1366213fcf3cd12a9cd3ae0a006d6b29b5ffc5cdc1ab24343e2ab882abfd719892fca5bf2134731332c5d3bef6c6e4013d84a853cb03d972146b655f0f8541bcd36c3c0c8a775bb606edfe50d07a5047fd0fe01eb125e83673930bc89e91609fd6dfe97132679374d3de4a0b3db8d3f76f31bed53e247da591401d508d65f9ee01d3511ee70e3644f3ab5d333ca7dbf737fe75217b4582d50d98b5d59098ea11627b7ed3e3e6ee3012eadd326cf74ec77192e98619427eb0591e949bf314db0fb932ed8be58258fb4f08e0ccd2cd18b997fb5cf50c90d5df66a9f3bb203bd22061956128b800e0157528d45c7f7208c65d0592ad846a711fa3c5601d81bb318a45cc1313b122d4361a7d7a954645b04667ff3f81d3366109772a41f66ece09eb93130abe04f2a51bb30e767dd37ec6ee6a342a4969b8b342f841193f4f6a9f0fac4611bc31b6cab1d25262feb31db0b8889b6f8d78be23f033994f2d3e18e00f3b0218101e1a7082782aa3680efc8502e1536c30c8c336b06ae936e2bcf9bbfb20dd514ed2867c03d4f44954867c97db35677d30760f37622b85089cc5d182a89e29ab0c6b9ef18138b16ab91d59c2312884172afa4874e6989172014168d3ed8db3d9522d6cbd631d581d166787c93209bec845d112e0cbd825f6df8b64363411270921837cfb2f9e7f2e74cdb9cd0d2b02058e5efd9583e2651239654b887ea36ce9537c392fc5dfca8c5a0facbe95b87dfc4232f229bd12e67937d32b7ffae2e837687d2d292c08ff6194a2256b17254748857c7e3c871c3fff380115e6f7faf435a430edf9f8a589f6711720cfc5cec6c8d0d94886a39bb9ac6c50b2e8ef6cf860415192ca4c1c3aaa97d36394021a62164d5a63975bcd84b8e6d74f361c17101e3808b4d8c31d1ee1a5cf3a2feda1ca2c0fd5a50edc9d95e09fb5158c9f9b0eb5e2c90a47deb0459cea593201ae7597e2e9245aa5848680f546256f3" + ], + [ + "0xd57bce545fb382c34570e5dfbf338f5e326d21bc67a4b34023d577585d72bfd7", + null + ], + [ + "0xd57bce545fb382c34570e5dfbf338f5ea36180b5cfb9f6541f8849df92a6ec93", + "0x00" + ], + [ + "0xd57bce545fb382c34570e5dfbf338f5ebddf84c5eb23e6f53af725880d8ffe90", + null + ], + [ + "0xd5c41b52a371aa36c9254ce34324f2a53b996bb988ea8ee15bad3ffd2f68dbda", + "0x00" + ], + [ + "0xf0c365c3cf59d671eb72da0e7a4113c49f1f0515f462cdcf84e0f1d6045dfcbb", + "0x50defc5172010000" + ], + [ + "0xf0c365c3cf59d671eb72da0e7a4113c4bbd108c4899964f707fdaffb82636065", + null + ], + [ + "0xf68f425cf5645aacb2ae59b51baed90420d49a14a763e1cbc887acd097f92014", + "0x9501800300008203000082030000840300008503000086030000870300008703000089030000890300008b0300008b0300008d0300008d0300008f0300008f0300009103000092030000920300009403000094030000960300009603000098030000990300009a0300009b0300009b0300009d0300009d0300009f0300009f030000a1030000a2030000a3030000a4030000a5030000a6030000a6030000a8030000a8030000aa030000ab030000ac030000ad030000ae030000af030000b0030000b1030000b1030000b3030000b3030000b5030000b6030000b7030000b8030000b9030000ba030000ba030000bc030000bc030000be030000be030000c0030000c1030000c2030000c2030000c4030000c5030000c5030000c7030000c7030000c9030000c9030000cb030000cc030000cd030000ce030000cf030000d0030000d0030000d2030000d2030000d4030000d4030000d6030000d7030000d8030000d9030000da030000db030000db030000dd030000dd030000df030000e0030000e1030000e2030000e3030000e4030000e4030000" + ], + [ + "0xf68f425cf5645aacb2ae59b51baed9049b58374218f48eaf5bc23b7b3e7cf08a", + "0xb3030000" + ], + [ + "0xf68f425cf5645aacb2ae59b51baed904b97380ce5f4e70fbf9d6b5866eb59527", + "0x9501800300008203000082030000840300008503000086030000870300008703000089030000890300008b0300008b0300008d0300008d0300008f0300008f0300009103000092030000920300009403000094030000960300009603000098030000990300009a0300009b0300009b0300009d0300009d0300009f0300009f030000a1030000a2030000a3030000a4030000a5030000a6030000a6030000a8030000a8030000aa030000ab030000ac030000ad030000ae030000af030000b0030000b1030000b1030000b3030000b3030000b5030000b6030000b7030000b8030000b9030000ba030000ba030000bc030000bc030000be030000be030000c0030000c1030000c2030000c2030000c4030000c5030000c5030000c7030000c7030000c9030000c9030000cb030000cc030000cd030000ce030000cf030000d0030000d0030000d2030000d2030000d4030000d4030000d6030000d7030000d8030000d9030000da030000db030000db030000dd030000dd030000df030000e0030000e1030000e2030000e3030000e4030000e4030000" + ] + ], + "offchainStorageDiff": [], + "runtimeLogs": [] } + } - main(); - - ``` + ``` -## Where to Go Next +## XCM Testing -
+To test XCM (Cross-Consensus Messaging) messages between networks, you can fork multiple parachains and a relay chain locally using Chopsticks. -- Tutorial __Fork a Chain with Chopsticks__ +- **`relaychain`**: Relay chain config file. +- **`parachain`**: Parachain config file. - --- +For example, to fork Moonbeam, Astar, and Polkadot enabling XCM between them, you can use the following command: - Visit this guide for step-by-step instructions for configuring and interacting with your forked chain. +```bash +npx @acala-network/chopsticks xcm \ +--r polkadot \ +--p moonbeam \ +--p astar +``` - [:octicons-arrow-right-24: Reference](/tutorials/polkadot-sdk/testing/fork-live-chains/) +After running it, you should see output similar to the following: +
+ npx @acala-network/chopsticks xcm \ + --r polkadot \ + --p moonbeam \ + --p astar +
+ [13:46:07.901] INFO: Loading config file https://raw.githubusercontent.com/AcalaNetwork/chopsticks/master/configs/moonbeam.yml + app: "chopsticks" + [13:46:12.631] INFO: Moonbeam RPC listening on port 8000 + app: "chopsticks" + [13:46:12.632] INFO: Loading config file https://raw.githubusercontent.com/AcalaNetwork/chopsticks/master/configs/astar.yml + app: "chopsticks" + chopsticks::executor TRACE: Calling Metadata_metadata + chopsticks::executor TRACE: Completed Metadata_metadata + [13:46:23.669] INFO: Astar RPC listening on port 8001 + app: "chopsticks" + [13:46:25.144] INFO (xcm): Connected parachains [2004,2006] + app: "chopsticks" + [13:46:25.144] INFO: Loading config file https://raw.githubusercontent.com/AcalaNetwork/chopsticks/master/configs/polkadot.yml + app: "chopsticks" + chopsticks::executor TRACE: Calling Metadata_metadata + chopsticks::executor TRACE: Completed Metadata_metadata + [13:46:53.320] INFO: Polkadot RPC listening on port 8002 + app: "chopsticks" + [13:46:54.038] INFO (xcm): Connected relaychain 'Polkadot' with parachain 'Moonbeam' + app: "chopsticks" + [13:46:55.028] INFO (xcm): Connected relaychain 'Polkadot' with parachain 'Astar' + app: "chopsticks"
+Now you can interact with your forked chains using the ports specified in the output. + --- -Page Title: Get Started +Page Title: Generate Chain Specs -- Source (raw): https://raw.githubusercontent.com/polkadot-developers/polkadot-docs/master/.ai/pages/parachains-testing-run-a-parachain-network.md -- Canonical (HTML): https://docs.polkadot.com/parachains/testing/run-a-parachain-network/ -- Summary: Quickly install and configure Zombienet to deploy and test Polkadot-based blockchain networks with this comprehensive getting-started guide. +- Source (raw): https://raw.githubusercontent.com/polkadot-developers/polkadot-docs/master/.ai/pages/develop-parachains-deployment-generate-chain-specs.md +- Canonical (HTML): https://docs.polkadot.com/develop/parachains/deployment/generate-chain-specs/ +- Summary: Describes the role of the chain specification in a network, how to specify its parameters when starting a node, and how to customize and distribute it. -# Get Started +# Generate Chain Specs ## Introduction -Zombienet is a robust testing framework designed for Polkadot SDK-based blockchain networks. It enables developers to efficiently deploy and test ephemeral blockchain environments on platforms like Kubernetes, Podman, and native setups. With its simple and versatile CLI, Zombienet provides an all-in-one solution for spawning networks, running tests, and validating performance. +A chain specification collects information that describes a Polkadot SDK-based network. A chain specification is a crucial parameter when starting a node, providing the genesis configurations, bootnodes, and other parameters relating to that particular network. It identifies the network a blockchain node connects to, the other nodes it initially communicates with, and the initial state that nodes must agree on to produce blocks. -This guide will outline the different installation methods for Zombienet, provide step-by-step instructions for setting up on various platforms, and highlight essential provider-specific features and requirements. +The chain specification is defined using the [`ChainSpec`](https://paritytech.github.io/polkadot-sdk/master/sc_chain_spec/struct.GenericChainSpec.html){target=\_blank} struct. This struct separates the information required for a chain into two parts: -By following this guide, Zombienet will be up and running quickly, ready to streamline your blockchain testing and development workflows. +- **Client specification**: Contains information the _node_ uses to communicate with network participants and send data to telemetry endpoints. Many of these chain specification settings can be overridden by command-line options when starting a node or can be changed after the blockchain has started. -## Install Zombienet +- **Initial genesis state**: Agreed upon by all nodes in the network. It must be set when the blockchain is first started and cannot be changed after that without starting a whole new blockchain. -Zombienet releases are available on the [Zombienet repository](https://github.com/paritytech/zombienet){target=\_blank}. +## Node Settings Customization -Multiple options are available for installing Zombienet, depending on the user's preferences and the environment where it will be used. The following section will guide you through the installation process for each option. +For the node, the chain specification controls information such as: -=== "Use the executable" +- The bootnodes the node will communicate with. +- The server endpoints for the node to send telemetry data to. +- The human and machine-readable names for the network the node will connect to. - Install Zombienet using executables by visiting the [latest release](https://github.com/paritytech/zombienet/releases){target=\_blank} page and selecting the appropriate asset for your operating system. You can download the executable and move it to a directory in your PATH. +The chain specification can be customized to include additional information. For example, you can configure the node to connect to specific blocks at specific heights to prevent long-range attacks when syncing a new node from genesis. - Each release includes executables for Linux and macOS. Executables are generated using [pkg](https://github.com/vercel/pkg){target=\_blank}, which allows the Zombienet CLI to operate without requiring Node.js to be installed. +Note that you can customize node settings after genesis. However, nodes only add peers that use the same [`protocolId`](https://paritytech.github.io/polkadot-sdk/master/sc_service/struct.GenericChainSpec.html#method.protocol_id){target=_blank}. - Then, ensure the downloaded file is executable: +## Genesis Configuration Customization - ```bash - chmod +x zombienet-macos-arm64 - ``` +All nodes in the network must agree on the genesis state before they can agree on any subsequent blocks. The information configured in the genesis portion of a chain specification is used to create a genesis block. When you start the first node, it takes effect and cannot be overridden with command-line options. However, you can configure some information in the genesis section of a chain specification. For example, you can customize it to include information such as: - Finally, you can run the following command to check if the installation was successful. If so, it will display the version of the installed Zombienet: +- Initial account balances. +- Accounts that are initially part of a governance council. +- The account that controls the `sudo` key. +- Any other genesis state for a pallet. - ```bash - ./zombienet-macos-arm64 version - ``` +Nodes also require the compiled Wasm to execute the runtime logic on the chain, so the initial runtime must also be supplied in the chain specification. For a more detailed look at customizing the genesis chain specification, be sure to check out the [Polkadot SDK Docs](https://paritytech.github.io/polkadot-sdk/master/polkadot_sdk_docs/reference_docs/chain_spec_genesis/index.html){target=_blank}. - If you want to add the `zombienet` executable to your PATH, you can move it to a directory in your PATH, such as `/usr/local/bin`: +## Declaring Storage Items for a Runtime - ```bash - mv zombienet-macos-arm64 /usr/local/bin/zombienet - ``` +A runtime usually requires some storage items to be configured at genesis. This includes the initial state for pallets, for example, how much balance specific accounts have, or which account will have sudo permissions. - Now you can refer to the `zombienet` executable directly. +These storage values are configured in the genesis portion of the chain specification. You can create a [patch](https://paritytech.github.io/polkadot-sdk/master/sc_chain_spec/index.html#chain-spec-formats){target=_blank} file and ingest it using the [`chain-spec-builder`](https://paritytech.github.io/polkadot-sdk/master/staging_chain_spec_builder/index.html){target=_blank} utility, that is explained in the [Creating a Custom Chain Specification](#creating-a-custom-chain-specification) section. - ```bash - zombienet version - ``` +## Chain Specification JSON Format -=== "Use Nix" +Users generally work with the JSON format of the chain specification. Internally, the chain specification is embedded in the [`GenericChainSpec`](https://paritytech.github.io/polkadot-sdk/master/sc_chain_spec/struct.GenericChainSpec.html){target=\_blank} struct, with specific properties accessible through the [`ChainSpec`](https://paritytech.github.io/polkadot-sdk/master/sc_chain_spec/trait.ChainSpec.html){target=\_blank} struct. The chain specification includes the following keys: - For Nix users, the Zombienet repository provides a [`flake.nix`](https://github.com/paritytech/zombienet/blob/main/flake.nix){target=\_blank} file to install Zombienet making it easy to incorporate Zombienet into Nix-based projects. - - To install Zombienet utilizing Nix, users can run the following command, triggering the fetching of the flake and subsequently installing the Zombienet package: +- **`name`**: The human-readable name for the network. +- **`id`**: The machine-readable identifier for the network. +- **`chainType`**: The type of chain to start (refer to [`ChainType`](https://paritytech.github.io/polkadot-sdk/master/sc_chain_spec/enum.ChainType.html){target=\_blank} for more details). +- **`bootNodes`**: A list of multiaddresses belonging to the chain's boot nodes. +- **`telemetryEndpoints`**: An optional list of multiaddresses for telemetry endpoints with verbosity levels ranging from 0 to 9 (0 being the lowest verbosity). +- **`protocolId`**: The optional protocol identifier for the network. +- **`forkId`**: An optional fork ID that should typically be left empty; it can be used to signal a fork at the network level when two chains share the same genesis hash. +- **`properties`**: Custom properties provided as a key-value JSON object. +- **`codeSubstitutes`**: An optional mapping of block numbers to Wasm code. +- **`genesis`**: The genesis configuration for the chain. - ```bash - nix run github:paritytech/zombienet/INSERT_ZOMBIENET_VERSION -- \ - spawn INSERT_ZOMBIENET_CONFIG_FILE_NAME.toml - ``` +For example, the following JSON shows a basic chain specification file: - Replace the `INSERT_ZOMBIENET_VERSION` with the desired version of Zombienet and the `INSERT_ZOMBIENET_CONFIG_FILE_NAME` with the name of the configuration file you want to use. +```json +{ + "name": "chainName", + "id": "chainId", + "chainType": "Local", + "bootNodes": [], + "telemetryEndpoints": null, + "protocolId": null, + "properties": null, + "codeSubstitutes": {}, + "genesis": { + "code": "0x..." + } +} - To run the command above, you need to have [Flakes](https://nixos.wiki/wiki/Flakes#Enable_flakes){target=\_blank} enabled. +``` - Alternatively, you can also include the Zombienet binary in the PATH for the current shell using the following command: - - ```bash - nix shell github:paritytech/zombienet/INSERT_ZOMBIENET_VERSION - ``` +## Creating a Custom Chain Specification -=== "Use Docker" +To create a custom chain specification, you can use the [`chain-spec-builder`](https://paritytech.github.io/polkadot-sdk/master/staging_chain_spec_builder/index.html){target=\_blank} tool. This is a CLI tool that is used to generate chain specifications from the runtime of a node. To install the tool, run the following command: - Zombienet can also be run using Docker. The Zombienet repository provides a Docker image that can be used to run the Zombienet CLI. To run Zombienet using Docker, you can use the following command: +```bash +cargo install --git https://github.com/paritytech/polkadot-sdk --force staging-chain-spec-builder +``` - ```bash - docker run -it --rm \ - -v $(pwd):/home/nonroot/zombie-net/host-current-files \ - paritytech/zombienet - ``` +To verify the installation, run the following: - The command above will run the Zombienet CLI inside a Docker container and mount the current directory to the `/home/nonroot/zombie-net/host-current-files` directory. This allows Zombienet to access the configuration file and other files in the current directory. If you want to mount a different directory, replace `$(pwd)` with the desired directory path. +```bash +chain-spec-builder --help +``` - Inside the Docker container, you can run the Zombienet CLI commands. First, you need to set up Zombienet to download the necessary binaries: +### Plain Chain Specifications - ```bash - npm run zombie -- setup polkadot polkadot-parachain - ``` +To create a plain chain specification, first ensure that the runtime has been compiled and is available at the specified path. Next, you can use the following utility within your project: - After that, you need to add those binaries to the PATH: +```bash +chain-spec-builder create -r INSERT_RUNTIME_WASM_PATH INSERT_COMMAND +``` - ```bash - export PATH=/home/nonroot/zombie-net:$PATH - ``` +Replace `INSERT_RUNTIME_WASM_PATH` with the path to the runtime Wasm file and `INSERT_COMMAND` with the command to insert the runtime into the chain specification. - Finally, you can run the Zombienet CLI commands. For example, to spawn a network using a specific configuration file, you can run the following command: +The available commands are: - ```bash - npm run zombie -- -p native spawn host-current-files/minimal.toml - ``` +- **`patch`**: Overwrites the runtime's default genesis config with the provided patch. You can check the following [patch file](https://github.com/paritytech/polkadot-sdk/blob/polkadot-stable2506-2/substrate/bin/utils/chain-spec-builder/tests/input/patch.json){target=\_blank} as a reference. +- **`full`**: Build the genesis config for runtime using the JSON file. No defaults will be used. As a reference, you can check the following [full file](https://github.com/paritytech/polkadot-sdk/blob/polkadot-stable2506-2/substrate/bin/utils/chain-spec-builder/tests/input/full.json){target=\_blank}. +- **`default`**: Gets the default genesis config for the runtime and uses it in `ChainSpec`. Please note that the default genesis config may not be valid. For some runtimes, initial values should be added there (e.g., session keys, BABE epoch). +- **`named-preset`**: Uses named preset provided by the runtime to build the chain spec. - The command above mounts the current directory to the `/workspace` directory inside the Docker container, allowing Zombienet to access the configuration file and other files in the current directory. If you want to mount a different directory, replace `$(pwd)` with the desired directory path. +### Raw Chain Specifications -## Providers +With runtime upgrades, the blockchain's runtime can be upgraded with newer business logic. Chain specifications contain information structured in a way that the node's runtime can understand. For example, consider this excerpt of a common entry for a chain specification: -Zombienet supports different backend providers for running the nodes. At this moment, [Kubernetes](https://kubernetes.io/){target=\_blank}, [Podman](https://podman.io/){target=\_blank}, and local providers are supported, which can be declared as `kubernetes`, `podman`, or `native`, respectively. +```json +"sudo": { + "key": "5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY" +} +``` -To use a particular provider, you can specify it in the network file or use the `--provider` flag in the CLI: +In the plain chain spec JSON file, the keys and associated values are in a human-readable format, which can be used to initialize the genesis storage. When the chain specification is loaded, the runtime converts these readable values into storage items within the trie. However, for long-lived networks like testnets or production chains, using the raw format for storage initialization is preferred. This avoids the need for conversion by the runtime and ensures that storage items remain consistent, even when runtime upgrades occur. + +To enable a node with an upgraded runtime to synchronize with a chain from genesis, the plain chain specification is encoded in a raw format. The raw format allows the distribution of chain specifications that all nodes can use to synchronize the chain even after runtime upgrades. + +To convert a plain chain specification to a raw chain specification, you can use the following utility: ```bash -zombienet spawn network.toml --provider INSERT_PROVIDER +chain-spec-builder convert-to-raw chain_spec.json ``` -Alternatively, you can set the provider in the network file: +After the conversion to the raw format, the `sudo key` snippet looks like this: -```toml -[settings] -provider = "INSERT_PROVIDER" -... +```json +"0x50a63a871aced22e88ee6466fe5aa5d9": "0xd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d", ``` -It's important to note that each provider has specific requirements and associated features. The following sections cover each provider's requirements and added features. +The raw chain specification can be used to initialize the genesis storage for a node. + +## Generate Custom Keys for Your Collator + +To securely deploy your parachain, you must generate custom cryptographic keys for your collators (block producers). Each collator requires two distinct sets of keys with different security requirements and operational purposes. + +- **Account keys**: Serve as the primary identity and financial controller for your collator. These keys are used to interact with the network and manage funds. They should be treated as cold storage and must never exist on the filesystem of the collator node. Secure offline backup is essential. -### Kubernetes +- **Session keys**: Handle block production operations to identify your node and sign blocks on the network. These keys are stored in the parachain keystore and function as operational "hot wallet" keys. If compromised, an attacker could impersonate your node, potentially resulting in slashing of your funds. To minimize these risks, implement regular session key rotation and treat them with the same caution as hot wallet keys. -Kubernetes is a portable, extensible, open-source platform for managing containerized workloads and services. Zombienet is designed to be compatible with a variety of Kubernetes clusters, including: +To perform this step, you can use [Subkey](https://docs.rs/crate/subkey/latest){target=\_blank}, a command-line tool for generating and managing keys: -- [Google Kubernetes Engine (GKE)](https://cloud.google.com/kubernetes-engine){target=\_blank} -- [Docker Desktop](https://docs.docker.com/desktop/features/kubernetes/){target=\_blank} -- [kind](https://kind.sigs.k8s.io/){target=\_blank} +```bash +docker run -it parity/subkey:latest generate --scheme sr25519 +``` -#### Requirements - -To effectively interact with your cluster, you'll need to ensure that [`kubectl`](https://kubernetes.io/docs/reference/kubectl/){target=\_blank} is installed on your system. This Kubernetes command-line tool allows you to run commands against Kubernetes clusters. If you don't have `kubectl` installed, you can follow the instructions provided in the [Kubernetes documentation](https://kubernetes.io/docs/tasks/tools/#kubectl){target=\_blank}. +The output should look similar to the following: -To create resources such as namespaces, pods, and CronJobs within the target cluster, you must grant your user or service account the appropriate permissions. These permissions are essential for managing and deploying applications effectively within Kubernetes. +
+ docker run -it parity/subkey:latest generate --scheme sr25519 +
Secret phrase: lemon play remain picture leopard frog mad bridge hire hazard best buddy
Network ID: substrate
Secret seed: 0xb748b501de061bae1fcab1c0b814255979d74d9637b84e06414a57a1a149c004
Public key (hex): 0xf4ec62ec6e70a3c0f8dcbe0531e2b1b8916cf16d30635bbe9232f6ed3f0bf422
Account ID: 0xf4ec62ec6e70a3c0f8dcbe0531e2b1b8916cf16d30635bbe9232f6ed3f0bf422
Public key (SS58): 5HbqmBBJ5ALUzho7tw1k1jEgKBJM7dNsQwrtfSfUskT1a3oe
SS58 Address: 5HbqmBBJ5ALUzho7tw1k1jEgKBJM7dNsQwrtfSfUskT1a3oe
+
-#### Features - -If available, Zombienet uses the Prometheus operator to oversee monitoring and visibility. This configuration ensures that only essential networking-related pods are deployed. Using the Prometheus operator, Zombienet improves its ability to monitor and manage network activities within the Kubernetes cluster efficiently. +Ensure that this command is executed twice to generate the keys for both the account and session keys. Save them for future reference. -### Podman +After generating the plain chain specification, you need to edit this file by inserting the account IDs and session keys in SS58 format generated for your collators in the `collatorSelection.invulnerables` and `session.keys` fields. -Podman is a daemonless container engine for developing, managing, and running Open Container Initiative (OCI) containers and container images on Linux-based systems. Zombienet supports Podman rootless as a provider on Linux machines. Although Podman has support for macOS through an internal virtual machine (VM), the Zombienet provider code requires Podman to run natively on Linux. +### Add Invulnerables -#### Requirements - -To use Podman as a provider, you need to have Podman installed on your system. You can install Podman by following the instructions provided on the [Podman website](https://podman.io/getting-started/installation){target=\_blank}. +In the `collatorSelection.invulnerables` array, add the SS58 addresses (account keys) of your collators. These addresses will be automatically included in the active collator set: -#### Features - -Using Podman, Zombienet deploys additional pods to enhance the monitoring and visibility of the active network. Specifically, pods for [Prometheus](https://prometheus.io/){target=\_blank}, [Tempo](https://grafana.com/docs/tempo/latest/operations/monitor/){target=\_blank}, and [Grafana](https://grafana.com/){target=\_blank} are included in the deployment. Grafana is configured with Prometheus and Tempo as data sources. +```json + "collatorSelection": { + "candidacyBond": 16000000000, + "desiredCandidates": 0, + "invulnerables": [ + "INSERT_ACCOUNT_ID_COLLATOR_1", + "INSERT_ACCOUNT_ID_COLLATOR_2", + "INSERT_ACCOUNT_ID_COLLATOR_3" + ] + } +``` -Upon launching Zombienet, access to these monitoring services is facilitated through specific URLs provided in the output: +- **`candidacyBond`**: Minimum stake required for collator candidates (in Planck units). +- **`desiredCandidates`**: Number of candidates beyond invulnerables (set to 0 for invulnerables-only). +- **`invulnerables`**: Use the SS58 addresses from your generated account keys as collators. -- **Prometheus**: `http://127.0.0.1:34123` -- **Tempo**: `http://127.0.0.1:34125` -- **Grafana**: `http://127.0.0.1:41461` +### Add Session Keys -It's important to note that Grafana is deployed with default administrator access. - -When network operations cease, either from halting a running spawn with the `Ctrl+C` command or test completion, Zombienet automatically removes all associated pods. +For each invulnerable collator, add a corresponding entry in the `session.keys` array. This maps each collator's account ID to their session keys: -### Local Provider +```json + "session": { + "keys": [ + [ + "INSERT_ACCOUNT_ID_COLLATOR_1", + "INSERT_ACCOUNT_ID_COLLATOR_1", + { + "aura": "INSERT_SESSION_KEY_COLLATOR_1" + } + ], + [ + "INSERT_ACCOUNT_ID_COLLATOR_2", + "INSERT_ACCOUNT_ID_COLLATOR_2", + { + "aura": "INSERT_SESSION_KEY_COLLATOR_2" + } + ], + [ + "INSERT_ACCOUNT_ID_COLLATOR_3", + "INSERT_ACCOUNT_ID_COLLATOR_3", + { + "aura": "INSERT_SESSION_KEY_COLLATOR_3" + } + ] + ], + "nonAuthorityKeys": [] + } +``` -The Zombienet local provider, also called native, enables you to run nodes as local processes in your environment. +## Where to Go Next -#### Requirements - -You must have the necessary binaries for your network (such as `polkadot` and `polkadot-parachain`). These binaries should be available in your PATH, allowing Zombienet to spawn the nodes as local processes. +After generating a chain specification, you can use it to initialize the genesis storage for a node. Refer to the following guides to learn how to proceed with the deployment of your blockchain: -To install the necessary binaries, you can use the Zombienet CLI command: +
-```bash -zombienet setup polkadot polkadot-parachain -``` +- Guide __Obtain Coretime__ -This command will download and prepare the necessary binaries for Zombienet's use. + --- -If you need to use a custom binary, ensure the binary is available in your PATH. You can also specify the binary path in the network configuration file. The following example uses the custom [OpenZeppelin template](https://github.com/OpenZeppelin/polkadot-runtime-templates){target=\_blank}: + Learn how to obtain the necessary coretime configuration to synchronize your blockchain’s timestamping and enhance its performance. -First, clone the OpenZeppelin template repository using the following command: + [:octicons-arrow-right-24: Reference](/parachains/launch-a-parachain/obtain-coretime/) -```bash -git clone https://github.com/OpenZeppelin/polkadot-runtime-templates \ -&& cd polkadot-runtime-templates/generic-template -``` +- Guide __Deployment__ -Next, run the command to build the custom binary: + --- -```bash -cargo build --release -``` + Explore the steps required to deploy your chain specification, ensuring a smooth launch of your network and proper node operation. -Finally, add the custom binary to your PATH as follows: -```bash -export PATH=$PATH:INSERT_PATH_TO_RUNTIME_TEMPLATES/parachain-template-node/target/release -``` + [:octicons-arrow-right-24: Reference](/develop/parachains/deployment/) -Alternatively, you can specify the binary path in the network configuration file. The local provider exclusively utilizes the command configuration for nodes, which supports both relative and absolute paths. You can employ the `default_command` configuration to specify the binary for spawning all nodes in the relay chain. +- Guide __Maintenance__ -```toml -[relaychain] -chain = "rococo-local" -default_command = "./bin-v1.6.0/polkadot" + --- -[parachain] -id = 1000 + Discover best practices for maintaining your blockchain post-deployment, including how to manage upgrades and monitor network health. - [parachain.collators] - name = "collator01" - command = "./target/release/parachain-template-node" -``` -#### Features + [:octicons-arrow-right-24: Reference](/develop/parachains/maintenance/) -The local provider does not offer any additional features. +
-## Configure Zombienet -Effective network configuration is crucial for deploying and managing blockchain systems. Zombienet simplifies this process by offering versatile configuration options in both JSON and TOML formats. Whether setting up a simple test network or a complex multi-node system, Zombienet's tools provide the flexibility to customize every aspect of your network's setup. +--- -The following sections will explore the structure and usage of Zombienet configuration files, explain key settings for network customization, and walk through CLI commands and flags to optimize your development workflow. +Page Title: Get Started -### Configuration Files +- Source (raw): https://raw.githubusercontent.com/polkadot-developers/polkadot-docs/master/.ai/pages/parachains-testing-fork-a-parachain.md +- Canonical (HTML): https://docs.polkadot.com/parachains/testing/fork-a-parachain/ +- Summary: Simplify Polkadot SDK development with Chopsticks. Learn essential features, how to install Chopsticks, and how to configure local blockchain forks. -The network configuration file can be either JSON or TOML format. The Zombienet repository also provides a collection of [example configuration files](https://github.com/paritytech/zombienet/tree/main/examples){target=\_blank} that can be used as a reference. +# Get Started -Each section may include provider-specific keys that aren't recognized by other providers. For example, if you use the local provider, any references to images for nodes will be disregarded. +## Introduction -### CLI Usage +[Chopsticks](https://github.com/AcalaNetwork/chopsticks/){target=\_blank}, developed by the [Acala Foundation](https://github.com/AcalaNetwork){target=\_blank}, is a versatile tool tailored for developers working on Polkadot SDK-based blockchains. With Chopsticks, you can fork live chains locally, replay blocks to analyze extrinsics, and simulate complex scenarios like XCM interactions all without deploying to a live network. -Zombienet provides a CLI that allows interaction with the tool. The CLI can receive commands and flags to perform different kinds of operations. These operations use the following syntax: +This guide walks you through installing Chopsticks and provides information on configuring a local blockchain fork. By streamlining testing and experimentation, Chopsticks empowers developers to innovate and accelerate their blockchain projects within the Polkadot ecosystem. -```bash -zombienet -``` +For additional support and information, please reach out through [GitHub Issues](https://github.com/AcalaNetwork/chopsticks/issues){target=_blank}. -The following sections will guide you through the primary usage of the Zombienet CLI and the available commands and flags. +!!! warning + Chopsticks uses [Smoldot](https://github.com/smol-dot/smoldot){target=_blank} light client, which only supports the native Polkadot SDK API. Consequently, a Chopsticks-based fork doesn't support Ethereum JSON-RPC calls, meaning you cannot use it to fork your chain and connect Metamask. -#### CLI Commands +## Prerequisites -- **`spawn `**: Spawn the network defined in the [configuration file](#configuration-files). -- **`test `**: Run tests on the spawned network using the assertions and tests defined in the [test file](/develop/toolkit/parachains/spawn-chains/zombienet/write-tests/#the-test-file){target=\_blank}. -- **`setup `**: Set up the Zombienet development environment to download and use the `polkadot` or `polkadot-parachain` executable. -- **`convert `**: Transforms a [polkadot-launch](https://github.com/paritytech/polkadot-launch){target=\_blank} configuration file with a `.js` or `.json` extension into a Zombienet configuration file. -- **`version`**: Prints Zombienet version. -- **`help`**: Prints help information. +Before you begin, ensure you have the following installed: -#### CLI Flags +- [Node.js](https://nodejs.org/en/){target=\_blank}. +- A package manager such as [npm](https://www.npmjs.com/){target=\_blank}, which should be installed with Node.js by default, or [Yarn](https://yarnpkg.com/){target=\_blank}. -You can use the following flags to customize the behavior of the CLI: +## Install Chopsticks -- **`-p`, `--provider`**: Override the [provider](#providers) to use. -- **`-d`, `--dir`**: Specify a directory path for placing the network files instead of using the default temporary path. -- **`-f`, `--force`**: Force override all prompt commands. -- **`-l`, `--logType`**: Type of logging on the console. Defaults to `table`. -- **`-m`, `--monitor`**: Start as monitor and don't auto clean up network. -- **`-c`, `--spawn-concurrency`**: Number of concurrent spawning processes to launch. Defaults to `1`. -- **`-h`, `--help`**: Display help for command. +You can install Chopsticks globally or locally in your project. Choose the option that best fits your development workflow. This documentation explains the features of Chopsticks version `1.2.2`. Make sure you're using the correct version to match these instructions. -### Settings +### Global Installation -Through the keyword `settings`, it's possible to define the general settings for the network. The available keys are: +To install Chopsticks globally, allowing you to use it across multiple projects, run: -- **`global_volumes?`** ++"GlobalVolume[]"++: A list of global volumes to use. +```bash +npm i -g @acala-network/chopsticks@1.2.2 +``` - ??? child "`GlobalVolume` interface definition" - ```js - export interface GlobalVolume { - name: string; - fs_type: string; - mount_path: string; - } - ``` +Now, you should be able to run the `chopsticks` command from your terminal. -- **`bootnode`** ++"boolean"++: Add bootnode to network. Defaults to `true`. -- **`bootnode_domain?`** ++"string"++: Domain to use for bootnode. -- **`timeout`** ++"number"++: Global timeout to use for spawning the whole network. -- **`node_spawn_timeout?`** ++"number"++: Timeout to spawn pod/process. -- **`grafana?`** ++"boolean"++: Deploy an instance of Grafana. -- **`prometheus?`** ++"boolean"++: Deploy an instance of Prometheus. -- **`telemetry?`** ++"boolean"++: Enable telemetry for the network. -- **`jaeger_agent?`** ++"string"++: The Jaeger agent endpoint passed to the nodes. Only available on Kubernetes. -- **`tracing_collator_url?`** ++"string"++: The URL of the tracing collator used to query by the tracing assertion. Should be tempo query compatible. -- **`tracing_collator_service_name?`** ++"string"++: Service name for tempo query frontend. Only available on Kubernetes. Defaults to `tempo-tempo-distributed-query-frontend`. -- **`tracing_collator_service_namespace?`** ++"string"++: Namespace where tempo is running. Only available on Kubernetes. Defaults to `tempo`. -- **`tracing_collator_service_port?`** ++"number"++: Port of the query instance of tempo. Only available on Kubernetes. Defaults to `3100`. -- **`enable_tracing?`** ++"boolean"++: Enable the tracing system. Only available on Kubernetes. Defaults to `true`. -- **`provider`** ++"string"++: Provider to use. Default is `kubernetes`". -- **`polkadot_introspector?`** ++"boolean"++: Deploy an instance of polkadot-introspector. Only available on Podman and Kubernetes. Defaults to `false`. -- **`backchannel?`** ++"boolean"++: Deploy an instance of backchannel server. Only available on Kubernetes. Defaults to `false`. -- **`image_pull_policy?`** ++"string"++: Image pull policy to use in the network. Possible values are `Always`, `IfNotPresent`, and `Never`. -- **`local_ip?`** ++"string"++: IP used for exposing local services (rpc/metrics/monitors). Defaults to `"127.0.0.1"`. -- **`global_delay_network_global_settings?`** ++"number"++: Delay in seconds to apply to the network. -- **`node_verifier?`** ++"string"++: Specify how to verify node readiness or deactivate by using `None`. Possible values are `None` and `Metric`. Defaults to `Metric`. +### Local Installation -For example, the following configuration file defines a minimal example for the settings: +To use Chopsticks in a specific project, first create a new directory and initialize a Node.js project: -=== "TOML" +```bash +mkdir my-chopsticks-project +cd my-chopsticks-project +npm init -y +``` - ```toml title="base-example.toml" - [settings] - timeout = 1000 - bootnode = false - provider = "kubernetes" - backchannel = false - # ... +Then, install Chopsticks as a local dependency: - ``` +```bash +npm i @acala-network/chopsticks@1.2.2 +``` -=== "JSON" +Finally, you can run Chopsticks using the `npx` command. To see all available options and commands, run it with the `--help` flag: - ```json title="base-example.json" - { - "settings": { - "timeout": 1000, - "bootnode": false, - "provider": "kubernetes", - "backchannel": false, - "...": {} - }, - "...": {} - } +```bash +npx @acala-network/chopsticks --help +``` - ``` +## Configure Chopsticks -### Relay Chain Configuration +To run Chopsticks, you need to configure some parameters. This can be set either through using a configuration file or the command line interface (CLI). The parameters that can be configured are as follows: -You can use the `relaychain` keyword to define further parameters for the relay chain at start-up. The available keys are: +- **`genesis`**: The link to a parachain's raw genesis file to build the fork from, instead of an endpoint. +- **`timestamp`**: Timestamp of the block to fork from. +- **`endpoint`**: The endpoint of the parachain to fork. +- **`block`**: Use to specify at which block hash or number to replay the fork. +- **`wasm-override`**: Path of the Wasm to use as the parachain runtime, instead of an endpoint's runtime. +- **`db`**: Path to the name of the file that stores or will store the parachain's database. +- **`config`**: Path or URL of the config file. +- **`port`**: The port to expose an endpoint on. +- **`build-block-mode`**: How blocks should be built in the fork: batch, manual, instant. +- **`import-storage`**: A pre-defined JSON/YAML storage path to override in the parachain's storage. +- **`allow-unresolved-imports`**: Whether to allow Wasm unresolved imports when using a Wasm to build the parachain. +- **`html`**: Include to generate storage diff preview between blocks. +- **`mock-signature-host`**: Mock signature host so that any signature starts with `0xdeadbeef` and filled by `0xcd` is considered valid. -- **`default_command?`** ++"string"++: The default command to run. Defaults to `polkadot`. -- **`default_image?`** ++"string"++: The default Docker image to use. -- **`default_resources?`** ++"Resources"++: Represents the resource limits/reservations the nodes need by default. Only available on Kubernetes. +### Configuration File - ??? child "`Resources` interface definition" - ```js - export interface Resources { - resources: { - requests?: { - memory?: string; - cpu?: string; - }; - limits?: { - memory?: string; - cpu?: string; - }; - }; - } - ``` +The Chopsticks source repository includes a collection of [YAML](https://yaml.org/){target=\_blank} files that can be used to set up various Polkadot SDK chains locally. You can download these configuration files from the [repository's `configs` folder](https://github.com/AcalaNetwork/chopsticks/tree/master/configs){target=\_blank}. -- **`default_db_snapshot?`** ++"string"++: The default database snapshot to use. -- **`default_prometheus_prefix`** ++"string"++: A parameter for customizing the metric's prefix. Defaults to `substrate`. -- **`default_substrate_cli_args_version?`** ++"SubstrateCliArgsVersion"++: Set the Substrate CLI arguments version. +An example of a configuration file for Polkadot is as follows: - ??? child "`SubstrateCliArgsVersion` enum definition" - ```js - export enum SubstrateCliArgsVersion { - V0 = 0, - V1 = 1, - V2 = 2, - V3 = 3, - } - ``` +{% raw %} +```yaml +endpoint: + - wss://rpc.ibp.network/polkadot + - wss://polkadot-rpc.dwellir.com +mock-signature-host: true +block: ${env.POLKADOT_BLOCK_NUMBER} +db: ./db.sqlite +runtime-log-level: 5 -- **`default_keystore_key_types?`** ++"string[]"++: Defines which keystore keys should be created. -- **`chain`** ++"string"++: The chain name. -- **`chain_spec_path?`** ++"string"++: Path to the chain spec file. Should be the plain version to allow customizations. -- **`chain_spec_command?`** ++"string"++: Command to generate the chain spec. It can't be used in combination with `chain_spec_path`. -- **`default_args?`** ++"string[]"++: An array of arguments to use as default to pass to the command. -- **`default_overrides?`** ++"Override[]"++: An array of overrides to upload to the node. +import-storage: + System: + Account: + - - - 5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY + - providers: 1 + data: + free: '10000000000000000000' + ParasDisputes: + $removePrefix: ['disputes'] # those can makes block building super slow - ??? child "`Override` interface definition" - ```js - export interface Override { - local_path: string; - remote_name: string; - } - ``` +``` +{% endraw %} -- **`random_nominators_count?`** ++"number"++: If set and the stacking pallet is enabled, Zombienet will generate the input quantity of nominators and inject them into the genesis. -- **`max_nominations`** ++"number"++: The max number of nominations allowed by a nominator. Should match the value set in the runtime. Defaults to `24`. -- **`nodes?`** ++"Node[]"++: An array of nodes to spawn. It is further defined in the [Node Configuration](#node-configuration) section. -- **`node_groups?`** ++"NodeGroup[]"++: An array of node groups to spawn. It is further defined in the [Node Group Configuration](#node-group-configuration) section. -- **`total_node_in_group?`** ++"number"++: The total number of nodes in the group. Defaults to `1`. -- **`genesis`** ++"JSON"++: The genesis configuration. -- **`default_delay_network_settings?`** ++"DelayNetworkSettings"++: Sets the expected configuration to delay the network. +The configuration file allows you to modify the storage of the forked network by rewriting the pallet, state component and value that you want to change. For example, Polkadot's file rewrites Alice's `system.Account` storage so that the free balance is set to `10000000000000000000`. - ??? child "`DelayNetworkSettings` interface definition" - ```js - export interface DelayNetworkSettings { - latency: string; - correlation?: string; // should be parsable as float by k8s - jitter?: string; - } - ``` +### CLI Flags -#### Node Configuration +Alternatively, all settings (except for genesis and timestamp) can be configured via command-line flags, providing a comprehensive method to set up the environment. -One specific key capable of receiving more subkeys is the `nodes` key. This key is used to define further parameters for the nodes. The available keys: +## WebSocket Commands -- **`name`** ++"string"++: Name of the node. Any whitespace will be replaced with a dash (for example, `new alice` will be converted to `new-alice`). -- **`image?`** ++"string"++: Override default Docker image to use for this node. -- **`command?`** ++"string"++: Override default command to run. -- **`command_with_args?`** ++"string"++: Override default command and arguments. -- **`args?`** ++"string[]"++: Arguments to be passed to the command. -- **`env?`** ++"envVars[]"++: Environment variables to set in the container. +Chopstick's internal WebSocket server has special endpoints that allow the manipulation of the local Polkadot SDK chain. - ??? child "`envVars` interface definition" - ```js - export interface EnvVars { - name: string; - value: string; - } - ``` +These are the methods that can be invoked and their parameters: -- **`prometheus_prefix?`** ++"string"++: Customizes the metric's prefix for the specific node. Defaults to `substrate`. -- **`db_snapshot?`** ++"string"++: Database snapshot to use. -- **`substrate_cli_args_version?`** ++"SubstrateCliArgsVersion"++: Set the Substrate CLI arguments version directly to skip binary evaluation overhead. +- **dev_newBlock** (newBlockParams): Generates one or more new blocks. - ??? child "`SubstrateCliArgsVersion` enum definition" - ```js - export enum SubstrateCliArgsVersion { - V0 = 0, - V1 = 1, - V2 = 2, - V3 = 3, - } - ``` + === "Parameters" -- **`resources?`** ++"Resources"++: Represent the resources limits/reservations needed by the node. + - **`newBlockParams` ++"NewBlockParams"++**: The parameters to build the new block with. Where the `NewBlockParams` interface includes the following properties. - ??? child "`Resources` interface definition" - ```js - export interface Resources { - resources: { - requests?: { - memory?: string; - cpu?: string; - }; - limits?: { - memory?: string; - cpu?: string; - }; - }; - } - ``` + - **`count` ++"number"++**: The number of blocks to build. + - **`dmp` ++"{ msg: string, sentAt: number }[]"++**: The downward messages to include in the block. + - **`hrmp` ++"Record"++**: The horizontal messages to include in the block. + - **`to` ++"number"++**: The block number to build to. + - **`transactions` ++"string[]"++**: The transactions to include in the block. + - **`ump` ++"Record"++**: The upward messages to include in the block. + - **`unsafeBlockHeight` ++"number"++**: Build block using a specific block height (unsafe). -- **`keystore_key_types?`** ++"string[]"++: Defines which keystore keys should be created. -- **`validator`** ++"boolean"++: Pass the `--validator` flag to the command. Defaults to `true`. -- **`invulnerable`** ++"boolean"++: If true, add the node to invulnerables in the chain spec. Defaults to `false`. -- **`balance`** ++"number"++: Balance to set in balances for node's account. Defaults to `2000000000000`. -- **`bootnodes?`** ++"string[]"++: Array of bootnodes to use. -- **`add_to_bootnodes?`** ++"boolean"++: Add this node to the bootnode list. Defaults to `false`. -- **`ws_port?`** ++"number"++: WS port to use. -- **`rpc_port?`** ++"number"++: RPC port to use. -- **`prometheus_port?`** ++"number"++: Prometheus port to use. -- **`p2p_cert_hash?`** ++"string"++: Libp2p certhash to use with webRTC transport. -- **`delay_network_settings?`** ++"DelayNetworkSettings"++: Sets the expected configuration to delay the network. + === "Example" - ??? child "`DelayNetworkSettings` interface definition" ```js - export interface DelayNetworkSettings { - latency: string; - correlation?: string; // should be parsable as float by k8s - jitter?: string; + import { ApiPromise, WsProvider } from '@polkadot/api'; + + async function main() { + const wsProvider = new WsProvider('ws://localhost:8000'); + const api = await ApiPromise.create({ provider: wsProvider }); + await api.isReady; + await api.rpc('dev_newBlock', { count: 1 }); } + + main(); + ``` -The following configuration file defines a minimal example for the relay chain, including the `nodes` key: +- **dev_setBlockBuildMode** (buildBlockMode): Sets block build mode. -=== "TOML" + === "Parameter" + + - **`buildBlockMode` ++"BuildBlockMode"++**: The build mode. Can be any of the following modes: - ```toml title="relaychain-example-nodes.toml" - [relaychain] - default_command = "polkadot" - default_image = "polkadot-debug:master" - chain = "rococo-local" - chain_spec_path = "INSERT_PATH_TO_CHAIN_SPEC" - default_args = ["--chain", "rococo-local"] + ```ts + export enum BuildBlockMode { + Batch = 'Batch', /** One block per batch (default) */ + Instant = 'Instant', /** One block per transaction */ + Manual = 'Manual', /** Only build when triggered */ + } + ``` + + === "Example" - [[relaychain.nodes]] - name = "alice" - validator = true - balance = 1000000000000 + ```js + import { ApiPromise, WsProvider } from '@polkadot/api'; - [[relaychain.nodes]] - name = "bob" - validator = true - balance = 1000000000000 - # ... + async function main() { + const wsProvider = new WsProvider('ws://localhost:8000'); + const api = await ApiPromise.create({ provider: wsProvider }); + await api.isReady; + await api.rpc('dev_setBlockBuildMode', 'Instant'); + } - ``` + main(); -=== "JSON" + ``` - ```json title="relaychain-example-nodes.json" - { - "relaychain": { - "default_command": "polkadot", - "default_image": "polkadot-debug:master", - "chain": "rococo-local", - "chain_spec_path": "INSERT_PATH_TO_CHAIN-SPEC.JSON", - "default_args": ["--chain", "rococo-local"], - "nodes": [ - { - "name": "alice", - "validator": true, - "balance": 1000000000000 - }, - { - "name": "bob", - "validator": true, - "balance": 1000000000000 - } - ] - } - } +- **dev_setHead** (hashOrNumber): Sets the head of the blockchain to a specific hash or number. - ``` + === "Parameter" -#### Node Group Configuration + - **`hashOrNumber` ++"string | number"++**: The block hash or number to set as head. -The `node_groups` key defines further parameters for the node groups. The available keys are: + === "Example" -- **`name`** ++"string"++: Name of the node. Any whitespace will be replaced with a dash (for example, `new alice` will be converted to `new-alice`). -- **`image?`** ++"string"++: Override default Docker image to use for this node. -- **`command?`** ++"string"++: Override default command to run. -- **`args?`** ++"string[]"++: Arguments to be passed to the command. -- **`env?`** ++"envVars[]"++: Environment variables to set in the container. - - ??? child "`envVars` interface definition" ```js - export interface EnvVars { - name: string; - value: string; + import { ApiPromise, WsProvider } from '@polkadot/api'; + + async function main() { + const wsProvider = new WsProvider('ws://localhost:8000'); + const api = await ApiPromise.create({ provider: wsProvider }); + await api.isReady; + await api.rpc('dev_setHead', 500); } - ``` -- **`overrides?`** ++"Override[]"++: Array of overrides definitions. + main(); - ??? child "`Override` interface definition" - ```js - export interface Override { - local_path: string; - remote_name: string; - } ``` -- **`prometheus_prefix?`** ++"string"++: Customizes the metric's prefix for the specific node. Defaults to `substrate`. -- **`db_snapshot?`** ++"string"++: Database snapshot to use. -- **`substrate_cli_args_version?`** ++"SubstrateCliArgsVersion"++: Set the Substrate CLI arguments version directly to skip binary evaluation overhead. +- **dev_setRuntimeLogLevel** (runtimeLogLevel): Sets the runtime log level. + + === "Parameter" + + - **`runtimeLogLevel` ++"number"++**: The runtime log level to set. + + === "Example" - ??? child "`SubstrateCliArgsVersion` enum definition" ```js - export enum SubstrateCliArgsVersion { - V0 = 0, - V1 = 1, - V2 = 2, - V3 = 3, + import { ApiPromise, WsProvider } from '@polkadot/api'; + + async function main() { + const wsProvider = new WsProvider('ws://localhost:8000'); + const api = await ApiPromise.create({ provider: wsProvider }); + await api.isReady; + await api.rpc('dev_setRuntimeLogLevel', 1); } + + main(); + ``` -- **`resources?`** ++"Resources"++: Represent the resources limits/reservations needed by the node. +- **dev_setStorage** (values, blockHash): Creates or overwrites the value of any storage. + + === "Parameters" + + - **`values` ++"object"++**: JSON object resembling the path to a storage value. + - **`blockHash` ++"string"++**: The block hash to set the storage value. + + === "Example" - ??? child "`Resources` interface definition" ```js - export interface Resources { - resources: { - requests?: { - memory?: string; - cpu?: string; - }; - limits?: { - memory?: string; - cpu?: string; - }; + import { ApiPromise, WsProvider } from '@polkadot/api'; + + import { Keyring } from '@polkadot/keyring'; + async function main() { + const wsProvider = new WsProvider('ws://localhost:8000'); + const api = await ApiPromise.create({ provider: wsProvider }); + await api.isReady; + const keyring = new Keyring({ type: 'ed25519' }); + const bob = keyring.addFromUri('//Bob'); + const storage = { + System: { + Account: [[[bob.address], { data: { free: 100000 }, nonce: 1 }]], + }, }; + await api.rpc('dev_setStorage', storage); } - ``` -- **`keystore_key_types?`** ++"string[]"++: Defines which keystore keys should be created. -- **`count`** ++"number | string"++: Number of nodes to launch for this group. -- **`delay_network_settings?`** ++"DelayNetworkSettings"++: Sets the expected configuration to delay the network. + main(); - ??? child "`DelayNetworkSettings` interface definition" - ```js - export interface DelayNetworkSettings { - latency: string; - correlation?: string; // should be parsable as float by k8s - jitter?: string; - } ``` -The following configuration file defines a minimal example for the relay chain, including the `node_groups` key: +- **dev_timeTravel** (date): Sets the timestamp of the block to a specific date". -=== "TOML" + === "Parameter" - ```toml title="relaychain-example-node-groups.toml" - [relaychain] - default_command = "polkadot" - default_image = "polkadot-debug:master" - chain = "rococo-local" - chain_spec_path = "INSERT_PATH_TO_CHAIN_SPEC" - default_args = ["--chain", "rococo-local"] + - **`date` ++"string"++**: Timestamp or date string to set. All future blocks will be sequentially created after this point in time. - [[relaychain.node_groups]] - name = "group-1" - count = 2 - image = "polkadot-debug:master" - command = "polkadot" - args = ["--chain", "rococo-local"] - # ... + === "Example" - ``` + ```js + import { ApiPromise, WsProvider } from '@polkadot/api'; -=== "JSON" + async function main() { + const wsProvider = new WsProvider('ws://localhost:8000'); + const api = await ApiPromise.create({ provider: wsProvider }); + await api.isReady; + await api.rpc('dev_timeTravel', '2030-08-15T00:00:00'); + } - ```json title="relaychain-example-node-groups.json" - { - "relaychain": { - "default_command": "polkadot", - "default_image": "polkadot-debug:master", - "chain": "rococo-local", - "chain_spec_path": "INSERT_PATH_TO_CHAIN-SPEC.JSON", - "default_args": ["--chain", "rococo-local"], - "node_groups": [ - { - "name": "group-1", - "count": 2, - "image": "polkadot-debug:master", - "command": "polkadot", - "args": ["--chain", "rococo-local"] - } - ], - "...": {} - }, - "...": {} - } + main(); - ``` + ``` -### Parachain Configuration +## Where to Go Next -The `parachain` keyword defines further parameters for the parachain. The available keys are: +
-- **`id`** ++"number"++: The id to assign to this parachain. Must be unique. -- **`chain?`** ++"string"++: The chain name. -- **`force_decorator?`** ++"string"++: Force the use of a specific decorator. -- **`genesis?`** ++"JSON"++: The genesis configuration. -- **`balance?`** ++"number"++: Balance to set in balances for parachain's account. -- **`delay_network_settings?`** ++"DelayNetworkSettings"++: Sets the expected configuration to delay the network. +- Tutorial __Fork a Chain with Chopsticks__ - ??? child "`DelayNetworkSettings` interface definition" - ```js - export interface DelayNetworkSettings { - latency: string; - correlation?: string; // should be parsable as float by k8s - jitter?: string; - } - ``` + --- -- **`add_to_genesis?`** ++"boolean"++: Flag to add parachain to genesis or register in runtime. Defaults to `true`. -- **`register_para?`** ++"boolean"++: Flag to specify whether the para should be registered. The `add_to_genesis` flag must be set to false for this flag to have any effect. Defaults to `true`. -- **`onboard_as_parachain?`** ++"boolean"++: Flag to specify whether the para should be onboarded as a parachain, rather than remaining a parathread. Defaults to `true`. -- **`genesis_wasm_path?`** ++"string"++: Path to the Wasm file to use. -- **`genesis_wasm_generator?`** ++"string"++: Command to generate the Wasm file. -- **`genesis_state_path?`** ++"string"++: Path to the state file to use. -- **`genesis_state_generator?`** ++"string"++: Command to generate the state file. -- **`chain_spec_path?`** ++"string"++: Path to the chain spec file. -- **`chain_spec_command?`** ++"string"++: Command to generate the chain spec. -- **`cumulus_based?`** ++"boolean"++: Flag to use cumulus command generation. Defaults to `true`. -- **`bootnodes?`** ++"string[]"++: Array of bootnodes to use. -- **`prometheus_prefix?`** ++"string"++: Parameter for customizing the metric's prefix for all parachain nodes/collators. Defaults to `substrate`. -- **`collator?`** ++"Collator"++: Further defined in the [Collator Configuration](#collator-configuration) section. -- **`collator_groups?`** ++"CollatorGroup[]"++: An array of collator groups to spawn. It is further defined in the [Collator Groups Configuration](#collator-groups-configuration) section. - -For example, the following configuration file defines a minimal example for the parachain: + Visit this guide for step-by-step instructions for configuring and interacting with your forked chain. -=== "TOML" + [:octicons-arrow-right-24: Reference](/tutorials/polkadot-sdk/testing/fork-live-chains/) - ```toml title="parachain-example.toml" - [parachain] - id = 100 - add_to_genesis = true - cumulus_based = true - genesis_wasm_path = "INSERT_PATH_TO_WASM" - genesis_state_path = "INSERT_PATH_TO_STATE" - # ... +
- ``` -=== "JSON" +--- - ```json title="parachain-example.json" - { - "parachain": { - "id": 100, - "add_to_genesis": true, - "cumulus_based": true, - "genesis_wasm_path": "INSERT_PATH_TO_WASM", - "genesis_state_path": "INSERT_PATH_TO_STATE", - "...": {} - }, - "...": {} - } +Page Title: Get Started - ``` +- Source (raw): https://raw.githubusercontent.com/polkadot-developers/polkadot-docs/master/.ai/pages/parachains-testing-run-a-parachain-network.md +- Canonical (HTML): https://docs.polkadot.com/parachains/testing/run-a-parachain-network/ +- Summary: Quickly install and configure Zombienet to deploy and test Polkadot-based blockchain networks with this comprehensive getting-started guide. -#### Collator Configuration +# Get Started -One specific key capable of receiving more subkeys is the `collator` key. This key defines further parameters for the nodes. The available keys are: +## Introduction -- **`name`** ++"string"++: Name of the collator. Any whitespace will be replaced with a dash (for example, `new alice` will be converted to `new-alice`). -- **`image?`** ++"string"++: Image to use for the collator. -- **`command_with_args?`** ++"string"++: Overrides both command and arguments for the collator. -- **`validator`** ++"boolean"++: Pass the `--validator` flag to the command. Defaults to `true`. -- **`invulnerable`** ++"boolean"++: If true, add the collator to invulnerables in the chain spec. Defaults to `false`. -- **`balance`** ++"number"++: Balance to set in balances for collator's account. Defaults to `2000000000000`. -- **`bootnodes?`** ++"string[]"++: Array of bootnodes to use. -- **`add_to_bootnodes?`** ++"boolean"++: Add this collator to the bootnode list. Defaults to `false`. -- **`ws_port?`** ++"number"++: WS port to use. -- **`rpc_port?`** ++"number"++: RPC port to use. -- **`prometheus_port?`** ++"number"++: Prometheus port to use. -- **`p2p_port?`** ++"number"++: P2P port to use. -- **`p2p_cert_hash?`** ++"string"++: Libp2p certhash to use with webRTC transport. -- **`delay_network_settings?`** ++"DelayNetworkSettings"++: Sets the expected configuration to delay the network. +Zombienet is a robust testing framework designed for Polkadot SDK-based blockchain networks. It enables developers to efficiently deploy and test ephemeral blockchain environments on platforms like Kubernetes, Podman, and native setups. With its simple and versatile CLI, Zombienet provides an all-in-one solution for spawning networks, running tests, and validating performance. - ??? child "`DelayNetworkSettings` interface definition" - ```js - export interface DelayNetworkSettings { - latency: string; - correlation?: string; // should be parsable as float by k8s - jitter?: string; - } - ``` +This guide will outline the different installation methods for Zombienet, provide step-by-step instructions for setting up on various platforms, and highlight essential provider-specific features and requirements. + +By following this guide, Zombienet will be up and running quickly, ready to streamline your blockchain testing and development workflows. + +## Install Zombienet -- **`command?`** ++"string"++: Override default command to run. -- **`args?`** ++"string[]"++: Arguments to be passed to the command. -- **`env?`** ++"envVars[]"++: Environment variables to set in the container. +Zombienet releases are available on the [Zombienet repository](https://github.com/paritytech/zombienet){target=\_blank}. - ??? child "`envVars` interface definition" - ```js - export interface EnvVars { - name: string; - value: string; - } - ``` +Multiple options are available for installing Zombienet, depending on the user's preferences and the environment where it will be used. The following section will guide you through the installation process for each option. -- **`overrides?`** ++"Override[]"++: Array of overrides definitions. +=== "Use the executable" - ??? child "`Override` interface definition" - ```js - export interface Override { - local_path: string; - remote_name: string; - } - ``` + Install Zombienet using executables by visiting the [latest release](https://github.com/paritytech/zombienet/releases){target=\_blank} page and selecting the appropriate asset for your operating system. You can download the executable and move it to a directory in your PATH. -- **`prometheus_prefix?`** ++"string"++: Customizes the metric's prefix for the specific node. Defaults to `substrate`. -- **`db_snapshot?`** ++"string"++: Database snapshot to use. -- **`substrate_cli_args_version?`** ++"SubstrateCliArgsVersion"++: Set the Substrate CLI arguments version directly to skip binary evaluation overhead. + Each release includes executables for Linux and macOS. Executables are generated using [pkg](https://github.com/vercel/pkg){target=\_blank}, which allows the Zombienet CLI to operate without requiring Node.js to be installed. - ??? child "`SubstrateCliArgsVersion` enum definition" - ```js - export enum SubstrateCliArgsVersion { - V0 = 0, - V1 = 1, - V2 = 2, - V3 = 3, - } - ``` + Then, ensure the downloaded file is executable: -- **`resources?`** ++"Resources"++: Represent the resources limits/reservations needed by the node. + ```bash + chmod +x zombienet-macos-arm64 + ``` - ??? child "`Resources` interface definition" - ```js - export interface Resources { - resources: { - requests?: { - memory?: string; - cpu?: string; - }; - limits?: { - memory?: string; - cpu?: string; - }; - }; - } - ``` + Finally, you can run the following command to check if the installation was successful. If so, it will display the version of the installed Zombienet: -- **`keystore_key_types?`** ++"string[]"++: Defines which keystore keys should be created. + ```bash + ./zombienet-macos-arm64 version + ``` -The configuration file below defines a minimal example for the collator: + If you want to add the `zombienet` executable to your PATH, you can move it to a directory in your PATH, such as `/usr/local/bin`: -=== "TOML" + ```bash + mv zombienet-macos-arm64 /usr/local/bin/zombienet + ``` - ```toml title="collator-example.toml" - [parachain] - id = 100 - add_to_genesis = true - cumulus_based = true - genesis_wasm_path = "INSERT_PATH_TO_WASM" - genesis_state_path = "INSERT_PATH_TO_STATE" + Now you can refer to the `zombienet` executable directly. - [[parachain.collators]] - name = "alice" - image = "polkadot-parachain" - command = "polkadot-parachain" - # ... + ```bash + zombienet version + ``` + +=== "Use Nix" + + For Nix users, the Zombienet repository provides a [`flake.nix`](https://github.com/paritytech/zombienet/blob/main/flake.nix){target=\_blank} file to install Zombienet making it easy to incorporate Zombienet into Nix-based projects. + + To install Zombienet utilizing Nix, users can run the following command, triggering the fetching of the flake and subsequently installing the Zombienet package: + ```bash + nix run github:paritytech/zombienet/INSERT_ZOMBIENET_VERSION -- \ + spawn INSERT_ZOMBIENET_CONFIG_FILE_NAME.toml ``` -=== "JSON" + Replace the `INSERT_ZOMBIENET_VERSION` with the desired version of Zombienet and the `INSERT_ZOMBIENET_CONFIG_FILE_NAME` with the name of the configuration file you want to use. - ```json title="collator-example.json" - { - "parachain": { - "id": 100, - "add_to_genesis": true, - "cumulus_based": true, - "genesis_wasm_path": "INSERT_PATH_TO_WASM", - "genesis_state_path": "INSERT_PATH_TO_STATE", - "collators": [ - { - "name": "alice", - "image": "polkadot-parachain", - "command": "polkadot-parachain", - "...": {} - } - ] - }, - "...": {} - } + To run the command above, you need to have [Flakes](https://nixos.wiki/wiki/Flakes#Enable_flakes){target=\_blank} enabled. + Alternatively, you can also include the Zombienet binary in the PATH for the current shell using the following command: + + ```bash + nix shell github:paritytech/zombienet/INSERT_ZOMBIENET_VERSION ``` -#### Collator Groups Configuration +=== "Use Docker" -The `collator_groups` key defines further parameters for the collator groups. The available keys are: + Zombienet can also be run using Docker. The Zombienet repository provides a Docker image that can be used to run the Zombienet CLI. To run Zombienet using Docker, you can use the following command: -- **`name`** ++"string"++: Name of the node. Any whitespace will be replaced with a dash (for example, `new alice` will be converted to `new-alice`). -- **`image?`** ++"string"++: Override default Docker image to use for this node. -- **`command?`** ++"string"++: Override default command to run. -- **`args?`** ++"string[]"++: Arguments to be passed to the command. -- **`env?`** ++"envVars[]"++: Environment variables to set in the container. + ```bash + docker run -it --rm \ + -v $(pwd):/home/nonroot/zombie-net/host-current-files \ + paritytech/zombienet + ``` - ??? child "`envVars` interface definition" - ```js - export interface EnvVars { - name: string; - value: string; - } - ``` + The command above will run the Zombienet CLI inside a Docker container and mount the current directory to the `/home/nonroot/zombie-net/host-current-files` directory. This allows Zombienet to access the configuration file and other files in the current directory. If you want to mount a different directory, replace `$(pwd)` with the desired directory path. -- **`overrides?`** ++"Override[]"++: Array of overrides definitions. + Inside the Docker container, you can run the Zombienet CLI commands. First, you need to set up Zombienet to download the necessary binaries: - ??? child "`Override` interface definition" - ```js - export interface Override { - local_path: string; - remote_name: string; - } - ``` + ```bash + npm run zombie -- setup polkadot polkadot-parachain + ``` -- **`prometheus_prefix?`** ++"string"++: Customizes the metric's prefix for the specific node. Defaults to `substrate`. -- **`db_snapshot?`** ++"string"++: Database snapshot to use. -- **`substrate_cli_args_version?`** ++"SubstrateCliArgsVersion"++: Set the Substrate CLI arguments version directly to skip binary evaluation overhead. + After that, you need to add those binaries to the PATH: - ??? child "`SubstrateCliArgsVersion` enum definition" - ```js - export enum SubstrateCliArgsVersion { - V0 = 0, - V1 = 1, - V2 = 2, - V3 = 3, - } - ``` + ```bash + export PATH=/home/nonroot/zombie-net:$PATH + ``` -- **`resources?`** ++"Resources"++: Represent the resources limits/reservations needed by the node. + Finally, you can run the Zombienet CLI commands. For example, to spawn a network using a specific configuration file, you can run the following command: - ??? child "`Resources` interface definition" - ```js - export interface Resources { - resources: { - requests?: { - memory?: string; - cpu?: string; - }; - limits?: { - memory?: string; - cpu?: string; - }; - }; - } - ``` + ```bash + npm run zombie -- -p native spawn host-current-files/minimal.toml + ``` -- **`keystore_key_types?`** ++"string[]"++: Defines which keystore keys should be created. -- **`count`** ++"number | string"++: Number of nodes to launch for this group. -- **`delay_network_settings?`** ++"DelayNetworkSettings"++: Sets the expected configuration to delay the network. + The command above mounts the current directory to the `/workspace` directory inside the Docker container, allowing Zombienet to access the configuration file and other files in the current directory. If you want to mount a different directory, replace `$(pwd)` with the desired directory path. - ??? child "`DelayNetworkSettings` interface definition" - ```js - export interface DelayNetworkSettings { - latency: string; - correlation?: string; // should be parsable as float by k8s - jitter?: string; - } - ``` +## Providers -For instance, the configuration file below defines a minimal example for the collator groups: +Zombienet supports different backend providers for running the nodes. At this moment, [Kubernetes](https://kubernetes.io/){target=\_blank}, [Podman](https://podman.io/){target=\_blank}, and local providers are supported, which can be declared as `kubernetes`, `podman`, or `native`, respectively. -=== "TOML" +To use a particular provider, you can specify it in the network file or use the `--provider` flag in the CLI: - ```toml title="collator-groups-example.toml" - [parachain] - id = 100 - add_to_genesis = true - cumulus_based = true - genesis_wasm_path = "INSERT_PATH_TO_WASM" - genesis_state_path = "INSERT_PATH_TO_STATE" +```bash +zombienet spawn network.toml --provider INSERT_PROVIDER +``` - [[parachain.collator_groups]] - name = "group-1" - count = 2 - image = "polkadot-parachain" - command = "polkadot-parachain" - # ... +Alternatively, you can set the provider in the network file: - ``` +```toml +[settings] +provider = "INSERT_PROVIDER" +... +``` -=== "JSON" +It's important to note that each provider has specific requirements and associated features. The following sections cover each provider's requirements and added features. - ```json title="collator-groups-example.json" - { - "parachain": { - "id": 100, - "add_to_genesis": true, - "cumulus_based": true, - "genesis_wasm_path": "INSERT_PATH_TO_WASM", - "genesis_state_path": "INSERT_PATH_TO_STATE", - "collator_groups": [ - { - "name": "group-1", - "count": 2, - "image": "polkadot-parachain", - "command": "polkadot-parachain", - "...": {} - } - ] - }, - "...": {} - } +### Kubernetes + +Kubernetes is a portable, extensible, open-source platform for managing containerized workloads and services. Zombienet is designed to be compatible with a variety of Kubernetes clusters, including: + +- [Google Kubernetes Engine (GKE)](https://cloud.google.com/kubernetes-engine){target=\_blank} +- [Docker Desktop](https://docs.docker.com/desktop/features/kubernetes/){target=\_blank} +- [kind](https://kind.sigs.k8s.io/){target=\_blank} - ``` +#### Requirements + +To effectively interact with your cluster, you'll need to ensure that [`kubectl`](https://kubernetes.io/docs/reference/kubectl/){target=\_blank} is installed on your system. This Kubernetes command-line tool allows you to run commands against Kubernetes clusters. If you don't have `kubectl` installed, you can follow the instructions provided in the [Kubernetes documentation](https://kubernetes.io/docs/tasks/tools/#kubectl){target=\_blank}. -### XCM Configuration +To create resources such as namespaces, pods, and CronJobs within the target cluster, you must grant your user or service account the appropriate permissions. These permissions are essential for managing and deploying applications effectively within Kubernetes. -You can use the `hrmp_channels` keyword to define further parameters for the XCM channels at start-up. The available keys are: +#### Features + +If available, Zombienet uses the Prometheus operator to oversee monitoring and visibility. This configuration ensures that only essential networking-related pods are deployed. Using the Prometheus operator, Zombienet improves its ability to monitor and manage network activities within the Kubernetes cluster efficiently. -- **`hrmp_channels`** ++"HrmpChannelsConfig[]"++: Array of Horizontal Relay-routed Message Passing (HRMP) channel configurations. +### Podman - ??? child "`HrmpChannelsConfig` interface definition" - ```js - export interface HrmpChannelsConfig { - sender: number; - recipient: number; - max_capacity: number; - max_message_size: number; - } - ``` - Each of the `HrmpChannelsConfig` keys are defined as follows: +Podman is a daemonless container engine for developing, managing, and running Open Container Initiative (OCI) containers and container images on Linux-based systems. Zombienet supports Podman rootless as a provider on Linux machines. Although Podman has support for macOS through an internal virtual machine (VM), the Zombienet provider code requires Podman to run natively on Linux. - - **`sender` ++"number"++**: Parachain ID of the sender. - - **`recipient` ++"number"++**: Parachain ID of the recipient. - - **`max_capacity` ++"number"++**: Maximum capacity of the HRMP channel. - - **`max_message_size` ++"number"++**: Maximum message size allowed in the HRMP channel. +#### Requirements + +To use Podman as a provider, you need to have Podman installed on your system. You can install Podman by following the instructions provided on the [Podman website](https://podman.io/getting-started/installation){target=\_blank}. -## Where to Go Next +#### Features + +Using Podman, Zombienet deploys additional pods to enhance the monitoring and visibility of the active network. Specifically, pods for [Prometheus](https://prometheus.io/){target=\_blank}, [Tempo](https://grafana.com/docs/tempo/latest/operations/monitor/){target=\_blank}, and [Grafana](https://grafana.com/){target=\_blank} are included in the deployment. Grafana is configured with Prometheus and Tempo as data sources. -
+Upon launching Zombienet, access to these monitoring services is facilitated through specific URLs provided in the output: -- External __Zombienet Support__ +- **Prometheus**: `http://127.0.0.1:34123` +- **Tempo**: `http://127.0.0.1:34125` +- **Grafana**: `http://127.0.0.1:41461` - --- +It's important to note that Grafana is deployed with default administrator access. + +When network operations cease, either from halting a running spawn with the `Ctrl+C` command or test completion, Zombienet automatically removes all associated pods. - [Parity Technologies](https://www.parity.io/){target=\_blank} has designed and developed this framework, now maintained by the Zombienet team. +### Local Provider - For further support and information, refer to the following contact points: +The Zombienet local provider, also called native, enables you to run nodes as local processes in your environment. - [:octicons-arrow-right-24: Zombienet repository](https://github.com/paritytech/zombienet){target=\_blank} +#### Requirements + +You must have the necessary binaries for your network (such as `polkadot` and `polkadot-parachain`). These binaries should be available in your PATH, allowing Zombienet to spawn the nodes as local processes. - [:octicons-arrow-right-24: Element public channel](https://matrix.to/#/!FWyuEyNvIFygLnWNMh:parity.io?via=parity.io&via=matrix.org&via=web3.foundation){target=\_blank} +To install the necessary binaries, you can use the Zombienet CLI command: +```bash +zombienet setup polkadot polkadot-parachain +``` -- Tutorial __Spawn a Basic Chain with Zombienet__ +This command will download and prepare the necessary binaries for Zombienet's use. - --- +If you need to use a custom binary, ensure the binary is available in your PATH. You can also specify the binary path in the network configuration file. The following example uses the custom [OpenZeppelin template](https://github.com/OpenZeppelin/polkadot-runtime-templates){target=\_blank}: - Learn to spawn, connect to and monitor a basic blockchain network with Zombienet, using customizable configurations for streamlined development and debugging. +First, clone the OpenZeppelin template repository using the following command: - [:octicons-arrow-right-24: Reference](/tutorials/polkadot-sdk/testing/spawn-basic-chain/) +```bash +git clone https://github.com/OpenZeppelin/polkadot-runtime-templates \ +&& cd polkadot-runtime-templates/generic-template +``` -
+Next, run the command to build the custom binary: +```bash +cargo build --release +``` ---- +Finally, add the custom binary to your PATH as follows: -Page Title: Get Started with Parachain Development +```bash +export PATH=$PATH:INSERT_PATH_TO_RUNTIME_TEMPLATES/parachain-template-node/target/release +``` -- Source (raw): https://raw.githubusercontent.com/polkadot-developers/polkadot-docs/master/.ai/pages/parachains-get-started.md -- Canonical (HTML): https://docs.polkadot.com/parachains/get-started/ -- Summary: Practical examples and tutorials for building and deploying Polkadot parachains, covering everything from launch to customization and cross-chain messaging. +Alternatively, you can specify the binary path in the network configuration file. The local provider exclusively utilizes the command configuration for nodes, which supports both relative and absolute paths. You can employ the `default_command` configuration to specify the binary for spawning all nodes in the relay chain. -# Get Started +```toml +[relaychain] +chain = "rococo-local" +default_command = "./bin-v1.6.0/polkadot" -The following sections provide practical recipes for building parachains on Polkadot—each focused on specific development scenarios with step-by-step, hands-on examples. +[parachain] +id = 1000 -## Quick Start Guides + [parachain.collators] + name = "collator01" + command = "./target/release/parachain-template-node" +``` -Quick start guides help developers set up and interact with the Polkadot parachain ecosystem using various tools and frameworks. +#### Features -| Tutorial | Tools | Description | -| :--------------------------------------------------------------------------------------------: | :----------------------------: | :---------------------------------------------------------------------: | -| [Set Up the Parachain Template](/parachains/launch-a-parachain/set-up-the-parachain-template/) | Polkadot SDK | Learn how to set up and run the Polkadot SDK Parachain Template locally | -| [Launch a Local Parachain](/parachains/testing/run-a-parachain-network/) | Zombienet, Chopsticks | Set up a local development environment for testing | -| [Connect to Polkadot](/chain-interactions/query-on-chain-data/query-sdks/) | Polkadot.js, Substrate Connect | Connect your application to Polkadot networks | -| [Fork an Existing Parachain](/parachains/testing/fork-a-parachain/) | Chopsticks | Create a local fork of a live parachain for testing | +The local provider does not offer any additional features. -## Launch a Simple Parachain +## Configure Zombienet -Learn the fundamentals of launching and deploying a parachain to the Polkadot network. +Effective network configuration is crucial for deploying and managing blockchain systems. Zombienet simplifies this process by offering versatile configuration options in both JSON and TOML formats. Whether setting up a simple test network or a complex multi-node system, Zombienet's tools provide the flexibility to customize every aspect of your network's setup. -| Tutorial | Description | -| :--------------------------------------------------------------------------------------------: | :-----------------------------------------------------------------------: | -| [Set Up the Parachain Template](/parachains/launch-a-parachain/set-up-the-parachain-template/) | Polkadot SDK | -| [Deploy to Polkadot](/parachains/launch-a-parachain/deploy-to-polkadot/) | Step-by-step tutorial to deploying your parachain to Polkadot | -| [Obtain Coretime](/parachains/launch-a-parachain/obtain-coretime/) | Learn how to acquire blockspace using Polkadot's coretime model (RegionX) | +The following sections will explore the structure and usage of Zombienet configuration files, explain key settings for network customization, and walk through CLI commands and flags to optimize your development workflow. -## Customize Your Runtime +### Configuration Files -Build custom functionality for your parachain by composing and creating pallets. +The network configuration file can be either JSON or TOML format. The Zombienet repository also provides a collection of [example configuration files](https://github.com/paritytech/zombienet/tree/main/examples){target=\_blank} that can be used as a reference. -| Tutorial | Description | -| :-------------------------------------------------------------------------------------------------: | :---------------------------------------------------------------: | -| [Add Existing Pallets to the Runtime](/parachains/customize-runtime/add-existing-pallets/) | Integrate pre-built pallets from the FRAME ecosystem | -| [Add Multiple Instances of a Pallet](/parachains/customize-runtime/add-pallet-instances/) | Configure and use multiple instances of the same pallet | -| [Add Smart Contract Functionality](/parachains/customize-runtime/add-smart-contract-functionality/) | Enable smart contract capabilities using Contracts or EVM pallets | +Each section may include provider-specific keys that aren't recognized by other providers. For example, if you use the local provider, any references to images for nodes will be disregarded. -### Pallet Development +### CLI Usage -Deep dive into creating and managing custom pallets for your parachain. +Zombienet provides a CLI that allows interaction with the tool. The CLI can receive commands and flags to perform different kinds of operations. These operations use the following syntax: -| Tutorial | Description | -| :--------------------------------------------------------------------------------------------------------------: | :-------------------------------------------------------: | -| [Create a Custom Pallet](/parachains/customize-runtime/pallet-development/create-a-pallet/) | Build a pallet from scratch with custom logic | -| [Mock Your Runtime](/parachains/customize-runtime/pallet-development/mock-runtime/) | Set up a mock runtime environment for testing | -| [Pallet Unit Testing](/parachains/customize-runtime/pallet-development/pallet-testing/) | Write comprehensive tests for your pallet logic | -| [Add Your Custom Pallet to the Runtime](/parachains/customize-runtime/pallet-development/add-pallet-to-runtime/) | Integrate your custom pallet into your parachain runtime | -| [Benchmark the Custom Pallet](/parachains/customize-runtime/pallet-development/benchmark-pallet/) | Measure and optimize pallet performance with benchmarking | +```bash +zombienet +``` -## Testing +The following sections will guide you through the primary usage of the Zombienet CLI and the available commands and flags. -Test your parachain in various environments before production deployment. +#### CLI Commands -| Tutorial | Description | -| :---------------------------------------------------------------------: | :-----------------------------------------------------: | -| [Fork a Parachain](/parachains/testing/fork-a-parachain/) | Use Chopsticks to create a local fork for testing | -| [Run a Parachain Network](/parachains/testing/run-a-parachain-network/) | Launch a complete parachain test network with Zombienet | +- **`spawn `**: Spawn the network defined in the [configuration file](#configuration-files). +- **`test `**: Run tests on the spawned network using the assertions and tests defined in the [test file](/develop/toolkit/parachains/spawn-chains/zombienet/write-tests/#the-test-file){target=\_blank}. +- **`setup `**: Set up the Zombienet development environment to download and use the `polkadot` or `polkadot-parachain` executable. +- **`convert `**: Transforms a [polkadot-launch](https://github.com/paritytech/polkadot-launch){target=\_blank} configuration file with a `.js` or `.json` extension into a Zombienet configuration file. +- **`version`**: Prints Zombienet version. +- **`help`**: Prints help information. -## Runtime Upgrades and Maintenance +#### CLI Flags -Manage your parachain's lifecycle with forkless upgrades and maintenance operations. +You can use the following flags to customize the behavior of the CLI: -| Tutorial | Description | -| :-----------------------------------------------------------------------: | :--------------------------------------------------: | -| [Runtime Upgrades](/parachains/runtime-maintenance/runtime-upgrades/) | Perform forkless runtime upgrades via governance | -| [Storage Migrations](/parachains/runtime-maintenance/storage-migrations/) | Safely migrate storage when updating runtime logic | -| [Unlock Parachains](/parachains/runtime-maintenance/unlock-parachains/) | Understand parachain lifecycle and unlock mechanisms | +- **`-p`, `--provider`**: Override the [provider](#providers) to use. +- **`-d`, `--dir`**: Specify a directory path for placing the network files instead of using the default temporary path. +- **`-f`, `--force`**: Force override all prompt commands. +- **`-l`, `--logType`**: Type of logging on the console. Defaults to `table`. +- **`-m`, `--monitor`**: Start as monitor and don't auto clean up network. +- **`-c`, `--spawn-concurrency`**: Number of concurrent spawning processes to launch. Defaults to `1`. +- **`-h`, `--help`**: Display help for command. -## Interoperability +### Settings -Configure your parachain for cross-chain communication using XCM (Cross-Consensus Messaging). +Through the keyword `settings`, it's possible to define the general settings for the network. The available keys are: -| Tutorial | Description | -| :--------------------------------------------------------------------------------------------------------: | :----------------------------------------------------: | -| [Open HRMP Channels Between Parachains](/parachains/interoperability/channels-between-parachains/) | Establish communication channels with other parachains | -| [Open HRMP Channels with System Parachains](/parachains/interoperability/channels-with-system-parachains/) | Connect with Asset Hub and other system parachains | +- **`global_volumes?`** ++"GlobalVolume[]"++: A list of global volumes to use. -## Integrations + ??? child "`GlobalVolume` interface definition" + ```js + export interface GlobalVolume { + name: string; + fs_type: string; + mount_path: string; + } + ``` -Integrate your parachain with essential ecosystem tools and services. +- **`bootnode`** ++"boolean"++: Add bootnode to network. Defaults to `true`. +- **`bootnode_domain?`** ++"string"++: Domain to use for bootnode. +- **`timeout`** ++"number"++: Global timeout to use for spawning the whole network. +- **`node_spawn_timeout?`** ++"number"++: Timeout to spawn pod/process. +- **`grafana?`** ++"boolean"++: Deploy an instance of Grafana. +- **`prometheus?`** ++"boolean"++: Deploy an instance of Prometheus. +- **`telemetry?`** ++"boolean"++: Enable telemetry for the network. +- **`jaeger_agent?`** ++"string"++: The Jaeger agent endpoint passed to the nodes. Only available on Kubernetes. +- **`tracing_collator_url?`** ++"string"++: The URL of the tracing collator used to query by the tracing assertion. Should be tempo query compatible. +- **`tracing_collator_service_name?`** ++"string"++: Service name for tempo query frontend. Only available on Kubernetes. Defaults to `tempo-tempo-distributed-query-frontend`. +- **`tracing_collator_service_namespace?`** ++"string"++: Namespace where tempo is running. Only available on Kubernetes. Defaults to `tempo`. +- **`tracing_collator_service_port?`** ++"number"++: Port of the query instance of tempo. Only available on Kubernetes. Defaults to `3100`. +- **`enable_tracing?`** ++"boolean"++: Enable the tracing system. Only available on Kubernetes. Defaults to `true`. +- **`provider`** ++"string"++: Provider to use. Default is `kubernetes`". +- **`polkadot_introspector?`** ++"boolean"++: Deploy an instance of polkadot-introspector. Only available on Podman and Kubernetes. Defaults to `false`. +- **`backchannel?`** ++"boolean"++: Deploy an instance of backchannel server. Only available on Kubernetes. Defaults to `false`. +- **`image_pull_policy?`** ++"string"++: Image pull policy to use in the network. Possible values are `Always`, `IfNotPresent`, and `Never`. +- **`local_ip?`** ++"string"++: IP used for exposing local services (rpc/metrics/monitors). Defaults to `"127.0.0.1"`. +- **`global_delay_network_global_settings?`** ++"number"++: Delay in seconds to apply to the network. +- **`node_verifier?`** ++"string"++: Specify how to verify node readiness or deactivate by using `None`. Possible values are `None` and `Metric`. Defaults to `Metric`. -| Tutorial | Description | -| :--------------------------------------------: | :----------------------------------------------------: | -| [Wallets](/parachains/integrations/wallets/) | Integrate wallet support for user interactions | -| [Indexers](/parachains/integrations/indexers/) | Set up indexing solutions for querying blockchain data | -| [Oracles](/parachains/integrations/oracles/) | Connect your parachain to off-chain data sources | +For example, the following configuration file defines a minimal example for the settings: -## Additional Resources +=== "TOML" -- [Polkadot SDK Documentation](https://paritytech.github.io/polkadot-sdk/master/polkadot_sdk_docs/polkadot_sdk/index.html) -- [Polkadot Wiki - Parachains](https://wiki.polkadot.network/docs/learn-parachains/) + ```toml title="base-example.toml" + [settings] + timeout = 1000 + bootnode = false + provider = "kubernetes" + backchannel = false + # ... + ``` ---- +=== "JSON" + + ```json title="base-example.json" + { + "settings": { + "timeout": 1000, + "bootnode": false, + "provider": "kubernetes", + "backchannel": false, + "...": {} + }, + "...": {} + } + + ``` + +### Relay Chain Configuration + +You can use the `relaychain` keyword to define further parameters for the relay chain at start-up. The available keys are: + +- **`default_command?`** ++"string"++: The default command to run. Defaults to `polkadot`. +- **`default_image?`** ++"string"++: The default Docker image to use. +- **`default_resources?`** ++"Resources"++: Represents the resource limits/reservations the nodes need by default. Only available on Kubernetes. + + ??? child "`Resources` interface definition" + ```js + export interface Resources { + resources: { + requests?: { + memory?: string; + cpu?: string; + }; + limits?: { + memory?: string; + cpu?: string; + }; + }; + } + ``` -Page Title: Get Started with Smart Contracts +- **`default_db_snapshot?`** ++"string"++: The default database snapshot to use. +- **`default_prometheus_prefix`** ++"string"++: A parameter for customizing the metric's prefix. Defaults to `substrate`. +- **`default_substrate_cli_args_version?`** ++"SubstrateCliArgsVersion"++: Set the Substrate CLI arguments version. -- Source (raw): https://raw.githubusercontent.com/polkadot-developers/polkadot-docs/master/.ai/pages/smart-contracts-get-started.md -- Canonical (HTML): https://docs.polkadot.com/smart-contracts/get-started/ -- Summary: Practical examples for building and deploying smart contracts on Polkadot Hub, from connecting and tooling to deployment, integrations, and precompiles. + ??? child "`SubstrateCliArgsVersion` enum definition" + ```js + export enum SubstrateCliArgsVersion { + V0 = 0, + V1 = 1, + V2 = 2, + V3 = 3, + } + ``` -# Get Started +- **`default_keystore_key_types?`** ++"string[]"++: Defines which keystore keys should be created. +- **`chain`** ++"string"++: The chain name. +- **`chain_spec_path?`** ++"string"++: Path to the chain spec file. Should be the plain version to allow customizations. +- **`chain_spec_command?`** ++"string"++: Command to generate the chain spec. It can't be used in combination with `chain_spec_path`. +- **`default_args?`** ++"string[]"++: An array of arguments to use as default to pass to the command. +- **`default_overrides?`** ++"Override[]"++: An array of overrides to upload to the node. -This resource provides quick-starts for building smart contracts on Polkadot Hub. Use the tables below to jump directly to the tools and workflows you need. + ??? child "`Override` interface definition" + ```js + export interface Override { + local_path: string; + remote_name: string; + } + ``` -## Quick Starts +- **`random_nominators_count?`** ++"number"++: If set and the stacking pallet is enabled, Zombienet will generate the input quantity of nominators and inject them into the genesis. +- **`max_nominations`** ++"number"++: The max number of nominations allowed by a nominator. Should match the value set in the runtime. Defaults to `24`. +- **`nodes?`** ++"Node[]"++: An array of nodes to spawn. It is further defined in the [Node Configuration](#node-configuration) section. +- **`node_groups?`** ++"NodeGroup[]"++: An array of node groups to spawn. It is further defined in the [Node Group Configuration](#node-group-configuration) section. +- **`total_node_in_group?`** ++"number"++: The total number of nodes in the group. Defaults to `1`. +- **`genesis`** ++"JSON"++: The genesis configuration. +- **`default_delay_network_settings?`** ++"DelayNetworkSettings"++: Sets the expected configuration to delay the network. -Kick off development fast with curated links for connecting, funding, exploring, and deploying your first contract. + ??? child "`DelayNetworkSettings` interface definition" + ```js + export interface DelayNetworkSettings { + latency: string; + correlation?: string; // should be parsable as float by k8s + jitter?: string; + } + ``` -| Quick Start | Tools | Description | -| :-------------------------------------------------------------------------------------------------: | :-------------------: | :-------------------------------------------------------------: | -| [Connect to Polkadot](/smart-contracts/connect/){target=\_blank} | Polkadot.js, MetaMask | Add the network, configure RPC, verify activity in the explorer | -| [Get Test Tokens](/smart-contracts/faucets/){target=\_blank} | - | Request test funds to deploy and interact with contracts | -| [Explore Transactions](/smart-contracts/explorers/){target=\_blank} | Subscan | Inspect transactions, logs, token transfers, and contract state | -| [Deploy with Remix](/smart-contracts/dev-environments/remix/deploy-a-contract/){target=\_blank} | Remix | One‑click browser deployment to Polkadot Hub | -| [Deploy with Foundry](/smart-contracts/dev-environments/foundry/deploy-a-contract/){target=\_blank} | Foundry | Scripted deployments and testing from the CLI | -| [Deploy with Hardhat](/smart-contracts/dev-environments/hardhat/deploy-a-contract/){target=\_blank} | Hardhat | Project scaffolding, testing, and deployments | +#### Node Configuration -## Build and Test Locally +One specific key capable of receiving more subkeys is the `nodes` key. This key is used to define further parameters for the nodes. The available keys: -Set up local environments and CI-friendly workflows to iterate quickly and validate changes before deploying. +- **`name`** ++"string"++: Name of the node. Any whitespace will be replaced with a dash (for example, `new alice` will be converted to `new-alice`). +- **`image?`** ++"string"++: Override default Docker image to use for this node. +- **`command?`** ++"string"++: Override default command to run. +- **`command_with_args?`** ++"string"++: Override default command and arguments. +- **`args?`** ++"string[]"++: Arguments to be passed to the command. +- **`env?`** ++"envVars[]"++: Environment variables to set in the container. -| Build and Test Locally | Tools | Description | -| :--------------------------------------------------------------------------------------------------------: | :---------------: | :--------------------------------------------------: | -| [Run a Local Dev Node](/smart-contracts/dev-environments/local-dev-node/){target=\_blank} | Polkadot SDK node | Spin up a local node for iterative development | -| [Remix: Get Started](/smart-contracts/dev-environments/remix/get-started/){target=\_blank} | Remix | Connect Remix to Polkadot Hub and configure accounts | -| [Remix: Verify a Contract](/smart-contracts/dev-environments/remix/verify-a-contract/){target=\_blank} | Remix | Publish verified source on explorers | -| [Foundry: Install and Config](/smart-contracts/dev-environments/foundry/install-and-config/){target=\_blank} | Foundry | Install toolchain and configure networks | -| [Foundry: Compile and Test](/smart-contracts/dev-environments/foundry/compile-and-test/){target=\_blank} | Foundry | Write and run Solidity tests locally | -| [Foundry: Verify a Contract](/smart-contracts/dev-environments/foundry/verify-a-contract/){target=\_blank} | Foundry | Verify deployed bytecode and metadata | -| [Hardhat: Install and Config](/smart-contracts/dev-environments/hardhat/install-and-config/){target=\_blank} | Hardhat | Initialize a project and configure networks | -| [Hardhat: Compile and Test](/smart-contracts/dev-environments/hardhat/compile-and-test/){target=\_blank} | Hardhat | Unit test contracts and run scripts | -| [Hardhat: Verify a Contract](/smart-contracts/dev-environments/hardhat/verify-a-contract/){target=\_blank} | Hardhat | Verify deployments on explorers | + ??? child "`envVars` interface definition" + ```js + export interface EnvVars { + name: string; + value: string; + } + ``` -## Ethereum Developer Resources +- **`prometheus_prefix?`** ++"string"++: Customizes the metric's prefix for the specific node. Defaults to `substrate`. +- **`db_snapshot?`** ++"string"++: Database snapshot to use. +- **`substrate_cli_args_version?`** ++"SubstrateCliArgsVersion"++: Set the Substrate CLI arguments version directly to skip binary evaluation overhead. -Bridge your Ethereum knowledge with Polkadot Hub specifics: account mapping, fees, JSON‑RPC, and deployment. + ??? child "`SubstrateCliArgsVersion` enum definition" + ```js + export enum SubstrateCliArgsVersion { + V0 = 0, + V1 = 1, + V2 = 2, + V3 = 3, + } + ``` -| Ethereum Developer Guides | Description | -| :-------------------------------------------------------------------------------------------------------: | :-------------------------------------------------------------: | -| [Accounts](/smart-contracts/for-eth-devs/accounts/){target=\_blank} | How 20‑byte Ethereum addresses map to 32‑byte Polkadot accounts | -| [Blocks, Transactions, and Fees](/smart-contracts/for-eth-devs/blocks-transactions-fees/){target=\_blank} | Transaction types, fees, and multi‑dimensional metering | -| [Gas Model](/smart-contracts/for-eth-devs/gas-model/){target=\_blank} | Gas vs. weight, proof size, and storage deposits | -| [Contract Deployment](/smart-contracts/for-eth-devs/contract-deployment/){target=\_blank} | Deployment patterns and best practices on Polkadot Hub | -| [JSON‑RPC APIs](/smart-contracts/for-eth-devs/json-rpc-apis/){target=\_blank} | Supported Ethereum JSON‑RPC methods and examples | -| [Migration](/smart-contracts/for-eth-devs/migration/){target=\_blank} | Port existing apps and tooling to Polkadot Hub | -| [Dual VM Stack](/smart-contracts/for-eth-devs/dual-vm-stack/){target=\_blank} | Overview of EVM and native execution on the Hub | +- **`resources?`** ++"Resources"++: Represent the resources limits/reservations needed by the node. -## Cookbook: Hands‑on Tutorials + ??? child "`Resources` interface definition" + ```js + export interface Resources { + resources: { + requests?: { + memory?: string; + cpu?: string; + }; + limits?: { + memory?: string; + cpu?: string; + }; + }; + } + ``` -Follow step‑by‑step guides that walk through common tasks and complete dApp examples. +- **`keystore_key_types?`** ++"string[]"++: Defines which keystore keys should be created. +- **`validator`** ++"boolean"++: Pass the `--validator` flag to the command. Defaults to `true`. +- **`invulnerable`** ++"boolean"++: If true, add the node to invulnerables in the chain spec. Defaults to `false`. +- **`balance`** ++"number"++: Balance to set in balances for node's account. Defaults to `2000000000000`. +- **`bootnodes?`** ++"string[]"++: Array of bootnodes to use. +- **`add_to_bootnodes?`** ++"boolean"++: Add this node to the bootnode list. Defaults to `false`. +- **`ws_port?`** ++"number"++: WS port to use. +- **`rpc_port?`** ++"number"++: RPC port to use. +- **`prometheus_port?`** ++"number"++: Prometheus port to use. +- **`p2p_cert_hash?`** ++"string"++: Libp2p certhash to use with webRTC transport. +- **`delay_network_settings?`** ++"DelayNetworkSettings"++: Sets the expected configuration to delay the network. -| Tutorial | Tools | Description | -| :------------------------------------------------------------------------------------------------: | :-----------------: | :---------------------------------------: | -| [Deploy a Basic Contract](/smart-contracts/cookbook/smart-contracts/deploy-basic/){target=\_blank} | Remix | Minimal deployment walkthrough | -| [Deploy an ERC‑20](/smart-contracts/cookbook/smart-contracts/deploy-erc20/){target=\_blank} | Remix, OpenZeppelin | Create, deploy, and mint a fungible token | -| [Deploy an NFT (ERC‑721)](/smart-contracts/cookbook/smart-contracts/deploy-nft/){target=\_blank} | Remix, OpenZeppelin | Build and deploy an NFT collection | -| [Uniswap V2](/smart-contracts/cookbook/eth-dapps/uniswap-v2/){target=\_blank} | Hardhat | Full dApp project: compile, test, deploy | -| [Zero‑to‑Hero dApp](/smart-contracts/cookbook/dapps/zero-to-hero/){target=\_blank} | Multiple | End‑to‑end dApp patterns and practices | + ??? child "`DelayNetworkSettings` interface definition" + ```js + export interface DelayNetworkSettings { + latency: string; + correlation?: string; // should be parsable as float by k8s + jitter?: string; + } + ``` -## Libraries +The following configuration file defines a minimal example for the relay chain, including the `nodes` key: -Choose the client libraries that fit your stack for connecting wallets and calling contracts. +=== "TOML" -| Library | Description | -| :----------------------------------------------------------------: | :-----------------------------------------------------: | -| [Ethers.js](/smart-contracts/libraries/ethers-js/){target=\_blank} | Connect, sign, and interact with contracts using Ethers | -| [viem](/smart-contracts/libraries/viem/){target=\_blank} | Type‑safe EVM interactions and utilities | -| [Wagmi](/smart-contracts/libraries/wagmi/){target=\_blank} | React hooks for wallet connections and contract calls | -| [Web3.js](/smart-contracts/libraries/web3-js/){target=\_blank} | Web3 provider and contract APIs | -| [Web3.py](/smart-contracts/libraries/web3-py/){target=\_blank} | Python toolkit for on‑chain interactions and scripts | + ```toml title="relaychain-example-nodes.toml" + [relaychain] + default_command = "polkadot" + default_image = "polkadot-debug:master" + chain = "rococo-local" + chain_spec_path = "INSERT_PATH_TO_CHAIN_SPEC" + default_args = ["--chain", "rococo-local"] -## Integrations + [[relaychain.nodes]] + name = "alice" + validator = true + balance = 1000000000000 -Integrate essential services like wallets, indexers, and oracles to round out your dApp. + [[relaychain.nodes]] + name = "bob" + validator = true + balance = 1000000000000 + # ... -| Integration | Description | -| :-----------------------------------------------------------------: | :---------------------------------------: | -| [Wallets](/smart-contracts/integrations/wallets/){target=\_blank} | Supported wallets and configuration notes | -| [Indexers](/smart-contracts/integrations/indexers/){target=\_blank} | Index and query blockchain data | -| [Oracles](/smart-contracts/integrations/oracles/){target=\_blank} | Bring external data on‑chain | + ``` -## Precompiles +=== "JSON" -Discover precompiled system contracts available on the Hub and how to use them. + ```json title="relaychain-example-nodes.json" + { + "relaychain": { + "default_command": "polkadot", + "default_image": "polkadot-debug:master", + "chain": "rococo-local", + "chain_spec_path": "INSERT_PATH_TO_CHAIN-SPEC.JSON", + "default_args": ["--chain", "rococo-local"], + "nodes": [ + { + "name": "alice", + "validator": true, + "balance": 1000000000000 + }, + { + "name": "bob", + "validator": true, + "balance": 1000000000000 + } + ] + } + } -| Topic | Description | -| :----------------------------------------------------------------------: | :-------------------------------------------------: | -| [Overview of Precompiles](/smart-contracts/precompiles/){target=\_blank} | What precompiles are available on the Hub | -| [ETH Native](/smart-contracts/precompiles/eth-native/){target=\_blank} | EVM precompiles and interfaces | -| [Staking](/smart-contracts/precompiles/staking/){target=\_blank} | Interact with staking functionality via precompiles | -| [XCM](/smart-contracts/precompiles/xcm/){target=\_blank} | Cross‑chain messaging helpers for contracts | + ``` -From here, follow the quick starts to get connected, iterate locally with your preferred tools, and use the guides, libraries, integrations, and precompiles as you grow into production‑ready dApps. If you get stuck, [open an issue](https://github.com/polkadot-developers/polkadot-docs/issues/new?template=docs-issue.yml){target=\_blank} or reach out in the community channels. +#### Node Group Configuration +The `node_groups` key defines further parameters for the node groups. The available keys are: ---- +- **`name`** ++"string"++: Name of the node. Any whitespace will be replaced with a dash (for example, `new alice` will be converted to `new-alice`). +- **`image?`** ++"string"++: Override default Docker image to use for this node. +- **`command?`** ++"string"++: Override default command to run. +- **`args?`** ++"string[]"++: Arguments to be passed to the command. +- **`env?`** ++"envVars[]"++: Environment variables to set in the container. + + ??? child "`envVars` interface definition" + ```js + export interface EnvVars { + name: string; + value: string; + } + ``` -Page Title: Glossary +- **`overrides?`** ++"Override[]"++: Array of overrides definitions. -- Source (raw): https://raw.githubusercontent.com/polkadot-developers/polkadot-docs/master/.ai/pages/reference-glossary.md -- Canonical (HTML): https://docs.polkadot.com/reference/glossary/ -- Summary: Glossary of terms used within the Polkadot ecosystem, Polkadot SDK, its subsequent libraries, and other relevant Web3 terminology. + ??? child "`Override` interface definition" + ```js + export interface Override { + local_path: string; + remote_name: string; + } + ``` -# Glossary +- **`prometheus_prefix?`** ++"string"++: Customizes the metric's prefix for the specific node. Defaults to `substrate`. +- **`db_snapshot?`** ++"string"++: Database snapshot to use. +- **`substrate_cli_args_version?`** ++"SubstrateCliArgsVersion"++: Set the Substrate CLI arguments version directly to skip binary evaluation overhead. -Key definitions, concepts, and terminology specific to the Polkadot ecosystem are included here. + ??? child "`SubstrateCliArgsVersion` enum definition" + ```js + export enum SubstrateCliArgsVersion { + V0 = 0, + V1 = 1, + V2 = 2, + V3 = 3, + } + ``` -Additional glossaries from around the ecosystem you might find helpful: +- **`resources?`** ++"Resources"++: Represent the resources limits/reservations needed by the node. -- [Polkadot Wiki Glossary](https://wiki.polkadot.com/general/glossary){target=\_blank} -- [Polkadot SDK Glossary](https://paritytech.github.io/polkadot-sdk/master/polkadot_sdk_docs/reference_docs/glossary/index.html){target=\_blank} + ??? child "`Resources` interface definition" + ```js + export interface Resources { + resources: { + requests?: { + memory?: string; + cpu?: string; + }; + limits?: { + memory?: string; + cpu?: string; + }; + }; + } + ``` -## Authority +- **`keystore_key_types?`** ++"string[]"++: Defines which keystore keys should be created. +- **`count`** ++"number | string"++: Number of nodes to launch for this group. +- **`delay_network_settings?`** ++"DelayNetworkSettings"++: Sets the expected configuration to delay the network. -The role in a blockchain that can participate in consensus mechanisms. + ??? child "`DelayNetworkSettings` interface definition" + ```js + export interface DelayNetworkSettings { + latency: string; + correlation?: string; // should be parsable as float by k8s + jitter?: string; + } + ``` -- **[GRANDPA](#grandpa)**: The authorities vote on chains they consider final. -- **[Blind Assignment of Blockchain Extension](#blind-assignment-of-blockchain-extension-babe) (BABE)**: The authorities are also [block authors](#block-author). +The following configuration file defines a minimal example for the relay chain, including the `node_groups` key: -Authority sets can be used as a basis for consensus mechanisms such as the [Nominated Proof of Stake (NPoS)](#nominated-proof-of-stake-npos) protocol. +=== "TOML" -## Authority Round (Aura) + ```toml title="relaychain-example-node-groups.toml" + [relaychain] + default_command = "polkadot" + default_image = "polkadot-debug:master" + chain = "rococo-local" + chain_spec_path = "INSERT_PATH_TO_CHAIN_SPEC" + default_args = ["--chain", "rococo-local"] -A deterministic [consensus](#consensus) protocol where block production is limited to a rotating list of [authorities](#authority) that take turns creating blocks. In authority round (Aura) consensus, most online authorities are assumed to be honest. It is often used in combination with [GRANDPA](#grandpa) as a [hybrid consensus](#hybrid-consensus) protocol. + [[relaychain.node_groups]] + name = "group-1" + count = 2 + image = "polkadot-debug:master" + command = "polkadot" + args = ["--chain", "rococo-local"] + # ... -Learn more by reading the official [Aura consensus algorithm](https://openethereum.github.io/Aura){target=\_blank} wiki article. + ``` -## Blind Assignment of Blockchain Extension (BABE) +=== "JSON" -A [block authoring](#block-author) protocol similar to [Aura](#authority-round-aura), except [authorities](#authority) win [slots](#slot) based on a Verifiable Random Function (VRF) instead of the round-robin selection method. The winning authority can select a chain and submit a new block. + ```json title="relaychain-example-node-groups.json" + { + "relaychain": { + "default_command": "polkadot", + "default_image": "polkadot-debug:master", + "chain": "rococo-local", + "chain_spec_path": "INSERT_PATH_TO_CHAIN-SPEC.JSON", + "default_args": ["--chain", "rococo-local"], + "node_groups": [ + { + "name": "group-1", + "count": 2, + "image": "polkadot-debug:master", + "command": "polkadot", + "args": ["--chain", "rococo-local"] + } + ], + "...": {} + }, + "...": {} + } -Learn more by reading the official Web3 Foundation [BABE research document](https://research.web3.foundation/Polkadot/protocols/block-production/Babe){target=\_blank}. + ``` -## Block Author +### Parachain Configuration -The node responsible for the creation of a block, also called _block producers_. In a Proof of Work (PoW) blockchain, these nodes are called _miners_. +The `parachain` keyword defines further parameters for the parachain. The available keys are: -## Byzantine Fault Tolerance (BFT) +- **`id`** ++"number"++: The id to assign to this parachain. Must be unique. +- **`chain?`** ++"string"++: The chain name. +- **`force_decorator?`** ++"string"++: Force the use of a specific decorator. +- **`genesis?`** ++"JSON"++: The genesis configuration. +- **`balance?`** ++"number"++: Balance to set in balances for parachain's account. +- **`delay_network_settings?`** ++"DelayNetworkSettings"++: Sets the expected configuration to delay the network. -The ability of a distributed computer network to remain operational if a certain proportion of its nodes or [authorities](#authority) are defective or behaving maliciously. A distributed network is typically considered Byzantine fault tolerant if it can remain functional, with up to one-third of nodes assumed to be defective, offline, actively malicious, and part of a coordinated attack. + ??? child "`DelayNetworkSettings` interface definition" + ```js + export interface DelayNetworkSettings { + latency: string; + correlation?: string; // should be parsable as float by k8s + jitter?: string; + } + ``` -### Byzantine Failure +- **`add_to_genesis?`** ++"boolean"++: Flag to add parachain to genesis or register in runtime. Defaults to `true`. +- **`register_para?`** ++"boolean"++: Flag to specify whether the para should be registered. The `add_to_genesis` flag must be set to false for this flag to have any effect. Defaults to `true`. +- **`onboard_as_parachain?`** ++"boolean"++: Flag to specify whether the para should be onboarded as a parachain, rather than remaining a parathread. Defaults to `true`. +- **`genesis_wasm_path?`** ++"string"++: Path to the Wasm file to use. +- **`genesis_wasm_generator?`** ++"string"++: Command to generate the Wasm file. +- **`genesis_state_path?`** ++"string"++: Path to the state file to use. +- **`genesis_state_generator?`** ++"string"++: Command to generate the state file. +- **`chain_spec_path?`** ++"string"++: Path to the chain spec file. +- **`chain_spec_command?`** ++"string"++: Command to generate the chain spec. +- **`cumulus_based?`** ++"boolean"++: Flag to use cumulus command generation. Defaults to `true`. +- **`bootnodes?`** ++"string[]"++: Array of bootnodes to use. +- **`prometheus_prefix?`** ++"string"++: Parameter for customizing the metric's prefix for all parachain nodes/collators. Defaults to `substrate`. +- **`collator?`** ++"Collator"++: Further defined in the [Collator Configuration](#collator-configuration) section. +- **`collator_groups?`** ++"CollatorGroup[]"++: An array of collator groups to spawn. It is further defined in the [Collator Groups Configuration](#collator-groups-configuration) section. + +For example, the following configuration file defines a minimal example for the parachain: -The loss of a network service due to node failures that exceed the proportion of nodes required to reach consensus. +=== "TOML" -### Practical Byzantine Fault Tolerance (pBFT) + ```toml title="parachain-example.toml" + [parachain] + id = 100 + add_to_genesis = true + cumulus_based = true + genesis_wasm_path = "INSERT_PATH_TO_WASM" + genesis_state_path = "INSERT_PATH_TO_STATE" + # ... -An early approach to Byzantine fault tolerance (BFT), practical Byzantine fault tolerance (pBFT) systems tolerate Byzantine behavior from up to one-third of participants. + ``` -The communication overhead for such systems is `O(n²)`, where `n` is the number of nodes (participants) in the system. +=== "JSON" -### Preimage + ```json title="parachain-example.json" + { + "parachain": { + "id": 100, + "add_to_genesis": true, + "cumulus_based": true, + "genesis_wasm_path": "INSERT_PATH_TO_WASM", + "genesis_state_path": "INSERT_PATH_TO_STATE", + "...": {} + }, + "...": {} + } -A preimage is the data that is input into a hash function to calculate a hash. Since a hash function is a [one-way function](https://en.wikipedia.org/wiki/One-way_function){target=\_blank}, the output, the hash, cannot be used to reveal the input, the preimage. + ``` -## Call +#### Collator Configuration -In the context of pallets containing functions to be dispatched to the runtime, `Call` is an enumeration data type that describes the functions that can be dispatched with one variant per pallet. A `Call` represents a [dispatch](#dispatchable) data structure object. +One specific key capable of receiving more subkeys is the `collator` key. This key defines further parameters for the nodes. The available keys are: -## Chain Specification +- **`name`** ++"string"++: Name of the collator. Any whitespace will be replaced with a dash (for example, `new alice` will be converted to `new-alice`). +- **`image?`** ++"string"++: Image to use for the collator. +- **`command_with_args?`** ++"string"++: Overrides both command and arguments for the collator. +- **`validator`** ++"boolean"++: Pass the `--validator` flag to the command. Defaults to `true`. +- **`invulnerable`** ++"boolean"++: If true, add the collator to invulnerables in the chain spec. Defaults to `false`. +- **`balance`** ++"number"++: Balance to set in balances for collator's account. Defaults to `2000000000000`. +- **`bootnodes?`** ++"string[]"++: Array of bootnodes to use. +- **`add_to_bootnodes?`** ++"boolean"++: Add this collator to the bootnode list. Defaults to `false`. +- **`ws_port?`** ++"number"++: WS port to use. +- **`rpc_port?`** ++"number"++: RPC port to use. +- **`prometheus_port?`** ++"number"++: Prometheus port to use. +- **`p2p_port?`** ++"number"++: P2P port to use. +- **`p2p_cert_hash?`** ++"string"++: Libp2p certhash to use with webRTC transport. +- **`delay_network_settings?`** ++"DelayNetworkSettings"++: Sets the expected configuration to delay the network. -A chain specification file defines the properties required to run a node in an active or new Polkadot SDK-built network. It often contains the initial genesis runtime code, network properties (such as the network's name), the initial state for some pallets, and the boot node list. The chain specification file makes it easy to use a single Polkadot SDK codebase as the foundation for multiple independently configured chains. + ??? child "`DelayNetworkSettings` interface definition" + ```js + export interface DelayNetworkSettings { + latency: string; + correlation?: string; // should be parsable as float by k8s + jitter?: string; + } + ``` -## Collator +- **`command?`** ++"string"++: Override default command to run. +- **`args?`** ++"string[]"++: Arguments to be passed to the command. +- **`env?`** ++"envVars[]"++: Environment variables to set in the container. -An [author](#block-author) of a [parachain](#parachain) network. -They aren't [authorities](#authority) in themselves, as they require a [relay chain](#relay-chain) to coordinate [consensus](#consensus). + ??? child "`envVars` interface definition" + ```js + export interface EnvVars { + name: string; + value: string; + } + ``` -More details are found on the [Polkadot Collator Wiki](https://wiki.polkadot.com/learn/learn-collator/){target=\_blank}. +- **`overrides?`** ++"Override[]"++: Array of overrides definitions. -## Collective + ??? child "`Override` interface definition" + ```js + export interface Override { + local_path: string; + remote_name: string; + } + ``` -Most often used to refer to an instance of the Collective pallet on Polkadot SDK-based networks such as [Kusama](#kusama) or [Polkadot](#polkadot) if the Collective pallet is part of the FRAME-based runtime for the network. +- **`prometheus_prefix?`** ++"string"++: Customizes the metric's prefix for the specific node. Defaults to `substrate`. +- **`db_snapshot?`** ++"string"++: Database snapshot to use. +- **`substrate_cli_args_version?`** ++"SubstrateCliArgsVersion"++: Set the Substrate CLI arguments version directly to skip binary evaluation overhead. -## Consensus + ??? child "`SubstrateCliArgsVersion` enum definition" + ```js + export enum SubstrateCliArgsVersion { + V0 = 0, + V1 = 1, + V2 = 2, + V3 = 3, + } + ``` -Consensus is the process blockchain nodes use to agree on a chain's canonical fork. It is composed of [authorship](#block-author), finality, and [fork-choice rule](#fork-choice-rulestrategy). In the Polkadot ecosystem, these three components are usually separate and the term consensus often refers specifically to authorship. +- **`resources?`** ++"Resources"++: Represent the resources limits/reservations needed by the node. -See also [hybrid consensus](#hybrid-consensus). + ??? child "`Resources` interface definition" + ```js + export interface Resources { + resources: { + requests?: { + memory?: string; + cpu?: string; + }; + limits?: { + memory?: string; + cpu?: string; + }; + }; + } + ``` -## Consensus Algorithm +- **`keystore_key_types?`** ++"string[]"++: Defines which keystore keys should be created. -Ensures a set of [actors](#authority)—who don't necessarily trust each other—can reach an agreement about the state as the result of some computation. Most consensus algorithms assume that up to one-third of the actors or nodes can be [Byzantine fault tolerant](#byzantine-fault-tolerance-bft). +The configuration file below defines a minimal example for the collator: -Consensus algorithms are generally concerned with ensuring two properties: +=== "TOML" -- **Safety**: Indicating that all honest nodes eventually agreed on the state of the chain. -- **Liveness**: Indicating the ability of the chain to keep progressing. + ```toml title="collator-example.toml" + [parachain] + id = 100 + add_to_genesis = true + cumulus_based = true + genesis_wasm_path = "INSERT_PATH_TO_WASM" + genesis_state_path = "INSERT_PATH_TO_STATE" -## Consensus Engine + [[parachain.collators]] + name = "alice" + image = "polkadot-parachain" + command = "polkadot-parachain" + # ... -The node subsystem responsible for consensus tasks. + ``` -For detailed information about the consensus strategies of the [Polkadot](#polkadot) network, see the [Polkadot Consensus](/reference/polkadot-hub/consensus-and-security/pos-consensus/){target=\_blank} blog series. +=== "JSON" -See also [hybrid consensus](#hybrid-consensus). + ```json title="collator-example.json" + { + "parachain": { + "id": 100, + "add_to_genesis": true, + "cumulus_based": true, + "genesis_wasm_path": "INSERT_PATH_TO_WASM", + "genesis_state_path": "INSERT_PATH_TO_STATE", + "collators": [ + { + "name": "alice", + "image": "polkadot-parachain", + "command": "polkadot-parachain", + "...": {} + } + ] + }, + "...": {} + } -## Coretime + ``` -The time allocated for utilizing a core, measured in relay chain blocks. There are two types of coretime: *on-demand* and *bulk*. +#### Collator Groups Configuration -On-demand coretime refers to coretime acquired through bidding in near real-time for the validation of a single parachain block on one of the cores reserved specifically for on-demand orders. They are available as an on-demand coretime pool. Set of cores that are available on-demand. Cores reserved through bulk coretime could also be made available in the on-demand coretime pool, in parts or in entirety. +The `collator_groups` key defines further parameters for the collator groups. The available keys are: -Bulk coretime is a fixed duration of continuous coretime represented by an NFT that can be split, shared, or resold. It is managed by the [Broker pallet](https://paritytech.github.io/polkadot-sdk/master/pallet_broker/index.html){target=\_blank}. +- **`name`** ++"string"++: Name of the node. Any whitespace will be replaced with a dash (for example, `new alice` will be converted to `new-alice`). +- **`image?`** ++"string"++: Override default Docker image to use for this node. +- **`command?`** ++"string"++: Override default command to run. +- **`args?`** ++"string[]"++: Arguments to be passed to the command. +- **`env?`** ++"envVars[]"++: Environment variables to set in the container. -## Development Phrase + ??? child "`envVars` interface definition" + ```js + export interface EnvVars { + name: string; + value: string; + } + ``` -A [mnemonic phrase](https://en.wikipedia.org/wiki/Mnemonic#For_numerical_sequences_and_mathematical_operations){target=\_blank} that is intentionally made public. +- **`overrides?`** ++"Override[]"++: Array of overrides definitions. -Well-known development accounts, such as Alice, Bob, Charlie, Dave, Eve, and Ferdie, are generated from the same secret phrase: + ??? child "`Override` interface definition" + ```js + export interface Override { + local_path: string; + remote_name: string; + } + ``` -``` -bottom drive obey lake curtain smoke basket hold race lonely fit walk -``` +- **`prometheus_prefix?`** ++"string"++: Customizes the metric's prefix for the specific node. Defaults to `substrate`. +- **`db_snapshot?`** ++"string"++: Database snapshot to use. +- **`substrate_cli_args_version?`** ++"SubstrateCliArgsVersion"++: Set the Substrate CLI arguments version directly to skip binary evaluation overhead. -Many tools in the Polkadot SDK ecosystem, such as [`subkey`](https://github.com/paritytech/polkadot-sdk/tree/polkadot-stable2506-2/substrate/bin/utils/subkey){target=\_blank}, allow you to implicitly specify an account using a derivation path such as `//Alice`. + ??? child "`SubstrateCliArgsVersion` enum definition" + ```js + export enum SubstrateCliArgsVersion { + V0 = 0, + V1 = 1, + V2 = 2, + V3 = 3, + } + ``` -## Digest +- **`resources?`** ++"Resources"++: Represent the resources limits/reservations needed by the node. -An extensible field of the [block header](#header) that encodes information needed by several actors in a blockchain network, including: + ??? child "`Resources` interface definition" + ```js + export interface Resources { + resources: { + requests?: { + memory?: string; + cpu?: string; + }; + limits?: { + memory?: string; + cpu?: string; + }; + }; + } + ``` -- [Light clients](#light-client) for chain synchronization. -- Consensus engines for block verification. -- The runtime itself, in the case of pre-runtime digests. +- **`keystore_key_types?`** ++"string[]"++: Defines which keystore keys should be created. +- **`count`** ++"number | string"++: Number of nodes to launch for this group. +- **`delay_network_settings?`** ++"DelayNetworkSettings"++: Sets the expected configuration to delay the network. -## Dispatchable + ??? child "`DelayNetworkSettings` interface definition" + ```js + export interface DelayNetworkSettings { + latency: string; + correlation?: string; // should be parsable as float by k8s + jitter?: string; + } + ``` -Function objects that act as the entry points in FRAME [pallets](#pallet). Internal or external entities can call them to interact with the blockchain’s state. They are a core aspect of the runtime logic, handling [transactions](#transaction) and other state-changing operations. +For instance, the configuration file below defines a minimal example for the collator groups: -## Events +=== "TOML" -A means of recording that some particular [state](#state) transition happened. + ```toml title="collator-groups-example.toml" + [parachain] + id = 100 + add_to_genesis = true + cumulus_based = true + genesis_wasm_path = "INSERT_PATH_TO_WASM" + genesis_state_path = "INSERT_PATH_TO_STATE" -In the context of [FRAME](#frame-framework-for-runtime-aggregation-of-modularized-entities), events are composable data types that each [pallet](#pallet) can individually define. Events in FRAME are implemented as a set of transient storage items inspected immediately after a block has been executed and reset during block initialization. + [[parachain.collator_groups]] + name = "group-1" + count = 2 + image = "polkadot-parachain" + command = "polkadot-parachain" + # ... -## Executor + ``` -A means of executing a function call in a given [runtime](#runtime) with a set of dependencies. -There are two orchestration engines in Polkadot SDK, _WebAssembly_ and _native_. +=== "JSON" -- The _native executor_ uses a natively compiled runtime embedded in the node to execute calls. This is a performance optimization available to up-to-date nodes. + ```json title="collator-groups-example.json" + { + "parachain": { + "id": 100, + "add_to_genesis": true, + "cumulus_based": true, + "genesis_wasm_path": "INSERT_PATH_TO_WASM", + "genesis_state_path": "INSERT_PATH_TO_STATE", + "collator_groups": [ + { + "name": "group-1", + "count": 2, + "image": "polkadot-parachain", + "command": "polkadot-parachain", + "...": {} + } + ] + }, + "...": {} + } -- The _WebAssembly executor_ uses a [Wasm](#webassembly-wasm) binary and a Wasm interpreter to execute calls. The binary is guaranteed to be up-to-date regardless of the version of the blockchain node because it is persisted in the [state](#state) of the Polkadot SDK-based chain. + ``` -## Existential Deposit +### XCM Configuration -The minimum balance an account is allowed to have in the [Balances pallet](https://paritytech.github.io/polkadot-sdk/master/pallet_balances/index.html){target=\_blank}. Accounts cannot be created with a balance less than the existential deposit amount. +You can use the `hrmp_channels` keyword to define further parameters for the XCM channels at start-up. The available keys are: -If an account balance drops below this amount, the Balances pallet uses [a FRAME System API](https://paritytech.github.io/substrate/master/frame_system/pallet/struct.Pallet.html#method.dec_ref){target=\_blank} to drop its references to that account. +- **`hrmp_channels`** ++"HrmpChannelsConfig[]"++: Array of Horizontal Relay-routed Message Passing (HRMP) channel configurations. -If the Balances pallet reference to an account is dropped, the account can be [reaped](https://paritytech.github.io/substrate/master/frame_system/pallet/struct.Pallet.html#method.allow_death){target=\_blank}. + ??? child "`HrmpChannelsConfig` interface definition" + ```js + export interface HrmpChannelsConfig { + sender: number; + recipient: number; + max_capacity: number; + max_message_size: number; + } + ``` + Each of the `HrmpChannelsConfig` keys are defined as follows: -## Extrinsic + - **`sender` ++"number"++**: Parachain ID of the sender. + - **`recipient` ++"number"++**: Parachain ID of the recipient. + - **`max_capacity` ++"number"++**: Maximum capacity of the HRMP channel. + - **`max_message_size` ++"number"++**: Maximum message size allowed in the HRMP channel. -A general term for data that originates outside the runtime, is included in a block, and leads to some action. This includes user-initiated transactions and inherent transactions placed into the block by the block builder. +## Where to Go Next -It is a SCALE-encoded array typically consisting of a version number, signature, and varying data types indicating the resulting runtime function to be called. Extrinsics can take two forms: [inherents](#inherent-transactions) and [transactions](#transaction). +
-For more technical details, see the [Polkadot spec](https://spec.polkadot.network/id-extrinsics){target=\_blank}. +- External __Zombienet Support__ -## Fork Choice Rule/Strategy + --- -A fork choice rule or strategy helps determine which chain is valid when reconciling several network forks. A common fork choice rule is the [longest chain](https://paritytech.github.io/polkadot-sdk/master/sc_consensus/struct.LongestChain.html){target=\_blank}, in which the chain with the most blocks is selected. + [Parity Technologies](https://www.parity.io/){target=\_blank} has designed and developed this framework, now maintained by the Zombienet team. -## FRAME (Framework for Runtime Aggregation of Modularized Entities) + For further support and information, refer to the following contact points: -Enables developers to create blockchain [runtime](#runtime) environments from a modular set of components called [pallets](#pallet). It utilizes a set of procedural macros to construct runtimes. + [:octicons-arrow-right-24: Zombienet repository](https://github.com/paritytech/zombienet){target=\_blank} -[Visit the Polkadot SDK docs for more details on FRAME.](https://paritytech.github.io/polkadot-sdk/master/polkadot_sdk_docs/polkadot_sdk/frame_runtime/index.html){target=\_blank} + [:octicons-arrow-right-24: Element public channel](https://matrix.to/#/!FWyuEyNvIFygLnWNMh:parity.io?via=parity.io&via=matrix.org&via=web3.foundation){target=\_blank} -## Full Node -A node that prunes historical states, keeping only recently finalized block states to reduce storage needs. Full nodes provide current chain state access and allow direct submission and validation of [extrinsics](#extrinsic), maintaining network decentralization. +- Tutorial __Spawn a Basic Chain with Zombienet__ -## Genesis Configuration + --- -A mechanism for specifying the initial state of a blockchain. By convention, this initial state or first block is commonly referred to as the genesis state or genesis block. The genesis configuration for Polkadot SDK-based chains is accomplished by way of a [chain specification](#chain-specification) file. + Learn to spawn, connect to and monitor a basic blockchain network with Zombienet, using customizable configurations for streamlined development and debugging. -## GRANDPA + [:octicons-arrow-right-24: Reference](/tutorials/polkadot-sdk/testing/spawn-basic-chain/) -A deterministic finality mechanism for blockchains that is implemented in the [Rust](https://www.rust-lang.org/){target=\_blank} programming language. +
-The [formal specification](https://github.com/w3f/consensus/blob/master/pdf/grandpa-old.pdf){target=\_blank} is maintained by the [Web3 Foundation](https://web3.foundation/){target=\_blank}. -## Header +--- -A structure that aggregates the information used to summarize a block. Primarily, it consists of cryptographic information used by [light clients](#light-client) to get minimally secure but very efficient chain synchronization. +Page Title: Get Started with Parachain Development -## Hybrid Consensus +- Source (raw): https://raw.githubusercontent.com/polkadot-developers/polkadot-docs/master/.ai/pages/parachains-get-started.md +- Canonical (HTML): https://docs.polkadot.com/parachains/get-started/ +- Summary: Practical examples and tutorials for building and deploying Polkadot parachains, covering everything from launch to customization and cross-chain messaging. -A blockchain consensus protocol that consists of independent or loosely coupled mechanisms for [block production](#block-author) and finality. +# Get Started -Hybrid consensus allows the chain to grow as fast as probabilistic consensus protocols, such as [Aura](#authority-round-aura), while maintaining the same level of security as deterministic finality consensus protocols, such as [GRANDPA](#grandpa). +The following sections provide practical recipes for building parachains on Polkadot—each focused on specific development scenarios with step-by-step, hands-on examples. -## Inherent Transactions +## Quick Start Guides -A special type of unsigned transaction, referred to as _inherents_, that enables a block authoring node to insert information that doesn't require validation directly into a block. +Quick start guides help developers set up and interact with the Polkadot parachain ecosystem using various tools and frameworks. -Only the block-authoring node that calls the inherent transaction function can insert data into its block. In general, validators assume the data inserted using an inherent transaction is valid and reasonable even if it can't be deterministically verified. +| Tutorial | Tools | Description | +| :--------------------------------------------------------------------------------------------: | :----------------------------: | :---------------------------------------------------------------------: | +| [Set Up the Parachain Template](/parachains/launch-a-parachain/set-up-the-parachain-template/) | Polkadot SDK | Learn how to set up and run the Polkadot SDK Parachain Template locally | +| [Launch a Local Parachain](/parachains/testing/run-a-parachain-network/) | Zombienet, Chopsticks | Set up a local development environment for testing | +| [Connect to Polkadot](/chain-interactions/query-on-chain-data/query-sdks/) | Polkadot.js, Substrate Connect | Connect your application to Polkadot networks | +| [Fork an Existing Parachain](/parachains/testing/fork-a-parachain/) | Chopsticks | Create a local fork of a live parachain for testing | -## JSON-RPC +## Launch a Simple Parachain -A stateless, lightweight remote procedure call protocol encoded in JavaScript Object Notation (JSON). JSON-RPC provides a standard way to call functions on a remote system by using JSON. +Learn the fundamentals of launching and deploying a parachain to the Polkadot network. -For Polkadot SDK, this protocol is implemented through the [Parity JSON-RPC](https://github.com/paritytech/jsonrpc){target=\_blank} crate. +| Tutorial | Description | +| :--------------------------------------------------------------------------------------------: | :-----------------------------------------------------------------------: | +| [Set Up the Parachain Template](/parachains/launch-a-parachain/set-up-the-parachain-template/) | Polkadot SDK | +| [Deploy to Polkadot](/parachains/launch-a-parachain/deploy-to-polkadot/) | Step-by-step tutorial to deploying your parachain to Polkadot | +| [Obtain Coretime](/parachains/launch-a-parachain/obtain-coretime/) | Learn how to acquire blockspace using Polkadot's coretime model (RegionX) | -## Keystore +## Customize Your Runtime -A subsystem for managing keys for the purpose of producing new blocks. +Build custom functionality for your parachain by composing and creating pallets. -## Kusama +| Tutorial | Description | +| :-------------------------------------------------------------------------------------------------: | :---------------------------------------------------------------: | +| [Add Existing Pallets to the Runtime](/parachains/customize-runtime/add-existing-pallets/) | Integrate pre-built pallets from the FRAME ecosystem | +| [Add Multiple Instances of a Pallet](/parachains/customize-runtime/add-pallet-instances/) | Configure and use multiple instances of the same pallet | +| [Add Smart Contract Functionality](/parachains/customize-runtime/add-smart-contract-functionality/) | Enable smart contract capabilities using Contracts or EVM pallets | -[Kusama](https://kusama.network/){target=\_blank} is a Polkadot SDK-based blockchain that implements a design similar to the [Polkadot](#polkadot) network. +### Pallet Development -Kusama is a [canary](https://en.wiktionary.org/wiki/canary_in_a_coal_mine){target=\_blank} network and is referred to as [Polkadot's "wild cousin."](https://wiki.polkadot.com/learn/learn-comparisons-kusama/){target=\_blank}. +Deep dive into creating and managing custom pallets for your parachain. -As a canary network, Kusama is expected to be more stable than a test network like [Westend](#westend) but less stable than a production network like [Polkadot](#polkadot). Kusama is controlled by its network participants and is intended to be stable enough to encourage meaningful experimentation. +| Tutorial | Description | +| :--------------------------------------------------------------------------------------------------------------: | :-------------------------------------------------------: | +| [Create a Custom Pallet](/parachains/customize-runtime/pallet-development/create-a-pallet/) | Build a pallet from scratch with custom logic | +| [Mock Your Runtime](/parachains/customize-runtime/pallet-development/mock-runtime/) | Set up a mock runtime environment for testing | +| [Pallet Unit Testing](/parachains/customize-runtime/pallet-development/pallet-testing/) | Write comprehensive tests for your pallet logic | +| [Add Your Custom Pallet to the Runtime](/parachains/customize-runtime/pallet-development/add-pallet-to-runtime/) | Integrate your custom pallet into your parachain runtime | +| [Benchmark the Custom Pallet](/parachains/customize-runtime/pallet-development/benchmark-pallet/) | Measure and optimize pallet performance with benchmarking | -## libp2p +## Testing -A peer-to-peer networking stack that allows the use of many transport mechanisms, including WebSockets (usable in a web browser). +Test your parachain in various environments before production deployment. -Polkadot SDK uses the [Rust implementation](https://github.com/libp2p/rust-libp2p){target=\_blank} of the `libp2p` networking stack. +| Tutorial | Description | +| :---------------------------------------------------------------------: | :-----------------------------------------------------: | +| [Fork a Parachain](/parachains/testing/fork-a-parachain/) | Use Chopsticks to create a local fork for testing | +| [Run a Parachain Network](/parachains/testing/run-a-parachain-network/) | Launch a complete parachain test network with Zombienet | -## Light Client +## Runtime Upgrades and Maintenance -A type of blockchain node that doesn't store the [chain state](#state) or produce blocks. +Manage your parachain's lifecycle with forkless upgrades and maintenance operations. -A light client can verify cryptographic primitives and provides a [remote procedure call (RPC)](https://en.wikipedia.org/wiki/Remote_procedure_call){target=\_blank} server, enabling blockchain users to interact with the network. +| Tutorial | Description | +| :-----------------------------------------------------------------------: | :--------------------------------------------------: | +| [Runtime Upgrades](/parachains/runtime-maintenance/runtime-upgrades/) | Perform forkless runtime upgrades via governance | +| [Storage Migrations](/parachains/runtime-maintenance/storage-migrations/) | Safely migrate storage when updating runtime logic | +| [Unlock Parachains](/parachains/runtime-maintenance/unlock-parachains/) | Understand parachain lifecycle and unlock mechanisms | -## Metadata +## Interoperability -Data that provides information about one or more aspects of a system. -The metadata that exposes information about a Polkadot SDK blockchain enables you to interact with that system. +Configure your parachain for cross-chain communication using XCM (Cross-Consensus Messaging). -## Nominated Proof of Stake (NPoS) +| Tutorial | Description | +| :--------------------------------------------------------------------------------------------------------: | :----------------------------------------------------: | +| [Open HRMP Channels Between Parachains](/parachains/interoperability/channels-between-parachains/) | Establish communication channels with other parachains | +| [Open HRMP Channels with System Parachains](/parachains/interoperability/channels-with-system-parachains/) | Connect with Asset Hub and other system parachains | -A method for determining [validators](#validator) or _[authorities](#authority)_ based on a willingness to commit their stake to the proper functioning of one or more block-producing nodes. +## Integrations -## Oracle +Integrate your parachain with essential ecosystem tools and services. -An entity that connects a blockchain to a non-blockchain data source. Oracles enable the blockchain to access and act upon information from existing data sources and incorporate data from non-blockchain systems and services. +| Tutorial | Description | +| :--------------------------------------------: | :----------------------------------------------------: | +| [Wallets](/parachains/integrations/wallets/) | Integrate wallet support for user interactions | +| [Indexers](/parachains/integrations/indexers/) | Set up indexing solutions for querying blockchain data | +| [Oracles](/parachains/integrations/oracles/) | Connect your parachain to off-chain data sources | -## Origin +## Additional Resources -A [FRAME](#frame-framework-for-runtime-aggregation-of-modularized-entities) primitive that identifies the source of a [dispatched](#dispatchable) function call into the [runtime](#runtime). The FRAME System pallet defines three built-in [origins](#origin). As a [pallet](#pallet) developer, you can also define custom origins, such as those defined by the [Collective pallet](https://paritytech.github.io/substrate/master/pallet_collective/enum.RawOrigin.html){target=\_blank}. +- [Polkadot SDK Documentation](https://paritytech.github.io/polkadot-sdk/master/polkadot_sdk_docs/polkadot_sdk/index.html) +- [Polkadot Wiki - Parachains](https://wiki.polkadot.network/docs/learn-parachains/) -## Pallet -A module that can be used to extend the capabilities of a [FRAME](#frame-framework-for-runtime-aggregation-of-modularized-entities)-based [runtime](#runtime). -Pallets bundle domain-specific logic with runtime primitives like [events](#events) and [storage items](#storage-item). +--- -## Parachain +Page Title: Get Started with Smart Contracts -A parachain is a blockchain that derives shared infrastructure and security from a _[relay chain](#relay-chain)_. -You can learn more about parachains on the [Polkadot Wiki](https://wiki.polkadot.com/learn/learn-parachains/){target=\_blank}. +- Source (raw): https://raw.githubusercontent.com/polkadot-developers/polkadot-docs/master/.ai/pages/smart-contracts-get-started.md +- Canonical (HTML): https://docs.polkadot.com/smart-contracts/get-started/ +- Summary: Practical examples for building and deploying smart contracts on Polkadot Hub, from connecting and tooling to deployment, integrations, and precompiles. -## Paseo +# Get Started -Paseo TestNet provisions testing on Polkadot's "production" runtime, which means less chance of feature or code mismatch when developing parachain apps. Specifically, after the [Polkadot Technical fellowship](https://wiki.polkadot.com/learn/learn-polkadot-technical-fellowship/){target=\_blank} proposes a runtime upgrade for Polkadot, this TestNet is updated, giving a period where the TestNet will be ahead of Polkadot to allow for testing. +This resource provides quick-starts for building smart contracts on Polkadot Hub. Use the tables below to jump directly to the tools and workflows you need. -## Polkadot +## Quick Starts -The [Polkadot network](https://polkadot.com/){target=\_blank} is a blockchain that serves as the central hub of a heterogeneous blockchain network. It serves the role of the [relay chain](#relay-chain) and provides shared infrastructure and security to support [parachains](#parachain). +Kick off development fast with curated links for connecting, funding, exploring, and deploying your first contract. -## Polkadot Cloud +| Quick Start | Tools | Description | +| :-------------------------------------------------------------------------------------------------: | :-------------------: | :-------------------------------------------------------------: | +| [Connect to Polkadot](/smart-contracts/connect/){target=\_blank} | Polkadot.js, MetaMask | Add the network, configure RPC, verify activity in the explorer | +| [Get Test Tokens](/smart-contracts/faucets/){target=\_blank} | - | Request test funds to deploy and interact with contracts | +| [Explore Transactions](/smart-contracts/explorers/){target=\_blank} | Subscan | Inspect transactions, logs, token transfers, and contract state | +| [Deploy with Remix](/smart-contracts/dev-environments/remix/deploy-a-contract/){target=\_blank} | Remix | One‑click browser deployment to Polkadot Hub | +| [Deploy with Foundry](/smart-contracts/dev-environments/foundry/deploy-a-contract/){target=\_blank} | Foundry | Scripted deployments and testing from the CLI | +| [Deploy with Hardhat](/smart-contracts/dev-environments/hardhat/deploy-a-contract/){target=\_blank} | Hardhat | Project scaffolding, testing, and deployments | -Polkadot Cloud is a platform for deploying resilient, customizable and scalable Web3 applications through Polkadot's functionality. It encompasses the wider Polkadot network infrastructure and security layer where parachains operate. The platform enables users to launch Ethereum-compatible chains, build specialized blockchains, and flexibly manage computing resources through on-demand or bulk coretime purchases. Initially launched with basic parachain functionality, Polkadot Cloud has evolved to offer enhanced flexibility with features like coretime, elastic scaling, and async backing for improved performance. +## Build and Test Locally -## Polkadot Hub +Set up local environments and CI-friendly workflows to iterate quickly and validate changes before deploying. -Polkadot Hub is a Layer 1 platform that serves as the primary entry point to the Polkadot ecosystem, providing essential functionality without requiring parachain deployment. It offers core services including smart contracts, identity management, staking, governance, and interoperability with other ecosystems, making it simple and fast for both builders and users to get started in Web3. +| Build and Test Locally | Tools | Description | +| :--------------------------------------------------------------------------------------------------------: | :---------------: | :--------------------------------------------------: | +| [Run a Local Dev Node](/smart-contracts/dev-environments/local-dev-node/){target=\_blank} | Polkadot SDK node | Spin up a local node for iterative development | +| [Remix: Get Started](/smart-contracts/dev-environments/remix/get-started/){target=\_blank} | Remix | Connect Remix to Polkadot Hub and configure accounts | +| [Remix: Verify a Contract](/smart-contracts/dev-environments/remix/verify-a-contract/){target=\_blank} | Remix | Publish verified source on explorers | +| [Foundry: Install and Config](/smart-contracts/dev-environments/foundry/install-and-config/){target=\_blank} | Foundry | Install toolchain and configure networks | +| [Foundry: Compile and Test](/smart-contracts/dev-environments/foundry/compile-and-test/){target=\_blank} | Foundry | Write and run Solidity tests locally | +| [Foundry: Verify a Contract](/smart-contracts/dev-environments/foundry/verify-a-contract/){target=\_blank} | Foundry | Verify deployed bytecode and metadata | +| [Hardhat: Install and Config](/smart-contracts/dev-environments/hardhat/install-and-config/){target=\_blank} | Hardhat | Initialize a project and configure networks | +| [Hardhat: Compile and Test](/smart-contracts/dev-environments/hardhat/compile-and-test/){target=\_blank} | Hardhat | Unit test contracts and run scripts | +| [Hardhat: Verify a Contract](/smart-contracts/dev-environments/hardhat/verify-a-contract/){target=\_blank} | Hardhat | Verify deployments on explorers | -## PolkaVM +## Ethereum Developer Resources -PolkaVM is a custom virtual machine optimized for performance, leveraging a RISC-V-based architecture to support Solidity and any language that compiles to RISC-V. It is specifically designed for the Polkadot ecosystem, enabling smart contract deployment and execution. +Bridge your Ethereum knowledge with Polkadot Hub specifics: account mapping, fees, JSON‑RPC, and deployment. -## Relay Chain +| Ethereum Developer Guides | Description | +| :-------------------------------------------------------------------------------------------------------: | :-------------------------------------------------------------: | +| [Accounts](/smart-contracts/for-eth-devs/accounts/){target=\_blank} | How 20‑byte Ethereum addresses map to 32‑byte Polkadot accounts | +| [Blocks, Transactions, and Fees](/smart-contracts/for-eth-devs/blocks-transactions-fees/){target=\_blank} | Transaction types, fees, and multi‑dimensional metering | +| [Gas Model](/smart-contracts/for-eth-devs/gas-model/){target=\_blank} | Gas vs. weight, proof size, and storage deposits | +| [Contract Deployment](/smart-contracts/for-eth-devs/contract-deployment/){target=\_blank} | Deployment patterns and best practices on Polkadot Hub | +| [JSON‑RPC APIs](/smart-contracts/for-eth-devs/json-rpc-apis/){target=\_blank} | Supported Ethereum JSON‑RPC methods and examples | +| [Migration](/smart-contracts/for-eth-devs/migration/){target=\_blank} | Port existing apps and tooling to Polkadot Hub | +| [Dual VM Stack](/smart-contracts/for-eth-devs/dual-vm-stack/){target=\_blank} | Overview of EVM and native execution on the Hub | -Relay chains are blockchains that provide shared infrastructure and security to the [parachains](#parachain) in the network. In addition to providing [consensus](#consensus) capabilities, relay chains allow parachains to communicate and exchange digital assets without needing to trust one another. +## Cookbook: Hands‑on Tutorials -## Rococo +Follow step‑by‑step guides that walk through common tasks and complete dApp examples. -A [parachain](#parachain) test network for the Polkadot network. The [Rococo](#rococo) network is a Polkadot SDK-based blockchain with an October 14, 2024 deprecation date. Development teams are encouraged to use the Paseo TestNet instead. +| Tutorial | Tools | Description | +| :------------------------------------------------------------------------------------------------: | :-----------------: | :---------------------------------------: | +| [Deploy a Basic Contract](/smart-contracts/cookbook/smart-contracts/deploy-basic/){target=\_blank} | Remix | Minimal deployment walkthrough | +| [Deploy an ERC‑20](/smart-contracts/cookbook/smart-contracts/deploy-erc20/){target=\_blank} | Remix, OpenZeppelin | Create, deploy, and mint a fungible token | +| [Deploy an NFT (ERC‑721)](/smart-contracts/cookbook/smart-contracts/deploy-nft/){target=\_blank} | Remix, OpenZeppelin | Build and deploy an NFT collection | +| [Uniswap V2](/smart-contracts/cookbook/eth-dapps/uniswap-v2/){target=\_blank} | Hardhat | Full dApp project: compile, test, deploy | +| [Zero‑to‑Hero dApp](/smart-contracts/cookbook/dapps/zero-to-hero/){target=\_blank} | Multiple | End‑to‑end dApp patterns and practices | -## Runtime +## Libraries -The runtime represents the [state transition function](#state-transition-function-stf) for a blockchain. In Polkadot SDK, the runtime is stored as a [Wasm](#webassembly-wasm) binary in the chain state. The Runtime is stored under a unique state key and can be modified during the execution of the state transition function. +Choose the client libraries that fit your stack for connecting wallets and calling contracts. -## Slot +| Library | Description | +| :----------------------------------------------------------------: | :-----------------------------------------------------: | +| [Ethers.js](/smart-contracts/libraries/ethers-js/){target=\_blank} | Connect, sign, and interact with contracts using Ethers | +| [viem](/smart-contracts/libraries/viem/){target=\_blank} | Type‑safe EVM interactions and utilities | +| [Wagmi](/smart-contracts/libraries/wagmi/){target=\_blank} | React hooks for wallet connections and contract calls | +| [Web3.js](/smart-contracts/libraries/web3-js/){target=\_blank} | Web3 provider and contract APIs | +| [Web3.py](/smart-contracts/libraries/web3-py/){target=\_blank} | Python toolkit for on‑chain interactions and scripts | -A fixed, equal interval of time used by consensus engines such as [Aura](#authority-round-aura) and [BABE](#blind-assignment-of-blockchain-extension-babe). In each slot, a subset of [authorities](#authority) is permitted, or obliged, to [author](#block-author) a block. +## Integrations -## Sovereign Account +Integrate essential services like wallets, indexers, and oracles to round out your dApp. -The unique account identifier for each chain in the relay chain ecosystem. It is often used in cross-consensus (XCM) interactions to sign XCM messages sent to the relay chain or other chains in the ecosystem. +| Integration | Description | +| :-----------------------------------------------------------------: | :---------------------------------------: | +| [Wallets](/smart-contracts/integrations/wallets/){target=\_blank} | Supported wallets and configuration notes | +| [Indexers](/smart-contracts/integrations/indexers/){target=\_blank} | Index and query blockchain data | +| [Oracles](/smart-contracts/integrations/oracles/){target=\_blank} | Bring external data on‑chain | -The sovereign account for each chain is a root-level account that can only be accessed using the Sudo pallet or through governance. The account identifier is calculated by concatenating the Blake2 hash of a specific text string and the registered parachain identifier. +## Precompiles -## SS58 Address Format +Discover precompiled system contracts available on the Hub and how to use them. -A public key address based on the Bitcoin [`Base-58-check`](https://en.bitcoin.it/wiki/Base58Check_encoding){target=\_blank} encoding. Each Polkadot SDK SS58 address uses a `base-58` encoded value to identify a specific account on a specific Polkadot SDK-based chain +| Topic | Description | +| :----------------------------------------------------------------------: | :-------------------------------------------------: | +| [Overview of Precompiles](/smart-contracts/precompiles/){target=\_blank} | What precompiles are available on the Hub | +| [ETH Native](/smart-contracts/precompiles/eth-native/){target=\_blank} | EVM precompiles and interfaces | +| [Staking](/smart-contracts/precompiles/staking/){target=\_blank} | Interact with staking functionality via precompiles | +| [XCM](/smart-contracts/precompiles/xcm/){target=\_blank} | Cross‑chain messaging helpers for contracts | -The [canonical `ss58-registry`](https://github.com/paritytech/ss58-registry){target=\_blank} provides additional details about the address format used by different Polkadot SDK-based chains, including the network prefix and website used for different networks +From here, follow the quick starts to get connected, iterate locally with your preferred tools, and use the guides, libraries, integrations, and precompiles as you grow into production‑ready dApps. If you get stuck, [open an issue](https://github.com/polkadot-developers/polkadot-docs/issues/new?template=docs-issue.yml){target=\_blank} or reach out in the community channels. -## State Transition Function (STF) -The logic of a blockchain that determines how the state changes when a block is processed. In Polkadot SDK, the state transition function is effectively equivalent to the [runtime](#runtime). +--- -## Storage Item +Page Title: Glossary -[FRAME](#frame-framework-for-runtime-aggregation-of-modularized-entities) primitives that provide type-safe data persistence capabilities to the [runtime](#runtime). -Learn more in the [storage items](https://paritytech.github.io/polkadot-sdk/master/frame_support/storage/types/index.html){target=\_blank} reference document in the Polkadot SDK. +- Source (raw): https://raw.githubusercontent.com/polkadot-developers/polkadot-docs/master/.ai/pages/reference-glossary.md +- Canonical (HTML): https://docs.polkadot.com/reference/glossary/ +- Summary: Glossary of terms used within the Polkadot ecosystem, Polkadot SDK, its subsequent libraries, and other relevant Web3 terminology. -## Substrate +# Glossary -A flexible framework for building modular, efficient, and upgradeable blockchains. Substrate is written in the [Rust](https://www.rust-lang.org/){target=\_blank} programming language and is maintained by [Parity Technologies](https://www.parity.io/){target=\_blank}. +Key definitions, concepts, and terminology specific to the Polkadot ecosystem are included here. -## Transaction +Additional glossaries from around the ecosystem you might find helpful: -An [extrinsic](#extrinsic) that includes a signature that can be used to verify the account authorizing it inherently or via [signed extensions](https://paritytech.github.io/polkadot-sdk/master/polkadot_sdk_docs/reference_docs/signed_extensions/index.html){target=\_blank}. +- [Polkadot Wiki Glossary](https://wiki.polkadot.com/general/glossary){target=\_blank} +- [Polkadot SDK Glossary](https://paritytech.github.io/polkadot-sdk/master/polkadot_sdk_docs/reference_docs/glossary/index.html){target=\_blank} -## Transaction Era +## Authority -A definable period expressed as a range of block numbers during which a transaction can be included in a block. -Transaction eras are used to protect against transaction replay attacks if an account is reaped and its replay-protecting nonce is reset to zero. +The role in a blockchain that can participate in consensus mechanisms. -## Trie (Patricia Merkle Tree) +- **[GRANDPA](#grandpa)**: The authorities vote on chains they consider final. +- **[Blind Assignment of Blockchain Extension](#blind-assignment-of-blockchain-extension-babe) (BABE)**: The authorities are also [block authors](#block-author). -A data structure used to represent sets of key-value pairs and enables the items in the data set to be stored and retrieved using a cryptographic hash. Because incremental changes to the data set result in a new hash, retrieving data is efficient even if the data set is very large. With this data structure, you can also prove whether the data set includes any particular key-value pair without access to the entire data set. +Authority sets can be used as a basis for consensus mechanisms such as the [Nominated Proof of Stake (NPoS)](#nominated-proof-of-stake-npos) protocol. -In Polkadot SDK-based blockchains, state is stored in a trie data structure that supports the efficient creation of incremental digests. This trie is exposed to the [runtime](#runtime) as [a simple key/value map](#storage-item) where both keys and values can be arbitrary byte arrays. +## Authority Round (Aura) -## Validator +A deterministic [consensus](#consensus) protocol where block production is limited to a rotating list of [authorities](#authority) that take turns creating blocks. In authority round (Aura) consensus, most online authorities are assumed to be honest. It is often used in combination with [GRANDPA](#grandpa) as a [hybrid consensus](#hybrid-consensus) protocol. -A validator is a node that participates in the consensus mechanism of the network. Its roles include block production, transaction validation, network integrity, and security maintenance. +Learn more by reading the official [Aura consensus algorithm](https://openethereum.github.io/Aura){target=\_blank} wiki article. -## WebAssembly (Wasm) +## Blind Assignment of Blockchain Extension (BABE) -An execution architecture that allows for the efficient, platform-neutral expression of -deterministic, machine-executable logic. +A [block authoring](#block-author) protocol similar to [Aura](#authority-round-aura), except [authorities](#authority) win [slots](#slot) based on a Verifiable Random Function (VRF) instead of the round-robin selection method. The winning authority can select a chain and submit a new block. -[Wasm](https://webassembly.org/){target=\_blank} can be compiled from many languages, including -the [Rust](https://www.rust-lang.org/){target=\_blank} programming language. Polkadot SDK-based chains use a Wasm binary to provide portable [runtimes](#runtime) that can be included as part of the chain's state. +Learn more by reading the official Web3 Foundation [BABE research document](https://research.web3.foundation/Polkadot/protocols/block-production/Babe){target=\_blank}. -## Weight +## Block Author -A convention used in Polkadot SDK-based blockchains to measure and manage the time it takes to validate a block. -Polkadot SDK defines one unit of weight as one picosecond of execution time on reference hardware. +The node responsible for the creation of a block, also called _block producers_. In a Proof of Work (PoW) blockchain, these nodes are called _miners_. -The maximum block weight should be equivalent to one-third of the target block time with an allocation of one-third each for: +## Byzantine Fault Tolerance (BFT) -- Block construction -- Network propagation -- Import and verification +The ability of a distributed computer network to remain operational if a certain proportion of its nodes or [authorities](#authority) are defective or behaving maliciously. A distributed network is typically considered Byzantine fault tolerant if it can remain functional, with up to one-third of nodes assumed to be defective, offline, actively malicious, and part of a coordinated attack. -By defining weights, you can trade-off the number of transactions per second and the hardware required to maintain the target block time appropriate for your use case. Weights are defined in the runtime, meaning you can tune them using runtime updates to keep up with hardware and software improvements. +### Byzantine Failure -## Westend +The loss of a network service due to node failures that exceed the proportion of nodes required to reach consensus. -Westend is a Parity-maintained, Polkadot SDK-based blockchain that serves as a test network for the [Polkadot](#polkadot) network. +### Practical Byzantine Fault Tolerance (pBFT) +An early approach to Byzantine fault tolerance (BFT), practical Byzantine fault tolerance (pBFT) systems tolerate Byzantine behavior from up to one-third of participants. ---- +The communication overhead for such systems is `O(n²)`, where `n` is the number of nodes (participants) in the system. -Page Title: Install Polkadot SDK Dependencies +### Preimage -- Source (raw): https://raw.githubusercontent.com/polkadot-developers/polkadot-docs/master/.ai/pages/parachains-install-polkadot-sdk.md -- Canonical (HTML): https://docs.polkadot.com/parachains/install-polkadot-sdk/ -- Summary: Install everything you need to begin working with Substrated-based blockchains and the Polkadot SDK, the framework for building blockchains. +A preimage is the data that is input into a hash function to calculate a hash. Since a hash function is a [one-way function](https://en.wikipedia.org/wiki/One-way_function){target=\_blank}, the output, the hash, cannot be used to reveal the input, the preimage. -# Install Polkadot SDK Dependencies +## Call -This guide provides step-by-step instructions for installing the dependencies you need to work with the Polkadot SDK-based chains on macOS, Linux, and Windows. Follow the appropriate section for your operating system to ensure all necessary tools are installed and configured properly. +In the context of pallets containing functions to be dispatched to the runtime, `Call` is an enumeration data type that describes the functions that can be dispatched with one variant per pallet. A `Call` represents a [dispatch](#dispatchable) data structure object. -## macOS +## Chain Specification -You can install Rust and set up a Substrate development environment on Apple macOS computers with Intel or Apple M1 processors. +A chain specification file defines the properties required to run a node in an active or new Polkadot SDK-built network. It often contains the initial genesis runtime code, network properties (such as the network's name), the initial state for some pallets, and the boot node list. The chain specification file makes it easy to use a single Polkadot SDK codebase as the foundation for multiple independently configured chains. -### Before You Begin +## Collator -Before you install Rust and set up your development environment on macOS, verify that your computer meets the following basic requirements: +An [author](#block-author) of a [parachain](#parachain) network. +They aren't [authorities](#authority) in themselves, as they require a [relay chain](#relay-chain) to coordinate [consensus](#consensus). -- Operating system version is 10.7 Lion or later. -- Processor speed of at least 2 GHz. Note that 3 GHz is recommended. -- Memory of at least 8 GB RAM. Note that 16 GB is recommended. -- Storage of at least 10 GB of available space. -- Broadband Internet connection. +More details are found on the [Polkadot Collator Wiki](https://wiki.polkadot.com/learn/learn-collator/){target=\_blank}. -#### Install Homebrew +## Collective -In most cases, you should use Homebrew to install and manage packages on macOS computers. If you don't already have Homebrew installed on your local computer, you should download and install it before continuing. +Most often used to refer to an instance of the Collective pallet on Polkadot SDK-based networks such as [Kusama](#kusama) or [Polkadot](#polkadot) if the Collective pallet is part of the FRAME-based runtime for the network. -To install Homebrew: +## Consensus -1. Open the Terminal application. -2. Download and install Homebrew by running the following command: +Consensus is the process blockchain nodes use to agree on a chain's canonical fork. It is composed of [authorship](#block-author), finality, and [fork-choice rule](#fork-choice-rulestrategy). In the Polkadot ecosystem, these three components are usually separate and the term consensus often refers specifically to authorship. - ```bash - /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install.sh)" - ``` +See also [hybrid consensus](#hybrid-consensus). -3. Verify Homebrew has been successfully installed by running the following command: +## Consensus Algorithm - ```bash - brew --version - ``` +Ensures a set of [actors](#authority)—who don't necessarily trust each other—can reach an agreement about the state as the result of some computation. Most consensus algorithms assume that up to one-third of the actors or nodes can be [Byzantine fault tolerant](#byzantine-fault-tolerance-bft). - The command displays output similar to the following: +Consensus algorithms are generally concerned with ensuring two properties: -
- brew --version - Homebrew 4.3.15 -
+- **Safety**: Indicating that all honest nodes eventually agreed on the state of the chain. +- **Liveness**: Indicating the ability of the chain to keep progressing. -#### Support for Apple Silicon +## Consensus Engine -Protobuf must be installed before the build process can begin. To install it, run the following command: +The node subsystem responsible for consensus tasks. -```bash -brew install protobuf -``` +For detailed information about the consensus strategies of the [Polkadot](#polkadot) network, see the [Polkadot Consensus](/reference/polkadot-hub/consensus-and-security/pos-consensus/){target=\_blank} blog series. -### Install Required Packages and Rust +See also [hybrid consensus](#hybrid-consensus). -Because the blockchain requires standard cryptography to support the generation of public/private key pairs and the validation of transaction signatures, you must also have a package that provides cryptography, such as `openssl`. +## Coretime -To install `openssl` and the Rust toolchain on macOS: +The time allocated for utilizing a core, measured in relay chain blocks. There are two types of coretime: *on-demand* and *bulk*. -1. Open the Terminal application. -2. Ensure you have an updated version of Homebrew by running the following command: +On-demand coretime refers to coretime acquired through bidding in near real-time for the validation of a single parachain block on one of the cores reserved specifically for on-demand orders. They are available as an on-demand coretime pool. Set of cores that are available on-demand. Cores reserved through bulk coretime could also be made available in the on-demand coretime pool, in parts or in entirety. - ```bash - brew update - ``` +Bulk coretime is a fixed duration of continuous coretime represented by an NFT that can be split, shared, or resold. It is managed by the [Broker pallet](https://paritytech.github.io/polkadot-sdk/master/pallet_broker/index.html){target=\_blank}. -3. Install the `openssl` package by running the following command: +## Development Phrase - ```bash - brew install openssl - ``` +A [mnemonic phrase](https://en.wikipedia.org/wiki/Mnemonic#For_numerical_sequences_and_mathematical_operations){target=\_blank} that is intentionally made public. -4. Download the `rustup` installation program and use it to install Rust by running the following command: +Well-known development accounts, such as Alice, Bob, Charlie, Dave, Eve, and Ferdie, are generated from the same secret phrase: - ```bash - curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh - ``` +``` +bottom drive obey lake curtain smoke basket hold race lonely fit walk +``` -5. Follow the prompts displayed to proceed with a default installation. -6. Update your current shell to include Cargo by running the following command: +Many tools in the Polkadot SDK ecosystem, such as [`subkey`](https://github.com/paritytech/polkadot-sdk/tree/polkadot-stable2506-2/substrate/bin/utils/subkey){target=\_blank}, allow you to implicitly specify an account using a derivation path such as `//Alice`. - ```bash - source ~/.cargo/env - ``` +## Digest -7. Configure the Rust toolchain to default to the latest stable version by running the following commands: +An extensible field of the [block header](#header) that encodes information needed by several actors in a blockchain network, including: - ```bash - rustup default stable - rustup update - rustup target add wasm32-unknown-unknown - rustup component add rust-src - ``` +- [Light clients](#light-client) for chain synchronization. +- Consensus engines for block verification. +- The runtime itself, in the case of pre-runtime digests. -8. [Verify your installation](#verifying-installation). -9. Install `cmake` using the following command: +## Dispatchable - ```bash - brew install cmake - ``` +Function objects that act as the entry points in FRAME [pallets](#pallet). Internal or external entities can call them to interact with the blockchain’s state. They are a core aspect of the runtime logic, handling [transactions](#transaction) and other state-changing operations. -## Linux +## Events -Rust supports most Linux distributions. Depending on the specific distribution and version of the operating system you use, you might need to add some software dependencies to your environment. In general, your development environment should include a linker or C-compatible compiler, such as `clang` and an appropriate integrated development environment (IDE). +A means of recording that some particular [state](#state) transition happened. -### Before You Begin {: #before-you-begin-linux } +In the context of [FRAME](#frame-framework-for-runtime-aggregation-of-modularized-entities), events are composable data types that each [pallet](#pallet) can individually define. Events in FRAME are implemented as a set of transient storage items inspected immediately after a block has been executed and reset during block initialization. -Check the documentation for your operating system for information about the installed packages and how to download and install any additional packages you might need. For example, if you use Ubuntu, you can use the Ubuntu Advanced Packaging Tool (`apt`) to install the `build-essential` package: +## Executor -```bash -sudo apt install build-essential -``` +A means of executing a function call in a given [runtime](#runtime) with a set of dependencies. +There are two orchestration engines in Polkadot SDK, _WebAssembly_ and _native_. -At a minimum, you need the following packages before you install Rust: +- The _native executor_ uses a natively compiled runtime embedded in the node to execute calls. This is a performance optimization available to up-to-date nodes. -```text -clang curl git make -``` +- The _WebAssembly executor_ uses a [Wasm](#webassembly-wasm) binary and a Wasm interpreter to execute calls. The binary is guaranteed to be up-to-date regardless of the version of the blockchain node because it is persisted in the [state](#state) of the Polkadot SDK-based chain. -Because the blockchain requires standard cryptography to support the generation of public/private key pairs and the validation of transaction signatures, you must also have a package that provides cryptography, such as `libssl-dev` or `openssl-devel`. +## Existential Deposit -### Install Required Packages and Rust {: #install-required-packages-and-rust-linux } +The minimum balance an account is allowed to have in the [Balances pallet](https://paritytech.github.io/polkadot-sdk/master/pallet_balances/index.html){target=\_blank}. Accounts cannot be created with a balance less than the existential deposit amount. -To install the Rust toolchain on Linux: +If an account balance drops below this amount, the Balances pallet uses [a FRAME System API](https://paritytech.github.io/substrate/master/frame_system/pallet/struct.Pallet.html#method.dec_ref){target=\_blank} to drop its references to that account. -1. Open a terminal shell. -2. Check the packages you have installed on the local computer by running an appropriate package management command for your Linux distribution. -3. Add any package dependencies you are missing to your local development environment by running the appropriate package management command for your Linux distribution: +If the Balances pallet reference to an account is dropped, the account can be [reaped](https://paritytech.github.io/substrate/master/frame_system/pallet/struct.Pallet.html#method.allow_death){target=\_blank}. - === "Ubuntu" +## Extrinsic - ```bash - sudo apt install --assume-yes git clang curl libssl-dev protobuf-compiler - ``` +A general term for data that originates outside the runtime, is included in a block, and leads to some action. This includes user-initiated transactions and inherent transactions placed into the block by the block builder. - === "Debian" +It is a SCALE-encoded array typically consisting of a version number, signature, and varying data types indicating the resulting runtime function to be called. Extrinsics can take two forms: [inherents](#inherent-transactions) and [transactions](#transaction). - ```sh - sudo apt install --assume-yes git clang curl libssl-dev llvm libudev-dev make protobuf-compiler - ``` +For more technical details, see the [Polkadot spec](https://spec.polkadot.network/id-extrinsics){target=\_blank}. - === "Arch" +## Fork Choice Rule/Strategy - ```sh - pacman -Syu --needed --noconfirm curl git clang make protobuf - ``` +A fork choice rule or strategy helps determine which chain is valid when reconciling several network forks. A common fork choice rule is the [longest chain](https://paritytech.github.io/polkadot-sdk/master/sc_consensus/struct.LongestChain.html){target=\_blank}, in which the chain with the most blocks is selected. - === "Fedora" +## FRAME (Framework for Runtime Aggregation of Modularized Entities) - ```sh - sudo dnf update - sudo dnf install clang curl git openssl-devel make protobuf-compiler - ``` +Enables developers to create blockchain [runtime](#runtime) environments from a modular set of components called [pallets](#pallet). It utilizes a set of procedural macros to construct runtimes. - === "OpenSUSE" +[Visit the Polkadot SDK docs for more details on FRAME.](https://paritytech.github.io/polkadot-sdk/master/polkadot_sdk_docs/polkadot_sdk/frame_runtime/index.html){target=\_blank} - ```sh - sudo zypper install clang curl git openssl-devel llvm-devel libudev-devel make protobuf - ``` +## Full Node - Remember that different distributions might use different package managers and bundle packages in different ways. For example, depending on your installation selections, Ubuntu Desktop and Ubuntu Server might have different packages and different requirements. However, the packages listed in the command-line examples are applicable for many common Linux distributions, including Debian, Linux Mint, MX Linux, and Elementary OS. +A node that prunes historical states, keeping only recently finalized block states to reduce storage needs. Full nodes provide current chain state access and allow direct submission and validation of [extrinsics](#extrinsic), maintaining network decentralization. -4. Download the `rustup` installation program and use it to install Rust by running the following command: +## Genesis Configuration - ```bash - curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh - ``` +A mechanism for specifying the initial state of a blockchain. By convention, this initial state or first block is commonly referred to as the genesis state or genesis block. The genesis configuration for Polkadot SDK-based chains is accomplished by way of a [chain specification](#chain-specification) file. -5. Follow the prompts displayed to proceed with a default installation. -6. Update your current shell to include Cargo by running the following command: +## GRANDPA - ```bash - source $HOME/.cargo/env - ``` +A deterministic finality mechanism for blockchains that is implemented in the [Rust](https://www.rust-lang.org/){target=\_blank} programming language. -7. Verify your installation by running the following command: +The [formal specification](https://github.com/w3f/consensus/blob/master/pdf/grandpa-old.pdf){target=\_blank} is maintained by the [Web3 Foundation](https://web3.foundation/){target=\_blank}. - ```bash - rustc --version - ``` +## Header -8. Configure the Rust toolchain to default to the latest stable version by running the following commands: +A structure that aggregates the information used to summarize a block. Primarily, it consists of cryptographic information used by [light clients](#light-client) to get minimally secure but very efficient chain synchronization. - ```bash - rustup default stable - rustup update - rustup target add wasm32-unknown-unknown - rustup component add rust-src - ``` +## Hybrid Consensus -9. [Verify your installation](#verifying-installation). +A blockchain consensus protocol that consists of independent or loosely coupled mechanisms for [block production](#block-author) and finality. -## Windows (WSL) +Hybrid consensus allows the chain to grow as fast as probabilistic consensus protocols, such as [Aura](#authority-round-aura), while maintaining the same level of security as deterministic finality consensus protocols, such as [GRANDPA](#grandpa). -In general, UNIX-based operating systems—like macOS or Linux—provide a better development environment for building Substrate-based blockchains. +## Inherent Transactions -However, suppose your local computer uses Microsoft Windows instead of a UNIX-based operating system. In that case, you can configure it with additional software to make it a suitable development environment for building Substrate-based blockchains. To prepare a development environment on a Microsoft Windows computer, you can use Windows Subsystem for Linux (WSL) to emulate a UNIX operating environment. +A special type of unsigned transaction, referred to as _inherents_, that enables a block authoring node to insert information that doesn't require validation directly into a block. -### Before You Begin {: #before-you-begin-windows } +Only the block-authoring node that calls the inherent transaction function can insert data into its block. In general, validators assume the data inserted using an inherent transaction is valid and reasonable even if it can't be deterministically verified. -Before installing on Microsoft Windows, verify the following basic requirements: +## JSON-RPC -- You have a computer running a supported Microsoft Windows operating system: - - **For Windows desktop**: You must be running Microsoft Windows 10, version 2004 or later, or Microsoft Windows 11 to install WSL. - - **For Windows server**: You must be running Microsoft Windows Server 2019, or later, to install WSL on a server operating system. -- You have good internet connection and access to a shell terminal on your local computer. +A stateless, lightweight remote procedure call protocol encoded in JavaScript Object Notation (JSON). JSON-RPC provides a standard way to call functions on a remote system by using JSON. -### Set Up Windows Subsystem for Linux +For Polkadot SDK, this protocol is implemented through the [Parity JSON-RPC](https://github.com/paritytech/jsonrpc){target=\_blank} crate. -WSL enables you to emulate a Linux environment on a computer that uses the Windows operating system. The primary advantage of this approach for Substrate development is that you can use all of the code and command-line examples as described in the Substrate documentation. For example, you can run common commands—such as `ls` and `ps`—unmodified. By using WSL, you can avoid configuring a virtual machine image or a dual-boot operating system. +## Keystore -To prepare a development environment using WSL: +A subsystem for managing keys for the purpose of producing new blocks. -1. Check your Windows version and build number to see if WSL is enabled by default. +## Kusama - If you have Microsoft Windows 10, version 2004 (Build 19041 and higher), or Microsoft Windows 11, WSL is available by default and you can continue to the next step. +[Kusama](https://kusama.network/){target=\_blank} is a Polkadot SDK-based blockchain that implements a design similar to the [Polkadot](#polkadot) network. - If you have an older version of Microsoft Windows installed, see the [WSL manual installation steps for older versions](https://learn.microsoft.com/en-us/windows/wsl/install-manual){target=\_blank}. If you are installing on an older version of Microsoft Windows, you can download and install WLS 2 if your computer has Windows 10, version 1903 or higher. +Kusama is a [canary](https://en.wiktionary.org/wiki/canary_in_a_coal_mine){target=\_blank} network and is referred to as [Polkadot's "wild cousin."](https://wiki.polkadot.com/learn/learn-comparisons-kusama/){target=\_blank}. -2. Select **Windows PowerShell** or **Command Prompt** from the **Start** menu, right-click, then **Run as administrator**. +As a canary network, Kusama is expected to be more stable than a test network like [Westend](#westend) but less stable than a production network like [Polkadot](#polkadot). Kusama is controlled by its network participants and is intended to be stable enough to encourage meaningful experimentation. -3. In the PowerShell or Command Prompt terminal, run the following command: +## libp2p - ```bash - wsl --install - ``` +A peer-to-peer networking stack that allows the use of many transport mechanisms, including WebSockets (usable in a web browser). - This command enables the required WSL 2 components that are part of the Windows operating system, downloads the latest Linux kernel, and installs the Ubuntu Linux distribution by default. +Polkadot SDK uses the [Rust implementation](https://github.com/libp2p/rust-libp2p){target=\_blank} of the `libp2p` networking stack. - If you want to review the other Linux distributions available, run the following command: +## Light Client - ```bash - wsl --list --online - ``` +A type of blockchain node that doesn't store the [chain state](#state) or produce blocks. -4. After the distribution is downloaded, close the terminal. +A light client can verify cryptographic primitives and provides a [remote procedure call (RPC)](https://en.wikipedia.org/wiki/Remote_procedure_call){target=\_blank} server, enabling blockchain users to interact with the network. -5. Click the **Start** menu, select **Shut down or sign out**, then click **Restart** to restart the computer. +## Metadata - Restarting the computer is required to start the installation of the Linux distribution. It can take a few minutes for the installation to complete after you restart. +Data that provides information about one or more aspects of a system. +The metadata that exposes information about a Polkadot SDK blockchain enables you to interact with that system. - For more information about setting up WSL as a development environment, see the [Set up a WSL development environment](https://learn.microsoft.com/en-us/windows/wsl/setup/environment){target=\_blank} docs. +## Nominated Proof of Stake (NPoS) -### Install Required Packages and Rust {: #install-required-packages-and-rust-windows } +A method for determining [validators](#validator) or _[authorities](#authority)_ based on a willingness to commit their stake to the proper functioning of one or more block-producing nodes. -To install the Rust toolchain on WSL: +## Oracle -1. Click the **Start** menu, then select **Ubuntu**. -2. Type a UNIX user name to create user account. -3. Type a password for your UNIX user, then retype the password to confirm it. -4. Download the latest updates for the Ubuntu distribution using the Ubuntu Advanced Packaging Tool (`apt`) by running the following command: +An entity that connects a blockchain to a non-blockchain data source. Oracles enable the blockchain to access and act upon information from existing data sources and incorporate data from non-blockchain systems and services. - ```bash - sudo apt update - ``` +## Origin -5. Add the required packages for the Ubuntu distribution by running the following command: +A [FRAME](#frame-framework-for-runtime-aggregation-of-modularized-entities) primitive that identifies the source of a [dispatched](#dispatchable) function call into the [runtime](#runtime). The FRAME System pallet defines three built-in [origins](#origin). As a [pallet](#pallet) developer, you can also define custom origins, such as those defined by the [Collective pallet](https://paritytech.github.io/substrate/master/pallet_collective/enum.RawOrigin.html){target=\_blank}. - ```bash - sudo apt install --assume-yes git clang curl libssl-dev llvm libudev-dev make protobuf-compiler - ``` +## Pallet -6. Download the `rustup` installation program and use it to install Rust for the Ubuntu distribution by running the following command: +A module that can be used to extend the capabilities of a [FRAME](#frame-framework-for-runtime-aggregation-of-modularized-entities)-based [runtime](#runtime). +Pallets bundle domain-specific logic with runtime primitives like [events](#events) and [storage items](#storage-item). - ```bash - curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh - ``` +## Parachain -7. Follow the prompts displayed to proceed with a default installation. +A parachain is a blockchain that derives shared infrastructure and security from a _[relay chain](#relay-chain)_. +You can learn more about parachains on the [Polkadot Wiki](https://wiki.polkadot.com/learn/learn-parachains/){target=\_blank}. -8. Update your current shell to include Cargo by running the following command: +## Paseo - ```bash - source ~/.cargo/env - ``` +Paseo TestNet provisions testing on Polkadot's "production" runtime, which means less chance of feature or code mismatch when developing parachain apps. Specifically, after the [Polkadot Technical fellowship](https://wiki.polkadot.com/learn/learn-polkadot-technical-fellowship/){target=\_blank} proposes a runtime upgrade for Polkadot, this TestNet is updated, giving a period where the TestNet will be ahead of Polkadot to allow for testing. -9. Verify your installation by running the following command: +## Polkadot - ```bash - rustc --version - ``` +The [Polkadot network](https://polkadot.com/){target=\_blank} is a blockchain that serves as the central hub of a heterogeneous blockchain network. It serves the role of the [relay chain](#relay-chain) and provides shared infrastructure and security to support [parachains](#parachain). -10. Configure the Rust toolchain to use the latest stable version as the default toolchain by running the following commands: +## Polkadot Cloud - ```bash - rustup default stable - rustup update - rustup target add wasm32-unknown-unknown - rustup component add rust-src - ``` +Polkadot Cloud is a platform for deploying resilient, customizable and scalable Web3 applications through Polkadot's functionality. It encompasses the wider Polkadot network infrastructure and security layer where parachains operate. The platform enables users to launch Ethereum-compatible chains, build specialized blockchains, and flexibly manage computing resources through on-demand or bulk coretime purchases. Initially launched with basic parachain functionality, Polkadot Cloud has evolved to offer enhanced flexibility with features like coretime, elastic scaling, and async backing for improved performance. -11. [Verify your installation](#verifying-installation). +## Polkadot Hub -## Verifying Installation +Polkadot Hub is a Layer 1 platform that serves as the primary entry point to the Polkadot ecosystem, providing essential functionality without requiring parachain deployment. It offers core services including smart contracts, identity management, staking, governance, and interoperability with other ecosystems, making it simple and fast for both builders and users to get started in Web3. -Verify the configuration of your development environment by running the following command: +## PolkaVM -```bash -rustup show -``` +PolkaVM is a custom virtual machine optimized for performance, leveraging a RISC-V-based architecture to support Solidity and any language that compiles to RISC-V. It is specifically designed for the Polkadot ecosystem, enabling smart contract deployment and execution. -The command displays output similar to the following: +## Relay Chain -
- rustup show - ... -
- active toolchain - ---------------- - name: stable-aarch64-apple-darwin - active because: it's the default toolchain - installed targets: - aarch64-apple-darwin - wasm32-unknown-unknown -
+Relay chains are blockchains that provide shared infrastructure and security to the [parachains](#parachain) in the network. In addition to providing [consensus](#consensus) capabilities, relay chains allow parachains to communicate and exchange digital assets without needing to trust one another. -## Where to Go Next +## Rococo -- **[Parachain Zero to Hero Tutorials](/tutorials/polkadot-sdk/parachains/zero-to-hero/){target=\_blank}**: A series of step-by-step guides to building, testing, and deploying custom pallets and runtimes using the Polkadot SDK. +A [parachain](#parachain) test network for the Polkadot network. The [Rococo](#rococo) network is a Polkadot SDK-based blockchain with an October 14, 2024 deprecation date. Development teams are encouraged to use the Paseo TestNet instead. +## Runtime ---- +The runtime represents the [state transition function](#state-transition-function-stf) for a blockchain. In Polkadot SDK, the runtime is stored as a [Wasm](#webassembly-wasm) binary in the chain state. The Runtime is stored under a unique state key and can be modified during the execution of the state transition function. -Page Title: Interoperability +## Slot -- Source (raw): https://raw.githubusercontent.com/polkadot-developers/polkadot-docs/master/.ai/pages/reference-parachains-interoperability.md -- Canonical (HTML): https://docs.polkadot.com/reference/parachains/interoperability/ -- Summary: Explore the importance of interoperability in the Polkadot ecosystem, covering XCM, bridges, and cross-chain communication. +A fixed, equal interval of time used by consensus engines such as [Aura](#authority-round-aura) and [BABE](#blind-assignment-of-blockchain-extension-babe). In each slot, a subset of [authorities](#authority) is permitted, or obliged, to [author](#block-author) a block. -# Interoperability +## Sovereign Account -## Introduction +The unique account identifier for each chain in the relay chain ecosystem. It is often used in cross-consensus (XCM) interactions to sign XCM messages sent to the relay chain or other chains in the ecosystem. -Interoperability lies at the heart of the Polkadot ecosystem, enabling communication and collaboration across a diverse range of blockchains. By bridging the gaps between parachains, relay chains, and even external networks, Polkadot unlocks the potential for truly decentralized applications, efficient resource sharing, and scalable solutions. +The sovereign account for each chain is a root-level account that can only be accessed using the Sudo pallet or through governance. The account identifier is calculated by concatenating the Blake2 hash of a specific text string and the registered parachain identifier. -Polkadot’s design ensures that blockchains can transcend their individual limitations by working together as part of a unified system. This cooperative architecture is what sets Polkadot apart in the blockchain landscape. +## SS58 Address Format -## Why Interoperability Matters +A public key address based on the Bitcoin [`Base-58-check`](https://en.bitcoin.it/wiki/Base58Check_encoding){target=\_blank} encoding. Each Polkadot SDK SS58 address uses a `base-58` encoded value to identify a specific account on a specific Polkadot SDK-based chain -The blockchain ecosystem is inherently fragmented. Different blockchains excel in specialized domains such as finance, gaming, or supply chain management, but these chains function in isolation without interoperability. This lack of connectivity stifles the broader utility of blockchain technology. +The [canonical `ss58-registry`](https://github.com/paritytech/ss58-registry){target=\_blank} provides additional details about the address format used by different Polkadot SDK-based chains, including the network prefix and website used for different networks -Interoperability solves this problem by enabling blockchains to: +## State Transition Function (STF) -- **Collaborate across networks**: Chains can interact to share assets, functionality, and data, creating synergies that amplify their individual strengths. -- **Achieve greater scalability**: Specialized chains can offload tasks to others, optimizing performance and resource utilization. -- **Expand use-case potential**: Cross-chain applications can leverage features from multiple blockchains, unlocking novel user experiences and solutions. +The logic of a blockchain that determines how the state changes when a block is processed. In Polkadot SDK, the state transition function is effectively equivalent to the [runtime](#runtime). -In the Polkadot ecosystem, interoperability transforms a collection of isolated chains into a cohesive, efficient network, pushing the boundaries of what blockchains can achieve together. +## Storage Item -## Key Mechanisms for Interoperability +[FRAME](#frame-framework-for-runtime-aggregation-of-modularized-entities) primitives that provide type-safe data persistence capabilities to the [runtime](#runtime). +Learn more in the [storage items](https://paritytech.github.io/polkadot-sdk/master/frame_support/storage/types/index.html){target=\_blank} reference document in the Polkadot SDK. -At the core of Polkadot's cross-chain collaboration are foundational technologies designed to break down barriers between networks. These mechanisms empower blockchains to communicate, share resources, and operate as a cohesive ecosystem. +## Substrate -### Cross-Consensus Messaging (XCM): The Backbone of Communication +A flexible framework for building modular, efficient, and upgradeable blockchains. Substrate is written in the [Rust](https://www.rust-lang.org/){target=\_blank} programming language and is maintained by [Parity Technologies](https://www.parity.io/){target=\_blank}. -Polkadot's Cross-Consensus Messaging (XCM) is the standard framework for interaction between parachains, relay chains, and, eventually, external blockchains. XCM provides a trustless, secure messaging format for exchanging assets, sharing data, and executing cross-chain operations. +## Transaction -Through XCM, decentralized applications can: +An [extrinsic](#extrinsic) that includes a signature that can be used to verify the account authorizing it inherently or via [signed extensions](https://paritytech.github.io/polkadot-sdk/master/polkadot_sdk_docs/reference_docs/signed_extensions/index.html){target=\_blank}. -- Transfer tokens and other assets across chains. -- Coordinate complex workflows that span multiple blockchains. -- Enable seamless user experiences where underlying blockchain differences are invisible. -- XCM exemplifies Polkadot’s commitment to creating a robust and interoperable ecosystem. +## Transaction Era -For further information about XCM, check the [Introduction to XCM](/parachains/interoperability/get-started/){target=\_blank} article. +A definable period expressed as a range of block numbers during which a transaction can be included in a block. +Transaction eras are used to protect against transaction replay attacks if an account is reaped and its replay-protecting nonce is reset to zero. -### Bridges: Connecting External Networks +## Trie (Patricia Merkle Tree) -While XCM enables interoperability within the Polkadot ecosystem, bridges extend this functionality to external blockchains such as Ethereum and Bitcoin. By connecting these networks, bridges allow Polkadot-based chains to access external liquidity, additional functionalities, and broader user bases. +A data structure used to represent sets of key-value pairs and enables the items in the data set to be stored and retrieved using a cryptographic hash. Because incremental changes to the data set result in a new hash, retrieving data is efficient even if the data set is very large. With this data structure, you can also prove whether the data set includes any particular key-value pair without access to the entire data set. -With bridges, developers and users gain the ability to: +In Polkadot SDK-based blockchains, state is stored in a trie data structure that supports the efficient creation of incremental digests. This trie is exposed to the [runtime](#runtime) as [a simple key/value map](#storage-item) where both keys and values can be arbitrary byte arrays. -- Integrate external assets into Polkadot-based applications. -- Combine the strengths of Polkadot’s scalability with the liquidity of other networks. -- Facilitate accurate multi-chain applications that transcend ecosystem boundaries. +## Validator -For more information about bridges in the Polkadot ecosystem, see the [Bridge Hub](/reference/polkadot-hub/bridging/){target=\_blank} guide. +A validator is a node that participates in the consensus mechanism of the network. Its roles include block production, transaction validation, network integrity, and security maintenance. -## The Polkadot Advantage +## WebAssembly (Wasm) -Polkadot was purpose-built for interoperability. Unlike networks that add interoperability as an afterthought, Polkadot integrates it as a fundamental design principle. This approach offers several distinct advantages: +An execution architecture that allows for the efficient, platform-neutral expression of +deterministic, machine-executable logic. -- **Developer empowerment**: Polkadot’s interoperability tools allow developers to build applications that leverage multiple chains’ capabilities without added complexity. -- **Enhanced ecosystem collaboration**: Chains in Polkadot can focus on their unique strengths while contributing to the ecosystem’s overall growth. -- **Future-proofing blockchain**: By enabling seamless communication, Polkadot ensures its ecosystem can adapt to evolving demands and technologies. +[Wasm](https://webassembly.org/){target=\_blank} can be compiled from many languages, including +the [Rust](https://www.rust-lang.org/){target=\_blank} programming language. Polkadot SDK-based chains use a Wasm binary to provide portable [runtimes](#runtime) that can be included as part of the chain's state. -## Looking Ahead +## Weight -Polkadot’s vision of interoperability extends beyond technical functionality, representing a shift towards a more collaborative blockchain landscape. By enabling chains to work together, Polkadot fosters innovation, efficiency, and accessibility, paving the way for a decentralized future where blockchains are not isolated competitors but interconnected collaborators. +A convention used in Polkadot SDK-based blockchains to measure and manage the time it takes to validate a block. +Polkadot SDK defines one unit of weight as one picosecond of execution time on reference hardware. +The maximum block weight should be equivalent to one-third of the target block time with an allocation of one-third each for: ---- +- Block construction +- Network propagation +- Import and verification -Page Title: Introduction to XCM +By defining weights, you can trade-off the number of transactions per second and the hardware required to maintain the target block time appropriate for your use case. Weights are defined in the runtime, meaning you can tune them using runtime updates to keep up with hardware and software improvements. -- Source (raw): https://raw.githubusercontent.com/polkadot-developers/polkadot-docs/master/.ai/pages/parachains-interoperability-get-started.md -- Canonical (HTML): https://docs.polkadot.com/parachains/interoperability/get-started/ -- Summary: Unlock blockchain interoperability with XCM — Polkadot's Cross-Consensus Messaging format for cross-chain interactions. +## Westend -# Introduction to XCM +Westend is a Parity-maintained, Polkadot SDK-based blockchain that serves as a test network for the [Polkadot](#polkadot) network. -## Introduction -Polkadot’s unique value lies in its ability to enable interoperability between parachains and other blockchain systems. At the core of this capability is XCM (Cross-Consensus Messaging)—a flexible messaging format that facilitates communication and collaboration between independent consensus systems. +--- -With XCM, one chain can send intents to another one, fostering a more interconnected ecosystem. Although it was developed specifically for Polkadot, XCM is a universal format, usable in any blockchain environment. This guide provides an overview of XCM’s core principles, design, and functionality, alongside practical examples of its implementation. +Page Title: Install Polkadot SDK Dependencies -## Messaging Format +- Source (raw): https://raw.githubusercontent.com/polkadot-developers/polkadot-docs/master/.ai/pages/parachains-install-polkadot-sdk.md +- Canonical (HTML): https://docs.polkadot.com/parachains/install-polkadot-sdk/ +- Summary: Install everything you need to begin working with Substrated-based blockchains and the Polkadot SDK, the framework for building blockchains. -XCM is not a protocol but a standardized [messaging format](https://github.com/polkadot-fellows/xcm-format){target=\_blank}. It defines the structure and behavior of messages but does not handle their delivery. This separation allows developers to focus on crafting instructions for target systems without worrying about transmission mechanics. +# Install Polkadot SDK Dependencies -XCM messages are intent-driven, outlining desired actions for the receiving blockchain to consider and potentially alter its state. These messages do not directly execute changes; instead, they rely on the host chain's environment to interpret and implement them. By utilizing asynchronous composability, XCM facilitates efficient execution where messages can be processed independently of their original order, similar to how RESTful services handle HTTP requests without requiring sequential processing. +This guide provides step-by-step instructions for installing the dependencies you need to work with the Polkadot SDK-based chains on macOS, Linux, and Windows. Follow the appropriate section for your operating system to ensure all necessary tools are installed and configured properly. -## The Four Principles of XCM +## macOS -XCM adheres to four guiding principles that ensure robust and reliable communication across consensus systems: +You can install Rust and set up a Substrate development environment on Apple macOS computers with Intel or Apple M1 processors. -- **Asynchronous**: XCM messages operate independently of sender acknowledgment, avoiding delays due to blocked processes. -- **Absolute**: XCM messages are guaranteed to be delivered and interpreted accurately, in order, and timely. Once a message is sent, one can be sure it will be processed as intended. -- **Asymmetric**: XCM messages follow the 'fire and forget' paradigm meaning no automatic feedback is provided to the sender. Any results must be communicated separately to the sender with an additional message back to the origin. -- **Agnostic**: XCM operates independently of the specific consensus mechanisms, making it compatible across diverse systems. +### Before You Begin -These principles guarantee that XCM provides a reliable framework for cross-chain communication, even in complex environments. +Before you install Rust and set up your development environment on macOS, verify that your computer meets the following basic requirements: -## The XCM Tech Stack +- Operating system version is 10.7 Lion or later. +- Processor speed of at least 2 GHz. Note that 3 GHz is recommended. +- Memory of at least 8 GB RAM. Note that 16 GB is recommended. +- Storage of at least 10 GB of available space. +- Broadband Internet connection. -![Diagram of the XCM tech stack](/images/parachains/interoperability/get-started/intro-to-xcm-01.webp) +#### Install Homebrew -The XCM tech stack is designed to facilitate seamless interoperable communication between chains that reside within the Polkadot ecosystem. XCM can be used to express the meaning of the messages over each of the communication channels. +In most cases, you should use Homebrew to install and manage packages on macOS computers. If you don't already have Homebrew installed on your local computer, you should download and install it before continuing. -## Core Functionalities of XCM +To install Homebrew: -XCM enhances cross-consensus communication by introducing several powerful features: +1. Open the Terminal application. +2. Download and install Homebrew by running the following command: -- **Programmability**: Supports dynamic message handling, allowing for more comprehensive use cases. Includes branching logic, safe dispatches for version checks, and asset operations like NFT management. -- **Functional Multichain Decomposition**: Enables mechanisms such as remote asset locking, asset namespacing, and inter-chain state referencing, with contextual message identification. -- **Bridging**: Establishes a universal reference framework for multi-hop setups, connecting disparate systems like Ethereum and Bitcoin with the Polkadot relay chain acting as a universal location. + ```bash + /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install.sh)" + ``` -The standardized format for messages allows parachains to handle tasks like user balances, governance, and staking, freeing the Polkadot relay chain to focus on shared security. These features make XCM indispensable for implementing scalable and interoperable blockchain applications. +3. Verify Homebrew has been successfully installed by running the following command: -## XCM Example + ```bash + brew --version + ``` -The following is a simplified XCM message demonstrating a token transfer from Alice to Bob on the same chain (ParaA). + The command displays output similar to the following: -```rust -let message = Xcm(vec![ - WithdrawAsset((Here, amount).into()), - BuyExecution { - fees: (Here, amount).into(), - weight_limit: WeightLimit::Unlimited - }, - DepositAsset { - assets: All.into(), - beneficiary: MultiLocation { - parents: 0, - interior: Junction::AccountId32 { - network: None, - id: BOB.clone().into() - }.into(), - }.into() - } -]); -``` +
+ brew --version + Homebrew 4.3.15 +
-The message consists of three instructions described as follows: +#### Support for Apple Silicon -- **[WithdrawAsset](https://github.com/polkadot-fellows/xcm-format?tab=readme-ov-file#withdrawasset){target=\_blank}**: Transfers a specified number of tokens from Alice's account to a holding register. +Protobuf must be installed before the build process can begin. To install it, run the following command: - ```rust - WithdrawAsset((Here, amount).into()), - ``` +```bash +brew install protobuf +``` - - **`Here`**: The native parachain token. - - **`amount`**: The number of tokens that are transferred. +### Install Required Packages and Rust - The first instruction takes as an input the MultiAsset that should be withdrawn. The MultiAsset describes the native parachain token with the `Here` keyword. The `amount` parameter is the number of tokens that are transferred. The withdrawal account depends on the origin of the message. In this example the origin of the message is Alice. The `WithdrawAsset` instruction moves `amount` number of native tokens from Alice's account into the holding register. +Because the blockchain requires standard cryptography to support the generation of public/private key pairs and the validation of transaction signatures, you must also have a package that provides cryptography, such as `openssl`. -- **[BuyExecution](https://github.com/polkadot-fellows/xcm-format?tab=readme-ov-file#buyexecution){target=\_blank}**: Allocates fees to cover the execution [weight](/reference/glossary/#weight){target=\_blank} of the XCM instructions. +To install `openssl` and the Rust toolchain on macOS: - ```rust - BuyExecution { - fees: (Here, amount).into(), - weight_limit: WeightLimit::Unlimited - }, - ``` +1. Open the Terminal application. +2. Ensure you have an updated version of Homebrew by running the following command: - - **`fees`**: Describes the asset in the holding register that should be used to pay for the weight. - - **`weight_limit`**: Defines the maximum fees that can be used to buy weight. + ```bash + brew update + ``` -- **[DepositAsset](https://github.com/polkadot-fellows/xcm-format?tab=readme-ov-file#depositasset){target=\_blank}**: Moves the remaining tokens from the holding register to Bob’s account. +3. Install the `openssl` package by running the following command: - ```rust - DepositAsset { - assets: All.into(), - beneficiary: MultiLocation { - parents: 0, - interior: Junction::AccountId32 { - network: None, - id: BOB.clone().into() - }.into(), - }.into() - } + ```bash + brew install openssl ``` - - **`All`**: The wildcard for the asset(s) to be deposited. In this case, all assets in the holding register should be deposited. - -This step-by-step process showcases how XCM enables precise state changes within a blockchain system. You can find a complete XCM message example in the [XCM repository](https://github.com/paritytech/xcm-docs/blob/main/examples/src/0_first_look/mod.rs){target=\_blank}. +4. Download the `rustup` installation program and use it to install Rust by running the following command: + + ```bash + curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh + ``` -## Overview +5. Follow the prompts displayed to proceed with a default installation. +6. Update your current shell to include Cargo by running the following command: -XCM revolutionizes cross-chain communication by enabling use cases such as: + ```bash + source ~/.cargo/env + ``` -- Token transfers between blockchains. -- Asset locking for cross-chain smart contract interactions. -- Remote execution of functions on other blockchains. +7. Configure the Rust toolchain to default to the latest stable version by running the following commands: -These functionalities empower developers to build innovative, multi-chain applications, leveraging the strengths of various blockchain networks. To stay updated on XCM’s evolving format or contribute, visit the [XCM repository](https://github.com/paritytech/xcm-docs/blob/main/examples/src/0_first_look/mod.rs){target=\_blank}. + ```bash + rustup default stable + rustup update + rustup target add wasm32-unknown-unknown + rustup component add rust-src + ``` +8. [Verify your installation](#verifying-installation). +9. Install `cmake` using the following command: ---- + ```bash + brew install cmake + ``` -Page Title: JSON-RPC APIs +## Linux -- Source (raw): https://raw.githubusercontent.com/polkadot-developers/polkadot-docs/master/.ai/pages/smart-contracts-for-eth-devs-json-rpc-apis.md -- Canonical (HTML): https://docs.polkadot.com/smart-contracts/for-eth-devs/json-rpc-apis/ -- Summary: JSON-RPC APIs guide for Polkadot Hub, covering supported methods, parameters, and examples for interacting with the chain. +Rust supports most Linux distributions. Depending on the specific distribution and version of the operating system you use, you might need to add some software dependencies to your environment. In general, your development environment should include a linker or C-compatible compiler, such as `clang` and an appropriate integrated development environment (IDE). -# JSON-RPC APIs +### Before You Begin {: #before-you-begin-linux } -!!! smartcontract "PolkaVM Preview Release" - PolkaVM smart contracts with Ethereum compatibility are in **early-stage development and may be unstable or incomplete**. -## Introduction +Check the documentation for your operating system for information about the installed packages and how to download and install any additional packages you might need. For example, if you use Ubuntu, you can use the Ubuntu Advanced Packaging Tool (`apt`) to install the `build-essential` package: -Polkadot Hub provides Ethereum compatibility through its JSON-RPC interface, allowing developers to interact with the chain using familiar Ethereum tooling and methods. This document outlines the supported [Ethereum JSON-RPC methods](https://ethereum.org/en/developers/docs/apis/json-rpc/#json-rpc-methods){target=\_blank} and provides examples of how to use them. +```bash +sudo apt install build-essential +``` -This guide uses the Polkadot Hub TestNet endpoint: +At a minimum, you need the following packages before you install Rust: ```text -https://testnet-passet-hub-eth-rpc.polkadot.io +clang curl git make ``` -## Available Methods +Because the blockchain requires standard cryptography to support the generation of public/private key pairs and the validation of transaction signatures, you must also have a package that provides cryptography, such as `libssl-dev` or `openssl-devel`. -### eth_accounts +### Install Required Packages and Rust {: #install-required-packages-and-rust-linux } -Returns a list of addresses owned by the client. [Reference](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_accounts){target=\_blank}. +To install the Rust toolchain on Linux: -**Parameters**: +1. Open a terminal shell. +2. Check the packages you have installed on the local computer by running an appropriate package management command for your Linux distribution. +3. Add any package dependencies you are missing to your local development environment by running the appropriate package management command for your Linux distribution: -None. + === "Ubuntu" -**Example**: + ```bash + sudo apt install --assume-yes git clang curl libssl-dev protobuf-compiler + ``` -```bash title="eth_accounts" -curl -X POST https://testnet-passet-hub-eth-rpc.polkadot.io \ --H "Content-Type: application/json" \ ---data '{ - "jsonrpc":"2.0", - "method":"eth_accounts", - "params":[], - "id":1 -}' -``` + === "Debian" ---- + ```sh + sudo apt install --assume-yes git clang curl libssl-dev llvm libudev-dev make protobuf-compiler + ``` -### eth_blockNumber + === "Arch" -Returns the number of the most recent block. [Reference](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_blocknumber){target=\_blank}. + ```sh + pacman -Syu --needed --noconfirm curl git clang make protobuf + ``` -**Parameters**: + === "Fedora" -None. + ```sh + sudo dnf update + sudo dnf install clang curl git openssl-devel make protobuf-compiler + ``` -**Example**: + === "OpenSUSE" -```bash title="eth_blockNumber" -curl -X POST https://testnet-passet-hub-eth-rpc.polkadot.io \ --H "Content-Type: application/json" \ ---data '{ - "jsonrpc":"2.0", - "method":"eth_blockNumber", - "params":[], - "id":1 -}' -``` + ```sh + sudo zypper install clang curl git openssl-devel llvm-devel libudev-devel make protobuf + ``` ---- + Remember that different distributions might use different package managers and bundle packages in different ways. For example, depending on your installation selections, Ubuntu Desktop and Ubuntu Server might have different packages and different requirements. However, the packages listed in the command-line examples are applicable for many common Linux distributions, including Debian, Linux Mint, MX Linux, and Elementary OS. -### eth_call +4. Download the `rustup` installation program and use it to install Rust by running the following command: -Executes a new message call immediately without creating a transaction. [Reference](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_call){target=\_blank}. + ```bash + curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh + ``` -**Parameters**: +5. Follow the prompts displayed to proceed with a default installation. +6. Update your current shell to include Cargo by running the following command: -- **`transaction` ++"object"++**: The transaction call object. - - **`to` ++"string"++**: Recipient address of the call. Must be a [20-byte data](https://ethereum.org/en/developers/docs/apis/json-rpc/#unformatted-data-encoding){target=\_blank} string. - - **`data` ++"string"++**: Hash of the method signature and encoded parameters. Must be a [data](https://ethereum.org/en/developers/docs/apis/json-rpc/#unformatted-data-encoding){target=\_blank} string. - - **`from` ++"string"++**: (Optional) Sender's address for the call. Must be a [20-byte data](https://ethereum.org/en/developers/docs/apis/json-rpc/#unformatted-data-encoding){target=\_blank} string. - - **`gas` ++"string"++**: (Optional) Gas limit to execute the call. Must be a [quantity](https://ethereum.org/en/developers/docs/apis/json-rpc/#quantities-encoding){target=\_blank} string. - - **`gasPrice` ++"string"++**: (Optional) Gas price per unit of gas. Must be a [quantity](https://ethereum.org/en/developers/docs/apis/json-rpc/#quantities-encoding){target=\_blank} string. - - **`value` ++"string"++**: (Optional) Value in wei to send with the call. Must be a [quantity](https://ethereum.org/en/developers/docs/apis/json-rpc/#quantities-encoding){target=\_blank} string. -- **`blockValue` ++"string"++**: (Optional) Block tag or block number to execute the call at. Must be a [quantity](https://ethereum.org/en/developers/docs/apis/json-rpc/#quantities-encoding){target=\_blank} string or a [default block parameter](https://ethereum.org/en/developers/docs/apis/json-rpc/#default-block){target=\_blank}. + ```bash + source $HOME/.cargo/env + ``` -**Example**: +7. Verify your installation by running the following command: -```bash title="eth_call" -curl -X POST https://testnet-passet-hub-eth-rpc.polkadot.io \ --H "Content-Type: application/json" \ ---data '{ - "jsonrpc":"2.0", - "method":"eth_call", - "params":[{ - "to": "INSERT_RECIPIENT_ADDRESS", - "data": "INSERT_ENCODED_CALL" - }, "INSERT_BLOCK_VALUE"], - "id":1 -}' -``` + ```bash + rustc --version + ``` -Ensure to replace the `INSERT_RECIPIENT_ADDRESS`, `INSERT_ENCODED_CALL`, and `INSERT_BLOCK_VALUE` with the proper values. +8. Configure the Rust toolchain to default to the latest stable version by running the following commands: ---- + ```bash + rustup default stable + rustup update + rustup target add wasm32-unknown-unknown + rustup component add rust-src + ``` -### eth_chainId +9. [Verify your installation](#verifying-installation). -Returns the chain ID used for signing transactions. [Reference](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_chainid){target=\_blank}. +## Windows (WSL) -**Parameters**: +In general, UNIX-based operating systems—like macOS or Linux—provide a better development environment for building Substrate-based blockchains. -None. +However, suppose your local computer uses Microsoft Windows instead of a UNIX-based operating system. In that case, you can configure it with additional software to make it a suitable development environment for building Substrate-based blockchains. To prepare a development environment on a Microsoft Windows computer, you can use Windows Subsystem for Linux (WSL) to emulate a UNIX operating environment. -**Example**: +### Before You Begin {: #before-you-begin-windows } -```bash title="eth_chainId" -curl -X POST https://testnet-passet-hub-eth-rpc.polkadot.io \ --H "Content-Type: application/json" \ ---data '{ - "jsonrpc":"2.0", - "method":"eth_chainId", - "params":[], - "id":1 -}' -``` +Before installing on Microsoft Windows, verify the following basic requirements: ---- +- You have a computer running a supported Microsoft Windows operating system: + - **For Windows desktop**: You must be running Microsoft Windows 10, version 2004 or later, or Microsoft Windows 11 to install WSL. + - **For Windows server**: You must be running Microsoft Windows Server 2019, or later, to install WSL on a server operating system. +- You have good internet connection and access to a shell terminal on your local computer. -### eth_estimateGas +### Set Up Windows Subsystem for Linux -Estimates gas required for a transaction. [Reference](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_estimategas){target=\_blank}. +WSL enables you to emulate a Linux environment on a computer that uses the Windows operating system. The primary advantage of this approach for Substrate development is that you can use all of the code and command-line examples as described in the Substrate documentation. For example, you can run common commands—such as `ls` and `ps`—unmodified. By using WSL, you can avoid configuring a virtual machine image or a dual-boot operating system. -**Parameters**: +To prepare a development environment using WSL: -- **`transaction` ++"object"++**: The transaction call object. - - **`to` ++"string"++**: Recipient address of the call. Must be a [20-byte data](https://ethereum.org/en/developers/docs/apis/json-rpc/#unformatted-data-encoding){target=\_blank} string. - - **`data` ++"string"++**: Hash of the method signature and encoded parameters. Must be a [data](https://ethereum.org/en/developers/docs/apis/json-rpc/#unformatted-data-encoding){target=\_blank} string. - - **`from` ++"string"++**: (Optional) Sender's address for the call. Must be a [20-byte data](https://ethereum.org/en/developers/docs/apis/json-rpc/#unformatted-data-encoding){target=\_blank} string. - - **`gas` ++"string"++**: (Optional) Gas limit to execute the call. Must be a [quantity](https://ethereum.org/en/developers/docs/apis/json-rpc/#quantities-encoding){target=\_blank} string. - - **`gasPrice` ++"string"++**: (Optional) Gas price per unit of gas. Must be a [quantity](https://ethereum.org/en/developers/docs/apis/json-rpc/#quantities-encoding){target=\_blank} string. - - **`value` ++"string"++**: (Optional) Value in wei to send with the call. Must be a [quantity](https://ethereum.org/en/developers/docs/apis/json-rpc/#quantities-encoding){target=\_blank} string. -- **`blockValue` ++"string"++**: (Optional) Block tag or block number to execute the call at. Must be a [quantity](https://ethereum.org/en/developers/docs/apis/json-rpc/#quantities-encoding){target=\_blank} string or a [default block parameter](https://ethereum.org/en/developers/docs/apis/json-rpc/#default-block){target=\_blank}. +1. Check your Windows version and build number to see if WSL is enabled by default. -**Example**: + If you have Microsoft Windows 10, version 2004 (Build 19041 and higher), or Microsoft Windows 11, WSL is available by default and you can continue to the next step. -```bash title="eth_estimateGas" -curl -X POST https://testnet-passet-hub-eth-rpc.polkadot.io \ --H "Content-Type: application/json" \ ---data '{ - "jsonrpc":"2.0", - "method":"eth_estimateGas", - "params":[{ - "to": "INSERT_RECIPIENT_ADDRESS", - "data": "INSERT_ENCODED_FUNCTION_CALL" - }], - "id":1 -}' -``` + If you have an older version of Microsoft Windows installed, see the [WSL manual installation steps for older versions](https://learn.microsoft.com/en-us/windows/wsl/install-manual){target=\_blank}. If you are installing on an older version of Microsoft Windows, you can download and install WLS 2 if your computer has Windows 10, version 1903 or higher. -Ensure to replace the `INSERT_RECIPIENT_ADDRESS` and `INSERT_ENCODED_CALL` with the proper values. +2. Select **Windows PowerShell** or **Command Prompt** from the **Start** menu, right-click, then **Run as administrator**. ---- +3. In the PowerShell or Command Prompt terminal, run the following command: -### eth_gasPrice + ```bash + wsl --install + ``` -Returns the current gas price in Wei. [Reference](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_gasprice){target=\_blank}. + This command enables the required WSL 2 components that are part of the Windows operating system, downloads the latest Linux kernel, and installs the Ubuntu Linux distribution by default. -**Parameters**: + If you want to review the other Linux distributions available, run the following command: -None. + ```bash + wsl --list --online + ``` -**Example**: +4. After the distribution is downloaded, close the terminal. -```bash title="eth_gasPrice" -curl -X POST https://testnet-passet-hub-eth-rpc.polkadot.io \ --H "Content-Type: application/json" \ ---data '{ - "jsonrpc":"2.0", - "method":"eth_gasPrice", - "params":[], - "id":1 -}' -``` +5. Click the **Start** menu, select **Shut down or sign out**, then click **Restart** to restart the computer. + + Restarting the computer is required to start the installation of the Linux distribution. It can take a few minutes for the installation to complete after you restart. + + For more information about setting up WSL as a development environment, see the [Set up a WSL development environment](https://learn.microsoft.com/en-us/windows/wsl/setup/environment){target=\_blank} docs. + +### Install Required Packages and Rust {: #install-required-packages-and-rust-windows } + +To install the Rust toolchain on WSL: + +1. Click the **Start** menu, then select **Ubuntu**. +2. Type a UNIX user name to create user account. +3. Type a password for your UNIX user, then retype the password to confirm it. +4. Download the latest updates for the Ubuntu distribution using the Ubuntu Advanced Packaging Tool (`apt`) by running the following command: ---- + ```bash + sudo apt update + ``` -### eth_getBalance +5. Add the required packages for the Ubuntu distribution by running the following command: -Returns the balance of a given address. [Reference](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_getbalance){target=\_blank}. + ```bash + sudo apt install --assume-yes git clang curl libssl-dev llvm libudev-dev make protobuf-compiler + ``` -**Parameters**: +6. Download the `rustup` installation program and use it to install Rust for the Ubuntu distribution by running the following command: -- **`address` ++"string"++**: Address to query balance. Must be a [20-byte data](https://ethereum.org/en/developers/docs/apis/json-rpc/#unformatted-data-encoding){target=\_blank} string. -- **`blockValue` ++"string"++**: (Optional) The block value to be fetched. Must be a [quantity](https://ethereum.org/en/developers/docs/apis/json-rpc/#quantities-encoding){target=\_blank} string or a [default block parameter](https://ethereum.org/en/developers/docs/apis/json-rpc/#default-block){target=\_blank}. + ```bash + curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh + ``` -**Example**: +7. Follow the prompts displayed to proceed with a default installation. -```bash title="eth_getBalance" -curl -X POST https://testnet-passet-hub-eth-rpc.polkadot.io \ --H "Content-Type: application/json" \ ---data '{ - "jsonrpc":"2.0", - "method":"eth_getBalance", - "params":["INSERT_ADDRESS", "INSERT_BLOCK_VALUE"], - "id":1 -}' -``` +8. Update your current shell to include Cargo by running the following command: -Ensure to replace the `INSERT_ADDRESS` and `INSERT_BLOCK_VALUE` with the proper values. + ```bash + source ~/.cargo/env + ``` ---- +9. Verify your installation by running the following command: -### eth_getBlockByHash + ```bash + rustc --version + ``` -Returns information about a block by its hash. [Reference](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_getblockbyhash){target=\_blank}. +10. Configure the Rust toolchain to use the latest stable version as the default toolchain by running the following commands: -**Parameters**: + ```bash + rustup default stable + rustup update + rustup target add wasm32-unknown-unknown + rustup component add rust-src + ``` -- **`blockHash` ++"string"++**: The hash of the block to retrieve. Must be a [32 byte data](https://ethereum.org/en/developers/docs/apis/json-rpc/#unformatted-data-encoding){target=\_blank} string. -- **`fullTransactions` ++"boolean"++**: If `true`, returns full transaction details; if `false`, returns only transaction hashes. +11. [Verify your installation](#verifying-installation). -**Example**: +## Verifying Installation -```bash title="eth_getBlockByHash" -curl -X POST https://testnet-passet-hub-eth-rpc.polkadot.io \ --H "Content-Type: application/json" \ ---data '{ - "jsonrpc":"2.0", - "method":"eth_getBlockByHash", - "params":["INSERT_BLOCK_HASH", INSERT_BOOLEAN], - "id":1 -}' +Verify the configuration of your development environment by running the following command: + +```bash +rustup show ``` -Ensure to replace the `INSERT_BLOCK_HASH` and `INSERT_BOOLEAN` with the proper values. +The command displays output similar to the following: ---- +
+ rustup show + ... +
+ active toolchain + ---------------- + name: stable-aarch64-apple-darwin + active because: it's the default toolchain + installed targets: + aarch64-apple-darwin + wasm32-unknown-unknown +
-### eth_getBlockByNumber +## Where to Go Next -Returns information about a block by its number. [Reference](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_getblockbynumber){target=\_blank}. +- **[Parachain Zero to Hero Tutorials](/tutorials/polkadot-sdk/parachains/zero-to-hero/){target=\_blank}**: A series of step-by-step guides to building, testing, and deploying custom pallets and runtimes using the Polkadot SDK. -**Parameters**: -- **`blockValue` ++"string"++**: (Optional) The block value to be fetched. Must be a [quantity](https://ethereum.org/en/developers/docs/apis/json-rpc/#quantities-encoding){target=\_blank} string or a [default block parameter](https://ethereum.org/en/developers/docs/apis/json-rpc/#default-block){target=\_blank}. -- **`fullTransactions` ++"boolean"++**: If `true`, returns full transaction details; if `false`, returns only transaction hashes. +--- -**Example**: +Page Title: Interoperability -```bash title="eth_getBlockByNumber" -curl -X POST https://testnet-passet-hub-eth-rpc.polkadot.io \ --H "Content-Type: application/json" \ ---data '{ - "jsonrpc":"2.0", - "method":"eth_getBlockByNumber", - "params":["INSERT_BLOCK_VALUE", INSERT_BOOLEAN], - "id":1 -}' -``` +- Source (raw): https://raw.githubusercontent.com/polkadot-developers/polkadot-docs/master/.ai/pages/reference-parachains-interoperability.md +- Canonical (HTML): https://docs.polkadot.com/reference/parachains/interoperability/ +- Summary: Explore the importance of interoperability in the Polkadot ecosystem, covering XCM, bridges, and cross-chain communication. -Ensure to replace the `INSERT_BLOCK_VALUE` and `INSERT_BOOLEAN` with the proper values. +# Interoperability ---- +## Introduction -### eth_getBlockTransactionCountByNumber +Interoperability lies at the heart of the Polkadot ecosystem, enabling communication and collaboration across a diverse range of blockchains. By bridging the gaps between parachains, relay chains, and even external networks, Polkadot unlocks the potential for truly decentralized applications, efficient resource sharing, and scalable solutions. -Returns the number of transactions in a block from a block number. [Reference](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_getblocktransactioncountbynumber){target=\_blank}. +Polkadot’s design ensures that blockchains can transcend their individual limitations by working together as part of a unified system. This cooperative architecture is what sets Polkadot apart in the blockchain landscape. -**Parameters**: +## Why Interoperability Matters -- **`blockValue` ++"string"++**: The block value to be fetched. Must be a [quantity](https://ethereum.org/en/developers/docs/apis/json-rpc/#quantities-encoding){target=\_blank} string or a [default block parameter](https://ethereum.org/en/developers/docs/apis/json-rpc/#default-block){target=\_blank}. +The blockchain ecosystem is inherently fragmented. Different blockchains excel in specialized domains such as finance, gaming, or supply chain management, but these chains function in isolation without interoperability. This lack of connectivity stifles the broader utility of blockchain technology. -**Example**: +Interoperability solves this problem by enabling blockchains to: -```bash title="eth_getBlockTransactionCountByNumber" -curl -X POST https://testnet-passet-hub-eth-rpc.polkadot.io \ --H "Content-Type: application/json" \ ---data '{ - "jsonrpc":"2.0", - "method":"eth_getBlockTransactionCountByNumber", - "params":["INSERT_BLOCK_VALUE"], - "id":1 -}' -``` +- **Collaborate across networks**: Chains can interact to share assets, functionality, and data, creating synergies that amplify their individual strengths. +- **Achieve greater scalability**: Specialized chains can offload tasks to others, optimizing performance and resource utilization. +- **Expand use-case potential**: Cross-chain applications can leverage features from multiple blockchains, unlocking novel user experiences and solutions. -Ensure to replace the `INSERT_BLOCK_VALUE` with the proper values. +In the Polkadot ecosystem, interoperability transforms a collection of isolated chains into a cohesive, efficient network, pushing the boundaries of what blockchains can achieve together. ---- +## Key Mechanisms for Interoperability -### eth_getBlockTransactionCountByHash +At the core of Polkadot's cross-chain collaboration are foundational technologies designed to break down barriers between networks. These mechanisms empower blockchains to communicate, share resources, and operate as a cohesive ecosystem. -Returns the number of transactions in a block from a block hash. [Reference](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_getblocktransactioncountbyhash){target=\_blank}. +### Cross-Consensus Messaging (XCM): The Backbone of Communication -**Parameters**: +Polkadot's Cross-Consensus Messaging (XCM) is the standard framework for interaction between parachains, relay chains, and, eventually, external blockchains. XCM provides a trustless, secure messaging format for exchanging assets, sharing data, and executing cross-chain operations. -- **`blockHash` ++"string"++**: The hash of the block to retrieve. Must be a [32 byte data](https://ethereum.org/en/developers/docs/apis/json-rpc/#unformatted-data-encoding){target=\_blank} string. +Through XCM, decentralized applications can: -**Example**: +- Transfer tokens and other assets across chains. +- Coordinate complex workflows that span multiple blockchains. +- Enable seamless user experiences where underlying blockchain differences are invisible. +- XCM exemplifies Polkadot’s commitment to creating a robust and interoperable ecosystem. -```bash title="eth_getBlockTransactionCountByHash" -curl -X POST https://testnet-passet-hub-eth-rpc.polkadot.io \ --H "Content-Type: application/json" \ ---data '{ - "jsonrpc":"2.0", - "method":"eth_getBlockTransactionCountByHash", - "params":["INSERT_BLOCK_HASH"], - "id":1 -}' -``` +For further information about XCM, check the [Introduction to XCM](/parachains/interoperability/get-started/){target=\_blank} article. -Ensure to replace the `INSERT_BLOCK_HASH` with the proper values. +### Bridges: Connecting External Networks ---- +While XCM enables interoperability within the Polkadot ecosystem, bridges extend this functionality to external blockchains such as Ethereum and Bitcoin. By connecting these networks, bridges allow Polkadot-based chains to access external liquidity, additional functionalities, and broader user bases. -### eth_getCode +With bridges, developers and users gain the ability to: -Returns the code at a given address. [Reference](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_getcode){target=\_blank}. +- Integrate external assets into Polkadot-based applications. +- Combine the strengths of Polkadot’s scalability with the liquidity of other networks. +- Facilitate accurate multi-chain applications that transcend ecosystem boundaries. -**Parameters**: +For more information about bridges in the Polkadot ecosystem, see the [Bridge Hub](/reference/polkadot-hub/bridging/){target=\_blank} guide. -- **`address` ++"string"++**: Contract or account address to query code. Must be a [20-byte data](https://ethereum.org/en/developers/docs/apis/json-rpc/#unformatted-data-encoding){target=\_blank} string. -- **`blockValue` ++"string"++**: (Optional) The block value to be fetched. Must be a [quantity](https://ethereum.org/en/developers/docs/apis/json-rpc/#quantities-encoding){target=\_blank} string or a [default block parameter](https://ethereum.org/en/developers/docs/apis/json-rpc/#default-block). +## The Polkadot Advantage -**Example**: +Polkadot was purpose-built for interoperability. Unlike networks that add interoperability as an afterthought, Polkadot integrates it as a fundamental design principle. This approach offers several distinct advantages: -```bash title="eth_getCode" -curl -X POST https://testnet-passet-hub-eth-rpc.polkadot.io \ --H "Content-Type: application/json" \ ---data '{ - "jsonrpc":"2.0", - "method":"eth_getCode", - "params":["INSERT_ADDRESS", "INSERT_BLOCK_VALUE"], - "id":1 -}' -``` +- **Developer empowerment**: Polkadot’s interoperability tools allow developers to build applications that leverage multiple chains’ capabilities without added complexity. +- **Enhanced ecosystem collaboration**: Chains in Polkadot can focus on their unique strengths while contributing to the ecosystem’s overall growth. +- **Future-proofing blockchain**: By enabling seamless communication, Polkadot ensures its ecosystem can adapt to evolving demands and technologies. + +## Looking Ahead + +Polkadot’s vision of interoperability extends beyond technical functionality, representing a shift towards a more collaborative blockchain landscape. By enabling chains to work together, Polkadot fosters innovation, efficiency, and accessibility, paving the way for a decentralized future where blockchains are not isolated competitors but interconnected collaborators. -Ensure to replace the `INSERT_ADDRESS` and `INSERT_BLOCK_VALUE` with the proper values. --- -### eth_getLogs +Page Title: Introduction to XCM -Returns an array of all logs matching a given filter object. [Reference](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_getlogs){target=\_blank}. +- Source (raw): https://raw.githubusercontent.com/polkadot-developers/polkadot-docs/master/.ai/pages/parachains-interoperability-get-started.md +- Canonical (HTML): https://docs.polkadot.com/parachains/interoperability/get-started/ +- Summary: Unlock blockchain interoperability with XCM — Polkadot's Cross-Consensus Messaging format for cross-chain interactions. -**Parameters**: +# Introduction to XCM -- **`filter` ++"object"++**: The filter object. - - **`fromBlock` ++"string"++**: (Optional) Block number or tag to start from. Must be a [quantity](https://ethereum.org/en/developers/docs/apis/json-rpc/#quantities-encoding){target=\_blank} string or a [default block parameter](https://ethereum.org/en/developers/docs/apis/json-rpc/#default-block){target=\_blank}. - - **`toBlock` ++"string"++**: (Optional) Block number or tag to end at. Must be a [quantity](https://ethereum.org/en/developers/docs/apis/json-rpc/#quantities-encoding){target=\_blank} string or a [default block parameter](https://ethereum.org/en/developers/docs/apis/json-rpc/#default-block){target=\_blank}. - - **`address` ++"string" or "array of strings"++**: (Optional) Contract address or a list of addresses from which to get logs. Must be a [20-byte data](https://ethereum.org/en/developers/docs/apis/json-rpc/#unformatted-data-encoding){target=\_blank} string. - - **`topics` ++"array of strings"++**: (Optional) Array of topics for filtering logs. Each topic can be a single [32 byte data](https://ethereum.org/en/developers/docs/apis/json-rpc/#unformatted-data-encoding){target=\_blank} string or an array of such strings (meaning OR). - - **`blockhash` ++"string"++**: (Optional) Hash of a specific block. Cannot be used with `fromBlock` or `toBlock`. Must be a [32 byte data](https://ethereum.org/en/developers/docs/apis/json-rpc/#unformatted-data-encoding){target=\_blank} string. +## Introduction -**Example**: +Polkadot’s unique value lies in its ability to enable interoperability between parachains and other blockchain systems. At the core of this capability is XCM (Cross-Consensus Messaging)—a flexible messaging format that facilitates communication and collaboration between independent consensus systems. -```bash title="eth_getLogs" -curl -X POST https://testnet-passet-hub-eth-rpc.polkadot.io \ --H "Content-Type: application/json" \ ---data '{ - "jsonrpc":"2.0", - "method":"eth_getLogs", - "params":[{ - "fromBlock": "latest", - "toBlock": "latest" - }], - "id":1 -}' -``` +With XCM, one chain can send intents to another one, fostering a more interconnected ecosystem. Although it was developed specifically for Polkadot, XCM is a universal format, usable in any blockchain environment. This guide provides an overview of XCM’s core principles, design, and functionality, alongside practical examples of its implementation. ---- +## Messaging Format -### eth_getStorageAt +XCM is not a protocol but a standardized [messaging format](https://github.com/polkadot-fellows/xcm-format){target=\_blank}. It defines the structure and behavior of messages but does not handle their delivery. This separation allows developers to focus on crafting instructions for target systems without worrying about transmission mechanics. -Returns the value from a storage position at a given address. [Reference](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_getstorageat){target=\_blank}. +XCM messages are intent-driven, outlining desired actions for the receiving blockchain to consider and potentially alter its state. These messages do not directly execute changes; instead, they rely on the host chain's environment to interpret and implement them. By utilizing asynchronous composability, XCM facilitates efficient execution where messages can be processed independently of their original order, similar to how RESTful services handle HTTP requests without requiring sequential processing. -**Parameters**: +## The Four Principles of XCM -- **`address` ++"string"++**: Contract or account address to query code. Must be a [20-byte data](https://ethereum.org/en/developers/docs/apis/json-rpc/#unformatted-data-encoding){target=\_blank} string. -- **`storageKey` ++"string"++**: Position in storage to retrieve data from. Must be a [quantity](https://ethereum.org/en/developers/docs/apis/json-rpc/#quantities-encoding){target=\_blank} string. -- **`blockValue` ++"string"++**: (Optional) The block value to be fetched. Must be a [quantity](https://ethereum.org/en/developers/docs/apis/json-rpc/#quantities-encoding){target=\_blank} string or a [default block parameter](https://ethereum.org/en/developers/docs/apis/json-rpc/#default-block). +XCM adheres to four guiding principles that ensure robust and reliable communication across consensus systems: -**Example**: +- **Asynchronous**: XCM messages operate independently of sender acknowledgment, avoiding delays due to blocked processes. +- **Absolute**: XCM messages are guaranteed to be delivered and interpreted accurately, in order, and timely. Once a message is sent, one can be sure it will be processed as intended. +- **Asymmetric**: XCM messages follow the 'fire and forget' paradigm meaning no automatic feedback is provided to the sender. Any results must be communicated separately to the sender with an additional message back to the origin. +- **Agnostic**: XCM operates independently of the specific consensus mechanisms, making it compatible across diverse systems. -```bash title="eth_getStorageAt" -curl -X POST https://testnet-passet-hub-eth-rpc.polkadot.io \ --H "Content-Type: application/json" \ ---data '{ - "jsonrpc":"2.0", - "method":"eth_getStorageAt", - "params":["INSERT_ADDRESS", "INSERT_STORAGE_KEY", "INSERT_BLOCK_VALUE"], - "id":1 -}' -``` +These principles guarantee that XCM provides a reliable framework for cross-chain communication, even in complex environments. + +## The XCM Tech Stack -Ensure to replace the `INSERT_ADDRESS`, `INSERT_STORAGE_KEY`, and `INSERT_BLOCK_VALUE` with the proper values. +![Diagram of the XCM tech stack](/images/parachains/interoperability/get-started/intro-to-xcm-01.webp) ---- +The XCM tech stack is designed to facilitate seamless interoperable communication between chains that reside within the Polkadot ecosystem. XCM can be used to express the meaning of the messages over each of the communication channels. -### eth_getTransactionCount +## Core Functionalities of XCM -Returns the number of transactions sent from an address (nonce). [Reference](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_gettransactioncount){target=\_blank}. +XCM enhances cross-consensus communication by introducing several powerful features: -**Parameters**: +- **Programmability**: Supports dynamic message handling, allowing for more comprehensive use cases. Includes branching logic, safe dispatches for version checks, and asset operations like NFT management. +- **Functional Multichain Decomposition**: Enables mechanisms such as remote asset locking, asset namespacing, and inter-chain state referencing, with contextual message identification. +- **Bridging**: Establishes a universal reference framework for multi-hop setups, connecting disparate systems like Ethereum and Bitcoin with the Polkadot relay chain acting as a universal location. -- **`address` ++"string"++**: Address to query balance. Must be a [20-byte data](https://ethereum.org/en/developers/docs/apis/json-rpc/#unformatted-data-encoding){target=\_blank} string. -- **`blockValue` ++"string"++**: (Optional) The block value to be fetched. Must be a [quantity](https://ethereum.org/en/developers/docs/apis/json-rpc/#quantities-encoding){target=\_blank} string or a [default block parameter](https://ethereum.org/en/developers/docs/apis/json-rpc/#default-block). +The standardized format for messages allows parachains to handle tasks like user balances, governance, and staking, freeing the Polkadot relay chain to focus on shared security. These features make XCM indispensable for implementing scalable and interoperable blockchain applications. -**Example**: +## XCM Example -```bash title="eth_getTransactionCount" -curl -X POST https://testnet-passet-hub-eth-rpc.polkadot.io \ --H "Content-Type: application/json" \ ---data '{ - "jsonrpc":"2.0", - "method":"eth_getTransactionCount", - "params":["INSERT_ADDRESS", "INSERT_BLOCK_VALUE"], - "id":1 -}' -``` +The following is a simplified XCM message demonstrating a token transfer from Alice to Bob on the same chain (ParaA). -Ensure to replace the `INSERT_ADDRESS` and `INSERT_BLOCK_VALUE` with the proper values. +```rust +let message = Xcm(vec![ + WithdrawAsset((Here, amount).into()), + BuyExecution { + fees: (Here, amount).into(), + weight_limit: WeightLimit::Unlimited + }, + DepositAsset { + assets: All.into(), + beneficiary: MultiLocation { + parents: 0, + interior: Junction::AccountId32 { + network: None, + id: BOB.clone().into() + }.into(), + }.into() + } +]); +``` ---- +The message consists of three instructions described as follows: -### eth_getTransactionByHash +- **[WithdrawAsset](https://github.com/polkadot-fellows/xcm-format?tab=readme-ov-file#withdrawasset){target=\_blank}**: Transfers a specified number of tokens from Alice's account to a holding register. -Returns information about a transaction by its hash. [Reference](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_gettransactionbyhash){target=\_blank}. + ```rust + WithdrawAsset((Here, amount).into()), + ``` -**Parameters**: + - **`Here`**: The native parachain token. + - **`amount`**: The number of tokens that are transferred. -- **`transactionHash` ++"string"++**: The hash of the transaction. Must be a [32 byte data](https://ethereum.org/en/developers/docs/apis/json-rpc/#unformatted-data-encoding){target=\_blank} string. + The first instruction takes as an input the MultiAsset that should be withdrawn. The MultiAsset describes the native parachain token with the `Here` keyword. The `amount` parameter is the number of tokens that are transferred. The withdrawal account depends on the origin of the message. In this example the origin of the message is Alice. The `WithdrawAsset` instruction moves `amount` number of native tokens from Alice's account into the holding register. -**Example**: +- **[BuyExecution](https://github.com/polkadot-fellows/xcm-format?tab=readme-ov-file#buyexecution){target=\_blank}**: Allocates fees to cover the execution [weight](/reference/glossary/#weight){target=\_blank} of the XCM instructions. -```bash title="eth_getTransactionByHash" -curl -X POST https://testnet-passet-hub-eth-rpc.polkadot.io \ --H "Content-Type: application/json" \ ---data '{ - "jsonrpc":"2.0", - "method":"eth_getTransactionByHash", - "params":["INSERT_TRANSACTION_HASH"], - "id":1 -}' -``` + ```rust + BuyExecution { + fees: (Here, amount).into(), + weight_limit: WeightLimit::Unlimited + }, + ``` -Ensure to replace the `INSERT_TRANSACTION_HASH` with the proper values. + - **`fees`**: Describes the asset in the holding register that should be used to pay for the weight. + - **`weight_limit`**: Defines the maximum fees that can be used to buy weight. ---- +- **[DepositAsset](https://github.com/polkadot-fellows/xcm-format?tab=readme-ov-file#depositasset){target=\_blank}**: Moves the remaining tokens from the holding register to Bob’s account. -### eth_getTransactionByBlockNumberAndIndex + ```rust + DepositAsset { + assets: All.into(), + beneficiary: MultiLocation { + parents: 0, + interior: Junction::AccountId32 { + network: None, + id: BOB.clone().into() + }.into(), + }.into() + } + ``` -Returns information about a transaction by block number and transaction index. [Reference](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_gettransactionbyblocknumberandindex){target=\_blank}. + - **`All`**: The wildcard for the asset(s) to be deposited. In this case, all assets in the holding register should be deposited. + +This step-by-step process showcases how XCM enables precise state changes within a blockchain system. You can find a complete XCM message example in the [XCM repository](https://github.com/paritytech/xcm-docs/blob/main/examples/src/0_first_look/mod.rs){target=\_blank}. -**Parameters**: +## Overview -- **`blockValue` ++"string"++**: The block value to be fetched. Must be a [quantity](https://ethereum.org/en/developers/docs/apis/json-rpc/#quantities-encoding){target=\_blank} string or a [default block parameter](https://ethereum.org/en/developers/docs/apis/json-rpc/#default-block){target=\_blank}. -- **`transactionIndex` ++"string"++**: The index of the transaction in the block. Must be a [quantity](https://ethereum.org/en/developers/docs/apis/json-rpc/#quantities-encoding){target=\_blank} string. +XCM revolutionizes cross-chain communication by enabling use cases such as: -**Example**: +- Token transfers between blockchains. +- Asset locking for cross-chain smart contract interactions. +- Remote execution of functions on other blockchains. -```bash title="eth_getTransactionByBlockNumberAndIndex" -curl -X POST https://testnet-passet-hub-eth-rpc.polkadot.io \ --H "Content-Type: application/json" \ ---data '{ - "jsonrpc":"2.0", - "method":"eth_getTransactionByBlockNumberAndIndex", - "params":["INSERT_BLOCK_VALUE", "INSERT_TRANSACTION_INDEX"], - "id":1 -}' -``` +These functionalities empower developers to build innovative, multi-chain applications, leveraging the strengths of various blockchain networks. To stay updated on XCM’s evolving format or contribute, visit the [XCM repository](https://github.com/paritytech/xcm-docs/blob/main/examples/src/0_first_look/mod.rs){target=\_blank}. -Ensure to replace the `INSERT_BLOCK_VALUE` and `INSERT_TRANSACTION_INDEX` with the proper values. --- -### eth_getTransactionByBlockHashAndIndex +Page Title: JSON-RPC APIs -Returns information about a transaction by block hash and transaction index. [Reference](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_gettransactionbyblockhashandindex){target=\_blank}. +- Source (raw): https://raw.githubusercontent.com/polkadot-developers/polkadot-docs/master/.ai/pages/smart-contracts-for-eth-devs-json-rpc-apis.md +- Canonical (HTML): https://docs.polkadot.com/smart-contracts/for-eth-devs/json-rpc-apis/ +- Summary: JSON-RPC APIs guide for Polkadot Hub, covering supported methods, parameters, and examples for interacting with the chain. -**Parameters**: +# JSON-RPC APIs -- **`blockHash` ++"string"++**: The hash of the block. Must be a [32 byte data](https://ethereum.org/en/developers/docs/apis/json-rpc/#unformatted-data-encoding){target=\_blank} string. -- **`transactionIndex` ++"string"++**: The index of the transaction in the block. Must be a [quantity](https://ethereum.org/en/developers/docs/apis/json-rpc/#quantities-encoding){target=\_blank} string. +!!! smartcontract "PolkaVM Preview Release" + PolkaVM smart contracts with Ethereum compatibility are in **early-stage development and may be unstable or incomplete**. +## Introduction -**Example**: +Polkadot Hub provides Ethereum compatibility through its JSON-RPC interface, allowing developers to interact with the chain using familiar Ethereum tooling and methods. This document outlines the supported [Ethereum JSON-RPC methods](https://ethereum.org/en/developers/docs/apis/json-rpc/#json-rpc-methods){target=\_blank} and provides examples of how to use them. -```bash title="eth_getTransactionByBlockHashAndIndex" -curl -X POST https://testnet-passet-hub-eth-rpc.polkadot.io \ --H "Content-Type: application/json" \ ---data '{ - "jsonrpc":"2.0", - "method":"eth_getTransactionByBlockHashAndIndex", - "params":["INSERT_BLOCK_HASH", "INSERT_TRANSACTION_INDEX"], - "id":1 -}' -``` +This guide uses the Polkadot Hub TestNet endpoint: -Ensure to replace the `INSERT_BLOCK_HASH` and `INSERT_TRANSACTION_INDEX` with the proper values. +```text +https://testnet-passet-hub-eth-rpc.polkadot.io +``` ---- +## Available Methods -### eth_getTransactionReceipt +### eth_accounts -Returns the receipt of a transaction by transaction hash. [Reference](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_gettransactionreceipt){target=\_blank}. +Returns a list of addresses owned by the client. [Reference](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_accounts){target=\_blank}. **Parameters**: -- **`transactionHash` ++"string"++**: The hash of the transaction. Must be a [32 byte data](https://ethereum.org/en/developers/docs/apis/json-rpc/#unformatted-data-encoding){target=\_blank} string. +None. **Example**: -```bash title="eth_getTransactionReceipt" +```bash title="eth_accounts" curl -X POST https://testnet-passet-hub-eth-rpc.polkadot.io \ -H "Content-Type: application/json" \ --data '{ "jsonrpc":"2.0", - "method":"eth_getTransactionReceipt", - "params":["INSERT_TRANSACTION_HASH"], + "method":"eth_accounts", + "params":[], "id":1 }' ``` -Ensure to replace the `INSERT_TRANSACTION_HASH` with the proper values. - --- -### eth_maxPriorityFeePerGas +### eth_blockNumber -Returns an estimate of the current priority fee per gas, in Wei, to be included in a block. +Returns the number of the most recent block. [Reference](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_blocknumber){target=\_blank}. **Parameters**: @@ -9551,12 +9924,12 @@ None. **Example**: -```bash title="eth_maxPriorityFeePerGas" +```bash title="eth_blockNumber" curl -X POST https://testnet-passet-hub-eth-rpc.polkadot.io \ -H "Content-Type: application/json" \ --data '{ "jsonrpc":"2.0", - "method":"eth_maxPriorityFeePerGas", + "method":"eth_blockNumber", "params":[], "id":1 }' @@ -9564,97 +9937,102 @@ curl -X POST https://testnet-passet-hub-eth-rpc.polkadot.io \ --- -### eth_sendRawTransaction +### eth_call -Submits a raw transaction. [Reference](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_sendrawtransaction){target=\_blank}. +Executes a new message call immediately without creating a transaction. [Reference](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_call){target=\_blank}. **Parameters**: -- **`callData` ++"string"++**: Signed transaction data. Must be a [data](https://ethereum.org/en/developers/docs/apis/json-rpc/#unformatted-data-encoding){target=\_blank} string. +- **`transaction` ++"object"++**: The transaction call object. + - **`to` ++"string"++**: Recipient address of the call. Must be a [20-byte data](https://ethereum.org/en/developers/docs/apis/json-rpc/#unformatted-data-encoding){target=\_blank} string. + - **`data` ++"string"++**: Hash of the method signature and encoded parameters. Must be a [data](https://ethereum.org/en/developers/docs/apis/json-rpc/#unformatted-data-encoding){target=\_blank} string. + - **`from` ++"string"++**: (Optional) Sender's address for the call. Must be a [20-byte data](https://ethereum.org/en/developers/docs/apis/json-rpc/#unformatted-data-encoding){target=\_blank} string. + - **`gas` ++"string"++**: (Optional) Gas limit to execute the call. Must be a [quantity](https://ethereum.org/en/developers/docs/apis/json-rpc/#quantities-encoding){target=\_blank} string. + - **`gasPrice` ++"string"++**: (Optional) Gas price per unit of gas. Must be a [quantity](https://ethereum.org/en/developers/docs/apis/json-rpc/#quantities-encoding){target=\_blank} string. + - **`value` ++"string"++**: (Optional) Value in wei to send with the call. Must be a [quantity](https://ethereum.org/en/developers/docs/apis/json-rpc/#quantities-encoding){target=\_blank} string. +- **`blockValue` ++"string"++**: (Optional) Block tag or block number to execute the call at. Must be a [quantity](https://ethereum.org/en/developers/docs/apis/json-rpc/#quantities-encoding){target=\_blank} string or a [default block parameter](https://ethereum.org/en/developers/docs/apis/json-rpc/#default-block){target=\_blank}. **Example**: -```bash title="eth_sendRawTransaction" +```bash title="eth_call" curl -X POST https://testnet-passet-hub-eth-rpc.polkadot.io \ -H "Content-Type: application/json" \ --data '{ "jsonrpc":"2.0", - "method":"eth_sendRawTransaction", - "params":["INSERT_CALL_DATA"], + "method":"eth_call", + "params":[{ + "to": "INSERT_RECIPIENT_ADDRESS", + "data": "INSERT_ENCODED_CALL" + }, "INSERT_BLOCK_VALUE"], "id":1 }' ``` -Ensure to replace the `INSERT_CALL_DATA` with the proper values. +Ensure to replace the `INSERT_RECIPIENT_ADDRESS`, `INSERT_ENCODED_CALL`, and `INSERT_BLOCK_VALUE` with the proper values. --- -### eth_sendTransaction +### eth_chainId -Creates and sends a new transaction. [Reference](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_sendtransaction){target=\_blank}. +Returns the chain ID used for signing transactions. [Reference](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_chainid){target=\_blank}. **Parameters**: -- **`transaction` ++"object"++**: The transaction object. - - **`from` ++"string"++**: Address sending the transaction. Must be a [20-byte data](https://ethereum.org/en/developers/docs/apis/json-rpc/#unformatted-data-encoding){target=\_blank} string. - - **`to` ++"string"++**: (Optional) Recipient address. No need to provide this value when deploying a contract. Must be a [20-byte data](https://ethereum.org/en/developers/docs/apis/json-rpc/#unformatted-data-encoding){target=\_blank} string. - - **`gas` ++"string"++**: (optional, default: `90000`) gas limit for execution. Must be a [quantity](https://ethereum.org/en/developers/docs/apis/json-rpc/#quantities-encoding){target=\_blank} string. - - **`gasPrice` ++"string"++**: (Optional) Gas price per unit. Must be a [quantity](https://ethereum.org/en/developers/docs/apis/json-rpc/#quantities-encoding){target=\_blank} string. - - **`value` ++"string"++**: (Optional) Amount of Ether to send. Must be a [quantity](https://ethereum.org/en/developers/docs/apis/json-rpc/#quantities-encoding){target=\_blank} string. - - **`data` ++"string"++**: (Optional) Contract bytecode or encoded method call. Must be a [data](https://ethereum.org/en/developers/docs/apis/json-rpc/#unformatted-data-encoding){target=\_blank} string. - - **`nonce` ++"string"++**: (Optional) Transaction nonce. Must be a [quantity](https://ethereum.org/en/developers/docs/apis/json-rpc/#quantities-encoding){target=\_blank} string. +None. **Example**: -```bash title="eth_sendTransaction" +```bash title="eth_chainId" curl -X POST https://testnet-passet-hub-eth-rpc.polkadot.io \ -H "Content-Type: application/json" \ --data '{ "jsonrpc":"2.0", - "method":"eth_sendTransaction", - "params":[{ - "from": "INSERT_SENDER_ADDRESS", - "to": "INSERT_RECIPIENT_ADDRESS", - "gas": "INSERT_GAS_LIMIT", - "gasPrice": "INSERT_GAS_PRICE", - "value": "INSERT_VALUE", - "input": "INSERT_INPUT_DATA", - "nonce": "INSERT_NONCE" - }], + "method":"eth_chainId", + "params":[], "id":1 }' ``` -Ensure to replace the `INSERT_SENDER_ADDRESS`, `INSERT_RECIPIENT_ADDRESS`, `INSERT_GAS_LIMIT`, `INSERT_GAS_PRICE`, `INSERT_VALUE`, `INSERT_INPUT_DATA`, and `INSERT_NONCE` with the proper values. - --- -### eth_syncing +### eth_estimateGas -Returns an object with syncing data or `false` if not syncing. [Reference](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_syncing){target=\_blank}. +Estimates gas required for a transaction. [Reference](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_estimategas){target=\_blank}. **Parameters**: -None. +- **`transaction` ++"object"++**: The transaction call object. + - **`to` ++"string"++**: Recipient address of the call. Must be a [20-byte data](https://ethereum.org/en/developers/docs/apis/json-rpc/#unformatted-data-encoding){target=\_blank} string. + - **`data` ++"string"++**: Hash of the method signature and encoded parameters. Must be a [data](https://ethereum.org/en/developers/docs/apis/json-rpc/#unformatted-data-encoding){target=\_blank} string. + - **`from` ++"string"++**: (Optional) Sender's address for the call. Must be a [20-byte data](https://ethereum.org/en/developers/docs/apis/json-rpc/#unformatted-data-encoding){target=\_blank} string. + - **`gas` ++"string"++**: (Optional) Gas limit to execute the call. Must be a [quantity](https://ethereum.org/en/developers/docs/apis/json-rpc/#quantities-encoding){target=\_blank} string. + - **`gasPrice` ++"string"++**: (Optional) Gas price per unit of gas. Must be a [quantity](https://ethereum.org/en/developers/docs/apis/json-rpc/#quantities-encoding){target=\_blank} string. + - **`value` ++"string"++**: (Optional) Value in wei to send with the call. Must be a [quantity](https://ethereum.org/en/developers/docs/apis/json-rpc/#quantities-encoding){target=\_blank} string. +- **`blockValue` ++"string"++**: (Optional) Block tag or block number to execute the call at. Must be a [quantity](https://ethereum.org/en/developers/docs/apis/json-rpc/#quantities-encoding){target=\_blank} string or a [default block parameter](https://ethereum.org/en/developers/docs/apis/json-rpc/#default-block){target=\_blank}. **Example**: -```bash title="eth_syncing" +```bash title="eth_estimateGas" curl -X POST https://testnet-passet-hub-eth-rpc.polkadot.io \ -H "Content-Type: application/json" \ --data '{ "jsonrpc":"2.0", - "method":"eth_syncing", - "params":[], + "method":"eth_estimateGas", + "params":[{ + "to": "INSERT_RECIPIENT_ADDRESS", + "data": "INSERT_ENCODED_FUNCTION_CALL" + }], "id":1 }' ``` +Ensure to replace the `INSERT_RECIPIENT_ADDRESS` and `INSERT_ENCODED_CALL` with the proper values. + --- -### net_listening +### eth_gasPrice -Returns `true` if the client is currently listening for network connections, otherwise `false`. [Reference](https://ethereum.org/en/developers/docs/apis/json-rpc/#net_listening){target=\_blank}. +Returns the current gas price in Wei. [Reference](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_gasprice){target=\_blank}. **Parameters**: @@ -9662,12 +10040,12 @@ None. **Example**: -```bash title="net_listening" +```bash title="eth_gasPrice" curl -X POST https://testnet-passet-hub-eth-rpc.polkadot.io \ -H "Content-Type: application/json" \ --data '{ "jsonrpc":"2.0", - "method":"net_listening", + "method":"eth_gasPrice", "params":[], "id":1 }' @@ -9675,1043 +10053,775 @@ curl -X POST https://testnet-passet-hub-eth-rpc.polkadot.io \ --- -### net_peerCount +### eth_getBalance -Returns the number of peers currently connected to the client. +Returns the balance of a given address. [Reference](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_getbalance){target=\_blank}. **Parameters**: -None. +- **`address` ++"string"++**: Address to query balance. Must be a [20-byte data](https://ethereum.org/en/developers/docs/apis/json-rpc/#unformatted-data-encoding){target=\_blank} string. +- **`blockValue` ++"string"++**: (Optional) The block value to be fetched. Must be a [quantity](https://ethereum.org/en/developers/docs/apis/json-rpc/#quantities-encoding){target=\_blank} string or a [default block parameter](https://ethereum.org/en/developers/docs/apis/json-rpc/#default-block){target=\_blank}. **Example**: -```bash title="net_peerCount" +```bash title="eth_getBalance" curl -X POST https://testnet-passet-hub-eth-rpc.polkadot.io \ -H "Content-Type: application/json" \ --data '{ "jsonrpc":"2.0", - "method":"net_peerCount", - "params":[], + "method":"eth_getBalance", + "params":["INSERT_ADDRESS", "INSERT_BLOCK_VALUE"], "id":1 }' ``` +Ensure to replace the `INSERT_ADDRESS` and `INSERT_BLOCK_VALUE` with the proper values. + --- -### net_version +### eth_getBlockByHash -Returns the current network ID as a string. [Reference](https://ethereum.org/en/developers/docs/apis/json-rpc/#net_version){target=\_blank}. +Returns information about a block by its hash. [Reference](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_getblockbyhash){target=\_blank}. **Parameters**: -None. +- **`blockHash` ++"string"++**: The hash of the block to retrieve. Must be a [32 byte data](https://ethereum.org/en/developers/docs/apis/json-rpc/#unformatted-data-encoding){target=\_blank} string. +- **`fullTransactions` ++"boolean"++**: If `true`, returns full transaction details; if `false`, returns only transaction hashes. **Example**: -```bash title="net_version" +```bash title="eth_getBlockByHash" curl -X POST https://testnet-passet-hub-eth-rpc.polkadot.io \ -H "Content-Type: application/json" \ --data '{ "jsonrpc":"2.0", - "method":"net_version", - "params":[], + "method":"eth_getBlockByHash", + "params":["INSERT_BLOCK_HASH", INSERT_BOOLEAN], "id":1 }' ``` +Ensure to replace the `INSERT_BLOCK_HASH` and `INSERT_BOOLEAN` with the proper values. + --- -### system_health +### eth_getBlockByNumber -Returns information about the health of the system. +Returns information about a block by its number. [Reference](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_getblockbynumber){target=\_blank}. **Parameters**: -None. +- **`blockValue` ++"string"++**: (Optional) The block value to be fetched. Must be a [quantity](https://ethereum.org/en/developers/docs/apis/json-rpc/#quantities-encoding){target=\_blank} string or a [default block parameter](https://ethereum.org/en/developers/docs/apis/json-rpc/#default-block){target=\_blank}. +- **`fullTransactions` ++"boolean"++**: If `true`, returns full transaction details; if `false`, returns only transaction hashes. **Example**: -```bash title="system_health" +```bash title="eth_getBlockByNumber" curl -X POST https://testnet-passet-hub-eth-rpc.polkadot.io \ -H "Content-Type: application/json" \ --data '{ "jsonrpc":"2.0", - "method":"system_health", - "params":[], + "method":"eth_getBlockByNumber", + "params":["INSERT_BLOCK_VALUE", INSERT_BOOLEAN], "id":1 }' ``` +Ensure to replace the `INSERT_BLOCK_VALUE` and `INSERT_BOOLEAN` with the proper values. + --- -### web3_clientVersion +### eth_getBlockTransactionCountByNumber -Returns the current client version. [Reference](https://ethereum.org/en/developers/docs/apis/json-rpc/#web3_clientversion){target=\_blank}. +Returns the number of transactions in a block from a block number. [Reference](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_getblocktransactioncountbynumber){target=\_blank}. **Parameters**: -None. +- **`blockValue` ++"string"++**: The block value to be fetched. Must be a [quantity](https://ethereum.org/en/developers/docs/apis/json-rpc/#quantities-encoding){target=\_blank} string or a [default block parameter](https://ethereum.org/en/developers/docs/apis/json-rpc/#default-block){target=\_blank}. **Example**: -```bash title="web3_clientVersion" +```bash title="eth_getBlockTransactionCountByNumber" curl -X POST https://testnet-passet-hub-eth-rpc.polkadot.io \ -H "Content-Type: application/json" \ --data '{ "jsonrpc":"2.0", - "method":"web3_clientVersion", - "params":[], + "method":"eth_getBlockTransactionCountByNumber", + "params":["INSERT_BLOCK_VALUE"], "id":1 }' ``` +Ensure to replace the `INSERT_BLOCK_VALUE` with the proper values. + --- -### debug_traceBlockByNumber +### eth_getBlockTransactionCountByHash -Traces a block's execution by its number and returns a detailed execution trace for each transaction. +Returns the number of transactions in a block from a block hash. [Reference](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_getblocktransactioncountbyhash){target=\_blank}. **Parameters**: -- **`blockValue` ++"string"++**: The block number or tag to trace. Must be a [quantity](https://ethereum.org/en/developers/docs/apis/json-rpc/#quantities-encoding){target=\_blank} string or a [default block parameter](https://ethereum.org/en/developers/docs/apis/json-rpc/#default-block){target=\_blank}. -- **`options` ++"object"++**: (Optional) An object containing tracer options. - - **`tracer` ++"string"++**: The name of the tracer to use (e.g., `"callTracer"`, `"opTracer"`). - - Other tracer-specific options may be supported. +- **`blockHash` ++"string"++**: The hash of the block to retrieve. Must be a [32 byte data](https://ethereum.org/en/developers/docs/apis/json-rpc/#unformatted-data-encoding){target=\_blank} string. **Example**: -```bash title="debug_traceBlockByNumber" +```bash title="eth_getBlockTransactionCountByHash" curl -X POST https://testnet-passet-hub-eth-rpc.polkadot.io \ -H "Content-Type: application/json" \ --data '{ "jsonrpc":"2.0", - "method":"debug_traceBlockByNumber", - "params":["INSERT_BLOCK_VALUE", {"tracer": "callTracer"}], + "method":"eth_getBlockTransactionCountByHash", + "params":["INSERT_BLOCK_HASH"], "id":1 }' ``` -Ensure to replace `INSERT_BLOCK_VALUE` with a proper block number if needed. +Ensure to replace the `INSERT_BLOCK_HASH` with the proper values. --- -### debug_traceTransaction +### eth_getCode -Traces the execution of a single transaction by its hash and returns a detailed execution trace. +Returns the code at a given address. [Reference](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_getcode){target=\_blank}. **Parameters**: -- **`transactionHash` ++"string"++**: The hash of the transaction to trace. Must be a [32 byte data](https://ethereum.org/en/developers/docs/apis/json-rpc/#unformatted-data-encoding){target=\_blank} string. -- **`options` ++"object"++**: (Optional) An object containing tracer options (e.g., `tracer: "callTracer"`). +- **`address` ++"string"++**: Contract or account address to query code. Must be a [20-byte data](https://ethereum.org/en/developers/docs/apis/json-rpc/#unformatted-data-encoding){target=\_blank} string. +- **`blockValue` ++"string"++**: (Optional) The block value to be fetched. Must be a [quantity](https://ethereum.org/en/developers/docs/apis/json-rpc/#quantities-encoding){target=\_blank} string or a [default block parameter](https://ethereum.org/en/developers/docs/apis/json-rpc/#default-block). **Example**: -```bash title="debug_traceTransaction" +```bash title="eth_getCode" curl -X POST https://testnet-passet-hub-eth-rpc.polkadot.io \ -H "Content-Type: application/json" \ --data '{ "jsonrpc":"2.0", - "method":"debug_traceTransaction", - "params":["INSERT_TRANSACTION_HASH", {"tracer": "callTracer"}], + "method":"eth_getCode", + "params":["INSERT_ADDRESS", "INSERT_BLOCK_VALUE"], "id":1 }' ``` -Ensure to replace the `INSERT_TRANSACTION_HASH` with the proper value. +Ensure to replace the `INSERT_ADDRESS` and `INSERT_BLOCK_VALUE` with the proper values. --- -### debug_traceCall +### eth_getLogs -Executes a new message call and returns a detailed execution trace without creating a transaction on the blockchain. +Returns an array of all logs matching a given filter object. [Reference](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_getlogs){target=\_blank}. **Parameters**: -- **`transaction` ++"object"++**: The transaction call object, similar to `eth_call` parameters. - - **`to` ++"string"++**: Recipient address of the call. Must be a [20-byte data](https://ethereum.org/en/developers/docs/apis/json-rpc/#unformatted-data-encoding){target=\_blank} string. - - **`data` ++"string"++**: Hash of the method signature and encoded parameters. Must be a [data](https://ethereum.org/en/developers/docs/apis/json-rpc/#unformatted-data-encoding){target=\_blank} string. - - **`from` ++"string"++**: (Optional) Sender's address for the call. Must be a [20-byte data](https://ethereum.org/en/developers/docs/apis/json-rpc/#unformatted-data-encoding){target=\_blank} string. - - **`gas` ++"string"++**: (Optional) Gas limit to execute the call. Must be a [quantity](https://ethereum.org/en/developers/docs/apis/json-rpc/#quantities-encoding){target=\_blank} string. - - **`gasPrice` ++"string"++**: (Optional) Gas price per unit of gas. Must be a [quantity](https://ethereum.org/en/developers/docs/apis/json-rpc/#quantities-encoding){target=\_blank} string. - - **`value` ++"string"++**: (Optional) Value in wei to send with the call. Must be a [quantity](https://ethereum.org/en/developers/docs/apis/json-rpc/#quantities-encoding){target=\_blank} string. -- **`blockValue` ++"string"++**: (Optional) Block tag or block number to execute the call at. Must be a [quantity](https://ethereum.org/en/developers/docs/apis/json-rpc/#quantities-encoding){target=\_blank} string or a [default block parameter](https://ethereum.org/en/developers/docs/apis/json-rpc/#default-block){target=\_blank}. -- **`options` ++"object"++**: (Optional) An object containing tracer options (e.g., `tracer: "callTracer"`). +- **`filter` ++"object"++**: The filter object. + - **`fromBlock` ++"string"++**: (Optional) Block number or tag to start from. Must be a [quantity](https://ethereum.org/en/developers/docs/apis/json-rpc/#quantities-encoding){target=\_blank} string or a [default block parameter](https://ethereum.org/en/developers/docs/apis/json-rpc/#default-block){target=\_blank}. + - **`toBlock` ++"string"++**: (Optional) Block number or tag to end at. Must be a [quantity](https://ethereum.org/en/developers/docs/apis/json-rpc/#quantities-encoding){target=\_blank} string or a [default block parameter](https://ethereum.org/en/developers/docs/apis/json-rpc/#default-block){target=\_blank}. + - **`address` ++"string" or "array of strings"++**: (Optional) Contract address or a list of addresses from which to get logs. Must be a [20-byte data](https://ethereum.org/en/developers/docs/apis/json-rpc/#unformatted-data-encoding){target=\_blank} string. + - **`topics` ++"array of strings"++**: (Optional) Array of topics for filtering logs. Each topic can be a single [32 byte data](https://ethereum.org/en/developers/docs/apis/json-rpc/#unformatted-data-encoding){target=\_blank} string or an array of such strings (meaning OR). + - **`blockhash` ++"string"++**: (Optional) Hash of a specific block. Cannot be used with `fromBlock` or `toBlock`. Must be a [32 byte data](https://ethereum.org/en/developers/docs/apis/json-rpc/#unformatted-data-encoding){target=\_blank} string. **Example**: -```bash title="debug_traceCall" +```bash title="eth_getLogs" curl -X POST https://testnet-passet-hub-eth-rpc.polkadot.io \ -H "Content-Type: application/json" \ --data '{ "jsonrpc":"2.0", - "method":"debug_traceCall", + "method":"eth_getLogs", "params":[{ - "from": "INSERT_SENDER_ADDRESS", - "to": "INSERT_RECIPIENT_ADDRESS", - "data": "INSERT_ENCODED_CALL" - }, "INSERT_BLOCK_VALUE", {"tracer": "callTracer"}], + "fromBlock": "latest", + "toBlock": "latest" + }], "id":1 }' ``` -Ensure to replace the `INSERT_SENDER_ADDRESS`, `INSERT_RECIPIENT_ADDRESS`, `INSERT_ENCODED_CALL`, and `INSERT_BLOCK_VALUE` with the proper value. - ---- - -## Response Format - -All responses follow the standard JSON-RPC 2.0 format: - -```json -{ - "jsonrpc": "2.0", - "id": 1, - "result": ... // The return value varies by method -} -``` - -## Error Handling - -If an error occurs, the response will include an error object: - -```json -{ - "jsonrpc": "2.0", - "id": 1, - "error": { - "code": -32000, - "message": "Error message here" - } -} -``` - - ---- - -Page Title: Light Clients - -- Source (raw): https://raw.githubusercontent.com/polkadot-developers/polkadot-docs/master/.ai/pages/reference-tools-light-clients.md -- Canonical (HTML): https://docs.polkadot.com/reference/tools/light-clients/ -- Summary: Light clients enable secure and efficient blockchain interaction without running a full node. Learn everything you need to know about light clients on Polkadot. - -# Light Clients - -## Introduction - -Light clients enable secure and efficient blockchain interaction without running a full node. They provide a trust-minimized alternative to JSON-RPC by verifying data through cryptographic proofs rather than blindly trusting remote nodes. - -This guide covers: - -- What light clients are and how they work. -- Their advantages compared to full nodes and JSON-RPC. -- Available implementations in the Polkadot ecosystem. -- How to use light clients in your applications. - -Light clients are particularly valuable for resource-constrained environments and applications requiring secure, decentralized blockchain access without the overhead of maintaining full nodes. - -!!!note "Light node or light client?" - The terms _light node_ and _light client_ are interchangeable. Both refer to a blockchain client that syncs without downloading the entire blockchain state. All nodes in a blockchain network are fundamentally clients, engaging in peer-to-peer communication. - -## Light Clients Workflow - -Unlike JSON-RPC interfaces, where an application must maintain a list of providers or rely on a single node, light clients are not limited to or dependent on a single node. They use cryptographic proofs to verify the blockchain's state, ensuring it is up-to-date and accurate. By verifying only block headers, light clients avoid syncing the entire state, making them ideal for resource-constrained environments. - -```mermaid -flowchart LR -DAPP([dApp])-- Query Account Info -->LC([Light Client]) -LC -- Request --> FN(((Full Node))) -LC -- Response --> DAPP -FN -- Response (validated via Merkle proof) --> LC -``` - -In the diagram above, the decentralized application queries on-chain account information through the light client. The light client runs as part of the application and requires minimal memory and computational resources. It uses Merkle proofs to verify the state retrieved from a full node in a trust-minimized manner. Polkadot-compatible light clients utilize [warp syncing](https://spec.polkadot.network/sect-lightclient#sect-sync-warp-lightclient){target=\_blank}, which downloads only block headers. - -Light clients can quickly verify the blockchain's state, including [GRANDPA finality](/polkadot-protocol/glossary#grandpa){target=\_blank} justifications. - -!!!note "What does it mean to be trust-minimized?" - _Trust-minimized_ means that the light client does not need to fully trust the full node from which it retrieves the state. This is achieved through the use of Merkle proofs, which allow the light client to verify the correctness of the state by checking the Merkle tree root. - -## JSON-RPC and Light Client Comparison - -Another common method of communication between a user interface (UI) and a node is through the JSON-RPC protocol. Generally, the UI retrieves information from the node, fetches network or [pallet](/polkadot-protocol/glossary#pallet){target=\_blank} data, and interacts with the blockchain. This is typically done in one of two ways: - -- **User-controlled nodes**: The UI connects to a node client installed on the user's machine. - - These nodes are secure, but installation and maintenance can be inconvenient. -- **Publicly accessible nodes**: The UI connects to a third-party-owned publicly accessible node client. - - These nodes are convenient but centralized and less secure. Applications must maintain a list of backup nodes in case the primary node becomes unavailable. - -While light clients still communicate with [full nodes](/polkadot-protocol/glossary#full-node), they offer significant advantages for applications requiring a secure alternative to running a full node: - -| Full Node | Light Client | -| :---------------------------------------------------------------------------------------------: | :------------------------------------------------------------: | -| Fully verifies all blocks of the chain | Verifies only the authenticity of blocks | -| Stores previous block data and the chain's storage in a database | Does not require a database | -| Installation, maintenance, and execution are resource-intensive and require technical expertise | No installation is typically included as part of the application | - -## Using Light Clients - -The [`smoldot`](https://github.com/smol-dot/smoldot){target=\_blank} client is the cornerstone of light client implementation for Polkadot SDK-based chains. It provides the primitives needed to build light clients and is also integrated into libraries such as [PAPI](#papi-light-client-support). - -### PAPI Light Client Support - -The [Polkadot API (PAPI)](/develop/toolkit/api-libraries/papi){target=\_blank} library natively supports light client configurations powered by [`smoldot`](https://github.com/smol-dot/smoldot){target=\_blank}. This allows developers to connect to multiple chains simultaneously using a light client. - -### Substrate Connect - Browser Extension - -The [Substrate Connect browser extension](https://www.npmjs.com/package/@substrate/connect-extension-protocol){target=\_blank} enables end-users to interact with applications connected to multiple blockchains or to connect their own blockchains to supported applications. - -Establishing a sufficient number of peers can be challenging due to browser limitations on WebSocket connections from HTTPS pages, as many nodes require TLS. The Substrate Connect browser extension addresses this limitation by keeping chains synced in the background, enabling faster application performance. - -Substrate Connect automatically detects whether the user has the extension installed. If not, an in-page Wasm light client is created for them. - -## Resources - -- [What is a light client and why you should care?](https://medium.com/paritytech/what-is-a-light-client-and-why-you-should-care-75f813ae2670){target=\_blank} -- [Introducing Substrate Connect: Browser-Based Light Clients for Connecting to Substrate Chains](https://www.parity.io/blog/introducing-substrate-connect){target=\_blank} -- [Substrate Connect GitHub Repository](https://github.com/paritytech/substrate-connect/tree/master/projects/extension){target=\_blank} -- [Light Clients - Polkadot Specification](https://spec.polkadot.network/sect-lightclient){target=\_blank} - - --- -Page Title: Make a Custom Pallet - -- Source (raw): https://raw.githubusercontent.com/polkadot-developers/polkadot-docs/master/.ai/pages/parachains-customize-runtime-pallet-development-create-a-pallet.md -- Canonical (HTML): https://docs.polkadot.com/parachains/customize-runtime/pallet-development/create-a-pallet/ -- Summary: Learn how to create custom pallets using FRAME, allowing for flexible, modular, and scalable blockchain development. Follow the step-by-step guide. - -# Make a Custom Pallet - -## Introduction - -[Framework for Runtime Aggregation of Modular Entities (FRAME)](https://paritytech.github.io/polkadot-sdk/master/polkadot_sdk_docs/polkadot_sdk/frame_runtime/index.html){target=\_blank} provides a powerful set of tools for blockchain development through modular components called [pallets](https://paritytech.github.io/polkadot-sdk/master/polkadot_sdk_docs/polkadot_sdk/frame_runtime/pallet/index.html){target=\_blank}. These Rust-based runtime modules allow you to build custom blockchain functionality with precision and flexibility. While FRAME includes a library of pre-built pallets, its true strength lies in the ability to create custom pallets tailored to your specific needs. +### eth_getStorageAt -In this guide, you'll learn how to build a custom counter pallet from scratch that demonstrates core pallet development concepts. The pallet you'll create includes: +Returns the value from a storage position at a given address. [Reference](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_getstorageat){target=\_blank}. -- User-triggered increment and decrement operations -- Root-only counter value setting -- Event emission for state changes -- Custom error handling -- Storage management -- User interaction tracking -- Genesis configuration for initial state +**Parameters**: -## Prerequisites +- **`address` ++"string"++**: Contract or account address to query code. Must be a [20-byte data](https://ethereum.org/en/developers/docs/apis/json-rpc/#unformatted-data-encoding){target=\_blank} string. +- **`storageKey` ++"string"++**: Position in storage to retrieve data from. Must be a [quantity](https://ethereum.org/en/developers/docs/apis/json-rpc/#quantities-encoding){target=\_blank} string. +- **`blockValue` ++"string"++**: (Optional) The block value to be fetched. Must be a [quantity](https://ethereum.org/en/developers/docs/apis/json-rpc/#quantities-encoding){target=\_blank} string or a [default block parameter](https://ethereum.org/en/developers/docs/apis/json-rpc/#default-block). -Before you begin, ensure you have: +**Example**: -- [Polkadot SDK dependencies installed](/parachains/install-polkadot-sdk/){target=\_blank} -- A [Polkadot SDK Parchain Template](/parachains/launch-a-parachain/set-up-the-parachain-template/){target=\_blank} set up locally -- Basic familiarity with [FRAME concepts](/parachains/customize-runtime/){target=\_blank} +```bash title="eth_getStorageAt" +curl -X POST https://testnet-passet-hub-eth-rpc.polkadot.io \ +-H "Content-Type: application/json" \ +--data '{ + "jsonrpc":"2.0", + "method":"eth_getStorageAt", + "params":["INSERT_ADDRESS", "INSERT_STORAGE_KEY", "INSERT_BLOCK_VALUE"], + "id":1 +}' +``` -## Core Pallet Components +Ensure to replace the `INSERT_ADDRESS`, `INSERT_STORAGE_KEY`, and `INSERT_BLOCK_VALUE` with the proper values. -As you build your custom pallet, you'll work with these key sections: +--- -- **Imports and dependencies**: Bring in necessary FRAME libraries and external modules. -- **Runtime configuration trait**: Specify types and constants for pallet-runtime interaction. -- **Runtime events**: Define signals that communicate state changes. -- **Runtime errors**: Define error types returned from dispatchable calls. -- **Runtime storage**: Declare on-chain storage items for your pallet's state. -- **Genesis configuration**: Set initial blockchain state. -- **Dispatchable functions (extrinsics)**: Create callable functions for user interactions. +### eth_getTransactionCount -For additional macros beyond those covered here, refer to the [pallet_macros](https://paritytech.github.io/polkadot-sdk/master/frame_support/pallet_macros/index.html){target=\_blank} section of the Polkadot SDK Docs. +Returns the number of transactions sent from an address (nonce). [Reference](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_gettransactioncount){target=\_blank}. -## Create the Pallet Project +**Parameters**: -Begin by creating a new Rust library project for your custom pallet within the [Polkadot SDK Parachain Template](https://github.com/paritytech/polkadot-sdk-parachain-template){target=\_blank}: +- **`address` ++"string"++**: Address to query balance. Must be a [20-byte data](https://ethereum.org/en/developers/docs/apis/json-rpc/#unformatted-data-encoding){target=\_blank} string. +- **`blockValue` ++"string"++**: (Optional) The block value to be fetched. Must be a [quantity](https://ethereum.org/en/developers/docs/apis/json-rpc/#quantities-encoding){target=\_blank} string or a [default block parameter](https://ethereum.org/en/developers/docs/apis/json-rpc/#default-block). -1. Navigate to the root directory of your parachain template: +**Example**: - ```bash - cd polkadot-sdk-parachain-template - ``` +```bash title="eth_getTransactionCount" +curl -X POST https://testnet-passet-hub-eth-rpc.polkadot.io \ +-H "Content-Type: application/json" \ +--data '{ + "jsonrpc":"2.0", + "method":"eth_getTransactionCount", + "params":["INSERT_ADDRESS", "INSERT_BLOCK_VALUE"], + "id":1 +}' +``` -2. Navigate to the `pallets` directory: +Ensure to replace the `INSERT_ADDRESS` and `INSERT_BLOCK_VALUE` with the proper values. - ```bash - cd pallets - ``` +--- -3. Create a new Rust library project: +### eth_getTransactionByHash - ```bash - cargo new --lib pallet-custom - ``` +Returns information about a transaction by its hash. [Reference](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_gettransactionbyhash){target=\_blank}. -4. Enter the new project directory: +**Parameters**: - ```bash - cd pallet-custom - ``` +- **`transactionHash` ++"string"++**: The hash of the transaction. Must be a [32 byte data](https://ethereum.org/en/developers/docs/apis/json-rpc/#unformatted-data-encoding){target=\_blank} string. -5. Verify the project structure. It should look like: +**Example**: - ``` - pallet-custom/ - ├── Cargo.toml - └── src/ - └── lib.rs - ``` +```bash title="eth_getTransactionByHash" +curl -X POST https://testnet-passet-hub-eth-rpc.polkadot.io \ +-H "Content-Type: application/json" \ +--data '{ + "jsonrpc":"2.0", + "method":"eth_getTransactionByHash", + "params":["INSERT_TRANSACTION_HASH"], + "id":1 +}' +``` -## Configure Dependencies +Ensure to replace the `INSERT_TRANSACTION_HASH` with the proper values. -To integrate your custom pallet into the Polkadot SDK-based runtime, configure the `Cargo.toml` file with the required dependencies. Since your pallet exists within the parachain template workspace, you'll use workspace inheritance to maintain version consistency. +--- -1. Open `Cargo.toml` and replace its contents with: +### eth_getTransactionByBlockNumberAndIndex - ```toml title="pallet-custom/Cargo.toml" - [package] - name = "pallet-custom" - description = "A custom counter pallet for demonstration purposes." - version = "0.1.0" - license = "Unlicense" - authors.workspace = true - homepage.workspace = true - repository.workspace = true - edition.workspace = true - publish = false +Returns information about a transaction by block number and transaction index. [Reference](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_gettransactionbyblocknumberandindex){target=\_blank}. - [package.metadata.docs.rs] - targets = ["x86_64-unknown-linux-gnu"] +**Parameters**: - [dependencies] - codec = { features = ["derive"], workspace = true } - scale-info = { features = ["derive"], workspace = true } - frame = { features = ["experimental", "runtime"], workspace = true } +- **`blockValue` ++"string"++**: The block value to be fetched. Must be a [quantity](https://ethereum.org/en/developers/docs/apis/json-rpc/#quantities-encoding){target=\_blank} string or a [default block parameter](https://ethereum.org/en/developers/docs/apis/json-rpc/#default-block){target=\_blank}. +- **`transactionIndex` ++"string"++**: The index of the transaction in the block. Must be a [quantity](https://ethereum.org/en/developers/docs/apis/json-rpc/#quantities-encoding){target=\_blank} string. - [features] - default = ["std"] - std = [ - "codec/std", - "scale-info/std", - "frame/std", - ] - ``` +**Example**: - !!!note "Version Management" - The parachain template uses workspace inheritance to maintain consistent dependency versions across all packages. The actual versions are defined in the root `Cargo.toml` file, ensuring compatibility throughout the project. By using `workspace = true`, your pallet automatically inherits the correct versions. +```bash title="eth_getTransactionByBlockNumberAndIndex" +curl -X POST https://testnet-passet-hub-eth-rpc.polkadot.io \ +-H "Content-Type: application/json" \ +--data '{ + "jsonrpc":"2.0", + "method":"eth_getTransactionByBlockNumberAndIndex", + "params":["INSERT_BLOCK_VALUE", "INSERT_TRANSACTION_INDEX"], + "id":1 +}' +``` -2. The parachain template already includes `pallets/*` in the workspace members, so your new pallet is automatically recognized. Verify this by checking the root `Cargo.toml`: +Ensure to replace the `INSERT_BLOCK_VALUE` and `INSERT_TRANSACTION_INDEX` with the proper values. - ```toml title="Cargo.toml" - [workspace.members] - members = [ - "node", - "pallets/*", - "runtime", - ] - ``` +--- -## Initialize the Pallet Structure +### eth_getTransactionByBlockHashAndIndex -With dependencies configured, set up the basic scaffold that will hold your pallet's logic: +Returns information about a transaction by block hash and transaction index. [Reference](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_gettransactionbyblockhashandindex){target=\_blank}. -1. Open `src/lib.rs` and delete all existing content. +**Parameters**: -2. Add the initial scaffold structure using the unified `frame` dependency: +- **`blockHash` ++"string"++**: The hash of the block. Must be a [32 byte data](https://ethereum.org/en/developers/docs/apis/json-rpc/#unformatted-data-encoding){target=\_blank} string. +- **`transactionIndex` ++"string"++**: The index of the transaction in the block. Must be a [quantity](https://ethereum.org/en/developers/docs/apis/json-rpc/#quantities-encoding){target=\_blank} string. - ```rust title="src/lib.rs" - #![cfg_attr(not(feature = "std"), no_std)] +**Example**: - pub use pallet::*; +```bash title="eth_getTransactionByBlockHashAndIndex" +curl -X POST https://testnet-passet-hub-eth-rpc.polkadot.io \ +-H "Content-Type: application/json" \ +--data '{ + "jsonrpc":"2.0", + "method":"eth_getTransactionByBlockHashAndIndex", + "params":["INSERT_BLOCK_HASH", "INSERT_TRANSACTION_INDEX"], + "id":1 +}' +``` - #[frame::pallet] - pub mod pallet { - use frame::prelude::*; +Ensure to replace the `INSERT_BLOCK_HASH` and `INSERT_TRANSACTION_INDEX` with the proper values. - #[pallet::pallet] - pub struct Pallet(_); +--- - #[pallet::config] - pub trait Config: frame_system::Config { - // Configuration will be added here - } +### eth_getTransactionReceipt - #[pallet::storage] - pub type CounterValue = StorageValue<_, u32, ValueQuery>; +Returns the receipt of a transaction by transaction hash. [Reference](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_gettransactionreceipt){target=\_blank}. - #[pallet::call] - impl Pallet { - // Dispatchable functions will be added here - } - } - ``` +**Parameters**: - !!!note - This setup starts with a minimal scaffold without events and errors. These will be added in the following sections after the `Config` trait is properly configured with the required `RuntimeEvent` type. +- **`transactionHash` ++"string"++**: The hash of the transaction. Must be a [32 byte data](https://ethereum.org/en/developers/docs/apis/json-rpc/#unformatted-data-encoding){target=\_blank} string. -3. Verify it compiles: +**Example**: - ```bash - cargo build --package pallet-custom - ``` +```bash title="eth_getTransactionReceipt" +curl -X POST https://testnet-passet-hub-eth-rpc.polkadot.io \ +-H "Content-Type: application/json" \ +--data '{ + "jsonrpc":"2.0", + "method":"eth_getTransactionReceipt", + "params":["INSERT_TRANSACTION_HASH"], + "id":1 +}' +``` -## Configure the Pallet +Ensure to replace the `INSERT_TRANSACTION_HASH` with the proper values. -The [`Config`](https://paritytech.github.io/polkadot-sdk/master/frame_system/pallet/trait.Config.html){target=\_blank} trait exposes configurable options and links your pallet to the runtime. All types and constants the pallet depends on must be declared here. These types are defined generically and become concrete when the pallet is instantiated at runtime. +--- -Replace the [`#[pallet::config]`](https://paritytech.github.io/polkadot-sdk/master/frame_support/pallet_macros/attr.config.html){target=\_blank} section with: +### eth_maxPriorityFeePerGas -```rust title="src/lib.rs" -#[pallet::config] -pub trait Config: frame_system::Config { - /// The overarching runtime event type. - type RuntimeEvent: From> + IsType<::RuntimeEvent>; - - /// Maximum value the counter can reach. - #[pallet::constant] - type CounterMaxValue: Get; -} -``` +Returns an estimate of the current priority fee per gas, in Wei, to be included in a block. -**Key configuration elements:** +**Parameters**: -- **[`RuntimeEvent`](https://paritytech.github.io/polkadot-sdk/master/frame_system/pallet/trait.Config.html#associatedtype.RuntimeEvent){target=\_blank}**: Required for the pallet to emit events that the runtime can process. -- **`CounterMaxValue`**: A constant that sets an upper limit on counter values, configurable per runtime. +None. -## Define Events +**Example**: -Events inform external entities (dApps, explorers, users) about significant runtime changes. Event details are included in the node's metadata, making them accessible to external tools. +```bash title="eth_maxPriorityFeePerGas" +curl -X POST https://testnet-passet-hub-eth-rpc.polkadot.io \ +-H "Content-Type: application/json" \ +--data '{ + "jsonrpc":"2.0", + "method":"eth_maxPriorityFeePerGas", + "params":[], + "id":1 +}' +``` -The [`#[pallet::generate_deposit]`](https://paritytech.github.io/polkadot-sdk/master/frame_support/pallet_macros/attr.generate_deposit.html){target=\_blank} macro automatically generates a `deposit_event` function that converts your pallet's events into the `RuntimeEvent` type and deposits them via [`frame_system::Pallet::deposit_event`](https://paritytech.github.io/polkadot-sdk/master/frame_system/pallet/struct.Pallet.html#method.deposit_event){target=\_blank}. +--- -Add the [`#[pallet::event]`](https://paritytech.github.io/polkadot-sdk/master/frame_support/pallet_macros/attr.event.html){target=\_blank} section after the `Config` trait: +### eth_sendRawTransaction -```rust title="src/lib.rs" -#[pallet::event] -#[pallet::generate_deposit(pub(super) fn deposit_event)] -pub enum Event { - /// Counter value was explicitly set. [new_value] - CounterValueSet { - new_value: u32 - }, - /// Counter was incremented. [new_value, who, amount] - CounterIncremented { - new_value: u32, - who: T::AccountId, - amount: u32, - }, - /// Counter was decremented. [new_value, who, amount] - CounterDecremented { - new_value: u32, - who: T::AccountId, - amount: u32, - }, -} +Submits a raw transaction. [Reference](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_sendrawtransaction){target=\_blank}. + +**Parameters**: + +- **`callData` ++"string"++**: Signed transaction data. Must be a [data](https://ethereum.org/en/developers/docs/apis/json-rpc/#unformatted-data-encoding){target=\_blank} string. + +**Example**: + +```bash title="eth_sendRawTransaction" +curl -X POST https://testnet-passet-hub-eth-rpc.polkadot.io \ +-H "Content-Type: application/json" \ +--data '{ + "jsonrpc":"2.0", + "method":"eth_sendRawTransaction", + "params":["INSERT_CALL_DATA"], + "id":1 +}' ``` -## Define Errors +Ensure to replace the `INSERT_CALL_DATA` with the proper values. -Errors indicate when and why a call fails. Use informative names and descriptions, as error documentation is included in the node's metadata. +--- -Error types must implement the [`TypeInfo`](https://paritytech.github.io/polkadot-sdk/master/frame_support/pallet_prelude/trait.TypeInfo.html){target=\_blank} trait, and runtime errors can be up to 4 bytes in size. +### eth_sendTransaction -Add the [`#[pallet::error]`](https://paritytech.github.io/polkadot-sdk/master/frame_support/pallet_macros/attr.error.html){target=\_blank} section after the events: +Creates and sends a new transaction. [Reference](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_sendtransaction){target=\_blank}. -```rust title="src/lib.rs" -#[pallet::error] -pub enum Error { - /// The counter value has not been set yet. - NoneValue, - /// Arithmetic operation would cause overflow. - Overflow, - /// Arithmetic operation would cause underflow. - Underflow, - /// The counter value would exceed the maximum allowed value. - CounterMaxValueExceeded, -} +**Parameters**: + +- **`transaction` ++"object"++**: The transaction object. + - **`from` ++"string"++**: Address sending the transaction. Must be a [20-byte data](https://ethereum.org/en/developers/docs/apis/json-rpc/#unformatted-data-encoding){target=\_blank} string. + - **`to` ++"string"++**: (Optional) Recipient address. No need to provide this value when deploying a contract. Must be a [20-byte data](https://ethereum.org/en/developers/docs/apis/json-rpc/#unformatted-data-encoding){target=\_blank} string. + - **`gas` ++"string"++**: (optional, default: `90000`) gas limit for execution. Must be a [quantity](https://ethereum.org/en/developers/docs/apis/json-rpc/#quantities-encoding){target=\_blank} string. + - **`gasPrice` ++"string"++**: (Optional) Gas price per unit. Must be a [quantity](https://ethereum.org/en/developers/docs/apis/json-rpc/#quantities-encoding){target=\_blank} string. + - **`value` ++"string"++**: (Optional) Amount of Ether to send. Must be a [quantity](https://ethereum.org/en/developers/docs/apis/json-rpc/#quantities-encoding){target=\_blank} string. + - **`data` ++"string"++**: (Optional) Contract bytecode or encoded method call. Must be a [data](https://ethereum.org/en/developers/docs/apis/json-rpc/#unformatted-data-encoding){target=\_blank} string. + - **`nonce` ++"string"++**: (Optional) Transaction nonce. Must be a [quantity](https://ethereum.org/en/developers/docs/apis/json-rpc/#quantities-encoding){target=\_blank} string. + +**Example**: + +```bash title="eth_sendTransaction" +curl -X POST https://testnet-passet-hub-eth-rpc.polkadot.io \ +-H "Content-Type: application/json" \ +--data '{ + "jsonrpc":"2.0", + "method":"eth_sendTransaction", + "params":[{ + "from": "INSERT_SENDER_ADDRESS", + "to": "INSERT_RECIPIENT_ADDRESS", + "gas": "INSERT_GAS_LIMIT", + "gasPrice": "INSERT_GAS_PRICE", + "value": "INSERT_VALUE", + "input": "INSERT_INPUT_DATA", + "nonce": "INSERT_NONCE" + }], + "id":1 +}' ``` -## Add Storage Items +Ensure to replace the `INSERT_SENDER_ADDRESS`, `INSERT_RECIPIENT_ADDRESS`, `INSERT_GAS_LIMIT`, `INSERT_GAS_PRICE`, `INSERT_VALUE`, `INSERT_INPUT_DATA`, and `INSERT_NONCE` with the proper values. -Storage items persist state on-chain. This pallet uses two storage items: +--- -- **`CounterValue`**: Stores the current counter value. -- **`UserInteractions`**: Tracks interaction counts per user account. +### eth_syncing -The initial scaffold already includes the `CounterValue` storage item. Now add the `UserInteractions` storage map after it: +Returns an object with syncing data or `false` if not syncing. [Reference](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_syncing){target=\_blank}. -```rust title="src/lib.rs" -/// Tracks the number of interactions per user. -#[pallet::storage] -pub type UserInteractions = StorageMap<_, Blake2_128Concat, T::AccountId, u32, ValueQuery>; -``` +**Parameters**: -Your storage section should now look like this: +None. -```rust title="src/lib.rs" -/// The current value of the counter. -#[pallet::storage] -pub type CounterValue = StorageValue<_, u32, ValueQuery>; +**Example**: -/// Tracks the number of interactions per user. -#[pallet::storage] -pub type UserInteractions = StorageMap<_, Blake2_128Concat, T::AccountId, u32, ValueQuery>; +```bash title="eth_syncing" +curl -X POST https://testnet-passet-hub-eth-rpc.polkadot.io \ +-H "Content-Type: application/json" \ +--data '{ + "jsonrpc":"2.0", + "method":"eth_syncing", + "params":[], + "id":1 +}' ``` -For more storage types and patterns, explore the [Polkadot SDK storage documentation](https://paritytech.github.io/polkadot-sdk/master/frame_support/storage/types/index.html){target=\_blank}. +--- -## Configure Genesis State +### net_listening -Genesis configuration allows you to set the initial state of your pallet when the blockchain first starts. This is essential for both production networks and testing environments. It is particularly useful for: +Returns `true` if the client is currently listening for network connections, otherwise `false`. [Reference](https://ethereum.org/en/developers/docs/apis/json-rpc/#net_listening){target=\_blank}. -- Setting initial parameter values. -- Pre-allocating resources or accounts. -- Establishing starting conditions for testing. -- Configuring network-specific initial state. +**Parameters**: -Add the [`#[pallet::genesis_config]`](https://paritytech.github.io/polkadot-sdk/master/frame_support/pallet_macros/attr.genesis_config.html){target=\_blank} and [`#[pallet::genesis_build]`](https://paritytech.github.io/polkadot-sdk/master/frame_support/pallet_macros/attr.genesis_build.html){target=\_blank} sections after your storage items: +None. -```rust title="src/lib.rs" -#[pallet::genesis_config] -#[derive(DefaultNoBound)] -pub struct GenesisConfig { - /// Initial value for the counter - pub initial_counter_value: u32, - /// Pre-populated user interactions - pub initial_user_interactions: Vec<(T::AccountId, u32)>, -} +**Example**: -#[pallet::genesis_build] -impl BuildGenesisConfig for GenesisConfig { - fn build(&self) { - // Set the initial counter value - CounterValue::::put(self.initial_counter_value); - - // Set initial user interactions - for (account, count) in &self.initial_user_interactions { - UserInteractions::::insert(account, count); - } - } -} +```bash title="net_listening" +curl -X POST https://testnet-passet-hub-eth-rpc.polkadot.io \ +-H "Content-Type: application/json" \ +--data '{ + "jsonrpc":"2.0", + "method":"net_listening", + "params":[], + "id":1 +}' ``` -**Genesis configuration components:** +--- -- **`GenesisConfig` struct**: Defines what can be configured at genesis. -- **`#[derive(DefaultNoBound)]`**: Provides sensible defaults (empty vec and 0 for the counter). -- **`BuildGenesisConfig` implementation**: Executes the logic to set initial storage values. -- **`build()` method**: Called once when the blockchain initializes. +### net_peerCount -## Implement Dispatchable Functions +Returns the number of peers currently connected to the client. -Dispatchable functions (extrinsics) allow users to interact with your pallet and trigger state changes. Each function must: +**Parameters**: -- Return a [`DispatchResult`](https://paritytech.github.io/polkadot-sdk/master/frame_support/dispatch/type.DispatchResult.html){target=\_blank}. -- Be annotated with a weight (computational cost). -- Have an explicit call index for backward compatibility. +None. -Replace the [`#[pallet::call]`](https://paritytech.github.io/polkadot-sdk/master/frame_support/pallet_macros/attr.call.html){target=\_blank} section with: +**Example**: -```rust title="src/lib.rs" -#[pallet::call] -impl Pallet { - /// Set the counter to a specific value. Root origin only. - #[pallet::call_index(0)] - #[pallet::weight(0)] - pub fn set_counter_value(origin: OriginFor, new_value: u32) -> DispatchResult { - // Ensure the caller is root - ensure_root(origin)?; - - // Validate the new value doesn't exceed the maximum - ensure!( - new_value <= T::CounterMaxValue::get(), - Error::::CounterMaxValueExceeded - ); - - // Update storage - CounterValue::::put(new_value); - - // Emit event - Self::deposit_event(Event::CounterValueSet { new_value }); - - Ok(()) - } +```bash title="net_peerCount" +curl -X POST https://testnet-passet-hub-eth-rpc.polkadot.io \ +-H "Content-Type: application/json" \ +--data '{ + "jsonrpc":"2.0", + "method":"net_peerCount", + "params":[], + "id":1 +}' +``` - /// Increment the counter by a specified amount. - #[pallet::call_index(1)] - #[pallet::weight(0)] - pub fn increment(origin: OriginFor, amount: u32) -> DispatchResult { - // Ensure the caller is signed - let who = ensure_signed(origin)?; - - // Get current counter value - let current_value = CounterValue::::get(); - - // Check for overflow - let new_value = current_value - .checked_add(amount) - .ok_or(Error::::Overflow)?; - - // Ensure new value doesn't exceed maximum - ensure!( - new_value <= T::CounterMaxValue::get(), - Error::::CounterMaxValueExceeded - ); - - // Update counter storage - CounterValue::::put(new_value); - - // Track user interaction - UserInteractions::::mutate(&who, |count| { - *count = count.saturating_add(1); - }); - - // Emit event - Self::deposit_event(Event::CounterIncremented { - new_value, - who, - amount, - }); - - Ok(()) - } +--- - /// Decrement the counter by a specified amount. - #[pallet::call_index(2)] - #[pallet::weight(0)] - pub fn decrement(origin: OriginFor, amount: u32) -> DispatchResult { - // Ensure the caller is signed - let who = ensure_signed(origin)?; - - // Get current counter value - let current_value = CounterValue::::get(); - - // Check for underflow - let new_value = current_value - .checked_sub(amount) - .ok_or(Error::::Underflow)?; - - // Update counter storage - CounterValue::::put(new_value); - - // Track user interaction - UserInteractions::::mutate(&who, |count| { - *count = count.saturating_add(1); - }); - - // Emit event - Self::deposit_event(Event::CounterDecremented { - new_value, - who, - amount, - }); - - Ok(()) - } -} -``` +### net_version + +Returns the current network ID as a string. [Reference](https://ethereum.org/en/developers/docs/apis/json-rpc/#net_version){target=\_blank}. -### Dispatchable Function Details +**Parameters**: -???+ interface "`set_counter_value`" +None. - - **Access**: Root origin only (privileged operations) - - **Purpose**: Set counter to a specific value - - **Validations**: New value must not exceed `CounterMaxValue` - - **State changes**: Updates `CounterValue` storage - - **Events**: Emits `CounterValueSet` +**Example**: -??? interface "`increment`" +```bash title="net_version" +curl -X POST https://testnet-passet-hub-eth-rpc.polkadot.io \ +-H "Content-Type: application/json" \ +--data '{ + "jsonrpc":"2.0", + "method":"net_version", + "params":[], + "id":1 +}' +``` - - **Access**: Any signed account - - **Purpose**: Increase counter by specified amount - - **Validations**: Checks for overflow and max value compliance - - **State changes**: Updates `CounterValue` and `UserInteractions` - - **Events**: Emits `CounterIncremented` +--- -??? interface "`decrement`" +### system_health - - **Access**: Any signed account - - **Purpose**: Decrease counter by specified amount - - **Validations**: Checks for underflow - - **State changes**: Updates `CounterValue` and `UserInteractions` - - **Events**: Emits `CounterDecremented` +Returns information about the health of the system. -## Verify Pallet Compilation +**Parameters**: + +None. -Before proceeding, ensure your pallet compiles without errors: +**Example**: -```bash -cargo build --package pallet-custom +```bash title="system_health" +curl -X POST https://testnet-passet-hub-eth-rpc.polkadot.io \ +-H "Content-Type: application/json" \ +--data '{ + "jsonrpc":"2.0", + "method":"system_health", + "params":[], + "id":1 +}' ``` -If you encounter errors, carefully review the code against this guide. Once the build completes successfully, your custom pallet is ready for integration. +--- -??? code "Complete Pallet Implementation" - - ```rust title="src/lib.rs" - #![cfg_attr(not(feature = "std"), no_std)] +### web3_clientVersion - pub use pallet::*; +Returns the current client version. [Reference](https://ethereum.org/en/developers/docs/apis/json-rpc/#web3_clientversion){target=\_blank}. - #[frame::pallet] - pub mod pallet { - use frame::prelude::*; +**Parameters**: - #[pallet::pallet] - pub struct Pallet(_); +None. - #[pallet::config] - pub trait Config: frame_system::Config { - type RuntimeEvent: From> + IsType<::RuntimeEvent>; - - #[pallet::constant] - type CounterMaxValue: Get; - } +**Example**: - #[pallet::event] - #[pallet::generate_deposit(pub(super) fn deposit_event)] - pub enum Event { - CounterValueSet { new_value: u32 }, - CounterIncremented { new_value: u32, who: T::AccountId, amount: u32 }, - CounterDecremented { new_value: u32, who: T::AccountId, amount: u32 }, - } +```bash title="web3_clientVersion" +curl -X POST https://testnet-passet-hub-eth-rpc.polkadot.io \ +-H "Content-Type: application/json" \ +--data '{ + "jsonrpc":"2.0", + "method":"web3_clientVersion", + "params":[], + "id":1 +}' +``` - #[pallet::error] - pub enum Error { - NoneValue, - Overflow, - Underflow, - CounterMaxValueExceeded, - } +--- - #[pallet::storage] - pub type CounterValue = StorageValue<_, u32, ValueQuery>; +### debug_traceBlockByNumber - #[pallet::storage] - pub type UserInteractions = StorageMap<_, Blake2_128Concat, T::AccountId, u32, ValueQuery>; +Traces a block's execution by its number and returns a detailed execution trace for each transaction. - #[pallet::genesis_config] - #[derive(DefaultNoBound)] - pub struct GenesisConfig { - pub initial_counter_value: u32, - pub initial_user_interactions: Vec<(T::AccountId, u32)>, - } +**Parameters**: - #[pallet::genesis_build] - impl BuildGenesisConfig for GenesisConfig { - fn build(&self) { - CounterValue::::put(self.initial_counter_value); - for (account, count) in &self.initial_user_interactions { - UserInteractions::::insert(account, count); - } - } - } +- **`blockValue` ++"string"++**: The block number or tag to trace. Must be a [quantity](https://ethereum.org/en/developers/docs/apis/json-rpc/#quantities-encoding){target=\_blank} string or a [default block parameter](https://ethereum.org/en/developers/docs/apis/json-rpc/#default-block){target=\_blank}. +- **`options` ++"object"++**: (Optional) An object containing tracer options. + - **`tracer` ++"string"++**: The name of the tracer to use (e.g., `"callTracer"`, `"opTracer"`). + - Other tracer-specific options may be supported. - #[pallet::call] - impl Pallet { - #[pallet::call_index(0)] - #[pallet::weight(0)] - pub fn set_counter_value(origin: OriginFor, new_value: u32) -> DispatchResult { - ensure_root(origin)?; - ensure!(new_value <= T::CounterMaxValue::get(), Error::::CounterMaxValueExceeded); - CounterValue::::put(new_value); - Self::deposit_event(Event::CounterValueSet { new_value }); - Ok(()) - } +**Example**: - #[pallet::call_index(1)] - #[pallet::weight(0)] - pub fn increment(origin: OriginFor, amount: u32) -> DispatchResult { - let who = ensure_signed(origin)?; - let current_value = CounterValue::::get(); - let new_value = current_value.checked_add(amount).ok_or(Error::::Overflow)?; - ensure!(new_value <= T::CounterMaxValue::get(), Error::::CounterMaxValueExceeded); - CounterValue::::put(new_value); - UserInteractions::::mutate(&who, |count| *count = count.saturating_add(1)); - Self::deposit_event(Event::CounterIncremented { new_value, who, amount }); - Ok(()) - } +```bash title="debug_traceBlockByNumber" +curl -X POST https://testnet-passet-hub-eth-rpc.polkadot.io \ +-H "Content-Type: application/json" \ +--data '{ + "jsonrpc":"2.0", + "method":"debug_traceBlockByNumber", + "params":["INSERT_BLOCK_VALUE", {"tracer": "callTracer"}], + "id":1 +}' +``` - #[pallet::call_index(2)] - #[pallet::weight(0)] - pub fn decrement(origin: OriginFor, amount: u32) -> DispatchResult { - let who = ensure_signed(origin)?; - let current_value = CounterValue::::get(); - let new_value = current_value.checked_sub(amount).ok_or(Error::::Underflow)?; - CounterValue::::put(new_value); - UserInteractions::::mutate(&who, |count| *count = count.saturating_add(1)); - Self::deposit_event(Event::CounterDecremented { new_value, who, amount }); - Ok(()) - } - } - } - ``` +Ensure to replace `INSERT_BLOCK_VALUE` with a proper block number if needed. -## Add the Pallet to Your Runtime +--- -Now that your custom pallet is complete, integrate it into the parachain runtime. +### debug_traceTransaction -### Add Runtime Dependency +Traces the execution of a single transaction by its hash and returns a detailed execution trace. -1. In the `runtime/Cargo.toml`, add your custom pallet to the `[dependencies]` section: +**Parameters**: - ```toml title="runtime/Cargo.toml" - [dependencies] - # Local dependencies - pallet-custom = { path = "../pallets/pallet-custom", default-features = false } - - # ... other dependencies - ``` +- **`transactionHash` ++"string"++**: The hash of the transaction to trace. Must be a [32 byte data](https://ethereum.org/en/developers/docs/apis/json-rpc/#unformatted-data-encoding){target=\_blank} string. +- **`options` ++"object"++**: (Optional) An object containing tracer options (e.g., `tracer: "callTracer"`). -2. Enable the `std` feature by adding it to the `[features]` section: +**Example**: - ```toml title="runtime/Cargo.toml" - [features] - default = ["std"] - std = [ - "codec/std", - "pallet-custom/std", - # ... other features - ] - ``` +```bash title="debug_traceTransaction" +curl -X POST https://testnet-passet-hub-eth-rpc.polkadot.io \ +-H "Content-Type: application/json" \ +--data '{ + "jsonrpc":"2.0", + "method":"debug_traceTransaction", + "params":["INSERT_TRANSACTION_HASH", {"tracer": "callTracer"}], + "id":1 +}' +``` -### Implement the Config Trait +Ensure to replace the `INSERT_TRANSACTION_HASH` with the proper value. -At the end of the `runtime/src/configs/mod.rs` file, add the implementation: +--- -```rust title="runtime/src/configs/mod.rs" -/// Configure the custom counter pallet -impl pallet_custom::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type CounterMaxValue = ConstU32<1000>; -} -``` +### debug_traceCall -This configuration: +Executes a new message call and returns a detailed execution trace without creating a transaction on the blockchain. -- Links the pallet's events to the runtime's event system -- Sets a maximum counter value of 1000 using [`ConstU32`](https://paritytech.github.io/polkadot-sdk/master/frame_support/traits/struct.ConstU32.html){target=\_blank} +**Parameters**: -### Add to Runtime Construct +- **`transaction` ++"object"++**: The transaction call object, similar to `eth_call` parameters. + - **`to` ++"string"++**: Recipient address of the call. Must be a [20-byte data](https://ethereum.org/en/developers/docs/apis/json-rpc/#unformatted-data-encoding){target=\_blank} string. + - **`data` ++"string"++**: Hash of the method signature and encoded parameters. Must be a [data](https://ethereum.org/en/developers/docs/apis/json-rpc/#unformatted-data-encoding){target=\_blank} string. + - **`from` ++"string"++**: (Optional) Sender's address for the call. Must be a [20-byte data](https://ethereum.org/en/developers/docs/apis/json-rpc/#unformatted-data-encoding){target=\_blank} string. + - **`gas` ++"string"++**: (Optional) Gas limit to execute the call. Must be a [quantity](https://ethereum.org/en/developers/docs/apis/json-rpc/#quantities-encoding){target=\_blank} string. + - **`gasPrice` ++"string"++**: (Optional) Gas price per unit of gas. Must be a [quantity](https://ethereum.org/en/developers/docs/apis/json-rpc/#quantities-encoding){target=\_blank} string. + - **`value` ++"string"++**: (Optional) Value in wei to send with the call. Must be a [quantity](https://ethereum.org/en/developers/docs/apis/json-rpc/#quantities-encoding){target=\_blank} string. +- **`blockValue` ++"string"++**: (Optional) Block tag or block number to execute the call at. Must be a [quantity](https://ethereum.org/en/developers/docs/apis/json-rpc/#quantities-encoding){target=\_blank} string or a [default block parameter](https://ethereum.org/en/developers/docs/apis/json-rpc/#default-block){target=\_blank}. +- **`options` ++"object"++**: (Optional) An object containing tracer options (e.g., `tracer: "callTracer"`). -In the `runtime/src/lib.rs` file, locate the [`#[frame_support::runtime]`](https://paritytech.github.io/polkadot-sdk/master/frame_support/attr.runtime.html){target=\_blank} section and add your pallet with a unique `pallet_index`: +**Example**: -```rust title="runtime/src/lib.rs" -#[frame_support::runtime] -mod runtime { - #[runtime::runtime] - #[runtime::derive( - RuntimeCall, - RuntimeEvent, - RuntimeError, - RuntimeOrigin, - RuntimeTask, - RuntimeFreezeReason, - RuntimeHoldReason, - RuntimeSlashReason, - RuntimeLockId, - RuntimeViewFunction - )] - pub struct Runtime; +```bash title="debug_traceCall" +curl -X POST https://testnet-passet-hub-eth-rpc.polkadot.io \ +-H "Content-Type: application/json" \ +--data '{ + "jsonrpc":"2.0", + "method":"debug_traceCall", + "params":[{ + "from": "INSERT_SENDER_ADDRESS", + "to": "INSERT_RECIPIENT_ADDRESS", + "data": "INSERT_ENCODED_CALL" + }, "INSERT_BLOCK_VALUE", {"tracer": "callTracer"}], + "id":1 +}' +``` - #[runtime::pallet_index(0)] - pub type System = frame_system; +Ensure to replace the `INSERT_SENDER_ADDRESS`, `INSERT_RECIPIENT_ADDRESS`, `INSERT_ENCODED_CALL`, and `INSERT_BLOCK_VALUE` with the proper value. + +--- + +## Response Format - // ... other pallets +All responses follow the standard JSON-RPC 2.0 format: - #[runtime::pallet_index(51)] - pub type CustomPallet = pallet_custom; +```json +{ + "jsonrpc": "2.0", + "id": 1, + "result": ... // The return value varies by method } ``` -!!!warning - Each pallet must have a unique index. Duplicate indices will cause compilation errors. Choose an index that doesn't conflict with existing pallets. +## Error Handling -### Configure Genesis for Your Runtime +If an error occurs, the response will include an error object: -To set initial values for your pallet when the chain starts, you'll need to configure the genesis in your chain specification. This is typically done in the `node/src/chain_spec.rs` file or when generating the chain specification. +```json +{ + "jsonrpc": "2.0", + "id": 1, + "error": { + "code": -32000, + "message": "Error message here" + } +} +``` -For development and testing, you can use the default values provided by the `#[derive(DefaultNoBound)]` macro. For production networks, you'll want to set these values in your chain specification explicitly. -### Verify Runtime Compilation +--- -Compile the runtime to ensure everything is configured correctly: +Page Title: Light Clients -```bash -cargo build --release -``` +- Source (raw): https://raw.githubusercontent.com/polkadot-developers/polkadot-docs/master/.ai/pages/reference-tools-light-clients.md +- Canonical (HTML): https://docs.polkadot.com/reference/tools/light-clients/ +- Summary: Light clients enable secure and efficient blockchain interaction without running a full node. Learn everything you need to know about light clients on Polkadot. -This command validates all pallet configurations and prepares the build for deployment. +# Light Clients -## Run Your Chain Locally +## Introduction -Launch your parachain locally to test the new pallet functionality using the [Polkadot Omni Node](https://crates.io/crates/polkadot-omni-node){target=\_blank}. +Light clients enable secure and efficient blockchain interaction without running a full node. They provide a trust-minimized alternative to JSON-RPC by verifying data through cryptographic proofs rather than blindly trusting remote nodes. -### Generate a Chain Specification +This guide covers: -Create a chain specification file with the updated runtime: +- What light clients are and how they work. +- Their advantages compared to full nodes and JSON-RPC. +- Available implementations in the Polkadot ecosystem. +- How to use light clients in your applications. -```bash -chain-spec-builder create -t development \ ---relay-chain paseo \ ---para-id 1000 \ ---runtime ./target/release/wbuild/parachain-template-runtime/parachain_template_runtime.compact.compressed.wasm \ -named-preset development -``` +Light clients are particularly valuable for resource-constrained environments and applications requiring secure, decentralized blockchain access without the overhead of maintaining full nodes. -This command generates a `chain_spec.json` that includes your custom pallet. +!!!note "Light node or light client?" + The terms _light node_ and _light client_ are interchangeable. Both refer to a blockchain client that syncs without downloading the entire blockchain state. All nodes in a blockchain network are fundamentally clients, engaging in peer-to-peer communication. -### Start the Parachain Node +## Light Clients Workflow -Launch the parachain: +Unlike JSON-RPC interfaces, where an application must maintain a list of providers or rely on a single node, light clients are not limited to or dependent on a single node. They use cryptographic proofs to verify the blockchain's state, ensuring it is up-to-date and accurate. By verifying only block headers, light clients avoid syncing the entire state, making them ideal for resource-constrained environments. -```bash -polkadot-omni-node --chain ./chain_spec.json --dev +```mermaid +flowchart LR +DAPP([dApp])-- Query Account Info -->LC([Light Client]) +LC -- Request --> FN(((Full Node))) +LC -- Response --> DAPP +FN -- Response (validated via Merkle proof) --> LC ``` -Verify the node starts successfully and begins producing blocks. - -## Interact with Your Pallet - -Use the Polkadot.js Apps interface to test your pallet: - -1. Navigate to [Polkadot.js Apps](https://polkadot.js.org/apps/?rpc=ws%3A%2F%2F127.0.0.1%3A9944#/extrinsics){target=\_blank}. +In the diagram above, the decentralized application queries on-chain account information through the light client. The light client runs as part of the application and requires minimal memory and computational resources. It uses Merkle proofs to verify the state retrieved from a full node in a trust-minimized manner. Polkadot-compatible light clients utilize [warp syncing](https://spec.polkadot.network/sect-lightclient#sect-sync-warp-lightclient){target=\_blank}, which downloads only block headers. -2. Ensure you're connected to your local node at `ws://127.0.0.1:9944`. +Light clients can quickly verify the blockchain's state, including [GRANDPA finality](/polkadot-protocol/glossary#grandpa){target=\_blank} justifications. -3. Go to **Developer** > **Extrinsics**. +!!!note "What does it mean to be trust-minimized?" + _Trust-minimized_ means that the light client does not need to fully trust the full node from which it retrieves the state. This is achieved through the use of Merkle proofs, which allow the light client to verify the correctness of the state by checking the Merkle tree root. -4. Locate **customPallet** in the pallet dropdown. +## JSON-RPC and Light Client Comparison -5. You should see the available extrinsics: +Another common method of communication between a user interface (UI) and a node is through the JSON-RPC protocol. Generally, the UI retrieves information from the node, fetches network or [pallet](/polkadot-protocol/glossary#pallet){target=\_blank} data, and interacts with the blockchain. This is typically done in one of two ways: - - **`increment(amount)`**: Increase the counter by a specified amount. - - **`decrement(amount)`**: Decrease the counter by a specified amount. - - **`setCounterValue(newValue)`**: Set counter to a specific value (requires sudo/root). +- **User-controlled nodes**: The UI connects to a node client installed on the user's machine. + - These nodes are secure, but installation and maintenance can be inconvenient. +- **Publicly accessible nodes**: The UI connects to a third-party-owned publicly accessible node client. + - These nodes are convenient but centralized and less secure. Applications must maintain a list of backup nodes in case the primary node becomes unavailable. -![](/images/parachains/customize-runtime/pallet-development/create-a-pallet/create-a-pallet-01.webp) +While light clients still communicate with [full nodes](/polkadot-protocol/glossary#full-node), they offer significant advantages for applications requiring a secure alternative to running a full node: -## Key Takeaways +| Full Node | Light Client | +| :---------------------------------------------------------------------------------------------: | :------------------------------------------------------------: | +| Fully verifies all blocks of the chain | Verifies only the authenticity of blocks | +| Stores previous block data and the chain's storage in a database | Does not require a database | +| Installation, maintenance, and execution are resource-intensive and require technical expertise | No installation is typically included as part of the application | -You've successfully created and integrated a custom pallet into a Polkadot SDK-based runtime. You learned: +## Using Light Clients -- **Configuration**: Defined runtime-specific types and constants via the `Config` trait. -- **Storage**: Implemented on-chain state using `StorageValue` and `StorageMap`. -- **Events**: Created signals to communicate state changes to external systems. -- **Errors**: Established clear error handling with descriptive error types. -- **Genesis**: Configured initial blockchain state for both production and testing. -- **Dispatchables**: Built callable functions with proper validation and access control. -- **Integration**: Successfully added the pallet to a runtime and tested it locally. +The [`smoldot`](https://github.com/smol-dot/smoldot){target=\_blank} client is the cornerstone of light client implementation for Polkadot SDK-based chains. It provides the primitives needed to build light clients and is also integrated into libraries such as [PAPI](#papi-light-client-support). -These components form the foundation for developing sophisticated blockchain logic in Polkadot SDK-based chains. +### PAPI Light Client Support -## Where to Go Next +The [Polkadot API (PAPI)](/develop/toolkit/api-libraries/papi){target=\_blank} library natively supports light client configurations powered by [`smoldot`](https://github.com/smol-dot/smoldot){target=\_blank}. This allows developers to connect to multiple chains simultaneously using a light client. -
+### Substrate Connect - Browser Extension -- Guide __Mock Your Runtime__ +The [Substrate Connect browser extension](https://www.npmjs.com/package/@substrate/connect-extension-protocol){target=\_blank} enables end-users to interact with applications connected to multiple blockchains or to connect their own blockchains to supported applications. - --- +Establishing a sufficient number of peers can be challenging due to browser limitations on WebSocket connections from HTTPS pages, as many nodes require TLS. The Substrate Connect browser extension addresses this limitation by keeping chains synced in the background, enabling faster application performance. - Learn to create a mock runtime environment for testing your pallet in isolation before integration. +Substrate Connect automatically detects whether the user has the extension installed. If not, an in-page Wasm light client is created for them. - [:octicons-arrow-right-24: Continue](/parachains/customize-runtime/pallet-development/mock-runtime/) +## Resources -
+- [What is a light client and why you should care?](https://medium.com/paritytech/what-is-a-light-client-and-why-you-should-care-75f813ae2670){target=\_blank} +- [Introducing Substrate Connect: Browser-Based Light Clients for Connecting to Substrate Chains](https://www.parity.io/blog/introducing-substrate-connect){target=\_blank} +- [Substrate Connect GitHub Repository](https://github.com/paritytech/substrate-connect/tree/master/projects/extension){target=\_blank} +- [Light Clients - Polkadot Specification](https://spec.polkadot.network/sect-lightclient){target=\_blank} --- @@ -10833,32 +10943,32 @@ Page Title: Mock Your Runtime Testing is a critical part of pallet development. Before integrating your pallet into a full runtime, you need a way to test its functionality in isolation. A mock runtime provides a minimal, simulated blockchain environment where you can verify your pallet's logic without the overhead of running a full node. -In this guide, you'll learn how to create a mock runtime for the custom counter pallet built in the [Make a Custom Pallet](/parachains/customize-runtime/pallet-development/create-a-pallet/) guide. This mock runtime will enable you to write comprehensive unit tests that verify: +In this guide, you'll learn how to create a mock runtime for the custom counter pallet built in the [Make a Custom Pallet](/parachains/customize-runtime/pallet-development/create-a-pallet/){target=\_blank} guide. This mock runtime will enable you to write comprehensive unit tests that verify: -- Dispatchable function behavior -- Storage state changes -- Event emission -- Error handling -- Access control and origin validation -- Genesis configuration +- Dispatchable function behavior. +- Storage state changes. +- Event emission. +- Error handling. +- Access control and origin validation. +- Genesis configuration. ## Prerequisites Before you begin, ensure you have: -- Completed the [Make a Custom Pallet](/parachains/customize-runtime/pallet-development/create-a-pallet/) guide -- The custom counter pallet from that guide available in `pallets/pallet-custom` -- Basic understanding of [Rust testing](https://doc.rust-lang.org/book/ch11-00-testing.html){target=\_blank} +- Completed the [Make a Custom Pallet](/parachains/customize-runtime/pallet-development/create-a-pallet/){target=\_blank} guide. +- The custom counter pallet from the Make a Custom Pallet guide. Available in `pallets/pallet-custom`. +- Basic understanding of [Rust testing](https://doc.rust-lang.org/book/ch11-00-testing.html){target=\_blank}. -## Understanding Mock Runtimes +## Understand Mock Runtimes A mock runtime is a minimal implementation of the runtime environment that: -- **Simulates blockchain state** - Provides storage and state management -- **Implements required traits** - Satisfies your pallet's `Config` trait requirements -- **Enables isolated testing** - Allows testing without external dependencies -- **Supports genesis configuration** - Sets initial blockchain state for tests -- **Speeds up development** - Provides instant feedback on code changes +- Simulates blockchain state to provide storage and state management. +- Satisfies your pallet's `Config` trait requirements. +- Allows isolated testing without external dependencies. +- Supports genesis configuration to set initial blockchain state for tests. +- Provides instant feedback on code changes for a faster development cycle. Mock runtimes are used exclusively for testing and are never deployed to a live blockchain. @@ -10878,9 +10988,9 @@ Start by creating a new module file within your pallet to house the mock runtime touch mock.rs ``` -3. Open `src/lib.rs` and add the mock module declaration at the top of the file, right after the `pub use pallet::*;` line: +3. Next, open `src/lib.rs` and add the mock module declaration at the top of the file, right after the `pub use pallet::*;` line: - ```rust + ```rust title="src/lib.rs" #![cfg_attr(not(feature = "std"), no_std)] pub use pallet::*; @@ -10892,21 +11002,22 @@ Start by creating a new module file within your pallet to house the mock runtime pub mod pallet { // ... existing pallet code } + ``` The `#[cfg(test)]` attribute ensures this module is only compiled during testing. -## Set Up Basic Mock Infrastructure +## Set Up Basic Mock Open `src/mock.rs` and add the foundational imports and type definitions: -```rust +```rust title="src/mock.rs" use crate as pallet_custom; use frame::{ deps::{ - frame_support::{derive_impl, traits::ConstU32}, + frame_support::{ derive_impl, traits::ConstU32 }, sp_io, - sp_runtime::{traits::IdentityLookup, BuildStorage}, + sp_runtime::{ traits::IdentityLookup, BuildStorage }, }, prelude::*, }; @@ -10915,25 +11026,25 @@ type Block = frame_system::mocking::MockBlock; // Configure a mock runtime to test the pallet. frame::deps::frame_support::construct_runtime!( - pub enum Test - { - System: frame_system, - CustomPallet: pallet_custom, - } -); + pub enum Test + { + System: frame_system, + CustomPallet: pallet_custom, + } + ); ``` -**Key components:** +The preceding code includes the following key components: -- **`construct_runtime!`** - Macro that builds a minimal runtime with only the pallets needed for testing -- **`Test`** - The mock runtime type used in tests -- **`Block`** - Type alias for the mock block type that the runtime will use +- **[`construct_runtime!`](https://paritytech.github.io/polkadot-sdk/master/polkadot_sdk_frame/runtime/apis/trait.ConstructRuntimeApi.html#tymethod.construct_runtime_api){target=\_blank}**: Macro that builds a minimal runtime with only the pallets needed for testing. +- **`Test`**: The mock runtime type used in tests. +- **`Block`**: Type alias for the mock block type that the runtime will use. -## Implement frame_system Configuration +## Implement Essential Configuration -The [`frame_system`](https://paritytech.github.io/polkadot-sdk/master/frame_system/index.html){target=\_blank} pallet provides core blockchain functionality and is required by all other pallets. Configure it for the test environment: +The [`frame_system`](https://paritytech.github.io/polkadot-sdk/master/frame_system/index.html){target=\_blank} pallet provides core blockchain functionality and is required by all other pallets. Configure it for the test environment as follows: -```rust +```rust title="src/mock.rs" #[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for Test { type Block = Block; @@ -10942,55 +11053,52 @@ impl frame_system::Config for Test { } ``` -**Simplified for testing:** +This simplified configuration for testing includes the following: -- **`#[derive_impl]`** - Automatically provides sensible test defaults for most `frame_system::Config` types -- **`AccountId = u64`** - Uses simple integers instead of cryptographic account IDs -- **`Lookup = IdentityLookup`** - Direct account ID mapping (no address conversion) -- **`Block = Block`** - Uses the mock block type we defined earlier +- **`#[derive_impl]`**: Automatically provides sensible test defaults for most `frame_system::Config` types. +- **`AccountId = u64`**: Uses simple integers instead of cryptographic account IDs. +- **`Lookup = IdentityLookup`**: Direct account ID mapping (no address conversion). +- **`Block = Block`**: Uses the mock block type we defined earlier. This approach is much more concise than manually specifying every configuration type, as the `TestDefaultConfig` preset provides appropriate defaults for testing. ## Implement Your Pallet's Configuration -Now implement the `Config` trait for your custom pallet. This must match the trait defined in your pallet's `lib.rs`: +Now implement the `Config` trait for your custom pallet. This trait must match the one defined in your pallet's `src/lib.rs`: -```rust +```rust title="src/mock.rs" impl pallet_custom::Config for Test { type RuntimeEvent = RuntimeEvent; type CounterMaxValue = ConstU32<1000>; } ``` -**Configuration details:** +Configuration details include: -- **`RuntimeEvent`** - Connects your pallet's events to the mock runtime's event system -- **`CounterMaxValue`** - Sets the maximum counter value to 1000, matching the production configuration +- **`RuntimeEvent`**: Connects your pallet's events to the mock runtime's event system. +- **`CounterMaxValue`**: Sets the maximum counter value to 1000, matching the production configuration. -!!!note - The configuration here should mirror what you'll use in production unless you specifically need different values for testing. +The configuration here should mirror what you'll use in production unless you specifically need different values for testing. ## Configure Genesis Storage -Genesis storage defines the initial state of your blockchain before any blocks are produced. Since your counter pallet includes genesis configuration (added in the previous guide), you can now set up test environments with different initial states. +Genesis storage defines the initial state of your blockchain before any blocks are produced. Since your counter pallet includes the genesis configuration (added in the previous guide), you can now set up test environments with different initial states. ### Basic Test Environment Create a helper function for the default test environment: -```rust +```rust title="src/mock.rs" // Build genesis storage according to the mock runtime. pub fn new_test_ext() -> sp_io::TestExternalities { - let mut t = frame_system::GenesisConfig::::default() - .build_storage() - .unwrap(); + let mut t = frame_system::GenesisConfig::::default().build_storage().unwrap(); - pallet_custom::GenesisConfig:: { + (pallet_custom::GenesisConfig:: { initial_counter_value: 0, initial_user_interactions: vec![], - } - .assimilate_storage(&mut t) - .unwrap(); + }) + .assimilate_storage(&mut t) + .unwrap(); t.into() } @@ -11002,19 +11110,17 @@ This function creates a clean blockchain state with an initial counter value of For testing specific scenarios, create additional helper functions with customized genesis states: -```rust +```rust title="src/mock.rs" // Helper function to create a test externalities with a specific initial counter value pub fn new_test_ext_with_counter(initial_value: u32) -> sp_io::TestExternalities { - let mut t = frame_system::GenesisConfig::::default() - .build_storage() - .unwrap(); + let mut t = frame_system::GenesisConfig::::default().build_storage().unwrap(); - pallet_custom::GenesisConfig:: { + (pallet_custom::GenesisConfig:: { initial_counter_value: initial_value, initial_user_interactions: vec![], - } - .assimilate_storage(&mut t) - .unwrap(); + }) + .assimilate_storage(&mut t) + .unwrap(); t.into() } @@ -11022,28 +11128,27 @@ pub fn new_test_ext_with_counter(initial_value: u32) -> sp_io::TestExternalities // Helper function to create a test externalities with initial user interactions pub fn new_test_ext_with_interactions( initial_value: u32, - interactions: Vec<(u64, u32)>, + interactions: Vec<(u64, u32)> ) -> sp_io::TestExternalities { - let mut t = frame_system::GenesisConfig::::default() - .build_storage() - .unwrap(); + let mut t = frame_system::GenesisConfig::::default().build_storage().unwrap(); - pallet_custom::GenesisConfig:: { + (pallet_custom::GenesisConfig:: { initial_counter_value: initial_value, initial_user_interactions: interactions, - } - .assimilate_storage(&mut t) - .unwrap(); + }) + .assimilate_storage(&mut t) + .unwrap(); t.into() } ``` -**Key methods:** +Key methods used in this step include: -- **[`BuildStorage::build_storage()`](https://paritytech.github.io/polkadot-sdk/master/sp_runtime/trait.BuildStorage.html#method.build_storage){target=\_blank}** - Creates the initial storage state -- **[`assimilate_storage`](https://paritytech.github.io/polkadot-sdk/master/sp_runtime/trait.BuildStorage.html#method.assimilate_storage){target=\_blank}** - Merges pallet genesis config into the existing storage -- **Multiple configurations** - You can chain multiple `assimilate_storage` calls for different pallets +- **[`BuildStorage::build_storage()`](https://paritytech.github.io/polkadot-sdk/master/sp_runtime/trait.BuildStorage.html#method.build_storage){target=\_blank}**: Creates the initial storage state. +- **[`assimilate_storage`](https://paritytech.github.io/polkadot-sdk/master/sp_runtime/trait.BuildStorage.html#method.assimilate_storage){target=\_blank}**: Merges pallet genesis config into the existing storage. + +You can chain multiple `assimilate_storage` calls to configure multiple pallets. ## Verify Mock Compilation @@ -11055,17 +11160,17 @@ cargo test --package pallet-custom --lib This command compiles the test code (including the mock and genesis configuration) without running tests yet. Address any compilation errors before continuing. -??? code "Complete Mock Runtime" +??? code "Complete mock runtime script" Here's the complete `mock.rs` file for reference: - ```rust + ```rust title="src/mock.rs" use crate as pallet_custom; use frame::{ deps::{ - frame_support::{derive_impl, traits::ConstU32}, + frame_support::{ derive_impl, traits::ConstU32 }, sp_io, - sp_runtime::{traits::IdentityLookup, BuildStorage}, + sp_runtime::{ traits::IdentityLookup, BuildStorage }, }, prelude::*, }; @@ -11074,12 +11179,12 @@ This command compiles the test code (including the mock and genesis configuratio // Configure a mock runtime to test the pallet. frame::deps::frame_support::construct_runtime!( - pub enum Test - { - System: frame_system, - CustomPallet: pallet_custom, - } - ); + pub enum Test + { + System: frame_system, + CustomPallet: pallet_custom, + } + ); #[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for Test { @@ -11095,32 +11200,28 @@ This command compiles the test code (including the mock and genesis configuratio // Build genesis storage according to the mock runtime. pub fn new_test_ext() -> sp_io::TestExternalities { - let mut t = frame_system::GenesisConfig::::default() - .build_storage() - .unwrap(); + let mut t = frame_system::GenesisConfig::::default().build_storage().unwrap(); - pallet_custom::GenesisConfig:: { + (pallet_custom::GenesisConfig:: { initial_counter_value: 0, initial_user_interactions: vec![], - } - .assimilate_storage(&mut t) - .unwrap(); + }) + .assimilate_storage(&mut t) + .unwrap(); t.into() } // Helper function to create a test externalities with a specific initial counter value pub fn new_test_ext_with_counter(initial_value: u32) -> sp_io::TestExternalities { - let mut t = frame_system::GenesisConfig::::default() - .build_storage() - .unwrap(); + let mut t = frame_system::GenesisConfig::::default().build_storage().unwrap(); - pallet_custom::GenesisConfig:: { + (pallet_custom::GenesisConfig:: { initial_counter_value: initial_value, initial_user_interactions: vec![], - } - .assimilate_storage(&mut t) - .unwrap(); + }) + .assimilate_storage(&mut t) + .unwrap(); t.into() } @@ -11128,18 +11229,16 @@ This command compiles the test code (including the mock and genesis configuratio // Helper function to create a test externalities with initial user interactions pub fn new_test_ext_with_interactions( initial_value: u32, - interactions: Vec<(u64, u32)>, + interactions: Vec<(u64, u32)> ) -> sp_io::TestExternalities { - let mut t = frame_system::GenesisConfig::::default() - .build_storage() - .unwrap(); + let mut t = frame_system::GenesisConfig::::default().build_storage().unwrap(); - pallet_custom::GenesisConfig:: { + (pallet_custom::GenesisConfig:: { initial_counter_value: initial_value, initial_user_interactions: interactions, - } - .assimilate_storage(&mut t) - .unwrap(); + }) + .assimilate_storage(&mut t) + .unwrap(); t.into() } @@ -11147,16 +11246,14 @@ This command compiles the test code (including the mock and genesis configuratio ## Key Takeaways -You've successfully created a mock runtime with genesis configuration for your custom pallet. You now have: +You've successfully created a mock runtime with a genesis configuration for your custom pallet. You can now: -- **Isolated testing environment** - Test your pallet without a full runtime -- **Simplified configuration** - Minimal setup for rapid development iteration -- **Genesis configuration** - Set initial blockchain state for different test scenarios -- **Multiple test helpers** - Different genesis setups for various testing needs -- **Foundation for unit tests** - Infrastructure to test all pallet functionality -- **Fast feedback loop** - Instant compilation and test execution +- Test your pallet without a full runtime. +- Set initial blockchain state for different test scenarios. +- Create different genesis setups for various testing needs. +- Use this minimal setup to test all pallet functionality. -The mock runtime with genesis configuration is essential for test-driven development, allowing you to verify logic under different initial conditions before integration into the actual parachain runtime. +The mock runtime with a genesis configuration is essential for test-driven development, enabling you to verify logic under different initial conditions before integrating it into the actual parachain runtime. ## Where to Go Next @@ -15231,121 +15328,6 @@ Support for encoding and decoding Polkadot SDK SS58 addresses has been implement - **TypeScript**: [`subsquid/squid-sdk`](https://github.com/subsquid/squid-sdk){target=\_blank} ---- - -Page Title: PolkaVM Design - -- Source (raw): https://raw.githubusercontent.com/polkadot-developers/polkadot-docs/master/.ai/pages/smart-contracts-for-eth-devs-dual-vm-stack.md -- Canonical (HTML): https://docs.polkadot.com/smart-contracts/for-eth-devs/dual-vm-stack/ -- Summary: Discover PolkaVM, a high-performance smart contract VM for Polkadot, enabling Ethereum compatibility via pallet_revive, Solidity support & optimized execution. - -# PolkaVM Design - -!!! smartcontract "PolkaVM Preview Release" - PolkaVM smart contracts with Ethereum compatibility are in **early-stage development and may be unstable or incomplete**. -## Introduction - -The Asset Hub smart contracts solution includes multiple components to ensure Ethereum compatibility and high performance. Its architecture allows for integration with current Ethereum tools, while its innovative virtual machine design enhances performance characteristics. - -## PolkaVM - -[**PolkaVM**](https://github.com/paritytech/polkavm){target=\_blank} is a custom virtual machine optimized for performance with [RISC-V-based](https://en.wikipedia.org/wiki/RISC-V){target=\_blank} architecture, supporting Solidity and additional high-performance languages. It serves as the core execution environment, integrated directly within the runtime. It features: - -- An efficient interpreter for immediate code execution. -- A planned JIT compiler for optimized performance. -- Dual-mode execution capability, allowing selection of the most appropriate backend for specific workloads. -- Optimized performance for short-running contract calls through the interpreter. - -The interpreter remains particularly beneficial for contracts with minimal code execution, as it eliminates JIT compilation overhead and enables immediate code execution through lazy interpretation. - -## Architecture - -The smart contract solution consists of the following key components that work together to enable Ethereum compatibility on Polkadot-based chains. - -### Pallet Revive - -[**`pallet_revive`**](https://paritytech.github.io/polkadot-sdk/master/pallet_revive/index.html){target=\_blank} is a runtime module that executes smart contracts by adding extrinsics, runtime APIs, and logic to convert Ethereum-style transactions into formats compatible with Polkadot SDK-based blockchains. It processes Ethereum-style transactions through the following workflow: - -```mermaid -sequenceDiagram - participant User as User/dApp - participant Proxy as Ethereum JSON RPC Proxy - participant Chain as Blockchain Node - participant Pallet as pallet_revive - - User->>Proxy: Submit Ethereum Transaction - Proxy->>Chain: Repackage as Polkadot Compatible Transaction - Chain->>Pallet: Process Transaction - Pallet->>Pallet: Decode Ethereum Transaction - Pallet->>Pallet: Execute Contract via PolkaVM - Pallet->>Chain: Return Results - Chain->>Proxy: Forward Results - Proxy->>User: Return Ethereum-compatible Response -``` - -This proxy-based approach eliminates the need for node binary modifications, maintaining compatibility across different client implementations. Preserving the original Ethereum transaction payload simplifies adapting existing tools, which can continue processing familiar transaction formats. - -### PolkaVM Design Fundamentals - -PolkaVM introduces two fundamental architectural differences compared to the Ethereum Virtual Machine (EVM): - -```mermaid -flowchart TB - subgraph "EVM Architecture" - EVMStack[Stack-Based] - EVM256[256-bit Word Size] - end - - subgraph "PolkaVM Architecture" - PVMReg[Register-Based] - PVM64[64-bit Word Size] - end -``` - -- **Register-based design**: PolkaVM utilizes a RISC-V register-based approach. This design: - - - Employs a finite set of registers for argument passing instead of an infinite stack. - - Facilitates efficient translation to underlying hardware architectures. - - Optimizes register allocation through careful register count selection. - - Enables simple 1:1 mapping to x86-64 instruction sets. - - Reduces compilation complexity through strategic register limitation. - - Improves overall execution performance through hardware-aligned design. - -- **64-bit word size**: PolkaVM operates with a 64-bit word size. This design: - - - Enables direct hardware-supported arithmetic operations. - - Maintains compatibility with Solidity's 256-bit operations through YUL translation. - - Allows integration of performance-critical components written in lower-level languages. - - Optimizes computation-intensive operations through native word size alignment. - - Reduces overhead for operations not requiring extended precision. - - Facilitates efficient integration with modern CPU architectures. - -## Compilation Process - -When compiling a Solidity smart contract, the code passes through the following stages: - -```mermaid -flowchart LR - Dev[Developer] --> |Solidity
Source
Code| Solc - - subgraph "Compilation Process" - direction LR - Solc[solc] --> |YUL
IR| Revive - Revive[Revive Compiler] --> |LLVM
IR| LLVM - LLVM[LLVM
Optimizer] --> |RISC-V ELF
Shared Object| PVMLinker - end - - PVMLinker[PVM Linker] --> PVM[PVM Blob
with Metadata] -``` - -The compilation process integrates several specialized components: - -1. **Solc**: The standard Ethereum Solidity compiler that translates Solidity source code to [YUL IR](https://docs.soliditylang.org/en/latest/yul.html){target=\_blank}. -2. **Revive Compiler**: Takes YUL IR and transforms it to [LLVM IR](https://llvm.org/){target=\_blank}. -3. **LLVM**: A compiler infrastructure that optimizes the code and generates RISC-V ELF objects. -4. **PVM linker**: Links the RISC-V ELF object into a final PolkaVM blob with metadata. - - --- Page Title: Quickstart Parachain Development with Pop CLI diff --git a/.ai/categories/polkadot-protocol.md b/.ai/categories/polkadot-protocol.md index 023abb5ad..b8ac4e161 100644 --- a/.ai/categories/polkadot-protocol.md +++ b/.ai/categories/polkadot-protocol.md @@ -3609,6 +3609,109 @@ Your deployed contract will appear in the **Deployed Contracts** section, ready
+--- + +Page Title: Dual Virtual Machine Stack + +- Source (raw): https://raw.githubusercontent.com/polkadot-developers/polkadot-docs/master/.ai/pages/smart-contracts-for-eth-devs-dual-vm-stack.md +- Canonical (HTML): https://docs.polkadot.com/smart-contracts/for-eth-devs/dual-vm-stack/ +- Summary: Compare Polkadot’s dual smart contract VMs—REVM for EVM compatibility and PolkaVM for RISC-V performance, flexibility, and efficiency. + +# Dual Virtual Machine Stack + +!!! smartcontract "PolkaVM Preview Release" + PolkaVM smart contracts with Ethereum compatibility are in **early-stage development and may be unstable or incomplete**. +## Introduction + +Polkadot's smart contract platform supports two distinct virtual machine (VM) architectures, providing developers with flexibility in selecting the optimal execution backend for their specific needs. This approach strikes a balance between immediate Ethereum compatibility and long-term innovation, enabling developers to deploy either unmodified (Ethereum Virtual Machine) EVM contracts using Rust Ethereum Virtual Machine (REVM) or optimize for higher performance using PolkaVM (PVM). + +Both VM options share common infrastructure, including RPC interfaces, tooling support, and precompiles. The following sections compare architectures and guide you in selecting the best VM for your project's needs. + +## Migrate from EVM + +The [REVM backend](https://github.com/bluealloy/revm){target=\_blank} integrates a complete Rust implementation of the EVM, enabling Solidity contracts to run unchanged on Polkadot's smart contract platform. + +REVM allows developers to use their existing Ethereum tooling and infrastructure to build on Polkadot. Choose REVM to: + +- Migrate existing Ethereum contracts without modifications. +- Retain exact EVM behavior for audit tools. +- Use developer tools that rely upon inspecting EVM bytecode. +- Prioritize rapid deployment over optimization. +- Work with established Ethereum infrastructure and tooling to build on Polkadot. + +REVM enables Ethereum developers to seamlessly migrate to Polkadot, achieving performance and fee improvements without modifying their existing contracts or developer tooling stack. + +## Upgrade to PolkaVM + +[**PolkaVM**](https://github.com/paritytech/polkavm){target=\_blank} is a custom virtual machine optimized for performance with [RISC-V-based](https://en.wikipedia.org/wiki/RISC-V){target=\_blank} architecture, supporting Solidity and additional high-performance languages. It serves as the core execution environment, integrated directly within the runtime. Choose the PolkaVM for: + +- An efficient interpreter for immediate code execution. +- A planned [Just In Time (JIT)](https://en.wikipedia.org/wiki/Just-in-time_compilation){target=\_blank} compiler for optimized performance. +- Dual-mode execution capability, allowing selection of the most appropriate backend for specific workloads. +- Optimized performance for short-running contract calls through the interpreter. + +The interpreter remains particularly beneficial for contracts with minimal code execution, as it enables immediate code execution through lazy interpretation. + +## Architecture + +The following key components of PolkaVM work together to enable Ethereum compatibility on Polkadot-based chains. + +### Revive Pallet + +[**`pallet_revive`**](https://paritytech.github.io/polkadot-sdk/master/pallet_revive/index.html){target=\_blank} is a runtime module that executes smart contracts by adding extrinsics, runtime APIs, and logic to convert Ethereum-style transactions into formats compatible with Polkadot SDK-based blockchains. It processes Ethereum-style transactions through the following workflow: + +```mermaid +sequenceDiagram + participant User as User/dApp + participant Proxy as Ethereum JSON RPC Proxy + participant Chain as Blockchain Node + participant Pallet as pallet_revive + + User->>Proxy: Submit Ethereum Transaction + Proxy->>Chain: Repackage as Polkadot Compatible Transaction + Chain->>Pallet: Process Transaction + Pallet->>Pallet: Decode Ethereum Transaction + Pallet->>Pallet: Execute Contract via PolkaVM + Pallet->>Chain: Return Results + Chain->>Proxy: Forward Results + Proxy->>User: Return Ethereum-compatible Response +``` + +This proxy-based approach eliminates the need for node binary modifications, maintaining compatibility across different client implementations. Preserving the original Ethereum transaction payload simplifies the adaptation of existing tools, which can continue processing familiar transaction formats. + +### PolkaVM Design Fundamentals + +PolkaVM differs from the EVM in two key ways that make it faster, more hardware-efficient, and easier to extend: + +- **Register-based design**: Instead of a stack machine, PolkaVM uses a RISC-V–style register model. This design: + + - Uses a fixed set of registers to pass arguments, not an infinite stack. + - Maps cleanly to real hardware like x86-64. + - Simplifies compilation and boosts runtime efficiency. + - Enables tighter control over register allocation and performance tuning. + +- **64-bit word size**: PolkaVM runs on a native 64-bit word size, aligning directly with modern CPUs. This design: + + - Executes arithmetic operations with direct hardware support. + - Maintains compatibility with Solidity’s 256-bit types via YUL translation. + - Accelerates computation-heavy workloads through native word alignment. + - Integrates easily with low-level, performance-focused components. + +## Where To Go Next + +
+ +- Learn __Contract Deployment__ + + --- + + Learn how REVM and PVM compare for compiling and deploying smart contracts. + + [:octicons-arrow-right-24: Reference](/smart-contracts/for-eth-devs/contract-deployment/) + +
+ + --- Page Title: Elastic Scaling @@ -8627,121 +8730,6 @@ Support for encoding and decoding Polkadot SDK SS58 addresses has been implement - **TypeScript**: [`subsquid/squid-sdk`](https://github.com/subsquid/squid-sdk){target=\_blank} ---- - -Page Title: PolkaVM Design - -- Source (raw): https://raw.githubusercontent.com/polkadot-developers/polkadot-docs/master/.ai/pages/smart-contracts-for-eth-devs-dual-vm-stack.md -- Canonical (HTML): https://docs.polkadot.com/smart-contracts/for-eth-devs/dual-vm-stack/ -- Summary: Discover PolkaVM, a high-performance smart contract VM for Polkadot, enabling Ethereum compatibility via pallet_revive, Solidity support & optimized execution. - -# PolkaVM Design - -!!! smartcontract "PolkaVM Preview Release" - PolkaVM smart contracts with Ethereum compatibility are in **early-stage development and may be unstable or incomplete**. -## Introduction - -The Asset Hub smart contracts solution includes multiple components to ensure Ethereum compatibility and high performance. Its architecture allows for integration with current Ethereum tools, while its innovative virtual machine design enhances performance characteristics. - -## PolkaVM - -[**PolkaVM**](https://github.com/paritytech/polkavm){target=\_blank} is a custom virtual machine optimized for performance with [RISC-V-based](https://en.wikipedia.org/wiki/RISC-V){target=\_blank} architecture, supporting Solidity and additional high-performance languages. It serves as the core execution environment, integrated directly within the runtime. It features: - -- An efficient interpreter for immediate code execution. -- A planned JIT compiler for optimized performance. -- Dual-mode execution capability, allowing selection of the most appropriate backend for specific workloads. -- Optimized performance for short-running contract calls through the interpreter. - -The interpreter remains particularly beneficial for contracts with minimal code execution, as it eliminates JIT compilation overhead and enables immediate code execution through lazy interpretation. - -## Architecture - -The smart contract solution consists of the following key components that work together to enable Ethereum compatibility on Polkadot-based chains. - -### Pallet Revive - -[**`pallet_revive`**](https://paritytech.github.io/polkadot-sdk/master/pallet_revive/index.html){target=\_blank} is a runtime module that executes smart contracts by adding extrinsics, runtime APIs, and logic to convert Ethereum-style transactions into formats compatible with Polkadot SDK-based blockchains. It processes Ethereum-style transactions through the following workflow: - -```mermaid -sequenceDiagram - participant User as User/dApp - participant Proxy as Ethereum JSON RPC Proxy - participant Chain as Blockchain Node - participant Pallet as pallet_revive - - User->>Proxy: Submit Ethereum Transaction - Proxy->>Chain: Repackage as Polkadot Compatible Transaction - Chain->>Pallet: Process Transaction - Pallet->>Pallet: Decode Ethereum Transaction - Pallet->>Pallet: Execute Contract via PolkaVM - Pallet->>Chain: Return Results - Chain->>Proxy: Forward Results - Proxy->>User: Return Ethereum-compatible Response -``` - -This proxy-based approach eliminates the need for node binary modifications, maintaining compatibility across different client implementations. Preserving the original Ethereum transaction payload simplifies adapting existing tools, which can continue processing familiar transaction formats. - -### PolkaVM Design Fundamentals - -PolkaVM introduces two fundamental architectural differences compared to the Ethereum Virtual Machine (EVM): - -```mermaid -flowchart TB - subgraph "EVM Architecture" - EVMStack[Stack-Based] - EVM256[256-bit Word Size] - end - - subgraph "PolkaVM Architecture" - PVMReg[Register-Based] - PVM64[64-bit Word Size] - end -``` - -- **Register-based design**: PolkaVM utilizes a RISC-V register-based approach. This design: - - - Employs a finite set of registers for argument passing instead of an infinite stack. - - Facilitates efficient translation to underlying hardware architectures. - - Optimizes register allocation through careful register count selection. - - Enables simple 1:1 mapping to x86-64 instruction sets. - - Reduces compilation complexity through strategic register limitation. - - Improves overall execution performance through hardware-aligned design. - -- **64-bit word size**: PolkaVM operates with a 64-bit word size. This design: - - - Enables direct hardware-supported arithmetic operations. - - Maintains compatibility with Solidity's 256-bit operations through YUL translation. - - Allows integration of performance-critical components written in lower-level languages. - - Optimizes computation-intensive operations through native word size alignment. - - Reduces overhead for operations not requiring extended precision. - - Facilitates efficient integration with modern CPU architectures. - -## Compilation Process - -When compiling a Solidity smart contract, the code passes through the following stages: - -```mermaid -flowchart LR - Dev[Developer] --> |Solidity
Source
Code| Solc - - subgraph "Compilation Process" - direction LR - Solc[solc] --> |YUL
IR| Revive - Revive[Revive Compiler] --> |LLVM
IR| LLVM - LLVM[LLVM
Optimizer] --> |RISC-V ELF
Shared Object| PVMLinker - end - - PVMLinker[PVM Linker] --> PVM[PVM Blob
with Metadata] -``` - -The compilation process integrates several specialized components: - -1. **Solc**: The standard Ethereum Solidity compiler that translates Solidity source code to [YUL IR](https://docs.soliditylang.org/en/latest/yul.html){target=\_blank}. -2. **Revive Compiler**: Takes YUL IR and transforms it to [LLVM IR](https://llvm.org/){target=\_blank}. -3. **LLVM**: A compiler infrastructure that optimizes the code and generates RISC-V ELF objects. -4. **PVM linker**: Links the RISC-V ELF object into a final PolkaVM blob with metadata. - - --- Page Title: Proof of Stake Consensus diff --git a/.ai/categories/smart-contracts.md b/.ai/categories/smart-contracts.md index 9449a5306..18e603f60 100644 --- a/.ai/categories/smart-contracts.md +++ b/.ai/categories/smart-contracts.md @@ -6036,6 +6036,109 @@ Now that you have the foundational knowledge to use Ethers.js with Polkadot Hub, - **Build scalable applications**: Combine Ethers.js with frameworks like [`Next.js`](https://nextjs.org/docs){target=\_blank} or [`Node.js`](https://nodejs.org/en){target=\_blank} to create full-stack decentralized applications (dApps). +--- + +Page Title: Dual Virtual Machine Stack + +- Source (raw): https://raw.githubusercontent.com/polkadot-developers/polkadot-docs/master/.ai/pages/smart-contracts-for-eth-devs-dual-vm-stack.md +- Canonical (HTML): https://docs.polkadot.com/smart-contracts/for-eth-devs/dual-vm-stack/ +- Summary: Compare Polkadot’s dual smart contract VMs—REVM for EVM compatibility and PolkaVM for RISC-V performance, flexibility, and efficiency. + +# Dual Virtual Machine Stack + +!!! smartcontract "PolkaVM Preview Release" + PolkaVM smart contracts with Ethereum compatibility are in **early-stage development and may be unstable or incomplete**. +## Introduction + +Polkadot's smart contract platform supports two distinct virtual machine (VM) architectures, providing developers with flexibility in selecting the optimal execution backend for their specific needs. This approach strikes a balance between immediate Ethereum compatibility and long-term innovation, enabling developers to deploy either unmodified (Ethereum Virtual Machine) EVM contracts using Rust Ethereum Virtual Machine (REVM) or optimize for higher performance using PolkaVM (PVM). + +Both VM options share common infrastructure, including RPC interfaces, tooling support, and precompiles. The following sections compare architectures and guide you in selecting the best VM for your project's needs. + +## Migrate from EVM + +The [REVM backend](https://github.com/bluealloy/revm){target=\_blank} integrates a complete Rust implementation of the EVM, enabling Solidity contracts to run unchanged on Polkadot's smart contract platform. + +REVM allows developers to use their existing Ethereum tooling and infrastructure to build on Polkadot. Choose REVM to: + +- Migrate existing Ethereum contracts without modifications. +- Retain exact EVM behavior for audit tools. +- Use developer tools that rely upon inspecting EVM bytecode. +- Prioritize rapid deployment over optimization. +- Work with established Ethereum infrastructure and tooling to build on Polkadot. + +REVM enables Ethereum developers to seamlessly migrate to Polkadot, achieving performance and fee improvements without modifying their existing contracts or developer tooling stack. + +## Upgrade to PolkaVM + +[**PolkaVM**](https://github.com/paritytech/polkavm){target=\_blank} is a custom virtual machine optimized for performance with [RISC-V-based](https://en.wikipedia.org/wiki/RISC-V){target=\_blank} architecture, supporting Solidity and additional high-performance languages. It serves as the core execution environment, integrated directly within the runtime. Choose the PolkaVM for: + +- An efficient interpreter for immediate code execution. +- A planned [Just In Time (JIT)](https://en.wikipedia.org/wiki/Just-in-time_compilation){target=\_blank} compiler for optimized performance. +- Dual-mode execution capability, allowing selection of the most appropriate backend for specific workloads. +- Optimized performance for short-running contract calls through the interpreter. + +The interpreter remains particularly beneficial for contracts with minimal code execution, as it enables immediate code execution through lazy interpretation. + +## Architecture + +The following key components of PolkaVM work together to enable Ethereum compatibility on Polkadot-based chains. + +### Revive Pallet + +[**`pallet_revive`**](https://paritytech.github.io/polkadot-sdk/master/pallet_revive/index.html){target=\_blank} is a runtime module that executes smart contracts by adding extrinsics, runtime APIs, and logic to convert Ethereum-style transactions into formats compatible with Polkadot SDK-based blockchains. It processes Ethereum-style transactions through the following workflow: + +```mermaid +sequenceDiagram + participant User as User/dApp + participant Proxy as Ethereum JSON RPC Proxy + participant Chain as Blockchain Node + participant Pallet as pallet_revive + + User->>Proxy: Submit Ethereum Transaction + Proxy->>Chain: Repackage as Polkadot Compatible Transaction + Chain->>Pallet: Process Transaction + Pallet->>Pallet: Decode Ethereum Transaction + Pallet->>Pallet: Execute Contract via PolkaVM + Pallet->>Chain: Return Results + Chain->>Proxy: Forward Results + Proxy->>User: Return Ethereum-compatible Response +``` + +This proxy-based approach eliminates the need for node binary modifications, maintaining compatibility across different client implementations. Preserving the original Ethereum transaction payload simplifies the adaptation of existing tools, which can continue processing familiar transaction formats. + +### PolkaVM Design Fundamentals + +PolkaVM differs from the EVM in two key ways that make it faster, more hardware-efficient, and easier to extend: + +- **Register-based design**: Instead of a stack machine, PolkaVM uses a RISC-V–style register model. This design: + + - Uses a fixed set of registers to pass arguments, not an infinite stack. + - Maps cleanly to real hardware like x86-64. + - Simplifies compilation and boosts runtime efficiency. + - Enables tighter control over register allocation and performance tuning. + +- **64-bit word size**: PolkaVM runs on a native 64-bit word size, aligning directly with modern CPUs. This design: + + - Executes arithmetic operations with direct hardware support. + - Maintains compatibility with Solidity’s 256-bit types via YUL translation. + - Accelerates computation-heavy workloads through native word alignment. + - Integrates easily with low-level, performance-focused components. + +## Where To Go Next + +
+ +- Learn __Contract Deployment__ + + --- + + Learn how REVM and PVM compare for compiling and deploying smart contracts. + + [:octicons-arrow-right-24: Reference](/smart-contracts/for-eth-devs/contract-deployment/) + +
+ + --- Page Title: Ethereum-Native Precompiles @@ -12653,121 +12756,6 @@ Support for encoding and decoding Polkadot SDK SS58 addresses has been implement - **TypeScript**: [`subsquid/squid-sdk`](https://github.com/subsquid/squid-sdk){target=\_blank} ---- - -Page Title: PolkaVM Design - -- Source (raw): https://raw.githubusercontent.com/polkadot-developers/polkadot-docs/master/.ai/pages/smart-contracts-for-eth-devs-dual-vm-stack.md -- Canonical (HTML): https://docs.polkadot.com/smart-contracts/for-eth-devs/dual-vm-stack/ -- Summary: Discover PolkaVM, a high-performance smart contract VM for Polkadot, enabling Ethereum compatibility via pallet_revive, Solidity support & optimized execution. - -# PolkaVM Design - -!!! smartcontract "PolkaVM Preview Release" - PolkaVM smart contracts with Ethereum compatibility are in **early-stage development and may be unstable or incomplete**. -## Introduction - -The Asset Hub smart contracts solution includes multiple components to ensure Ethereum compatibility and high performance. Its architecture allows for integration with current Ethereum tools, while its innovative virtual machine design enhances performance characteristics. - -## PolkaVM - -[**PolkaVM**](https://github.com/paritytech/polkavm){target=\_blank} is a custom virtual machine optimized for performance with [RISC-V-based](https://en.wikipedia.org/wiki/RISC-V){target=\_blank} architecture, supporting Solidity and additional high-performance languages. It serves as the core execution environment, integrated directly within the runtime. It features: - -- An efficient interpreter for immediate code execution. -- A planned JIT compiler for optimized performance. -- Dual-mode execution capability, allowing selection of the most appropriate backend for specific workloads. -- Optimized performance for short-running contract calls through the interpreter. - -The interpreter remains particularly beneficial for contracts with minimal code execution, as it eliminates JIT compilation overhead and enables immediate code execution through lazy interpretation. - -## Architecture - -The smart contract solution consists of the following key components that work together to enable Ethereum compatibility on Polkadot-based chains. - -### Pallet Revive - -[**`pallet_revive`**](https://paritytech.github.io/polkadot-sdk/master/pallet_revive/index.html){target=\_blank} is a runtime module that executes smart contracts by adding extrinsics, runtime APIs, and logic to convert Ethereum-style transactions into formats compatible with Polkadot SDK-based blockchains. It processes Ethereum-style transactions through the following workflow: - -```mermaid -sequenceDiagram - participant User as User/dApp - participant Proxy as Ethereum JSON RPC Proxy - participant Chain as Blockchain Node - participant Pallet as pallet_revive - - User->>Proxy: Submit Ethereum Transaction - Proxy->>Chain: Repackage as Polkadot Compatible Transaction - Chain->>Pallet: Process Transaction - Pallet->>Pallet: Decode Ethereum Transaction - Pallet->>Pallet: Execute Contract via PolkaVM - Pallet->>Chain: Return Results - Chain->>Proxy: Forward Results - Proxy->>User: Return Ethereum-compatible Response -``` - -This proxy-based approach eliminates the need for node binary modifications, maintaining compatibility across different client implementations. Preserving the original Ethereum transaction payload simplifies adapting existing tools, which can continue processing familiar transaction formats. - -### PolkaVM Design Fundamentals - -PolkaVM introduces two fundamental architectural differences compared to the Ethereum Virtual Machine (EVM): - -```mermaid -flowchart TB - subgraph "EVM Architecture" - EVMStack[Stack-Based] - EVM256[256-bit Word Size] - end - - subgraph "PolkaVM Architecture" - PVMReg[Register-Based] - PVM64[64-bit Word Size] - end -``` - -- **Register-based design**: PolkaVM utilizes a RISC-V register-based approach. This design: - - - Employs a finite set of registers for argument passing instead of an infinite stack. - - Facilitates efficient translation to underlying hardware architectures. - - Optimizes register allocation through careful register count selection. - - Enables simple 1:1 mapping to x86-64 instruction sets. - - Reduces compilation complexity through strategic register limitation. - - Improves overall execution performance through hardware-aligned design. - -- **64-bit word size**: PolkaVM operates with a 64-bit word size. This design: - - - Enables direct hardware-supported arithmetic operations. - - Maintains compatibility with Solidity's 256-bit operations through YUL translation. - - Allows integration of performance-critical components written in lower-level languages. - - Optimizes computation-intensive operations through native word size alignment. - - Reduces overhead for operations not requiring extended precision. - - Facilitates efficient integration with modern CPU architectures. - -## Compilation Process - -When compiling a Solidity smart contract, the code passes through the following stages: - -```mermaid -flowchart LR - Dev[Developer] --> |Solidity
Source
Code| Solc - - subgraph "Compilation Process" - direction LR - Solc[solc] --> |YUL
IR| Revive - Revive[Revive Compiler] --> |LLVM
IR| LLVM - LLVM[LLVM
Optimizer] --> |RISC-V ELF
Shared Object| PVMLinker - end - - PVMLinker[PVM Linker] --> PVM[PVM Blob
with Metadata] -``` - -The compilation process integrates several specialized components: - -1. **Solc**: The standard Ethereum Solidity compiler that translates Solidity source code to [YUL IR](https://docs.soliditylang.org/en/latest/yul.html){target=\_blank}. -2. **Revive Compiler**: Takes YUL IR and transforms it to [LLVM IR](https://llvm.org/){target=\_blank}. -3. **LLVM**: A compiler infrastructure that optimizes the code and generates RISC-V ELF objects. -4. **PVM linker**: Links the RISC-V ELF object into a final PolkaVM blob with metadata. - - --- Page Title: Randomness diff --git a/.ai/categories/tooling.md b/.ai/categories/tooling.md index da10eaa92..88d0f63bc 100644 --- a/.ai/categories/tooling.md +++ b/.ai/categories/tooling.md @@ -5825,6 +5825,109 @@ To build on this foundation, you could extend this project by implementing funct This knowledge can be leveraged to build more complex DeFi applications or to integrate Uniswap V2 functionality into your existing projects on Polkadot. +--- + +Page Title: Dual Virtual Machine Stack + +- Source (raw): https://raw.githubusercontent.com/polkadot-developers/polkadot-docs/master/.ai/pages/smart-contracts-for-eth-devs-dual-vm-stack.md +- Canonical (HTML): https://docs.polkadot.com/smart-contracts/for-eth-devs/dual-vm-stack/ +- Summary: Compare Polkadot’s dual smart contract VMs—REVM for EVM compatibility and PolkaVM for RISC-V performance, flexibility, and efficiency. + +# Dual Virtual Machine Stack + +!!! smartcontract "PolkaVM Preview Release" + PolkaVM smart contracts with Ethereum compatibility are in **early-stage development and may be unstable or incomplete**. +## Introduction + +Polkadot's smart contract platform supports two distinct virtual machine (VM) architectures, providing developers with flexibility in selecting the optimal execution backend for their specific needs. This approach strikes a balance between immediate Ethereum compatibility and long-term innovation, enabling developers to deploy either unmodified (Ethereum Virtual Machine) EVM contracts using Rust Ethereum Virtual Machine (REVM) or optimize for higher performance using PolkaVM (PVM). + +Both VM options share common infrastructure, including RPC interfaces, tooling support, and precompiles. The following sections compare architectures and guide you in selecting the best VM for your project's needs. + +## Migrate from EVM + +The [REVM backend](https://github.com/bluealloy/revm){target=\_blank} integrates a complete Rust implementation of the EVM, enabling Solidity contracts to run unchanged on Polkadot's smart contract platform. + +REVM allows developers to use their existing Ethereum tooling and infrastructure to build on Polkadot. Choose REVM to: + +- Migrate existing Ethereum contracts without modifications. +- Retain exact EVM behavior for audit tools. +- Use developer tools that rely upon inspecting EVM bytecode. +- Prioritize rapid deployment over optimization. +- Work with established Ethereum infrastructure and tooling to build on Polkadot. + +REVM enables Ethereum developers to seamlessly migrate to Polkadot, achieving performance and fee improvements without modifying their existing contracts or developer tooling stack. + +## Upgrade to PolkaVM + +[**PolkaVM**](https://github.com/paritytech/polkavm){target=\_blank} is a custom virtual machine optimized for performance with [RISC-V-based](https://en.wikipedia.org/wiki/RISC-V){target=\_blank} architecture, supporting Solidity and additional high-performance languages. It serves as the core execution environment, integrated directly within the runtime. Choose the PolkaVM for: + +- An efficient interpreter for immediate code execution. +- A planned [Just In Time (JIT)](https://en.wikipedia.org/wiki/Just-in-time_compilation){target=\_blank} compiler for optimized performance. +- Dual-mode execution capability, allowing selection of the most appropriate backend for specific workloads. +- Optimized performance for short-running contract calls through the interpreter. + +The interpreter remains particularly beneficial for contracts with minimal code execution, as it enables immediate code execution through lazy interpretation. + +## Architecture + +The following key components of PolkaVM work together to enable Ethereum compatibility on Polkadot-based chains. + +### Revive Pallet + +[**`pallet_revive`**](https://paritytech.github.io/polkadot-sdk/master/pallet_revive/index.html){target=\_blank} is a runtime module that executes smart contracts by adding extrinsics, runtime APIs, and logic to convert Ethereum-style transactions into formats compatible with Polkadot SDK-based blockchains. It processes Ethereum-style transactions through the following workflow: + +```mermaid +sequenceDiagram + participant User as User/dApp + participant Proxy as Ethereum JSON RPC Proxy + participant Chain as Blockchain Node + participant Pallet as pallet_revive + + User->>Proxy: Submit Ethereum Transaction + Proxy->>Chain: Repackage as Polkadot Compatible Transaction + Chain->>Pallet: Process Transaction + Pallet->>Pallet: Decode Ethereum Transaction + Pallet->>Pallet: Execute Contract via PolkaVM + Pallet->>Chain: Return Results + Chain->>Proxy: Forward Results + Proxy->>User: Return Ethereum-compatible Response +``` + +This proxy-based approach eliminates the need for node binary modifications, maintaining compatibility across different client implementations. Preserving the original Ethereum transaction payload simplifies the adaptation of existing tools, which can continue processing familiar transaction formats. + +### PolkaVM Design Fundamentals + +PolkaVM differs from the EVM in two key ways that make it faster, more hardware-efficient, and easier to extend: + +- **Register-based design**: Instead of a stack machine, PolkaVM uses a RISC-V–style register model. This design: + + - Uses a fixed set of registers to pass arguments, not an infinite stack. + - Maps cleanly to real hardware like x86-64. + - Simplifies compilation and boosts runtime efficiency. + - Enables tighter control over register allocation and performance tuning. + +- **64-bit word size**: PolkaVM runs on a native 64-bit word size, aligning directly with modern CPUs. This design: + + - Executes arithmetic operations with direct hardware support. + - Maintains compatibility with Solidity’s 256-bit types via YUL translation. + - Accelerates computation-heavy workloads through native word alignment. + - Integrates easily with low-level, performance-focused components. + +## Where To Go Next + +
+ +- Learn __Contract Deployment__ + + --- + + Learn how REVM and PVM compare for compiling and deploying smart contracts. + + [:octicons-arrow-right-24: Reference](/smart-contracts/for-eth-devs/contract-deployment/) + +
+ + --- Page Title: E2E Testing with Moonwall @@ -17826,121 +17929,6 @@ The `alice` keypair in the example comes from a `Keyring` object. For more detai For more detailed information about the Polkadot.js API, check the [official documentation](https://polkadot.js.org/docs/){target=\_blank}. ---- - -Page Title: PolkaVM Design - -- Source (raw): https://raw.githubusercontent.com/polkadot-developers/polkadot-docs/master/.ai/pages/smart-contracts-for-eth-devs-dual-vm-stack.md -- Canonical (HTML): https://docs.polkadot.com/smart-contracts/for-eth-devs/dual-vm-stack/ -- Summary: Discover PolkaVM, a high-performance smart contract VM for Polkadot, enabling Ethereum compatibility via pallet_revive, Solidity support & optimized execution. - -# PolkaVM Design - -!!! smartcontract "PolkaVM Preview Release" - PolkaVM smart contracts with Ethereum compatibility are in **early-stage development and may be unstable or incomplete**. -## Introduction - -The Asset Hub smart contracts solution includes multiple components to ensure Ethereum compatibility and high performance. Its architecture allows for integration with current Ethereum tools, while its innovative virtual machine design enhances performance characteristics. - -## PolkaVM - -[**PolkaVM**](https://github.com/paritytech/polkavm){target=\_blank} is a custom virtual machine optimized for performance with [RISC-V-based](https://en.wikipedia.org/wiki/RISC-V){target=\_blank} architecture, supporting Solidity and additional high-performance languages. It serves as the core execution environment, integrated directly within the runtime. It features: - -- An efficient interpreter for immediate code execution. -- A planned JIT compiler for optimized performance. -- Dual-mode execution capability, allowing selection of the most appropriate backend for specific workloads. -- Optimized performance for short-running contract calls through the interpreter. - -The interpreter remains particularly beneficial for contracts with minimal code execution, as it eliminates JIT compilation overhead and enables immediate code execution through lazy interpretation. - -## Architecture - -The smart contract solution consists of the following key components that work together to enable Ethereum compatibility on Polkadot-based chains. - -### Pallet Revive - -[**`pallet_revive`**](https://paritytech.github.io/polkadot-sdk/master/pallet_revive/index.html){target=\_blank} is a runtime module that executes smart contracts by adding extrinsics, runtime APIs, and logic to convert Ethereum-style transactions into formats compatible with Polkadot SDK-based blockchains. It processes Ethereum-style transactions through the following workflow: - -```mermaid -sequenceDiagram - participant User as User/dApp - participant Proxy as Ethereum JSON RPC Proxy - participant Chain as Blockchain Node - participant Pallet as pallet_revive - - User->>Proxy: Submit Ethereum Transaction - Proxy->>Chain: Repackage as Polkadot Compatible Transaction - Chain->>Pallet: Process Transaction - Pallet->>Pallet: Decode Ethereum Transaction - Pallet->>Pallet: Execute Contract via PolkaVM - Pallet->>Chain: Return Results - Chain->>Proxy: Forward Results - Proxy->>User: Return Ethereum-compatible Response -``` - -This proxy-based approach eliminates the need for node binary modifications, maintaining compatibility across different client implementations. Preserving the original Ethereum transaction payload simplifies adapting existing tools, which can continue processing familiar transaction formats. - -### PolkaVM Design Fundamentals - -PolkaVM introduces two fundamental architectural differences compared to the Ethereum Virtual Machine (EVM): - -```mermaid -flowchart TB - subgraph "EVM Architecture" - EVMStack[Stack-Based] - EVM256[256-bit Word Size] - end - - subgraph "PolkaVM Architecture" - PVMReg[Register-Based] - PVM64[64-bit Word Size] - end -``` - -- **Register-based design**: PolkaVM utilizes a RISC-V register-based approach. This design: - - - Employs a finite set of registers for argument passing instead of an infinite stack. - - Facilitates efficient translation to underlying hardware architectures. - - Optimizes register allocation through careful register count selection. - - Enables simple 1:1 mapping to x86-64 instruction sets. - - Reduces compilation complexity through strategic register limitation. - - Improves overall execution performance through hardware-aligned design. - -- **64-bit word size**: PolkaVM operates with a 64-bit word size. This design: - - - Enables direct hardware-supported arithmetic operations. - - Maintains compatibility with Solidity's 256-bit operations through YUL translation. - - Allows integration of performance-critical components written in lower-level languages. - - Optimizes computation-intensive operations through native word size alignment. - - Reduces overhead for operations not requiring extended precision. - - Facilitates efficient integration with modern CPU architectures. - -## Compilation Process - -When compiling a Solidity smart contract, the code passes through the following stages: - -```mermaid -flowchart LR - Dev[Developer] --> |Solidity
Source
Code| Solc - - subgraph "Compilation Process" - direction LR - Solc[solc] --> |YUL
IR| Revive - Revive[Revive Compiler] --> |LLVM
IR| LLVM - LLVM[LLVM
Optimizer] --> |RISC-V ELF
Shared Object| PVMLinker - end - - PVMLinker[PVM Linker] --> PVM[PVM Blob
with Metadata] -``` - -The compilation process integrates several specialized components: - -1. **Solc**: The standard Ethereum Solidity compiler that translates Solidity source code to [YUL IR](https://docs.soliditylang.org/en/latest/yul.html){target=\_blank}. -2. **Revive Compiler**: Takes YUL IR and transforms it to [LLVM IR](https://llvm.org/){target=\_blank}. -3. **LLVM**: A compiler infrastructure that optimizes the code and generates RISC-V ELF objects. -4. **PVM linker**: Links the RISC-V ELF object into a final PolkaVM blob with metadata. - - --- Page Title: Python Substrate Interface diff --git a/.ai/pages/parachains-customize-runtime-pallet-development-create-a-pallet.md b/.ai/pages/parachains-customize-runtime-pallet-development-create-a-pallet.md index 9d41783c9..6b36c500f 100644 --- a/.ai/pages/parachains-customize-runtime-pallet-development-create-a-pallet.md +++ b/.ai/pages/parachains-customize-runtime-pallet-development-create-a-pallet.md @@ -1,33 +1,25 @@ --- -title: Make a Custom Pallet +title: Create a Custom Pallet description: Learn how to create custom pallets using FRAME, allowing for flexible, modular, and scalable blockchain development. Follow the step-by-step guide. categories: Parachains url: https://docs.polkadot.com/parachains/customize-runtime/pallet-development/create-a-pallet/ --- -# Make a Custom Pallet +# Create a Custom Pallet ## Introduction -[Framework for Runtime Aggregation of Modular Entities (FRAME)](https://paritytech.github.io/polkadot-sdk/master/polkadot_sdk_docs/polkadot_sdk/frame_runtime/index.html){target=\_blank} provides a powerful set of tools for blockchain development through modular components called [pallets](https://paritytech.github.io/polkadot-sdk/master/polkadot_sdk_docs/polkadot_sdk/frame_runtime/pallet/index.html){target=\_blank}. These Rust-based runtime modules allow you to build custom blockchain functionality with precision and flexibility. While FRAME includes a library of pre-built pallets, its true strength lies in the ability to create custom pallets tailored to your specific needs. +[Framework for Runtime Aggregation of Modular Entities (FRAME)](https://paritytech.github.io/polkadot-sdk/master/polkadot_sdk_docs/polkadot_sdk/frame_runtime/index.html){target=\_blank} provides a powerful set of tools for blockchain development through modular components called [pallets](https://paritytech.github.io/polkadot-sdk/master/polkadot_sdk_docs/polkadot_sdk/frame_runtime/pallet/index.html){target=\_blank}. These Rust-based runtime modules allow you to build custom blockchain functionality with precision and flexibility. While FRAME includes a library of pre-built pallets, its true strength lies in creating custom pallets tailored to your specific needs. -In this guide, you'll learn how to build a custom counter pallet from scratch that demonstrates core pallet development concepts. The pallet you'll create includes: - -- User-triggered increment and decrement operations -- Root-only counter value setting -- Event emission for state changes -- Custom error handling -- Storage management -- User interaction tracking -- Genesis configuration for initial state +In this guide, you'll learn how to build a custom counter pallet from scratch that demonstrates core pallet development concepts. ## Prerequisites Before you begin, ensure you have: -- [Polkadot SDK dependencies installed](/parachains/install-polkadot-sdk/){target=\_blank} -- A [Polkadot SDK Parchain Template](/parachains/launch-a-parachain/set-up-the-parachain-template/){target=\_blank} set up locally -- Basic familiarity with [FRAME concepts](/parachains/customize-runtime/){target=\_blank} +- [Polkadot SDK dependencies installed](/parachains/install-polkadot-sdk/){target=\_blank}. +- A [Polkadot SDK Parchain Template](/parachains/launch-a-parachain/set-up-the-parachain-template/){target=\_blank} set up locally. +- Basic familiarity with [FRAME concepts](/parachains/customize-runtime/){target=\_blank}. ## Core Pallet Components @@ -88,31 +80,31 @@ To integrate your custom pallet into the Polkadot SDK-based runtime, configure t ```toml title="pallet-custom/Cargo.toml" [package] - name = "pallet-custom" - description = "A custom counter pallet for demonstration purposes." - version = "0.1.0" - license = "Unlicense" - authors.workspace = true - homepage.workspace = true - repository.workspace = true - edition.workspace = true - publish = false - - [package.metadata.docs.rs] - targets = ["x86_64-unknown-linux-gnu"] - - [dependencies] - codec = { features = ["derive"], workspace = true } - scale-info = { features = ["derive"], workspace = true } - frame = { features = ["experimental", "runtime"], workspace = true } - - [features] - default = ["std"] - std = [ - "codec/std", - "scale-info/std", - "frame/std", - ] + name = "pallet-custom" + description = "A custom counter pallet for demonstration purposes." + version = "0.1.0" + license = "Unlicense" + authors.workspace = true + homepage.workspace = true + repository.workspace = true + edition.workspace = true + publish = false + + [package.metadata.docs.rs] + targets = ["x86_64-unknown-linux-gnu"] + + [dependencies] + codec = { features = ["derive"], workspace = true } + scale-info = { features = ["derive"], workspace = true } + frame = { features = ["experimental", "runtime"], workspace = true } + + [features] + default = ["std"] + std = [ + "codec/std", + "scale-info/std", + "frame/std", + ] ``` !!!note "Version Management" @@ -121,12 +113,12 @@ To integrate your custom pallet into the Polkadot SDK-based runtime, configure t 2. The parachain template already includes `pallets/*` in the workspace members, so your new pallet is automatically recognized. Verify this by checking the root `Cargo.toml`: ```toml title="Cargo.toml" - [workspace.members] - members = [ - "node", - "pallets/*", - "runtime", - ] + [workspace.members] + members = [ + "node", + "pallets/*", + "runtime", + ] ``` ## Initialize the Pallet Structure @@ -164,10 +156,9 @@ With dependencies configured, set up the basic scaffold that will hold your pall } ``` - !!!note - This setup starts with a minimal scaffold without events and errors. These will be added in the following sections after the `Config` trait is properly configured with the required `RuntimeEvent` type. + This setup starts with a minimal scaffold without events and errors. These will be added in the following sections after the `Config` trait is correctly configured with the required `RuntimeEvent` type. -3. Verify it compiles: +3. Verify it compiles using the following command: ```bash cargo build --package pallet-custom @@ -184,14 +175,15 @@ Replace the [`#[pallet::config]`](https://paritytech.github.io/polkadot-sdk/mast pub trait Config: frame_system::Config { /// The overarching runtime event type. type RuntimeEvent: From> + IsType<::RuntimeEvent>; - + /// Maximum value the counter can reach. #[pallet::constant] type CounterMaxValue: Get; } + ``` -**Key configuration elements:** +Key configuration elements include the following: - **[`RuntimeEvent`](https://paritytech.github.io/polkadot-sdk/master/frame_system/pallet/trait.Config.html#associatedtype.RuntimeEvent){target=\_blank}**: Required for the pallet to emit events that the runtime can process. - **`CounterMaxValue`**: A constant that sets an upper limit on counter values, configurable per runtime. @@ -209,8 +201,8 @@ Add the [`#[pallet::event]`](https://paritytech.github.io/polkadot-sdk/master/fr #[pallet::generate_deposit(pub(super) fn deposit_event)] pub enum Event { /// Counter value was explicitly set. [new_value] - CounterValueSet { - new_value: u32 + CounterValueSet { + new_value: u32, }, /// Counter was incremented. [new_value, who, amount] CounterIncremented { @@ -225,6 +217,7 @@ pub enum Event { amount: u32, }, } + ``` ## Define Errors @@ -247,6 +240,7 @@ pub enum Error { /// The counter value would exceed the maximum allowed value. CounterMaxValueExceeded, } + ``` ## Add Storage Items @@ -280,7 +274,7 @@ For more storage types and patterns, explore the [Polkadot SDK storage documenta ## Configure Genesis State -Genesis configuration allows you to set the initial state of your pallet when the blockchain first starts. This is essential for both production networks and testing environments. It is particularly useful for: +Genesis configuration allows you to set the initial state of your pallet when the blockchain first starts and is essential for both production networks and testing environments. It is beneficial for: - Setting initial parameter values. - Pre-allocating resources or accounts. @@ -304,16 +298,17 @@ impl BuildGenesisConfig for GenesisConfig { fn build(&self) { // Set the initial counter value CounterValue::::put(self.initial_counter_value); - + // Set initial user interactions for (account, count) in &self.initial_user_interactions { UserInteractions::::insert(account, count); } } } + ``` -**Genesis configuration components:** +Genesis configuration components include the following: - **`GenesisConfig` struct**: Defines what can be configured at genesis. - **`#[derive(DefaultNoBound)]`**: Provides sensible defaults (empty vec and 0 for the counter). @@ -339,19 +334,16 @@ impl Pallet { pub fn set_counter_value(origin: OriginFor, new_value: u32) -> DispatchResult { // Ensure the caller is root ensure_root(origin)?; - + // Validate the new value doesn't exceed the maximum - ensure!( - new_value <= T::CounterMaxValue::get(), - Error::::CounterMaxValueExceeded - ); - + ensure!(new_value <= T::CounterMaxValue::get(), Error::::CounterMaxValueExceeded); + // Update storage CounterValue::::put(new_value); - + // Emit event Self::deposit_event(Event::CounterValueSet { new_value }); - + Ok(()) } @@ -361,36 +353,31 @@ impl Pallet { pub fn increment(origin: OriginFor, amount: u32) -> DispatchResult { // Ensure the caller is signed let who = ensure_signed(origin)?; - + // Get current counter value let current_value = CounterValue::::get(); - + // Check for overflow - let new_value = current_value - .checked_add(amount) - .ok_or(Error::::Overflow)?; - + let new_value = current_value.checked_add(amount).ok_or(Error::::Overflow)?; + // Ensure new value doesn't exceed maximum - ensure!( - new_value <= T::CounterMaxValue::get(), - Error::::CounterMaxValueExceeded - ); - + ensure!(new_value <= T::CounterMaxValue::get(), Error::::CounterMaxValueExceeded); + // Update counter storage CounterValue::::put(new_value); - + // Track user interaction UserInteractions::::mutate(&who, |count| { *count = count.saturating_add(1); }); - + // Emit event Self::deposit_event(Event::CounterIncremented { new_value, who, amount, }); - + Ok(()) } @@ -400,64 +387,63 @@ impl Pallet { pub fn decrement(origin: OriginFor, amount: u32) -> DispatchResult { // Ensure the caller is signed let who = ensure_signed(origin)?; - + // Get current counter value let current_value = CounterValue::::get(); - + // Check for underflow - let new_value = current_value - .checked_sub(amount) - .ok_or(Error::::Underflow)?; - + let new_value = current_value.checked_sub(amount).ok_or(Error::::Underflow)?; + // Update counter storage CounterValue::::put(new_value); - + // Track user interaction UserInteractions::::mutate(&who, |count| { *count = count.saturating_add(1); }); - + // Emit event Self::deposit_event(Event::CounterDecremented { new_value, who, amount, }); - + Ok(()) } } + ``` ### Dispatchable Function Details ???+ interface "`set_counter_value`" - - **Access**: Root origin only (privileged operations) - - **Purpose**: Set counter to a specific value - - **Validations**: New value must not exceed `CounterMaxValue` - - **State changes**: Updates `CounterValue` storage - - **Events**: Emits `CounterValueSet` + - **Access**: Root origin only (privileged operations). + - **Purpose**: Set counter to a specific value. + - **Validations**: New value must not exceed `CounterMaxValue`. + - **State changes**: Updates `CounterValue` storage. + - **Events**: Emits `CounterValueSet`. ??? interface "`increment`" - - **Access**: Any signed account - - **Purpose**: Increase counter by specified amount - - **Validations**: Checks for overflow and max value compliance - - **State changes**: Updates `CounterValue` and `UserInteractions` - - **Events**: Emits `CounterIncremented` + - **Access**: Any signed account. + - **Purpose**: Increase counter by specified amount. + - **Validations**: Checks for overflow and max value compliance. + - **State changes**: Updates `CounterValue` and `UserInteractions`. + - **Events**: Emits `CounterIncremented`. ??? interface "`decrement`" - - **Access**: Any signed account - - **Purpose**: Decrease counter by specified amount - - **Validations**: Checks for underflow - - **State changes**: Updates `CounterValue` and `UserInteractions` - - **Events**: Emits `CounterDecremented` + - **Access**: Any signed account. + - **Purpose**: Decrease counter by specified amount. + - **Validations**: Checks for underflow. + - **State changes**: Updates `CounterValue` and `UserInteractions`. + - **Events**: Emits `CounterDecremented`. ## Verify Pallet Compilation -Before proceeding, ensure your pallet compiles without errors: +Before proceeding, ensure your pallet compiles without errors by running the following command: ```bash cargo build --package pallet-custom @@ -482,7 +468,7 @@ If you encounter errors, carefully review the code against this guide. Once the #[pallet::config] pub trait Config: frame_system::Config { type RuntimeEvent: From> + IsType<::RuntimeEvent>; - + #[pallet::constant] type CounterMaxValue: Get; } @@ -490,9 +476,19 @@ If you encounter errors, carefully review the code against this guide. Once the #[pallet::event] #[pallet::generate_deposit(pub(super) fn deposit_event)] pub enum Event { - CounterValueSet { new_value: u32 }, - CounterIncremented { new_value: u32, who: T::AccountId, amount: u32 }, - CounterDecremented { new_value: u32, who: T::AccountId, amount: u32 }, + CounterValueSet { + new_value: u32, + }, + CounterIncremented { + new_value: u32, + who: T::AccountId, + amount: u32, + }, + CounterDecremented { + new_value: u32, + who: T::AccountId, + amount: u32, + }, } #[pallet::error] @@ -507,7 +503,13 @@ If you encounter errors, carefully review the code against this guide. Once the pub type CounterValue = StorageValue<_, u32, ValueQuery>; #[pallet::storage] - pub type UserInteractions = StorageMap<_, Blake2_128Concat, T::AccountId, u32, ValueQuery>; + pub type UserInteractions = StorageMap< + _, + Blake2_128Concat, + T::AccountId, + u32, + ValueQuery + >; #[pallet::genesis_config] #[derive(DefaultNoBound)] @@ -546,7 +548,9 @@ If you encounter errors, carefully review the code against this guide. Once the let new_value = current_value.checked_add(amount).ok_or(Error::::Overflow)?; ensure!(new_value <= T::CounterMaxValue::get(), Error::::CounterMaxValueExceeded); CounterValue::::put(new_value); - UserInteractions::::mutate(&who, |count| *count = count.saturating_add(1)); + UserInteractions::::mutate(&who, |count| { + *count = count.saturating_add(1); + }); Self::deposit_event(Event::CounterIncremented { new_value, who, amount }); Ok(()) } @@ -558,17 +562,20 @@ If you encounter errors, carefully review the code against this guide. Once the let current_value = CounterValue::::get(); let new_value = current_value.checked_sub(amount).ok_or(Error::::Underflow)?; CounterValue::::put(new_value); - UserInteractions::::mutate(&who, |count| *count = count.saturating_add(1)); + UserInteractions::::mutate(&who, |count| { + *count = count.saturating_add(1); + }); Self::deposit_event(Event::CounterDecremented { new_value, who, amount }); Ok(()) } } } + ``` ## Add the Pallet to Your Runtime -Now that your custom pallet is complete, integrate it into the parachain runtime. +Now that your custom pallet is complete, you can integrate it into the parachain runtime. ### Add Runtime Dependency @@ -579,7 +586,7 @@ Now that your custom pallet is complete, integrate it into the parachain runtime # Local dependencies pallet-custom = { path = "../pallets/pallet-custom", default-features = false } - # ... other dependencies + # Other dependencies ``` 2. Enable the `std` feature by adding it to the `[features]` section: @@ -608,8 +615,8 @@ impl pallet_custom::Config for Runtime { This configuration: -- Links the pallet's events to the runtime's event system -- Sets a maximum counter value of 1000 using [`ConstU32`](https://paritytech.github.io/polkadot-sdk/master/frame_support/traits/struct.ConstU32.html){target=\_blank} +- Links the pallet's events to the runtime's event system. +- Sets a maximum counter value of 1000 using [`ConstU32`](https://paritytech.github.io/polkadot-sdk/master/frame_support/traits/struct.ConstU32.html){target=\_blank}. ### Add to Runtime Construct @@ -648,9 +655,9 @@ mod runtime { ### Configure Genesis for Your Runtime -To set initial values for your pallet when the chain starts, you'll need to configure the genesis in your chain specification. This is typically done in the `node/src/chain_spec.rs` file or when generating the chain specification. +To set initial values for your pallet when the chain starts, you'll need to configure the genesis in your chain specification. Genesis configuration is typically done in the `node/src/chain_spec.rs` file or when generating the chain specification. -For development and testing, you can use the default values provided by the `#[derive(DefaultNoBound)]` macro. For production networks, you'll want to set these values in your chain specification explicitly. +For development and testing, you can use the default values provided by the `#[derive(DefaultNoBound)]` macro. For production networks, you'll want to explicitly set these values in your chain specification. ### Verify Runtime Compilation @@ -712,15 +719,15 @@ Use the Polkadot.js Apps interface to test your pallet: ## Key Takeaways -You've successfully created and integrated a custom pallet into a Polkadot SDK-based runtime. You learned: +You've successfully created and integrated a custom pallet into a Polkadot SDK-based runtime. You have now successfully: -- **Configuration**: Defined runtime-specific types and constants via the `Config` trait. -- **Storage**: Implemented on-chain state using `StorageValue` and `StorageMap`. -- **Events**: Created signals to communicate state changes to external systems. -- **Errors**: Established clear error handling with descriptive error types. -- **Genesis**: Configured initial blockchain state for both production and testing. -- **Dispatchables**: Built callable functions with proper validation and access control. -- **Integration**: Successfully added the pallet to a runtime and tested it locally. +- Defined runtime-specific types and constants via the `Config` trait. +- Implemented on-chain state using `StorageValue` and `StorageMap`. +- Created signals to communicate state changes to external systems. +- Established clear error handling with descriptive error types. +- Configured initial blockchain state for both production and testing. +- Built callable functions with proper validation and access control. +- Added the pallet to a runtime and tested it locally. These components form the foundation for developing sophisticated blockchain logic in Polkadot SDK-based chains. diff --git a/.ai/pages/parachains-customize-runtime-pallet-development-mock-runtime.md b/.ai/pages/parachains-customize-runtime-pallet-development-mock-runtime.md index eb555a1a9..af4f28314 100644 --- a/.ai/pages/parachains-customize-runtime-pallet-development-mock-runtime.md +++ b/.ai/pages/parachains-customize-runtime-pallet-development-mock-runtime.md @@ -11,32 +11,32 @@ url: https://docs.polkadot.com/parachains/customize-runtime/pallet-development/m Testing is a critical part of pallet development. Before integrating your pallet into a full runtime, you need a way to test its functionality in isolation. A mock runtime provides a minimal, simulated blockchain environment where you can verify your pallet's logic without the overhead of running a full node. -In this guide, you'll learn how to create a mock runtime for the custom counter pallet built in the [Make a Custom Pallet](/parachains/customize-runtime/pallet-development/create-a-pallet/) guide. This mock runtime will enable you to write comprehensive unit tests that verify: +In this guide, you'll learn how to create a mock runtime for the custom counter pallet built in the [Make a Custom Pallet](/parachains/customize-runtime/pallet-development/create-a-pallet/){target=\_blank} guide. This mock runtime will enable you to write comprehensive unit tests that verify: -- Dispatchable function behavior -- Storage state changes -- Event emission -- Error handling -- Access control and origin validation -- Genesis configuration +- Dispatchable function behavior. +- Storage state changes. +- Event emission. +- Error handling. +- Access control and origin validation. +- Genesis configuration. ## Prerequisites Before you begin, ensure you have: -- Completed the [Make a Custom Pallet](/parachains/customize-runtime/pallet-development/create-a-pallet/) guide -- The custom counter pallet from that guide available in `pallets/pallet-custom` -- Basic understanding of [Rust testing](https://doc.rust-lang.org/book/ch11-00-testing.html){target=\_blank} +- Completed the [Make a Custom Pallet](/parachains/customize-runtime/pallet-development/create-a-pallet/){target=\_blank} guide. +- The custom counter pallet from the Make a Custom Pallet guide. Available in `pallets/pallet-custom`. +- Basic understanding of [Rust testing](https://doc.rust-lang.org/book/ch11-00-testing.html){target=\_blank}. -## Understanding Mock Runtimes +## Understand Mock Runtimes A mock runtime is a minimal implementation of the runtime environment that: -- **Simulates blockchain state** - Provides storage and state management -- **Implements required traits** - Satisfies your pallet's `Config` trait requirements -- **Enables isolated testing** - Allows testing without external dependencies -- **Supports genesis configuration** - Sets initial blockchain state for tests -- **Speeds up development** - Provides instant feedback on code changes +- Simulates blockchain state to provide storage and state management. +- Satisfies your pallet's `Config` trait requirements. +- Allows isolated testing without external dependencies. +- Supports genesis configuration to set initial blockchain state for tests. +- Provides instant feedback on code changes for a faster development cycle. Mock runtimes are used exclusively for testing and are never deployed to a live blockchain. @@ -56,9 +56,9 @@ Start by creating a new module file within your pallet to house the mock runtime touch mock.rs ``` -3. Open `src/lib.rs` and add the mock module declaration at the top of the file, right after the `pub use pallet::*;` line: +3. Next, open `src/lib.rs` and add the mock module declaration at the top of the file, right after the `pub use pallet::*;` line: - ```rust + ```rust title="src/lib.rs" #![cfg_attr(not(feature = "std"), no_std)] pub use pallet::*; @@ -70,21 +70,22 @@ Start by creating a new module file within your pallet to house the mock runtime pub mod pallet { // ... existing pallet code } + ``` The `#[cfg(test)]` attribute ensures this module is only compiled during testing. -## Set Up Basic Mock Infrastructure +## Set Up Basic Mock Open `src/mock.rs` and add the foundational imports and type definitions: -```rust +```rust title="src/mock.rs" use crate as pallet_custom; use frame::{ deps::{ - frame_support::{derive_impl, traits::ConstU32}, + frame_support::{ derive_impl, traits::ConstU32 }, sp_io, - sp_runtime::{traits::IdentityLookup, BuildStorage}, + sp_runtime::{ traits::IdentityLookup, BuildStorage }, }, prelude::*, }; @@ -93,25 +94,25 @@ type Block = frame_system::mocking::MockBlock; // Configure a mock runtime to test the pallet. frame::deps::frame_support::construct_runtime!( - pub enum Test - { - System: frame_system, - CustomPallet: pallet_custom, - } -); + pub enum Test + { + System: frame_system, + CustomPallet: pallet_custom, + } + ); ``` -**Key components:** +The preceding code includes the following key components: -- **`construct_runtime!`** - Macro that builds a minimal runtime with only the pallets needed for testing -- **`Test`** - The mock runtime type used in tests -- **`Block`** - Type alias for the mock block type that the runtime will use +- **[`construct_runtime!`](https://paritytech.github.io/polkadot-sdk/master/polkadot_sdk_frame/runtime/apis/trait.ConstructRuntimeApi.html#tymethod.construct_runtime_api){target=\_blank}**: Macro that builds a minimal runtime with only the pallets needed for testing. +- **`Test`**: The mock runtime type used in tests. +- **`Block`**: Type alias for the mock block type that the runtime will use. -## Implement frame_system Configuration +## Implement Essential Configuration -The [`frame_system`](https://paritytech.github.io/polkadot-sdk/master/frame_system/index.html){target=\_blank} pallet provides core blockchain functionality and is required by all other pallets. Configure it for the test environment: +The [`frame_system`](https://paritytech.github.io/polkadot-sdk/master/frame_system/index.html){target=\_blank} pallet provides core blockchain functionality and is required by all other pallets. Configure it for the test environment as follows: -```rust +```rust title="src/mock.rs" #[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for Test { type Block = Block; @@ -120,55 +121,52 @@ impl frame_system::Config for Test { } ``` -**Simplified for testing:** +This simplified configuration for testing includes the following: -- **`#[derive_impl]`** - Automatically provides sensible test defaults for most `frame_system::Config` types -- **`AccountId = u64`** - Uses simple integers instead of cryptographic account IDs -- **`Lookup = IdentityLookup`** - Direct account ID mapping (no address conversion) -- **`Block = Block`** - Uses the mock block type we defined earlier +- **`#[derive_impl]`**: Automatically provides sensible test defaults for most `frame_system::Config` types. +- **`AccountId = u64`**: Uses simple integers instead of cryptographic account IDs. +- **`Lookup = IdentityLookup`**: Direct account ID mapping (no address conversion). +- **`Block = Block`**: Uses the mock block type we defined earlier. This approach is much more concise than manually specifying every configuration type, as the `TestDefaultConfig` preset provides appropriate defaults for testing. ## Implement Your Pallet's Configuration -Now implement the `Config` trait for your custom pallet. This must match the trait defined in your pallet's `lib.rs`: +Now implement the `Config` trait for your custom pallet. This trait must match the one defined in your pallet's `src/lib.rs`: -```rust +```rust title="src/mock.rs" impl pallet_custom::Config for Test { type RuntimeEvent = RuntimeEvent; type CounterMaxValue = ConstU32<1000>; } ``` -**Configuration details:** +Configuration details include: -- **`RuntimeEvent`** - Connects your pallet's events to the mock runtime's event system -- **`CounterMaxValue`** - Sets the maximum counter value to 1000, matching the production configuration +- **`RuntimeEvent`**: Connects your pallet's events to the mock runtime's event system. +- **`CounterMaxValue`**: Sets the maximum counter value to 1000, matching the production configuration. -!!!note - The configuration here should mirror what you'll use in production unless you specifically need different values for testing. +The configuration here should mirror what you'll use in production unless you specifically need different values for testing. ## Configure Genesis Storage -Genesis storage defines the initial state of your blockchain before any blocks are produced. Since your counter pallet includes genesis configuration (added in the previous guide), you can now set up test environments with different initial states. +Genesis storage defines the initial state of your blockchain before any blocks are produced. Since your counter pallet includes the genesis configuration (added in the previous guide), you can now set up test environments with different initial states. ### Basic Test Environment Create a helper function for the default test environment: -```rust +```rust title="src/mock.rs" // Build genesis storage according to the mock runtime. pub fn new_test_ext() -> sp_io::TestExternalities { - let mut t = frame_system::GenesisConfig::::default() - .build_storage() - .unwrap(); + let mut t = frame_system::GenesisConfig::::default().build_storage().unwrap(); - pallet_custom::GenesisConfig:: { + (pallet_custom::GenesisConfig:: { initial_counter_value: 0, initial_user_interactions: vec![], - } - .assimilate_storage(&mut t) - .unwrap(); + }) + .assimilate_storage(&mut t) + .unwrap(); t.into() } @@ -180,19 +178,17 @@ This function creates a clean blockchain state with an initial counter value of For testing specific scenarios, create additional helper functions with customized genesis states: -```rust +```rust title="src/mock.rs" // Helper function to create a test externalities with a specific initial counter value pub fn new_test_ext_with_counter(initial_value: u32) -> sp_io::TestExternalities { - let mut t = frame_system::GenesisConfig::::default() - .build_storage() - .unwrap(); + let mut t = frame_system::GenesisConfig::::default().build_storage().unwrap(); - pallet_custom::GenesisConfig:: { + (pallet_custom::GenesisConfig:: { initial_counter_value: initial_value, initial_user_interactions: vec![], - } - .assimilate_storage(&mut t) - .unwrap(); + }) + .assimilate_storage(&mut t) + .unwrap(); t.into() } @@ -200,28 +196,27 @@ pub fn new_test_ext_with_counter(initial_value: u32) -> sp_io::TestExternalities // Helper function to create a test externalities with initial user interactions pub fn new_test_ext_with_interactions( initial_value: u32, - interactions: Vec<(u64, u32)>, + interactions: Vec<(u64, u32)> ) -> sp_io::TestExternalities { - let mut t = frame_system::GenesisConfig::::default() - .build_storage() - .unwrap(); + let mut t = frame_system::GenesisConfig::::default().build_storage().unwrap(); - pallet_custom::GenesisConfig:: { + (pallet_custom::GenesisConfig:: { initial_counter_value: initial_value, initial_user_interactions: interactions, - } - .assimilate_storage(&mut t) - .unwrap(); + }) + .assimilate_storage(&mut t) + .unwrap(); t.into() } ``` -**Key methods:** +Key methods used in this step include: + +- **[`BuildStorage::build_storage()`](https://paritytech.github.io/polkadot-sdk/master/sp_runtime/trait.BuildStorage.html#method.build_storage){target=\_blank}**: Creates the initial storage state. +- **[`assimilate_storage`](https://paritytech.github.io/polkadot-sdk/master/sp_runtime/trait.BuildStorage.html#method.assimilate_storage){target=\_blank}**: Merges pallet genesis config into the existing storage. -- **[`BuildStorage::build_storage()`](https://paritytech.github.io/polkadot-sdk/master/sp_runtime/trait.BuildStorage.html#method.build_storage){target=\_blank}** - Creates the initial storage state -- **[`assimilate_storage`](https://paritytech.github.io/polkadot-sdk/master/sp_runtime/trait.BuildStorage.html#method.assimilate_storage){target=\_blank}** - Merges pallet genesis config into the existing storage -- **Multiple configurations** - You can chain multiple `assimilate_storage` calls for different pallets +You can chain multiple `assimilate_storage` calls to configure multiple pallets. ## Verify Mock Compilation @@ -233,17 +228,17 @@ cargo test --package pallet-custom --lib This command compiles the test code (including the mock and genesis configuration) without running tests yet. Address any compilation errors before continuing. -??? code "Complete Mock Runtime" +??? code "Complete mock runtime script" Here's the complete `mock.rs` file for reference: - ```rust + ```rust title="src/mock.rs" use crate as pallet_custom; use frame::{ deps::{ - frame_support::{derive_impl, traits::ConstU32}, + frame_support::{ derive_impl, traits::ConstU32 }, sp_io, - sp_runtime::{traits::IdentityLookup, BuildStorage}, + sp_runtime::{ traits::IdentityLookup, BuildStorage }, }, prelude::*, }; @@ -252,12 +247,12 @@ This command compiles the test code (including the mock and genesis configuratio // Configure a mock runtime to test the pallet. frame::deps::frame_support::construct_runtime!( - pub enum Test - { - System: frame_system, - CustomPallet: pallet_custom, - } - ); + pub enum Test + { + System: frame_system, + CustomPallet: pallet_custom, + } + ); #[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for Test { @@ -273,32 +268,28 @@ This command compiles the test code (including the mock and genesis configuratio // Build genesis storage according to the mock runtime. pub fn new_test_ext() -> sp_io::TestExternalities { - let mut t = frame_system::GenesisConfig::::default() - .build_storage() - .unwrap(); + let mut t = frame_system::GenesisConfig::::default().build_storage().unwrap(); - pallet_custom::GenesisConfig:: { + (pallet_custom::GenesisConfig:: { initial_counter_value: 0, initial_user_interactions: vec![], - } - .assimilate_storage(&mut t) - .unwrap(); + }) + .assimilate_storage(&mut t) + .unwrap(); t.into() } // Helper function to create a test externalities with a specific initial counter value pub fn new_test_ext_with_counter(initial_value: u32) -> sp_io::TestExternalities { - let mut t = frame_system::GenesisConfig::::default() - .build_storage() - .unwrap(); + let mut t = frame_system::GenesisConfig::::default().build_storage().unwrap(); - pallet_custom::GenesisConfig:: { + (pallet_custom::GenesisConfig:: { initial_counter_value: initial_value, initial_user_interactions: vec![], - } - .assimilate_storage(&mut t) - .unwrap(); + }) + .assimilate_storage(&mut t) + .unwrap(); t.into() } @@ -306,18 +297,16 @@ This command compiles the test code (including the mock and genesis configuratio // Helper function to create a test externalities with initial user interactions pub fn new_test_ext_with_interactions( initial_value: u32, - interactions: Vec<(u64, u32)>, + interactions: Vec<(u64, u32)> ) -> sp_io::TestExternalities { - let mut t = frame_system::GenesisConfig::::default() - .build_storage() - .unwrap(); + let mut t = frame_system::GenesisConfig::::default().build_storage().unwrap(); - pallet_custom::GenesisConfig:: { + (pallet_custom::GenesisConfig:: { initial_counter_value: initial_value, initial_user_interactions: interactions, - } - .assimilate_storage(&mut t) - .unwrap(); + }) + .assimilate_storage(&mut t) + .unwrap(); t.into() } @@ -325,16 +314,14 @@ This command compiles the test code (including the mock and genesis configuratio ## Key Takeaways -You've successfully created a mock runtime with genesis configuration for your custom pallet. You now have: +You've successfully created a mock runtime with a genesis configuration for your custom pallet. You can now: -- **Isolated testing environment** - Test your pallet without a full runtime -- **Simplified configuration** - Minimal setup for rapid development iteration -- **Genesis configuration** - Set initial blockchain state for different test scenarios -- **Multiple test helpers** - Different genesis setups for various testing needs -- **Foundation for unit tests** - Infrastructure to test all pallet functionality -- **Fast feedback loop** - Instant compilation and test execution +- Test your pallet without a full runtime. +- Set initial blockchain state for different test scenarios. +- Create different genesis setups for various testing needs. +- Use this minimal setup to test all pallet functionality. -The mock runtime with genesis configuration is essential for test-driven development, allowing you to verify logic under different initial conditions before integration into the actual parachain runtime. +The mock runtime with a genesis configuration is essential for test-driven development, enabling you to verify logic under different initial conditions before integrating it into the actual parachain runtime. ## Where to Go Next diff --git a/.ai/pages/smart-contracts-for-eth-devs-dual-vm-stack.md b/.ai/pages/smart-contracts-for-eth-devs-dual-vm-stack.md index 4d5f80fe2..4b74cfc8d 100644 --- a/.ai/pages/smart-contracts-for-eth-devs-dual-vm-stack.md +++ b/.ai/pages/smart-contracts-for-eth-devs-dual-vm-stack.md @@ -1,34 +1,50 @@ --- -title: PolkaVM Design -description: Discover PolkaVM, a high-performance smart contract VM for Polkadot, enabling Ethereum compatibility via pallet_revive, Solidity support & optimized execution. +title: Dual Virtual Machine Stack +description: Compare Polkadot’s dual smart contract VMs—REVM for EVM compatibility and PolkaVM for RISC-V performance, flexibility, and efficiency. categories: Basics, Polkadot Protocol url: https://docs.polkadot.com/smart-contracts/for-eth-devs/dual-vm-stack/ --- -# PolkaVM Design +# Dual Virtual Machine Stack !!! smartcontract "PolkaVM Preview Release" PolkaVM smart contracts with Ethereum compatibility are in **early-stage development and may be unstable or incomplete**. ## Introduction -The Asset Hub smart contracts solution includes multiple components to ensure Ethereum compatibility and high performance. Its architecture allows for integration with current Ethereum tools, while its innovative virtual machine design enhances performance characteristics. +Polkadot's smart contract platform supports two distinct virtual machine (VM) architectures, providing developers with flexibility in selecting the optimal execution backend for their specific needs. This approach strikes a balance between immediate Ethereum compatibility and long-term innovation, enabling developers to deploy either unmodified (Ethereum Virtual Machine) EVM contracts using Rust Ethereum Virtual Machine (REVM) or optimize for higher performance using PolkaVM (PVM). -## PolkaVM +Both VM options share common infrastructure, including RPC interfaces, tooling support, and precompiles. The following sections compare architectures and guide you in selecting the best VM for your project's needs. -[**PolkaVM**](https://github.com/paritytech/polkavm){target=\_blank} is a custom virtual machine optimized for performance with [RISC-V-based](https://en.wikipedia.org/wiki/RISC-V){target=\_blank} architecture, supporting Solidity and additional high-performance languages. It serves as the core execution environment, integrated directly within the runtime. It features: +## Migrate from EVM + +The [REVM backend](https://github.com/bluealloy/revm){target=\_blank} integrates a complete Rust implementation of the EVM, enabling Solidity contracts to run unchanged on Polkadot's smart contract platform. + +REVM allows developers to use their existing Ethereum tooling and infrastructure to build on Polkadot. Choose REVM to: + +- Migrate existing Ethereum contracts without modifications. +- Retain exact EVM behavior for audit tools. +- Use developer tools that rely upon inspecting EVM bytecode. +- Prioritize rapid deployment over optimization. +- Work with established Ethereum infrastructure and tooling to build on Polkadot. + +REVM enables Ethereum developers to seamlessly migrate to Polkadot, achieving performance and fee improvements without modifying their existing contracts or developer tooling stack. + +## Upgrade to PolkaVM + +[**PolkaVM**](https://github.com/paritytech/polkavm){target=\_blank} is a custom virtual machine optimized for performance with [RISC-V-based](https://en.wikipedia.org/wiki/RISC-V){target=\_blank} architecture, supporting Solidity and additional high-performance languages. It serves as the core execution environment, integrated directly within the runtime. Choose the PolkaVM for: - An efficient interpreter for immediate code execution. -- A planned JIT compiler for optimized performance. +- A planned [Just In Time (JIT)](https://en.wikipedia.org/wiki/Just-in-time_compilation){target=\_blank} compiler for optimized performance. - Dual-mode execution capability, allowing selection of the most appropriate backend for specific workloads. - Optimized performance for short-running contract calls through the interpreter. -The interpreter remains particularly beneficial for contracts with minimal code execution, as it eliminates JIT compilation overhead and enables immediate code execution through lazy interpretation. +The interpreter remains particularly beneficial for contracts with minimal code execution, as it enables immediate code execution through lazy interpretation. ## Architecture -The smart contract solution consists of the following key components that work together to enable Ethereum compatibility on Polkadot-based chains. +The following key components of PolkaVM work together to enable Ethereum compatibility on Polkadot-based chains. -### Pallet Revive +### Revive Pallet [**`pallet_revive`**](https://paritytech.github.io/polkadot-sdk/master/pallet_revive/index.html){target=\_blank} is a runtime module that executes smart contracts by adding extrinsics, runtime APIs, and logic to convert Ethereum-style transactions into formats compatible with Polkadot SDK-based blockchains. It processes Ethereum-style transactions through the following workflow: @@ -49,64 +65,36 @@ sequenceDiagram Proxy->>User: Return Ethereum-compatible Response ``` -This proxy-based approach eliminates the need for node binary modifications, maintaining compatibility across different client implementations. Preserving the original Ethereum transaction payload simplifies adapting existing tools, which can continue processing familiar transaction formats. +This proxy-based approach eliminates the need for node binary modifications, maintaining compatibility across different client implementations. Preserving the original Ethereum transaction payload simplifies the adaptation of existing tools, which can continue processing familiar transaction formats. ### PolkaVM Design Fundamentals -PolkaVM introduces two fundamental architectural differences compared to the Ethereum Virtual Machine (EVM): +PolkaVM differs from the EVM in two key ways that make it faster, more hardware-efficient, and easier to extend: -```mermaid -flowchart TB - subgraph "EVM Architecture" - EVMStack[Stack-Based] - EVM256[256-bit Word Size] - end - - subgraph "PolkaVM Architecture" - PVMReg[Register-Based] - PVM64[64-bit Word Size] - end -``` +- **Register-based design**: Instead of a stack machine, PolkaVM uses a RISC-V–style register model. This design: -- **Register-based design**: PolkaVM utilizes a RISC-V register-based approach. This design: + - Uses a fixed set of registers to pass arguments, not an infinite stack. + - Maps cleanly to real hardware like x86-64. + - Simplifies compilation and boosts runtime efficiency. + - Enables tighter control over register allocation and performance tuning. - - Employs a finite set of registers for argument passing instead of an infinite stack. - - Facilitates efficient translation to underlying hardware architectures. - - Optimizes register allocation through careful register count selection. - - Enables simple 1:1 mapping to x86-64 instruction sets. - - Reduces compilation complexity through strategic register limitation. - - Improves overall execution performance through hardware-aligned design. +- **64-bit word size**: PolkaVM runs on a native 64-bit word size, aligning directly with modern CPUs. This design: -- **64-bit word size**: PolkaVM operates with a 64-bit word size. This design: + - Executes arithmetic operations with direct hardware support. + - Maintains compatibility with Solidity’s 256-bit types via YUL translation. + - Accelerates computation-heavy workloads through native word alignment. + - Integrates easily with low-level, performance-focused components. - - Enables direct hardware-supported arithmetic operations. - - Maintains compatibility with Solidity's 256-bit operations through YUL translation. - - Allows integration of performance-critical components written in lower-level languages. - - Optimizes computation-intensive operations through native word size alignment. - - Reduces overhead for operations not requiring extended precision. - - Facilitates efficient integration with modern CPU architectures. +## Where To Go Next -## Compilation Process +
-When compiling a Solidity smart contract, the code passes through the following stages: +- Learn __Contract Deployment__ -```mermaid -flowchart LR - Dev[Developer] --> |Solidity
Source
Code| Solc - - subgraph "Compilation Process" - direction LR - Solc[solc] --> |YUL
IR| Revive - Revive[Revive Compiler] --> |LLVM
IR| LLVM - LLVM[LLVM
Optimizer] --> |RISC-V ELF
Shared Object| PVMLinker - end - - PVMLinker[PVM Linker] --> PVM[PVM Blob
with Metadata] -``` + --- + + Learn how REVM and PVM compare for compiling and deploying smart contracts. -The compilation process integrates several specialized components: + [:octicons-arrow-right-24: Reference](/smart-contracts/for-eth-devs/contract-deployment/) -1. **Solc**: The standard Ethereum Solidity compiler that translates Solidity source code to [YUL IR](https://docs.soliditylang.org/en/latest/yul.html){target=\_blank}. -2. **Revive Compiler**: Takes YUL IR and transforms it to [LLVM IR](https://llvm.org/){target=\_blank}. -3. **LLVM**: A compiler infrastructure that optimizes the code and generates RISC-V ELF objects. -4. **PVM linker**: Links the RISC-V ELF object into a final PolkaVM blob with metadata. +
diff --git a/.ai/site-index.json b/.ai/site-index.json index ca1ae0810..814768041 100644 --- a/.ai/site-index.json +++ b/.ai/site-index.json @@ -4883,7 +4883,7 @@ }, { "id": "parachains-customize-runtime-pallet-development-create-a-pallet", - "title": "Make a Custom Pallet", + "title": "Create a Custom Pallet", "slug": "parachains-customize-runtime-pallet-development-create-a-pallet", "categories": [ "Parachains" @@ -5024,12 +5024,12 @@ } ], "stats": { - "chars": 26806, - "words": 3069, + "chars": 26671, + "words": 3041, "headings": 26, - "estimated_token_count_total": 6172 + "estimated_token_count_total": 6113 }, - "hash": "sha256:0746676ba45f623d2c9cb71bf24162bc1dcf687f3f1ec74d02a19732d3bc7161", + "hash": "sha256:607e283aaa1295de0af191d97de7f6f87afb722c601a447821fde6a09b97f1af", "token_estimator": "heuristic-v1" }, { @@ -5055,8 +5055,8 @@ }, { "depth": 2, - "title": "Understanding Mock Runtimes", - "anchor": "understanding-mock-runtimes" + "title": "Understand Mock Runtimes", + "anchor": "understand-mock-runtimes" }, { "depth": 2, @@ -5065,13 +5065,13 @@ }, { "depth": 2, - "title": "Set Up Basic Mock Infrastructure", - "anchor": "set-up-basic-mock-infrastructure" + "title": "Set Up Basic Mock", + "anchor": "set-up-basic-mock" }, { "depth": 2, - "title": "Implement frame_system Configuration", - "anchor": "implement-frame_system-configuration" + "title": "Implement Essential Configuration", + "anchor": "implement-essential-configuration" }, { "depth": 2, @@ -5110,12 +5110,12 @@ } ], "stats": { - "chars": 11634, - "words": 1317, + "chars": 11766, + "words": 1369, "headings": 13, - "estimated_token_count_total": 2434 + "estimated_token_count_total": 2514 }, - "hash": "sha256:01fef3706d6e8e162d7faaf15599311a5cb104793b924379f55e0d3d9b827869", + "hash": "sha256:dd784a5d2daebb9a885fe09f6a967e6c84958d96ddb38d8366eabe9d860fa539", "token_estimator": "heuristic-v1" }, { @@ -11963,7 +11963,7 @@ }, { "id": "smart-contracts-for-eth-devs-dual-vm-stack", - "title": "PolkaVM Design", + "title": "Dual Virtual Machine Stack", "slug": "smart-contracts-for-eth-devs-dual-vm-stack", "categories": [ "Basics", @@ -11980,8 +11980,13 @@ }, { "depth": 2, - "title": "PolkaVM", - "anchor": "polkavm" + "title": "Migrate from EVM", + "anchor": "migrate-from-evm" + }, + { + "depth": 2, + "title": "Upgrade to PolkaVM", + "anchor": "upgrade-to-polkavm" }, { "depth": 2, @@ -11990,8 +11995,8 @@ }, { "depth": 3, - "title": "Pallet Revive", - "anchor": "pallet-revive" + "title": "Revive Pallet", + "anchor": "revive-pallet" }, { "depth": 3, @@ -12000,17 +12005,17 @@ }, { "depth": 2, - "title": "Compilation Process", - "anchor": "compilation-process" + "title": "Where To Go Next", + "anchor": "where-to-go-next" } ], "stats": { - "chars": 5334, - "words": 666, - "headings": 6, - "estimated_token_count_total": 994 + "chars": 5383, + "words": 702, + "headings": 7, + "estimated_token_count_total": 986 }, - "hash": "sha256:6992c9a2d1b315b64d9782880105cf2d436750249a84577aceb95cc213863009", + "hash": "sha256:2d918017faecf489ec786f34de6cd4366a86e9f1cecfbb7722cc03079e6b64ea", "token_estimator": "heuristic-v1" }, { diff --git a/llms-full.jsonl b/llms-full.jsonl index 543d3536b..1ff8f8c8f 100644 --- a/llms-full.jsonl +++ b/llms-full.jsonl @@ -571,45 +571,45 @@ {"page_id": "parachains-customize-runtime-pallet-development-benchmark-pallet", "page_title": "Benchmarking FRAME Pallets", "index": 6, "depth": 3, "title": "Add Benchmarks to Runtime", "anchor": "add-benchmarks-to-runtime", "start_char": 7718, "end_char": 9847, "estimated_token_count": 418, "token_estimator": "heuristic-v1", "text": "### Add Benchmarks to Runtime\n\nBefore running the benchmarking tool, you must integrate benchmarks with your runtime as follows:\n\n1. Navigate to your `runtime/src` directory and check if a `benchmarks.rs` file exists. If not, create one. This file will contain the macro that registers all pallets for benchmarking along with their respective configurations:\n\n ```rust title=\"benchmarks.rs\"\n frame_benchmarking::define_benchmarks!(\n [frame_system, SystemBench::]\n [pallet_parachain_template, TemplatePallet]\n [pallet_balances, Balances]\n [pallet_session, SessionBench::]\n [pallet_timestamp, Timestamp]\n [pallet_message_queue, MessageQueue]\n [pallet_sudo, Sudo]\n [pallet_collator_selection, CollatorSelection]\n [cumulus_pallet_parachain_system, ParachainSystem]\n [cumulus_pallet_xcmp_queue, XcmpQueue]\n );\n ```\n\n For example, to add a new pallet named `pallet_parachain_template` for benchmarking, include it in the macro as shown:\n ```rust title=\"benchmarks.rs\" hl_lines=\"3\"\n frame_benchmarking::define_benchmarks!(\n [frame_system, SystemBench::]\n [pallet_parachain_template, TemplatePallet]\n );\n ```\n\n !!!warning \"Updating `define_benchmarks!` macro is required\"\n Any pallet that needs to be benchmarked must be included in the [`define_benchmarks!`](https://paritytech.github.io/polkadot-sdk/master/frame_benchmarking/macro.define_benchmarks.html){target=\\_blank} macro. The CLI will only be able to access and benchmark pallets that are registered here.\n\n2. Check your runtime's `lib.rs` file to ensure the `benchmarks` module is imported. The import should look like this:\n\n ```rust title=\"lib.rs\"\n #[cfg(feature = \"runtime-benchmarks\")]\n mod benchmarks;\n ```\n\n The `runtime-benchmarks` feature gate ensures benchmark tests are isolated from production runtime code.\n\n3. Enable runtime benchmarking for your pallet in `runtime/Cargo.toml`:\n\n ```toml\n runtime-benchmarks = [\n # ...\n \"pallet_parachain_template/runtime-benchmarks\",\n ]\n\n ```"} {"page_id": "parachains-customize-runtime-pallet-development-benchmark-pallet", "page_title": "Benchmarking FRAME Pallets", "index": 7, "depth": 3, "title": "Run Benchmarks", "anchor": "run-benchmarks", "start_char": 9847, "end_char": 14232, "estimated_token_count": 1100, "token_estimator": "heuristic-v1", "text": "### Run Benchmarks\n\nYou can now compile your runtime with the `runtime-benchmarks` feature flag. This feature flag is crucial as the benchmarking tool will look for this feature being enabled to know when it should run benchmark tests. Follow these steps to compile the runtime with benchmarking enabled:\n\n1. Run `build` with the feature flag included:\n\n ```bash\n cargo build --features runtime-benchmarks --release\n ```\n\n2. Create a `weights.rs` file in your pallet's `src/` directory. This file will store the auto-generated weight calculations:\n\n ```bash\n touch weights.rs\n ```\n\n3. Before running the benchmarking tool, you'll need a template file that defines how weight information should be formatted. Download the official template from the Polkadot SDK repository and save it in your project folders for future use:\n\n ```bash\n curl https://raw.githubusercontent.com/paritytech/polkadot-sdk/refs/tags/polkadot-stable2412/substrate/.maintain/frame-weight-template.hbs \\\n --output ./pallets/benchmarking/frame-weight-template.hbs\n ```\n\n4. Run the benchmarking tool to measure extrinsic weights:\n\n ```bash\n frame-omni-bencher v1 benchmark pallet \\\n --runtime INSERT_PATH_TO_WASM_RUNTIME \\\n --pallet INSERT_NAME_OF_PALLET \\\n --extrinsic \"\" \\\n --template ./frame-weight-template.hbs \\\n --output weights.rs\n ```\n\n !!! tip \"Flag definitions\"\n - **`--runtime`**: The path to your runtime's Wasm.\n - **`--pallet`**: The name of the pallet you wish to benchmark. This pallet must be configured in your runtime and defined in `define_benchmarks`.\n - **`--extrinsic`**: Which extrinsic to test. Using `\"\"` implies all extrinsics will be benchmarked.\n - **`--template`**: Defines how weight information should be formatted.\n - **`--output`**: Where the output of the auto-generated weights will reside.\n\nThe generated `weights.rs` file contains weight annotations for your extrinsics, ready to be added to your pallet. The output should be similar to the following. Some output is omitted for brevity:\n\n
\n frame-omni-bencher v1 benchmark pallet \\\n --runtime INSERT_PATH_TO_WASM_RUNTIME \\\n --pallet \"INSERT_NAME_OF_PALLET\" \\\n --extrinsic \"\" \\\n --template ./frame-weight-template.hbs \\\n --output ./weights.rs\n ...\n 2025-01-15T16:41:33.557045Z INFO polkadot_sdk_frame::benchmark::pallet: [ 0 % ] Starting benchmark: pallet_parachain_template::do_something\n 2025-01-15T16:41:33.564644Z INFO polkadot_sdk_frame::benchmark::pallet: [ 50 % ] Starting benchmark: pallet_parachain_template::cause_error\n ...\n Created file: \"weights.rs\"\n \n
\n\n#### Add Benchmark Weights to Pallet\n\nOnce the `weights.rs` is generated, you must integrate it with your pallet. \n\n1. To begin the integration, import the `weights` module and the `WeightInfo` trait, then add both to your pallet's `Config` trait. Complete the following steps to set up the configuration:\n\n ```rust title=\"lib.rs\"\n pub mod weights;\n use crate::weights::WeightInfo;\n\n /// Configure the pallet by specifying the parameters and types on which it depends.\n #[pallet::config]\n pub trait Config: frame_system::Config {\n // ...\n /// A type representing the weights required by the dispatchables of this pallet.\n type WeightInfo: WeightInfo;\n }\n ```\n\n2. Next, you must add this to the `#[pallet::weight]` annotation in all the extrinsics via the `Config` as follows:\n\n ```rust hl_lines=\"2\" title=\"lib.rs\"\n #[pallet::call_index(0)]\n #[pallet::weight(T::WeightInfo::do_something())]\n pub fn do_something(origin: OriginFor) -> DispatchResultWithPostInfo { Ok(()) }\n ```\n\n3. Finally, configure the actual weight values in your runtime. In `runtime/src/config/mod.rs`, add the following code:\n\n ```rust title=\"mod.rs\"\n // Configure pallet.\n impl pallet_parachain_template::Config for Runtime {\n // ...\n type WeightInfo = pallet_parachain_template::weights::SubstrateWeight;\n }\n ```"} {"page_id": "parachains-customize-runtime-pallet-development-benchmark-pallet", "page_title": "Benchmarking FRAME Pallets", "index": 8, "depth": 2, "title": "Where to Go Next", "anchor": "where-to-go-next", "start_char": 14232, "end_char": 14715, "estimated_token_count": 114, "token_estimator": "heuristic-v1", "text": "## Where to Go Next\n\n- View the Rust Docs for a more comprehensive, low-level view of the [FRAME V2 Benchmarking Suite](https://paritytech.github.io/polkadot-sdk/master/frame_benchmarking/v2/index.html){target=_blank}.\n- Read the [FRAME Benchmarking and Weights](https://paritytech.github.io/polkadot-sdk/master/polkadot_sdk_docs/reference_docs/frame_benchmarking_weight/index.html){target=_blank} reference document, a concise guide which details how weights and benchmarking work."} -{"page_id": "parachains-customize-runtime-pallet-development-create-a-pallet", "page_title": "Make a Custom Pallet", "index": 0, "depth": 2, "title": "Introduction", "anchor": "introduction", "start_char": 24, "end_char": 1130, "estimated_token_count": 216, "token_estimator": "heuristic-v1", "text": "## Introduction\n\n[Framework for Runtime Aggregation of Modular Entities (FRAME)](https://paritytech.github.io/polkadot-sdk/master/polkadot_sdk_docs/polkadot_sdk/frame_runtime/index.html){target=\\_blank} provides a powerful set of tools for blockchain development through modular components called [pallets](https://paritytech.github.io/polkadot-sdk/master/polkadot_sdk_docs/polkadot_sdk/frame_runtime/pallet/index.html){target=\\_blank}. These Rust-based runtime modules allow you to build custom blockchain functionality with precision and flexibility. While FRAME includes a library of pre-built pallets, its true strength lies in the ability to create custom pallets tailored to your specific needs.\n\nIn this guide, you'll learn how to build a custom counter pallet from scratch that demonstrates core pallet development concepts. The pallet you'll create includes:\n\n- User-triggered increment and decrement operations\n- Root-only counter value setting\n- Event emission for state changes\n- Custom error handling\n- Storage management\n- User interaction tracking\n- Genesis configuration for initial state"} -{"page_id": "parachains-customize-runtime-pallet-development-create-a-pallet", "page_title": "Make a Custom Pallet", "index": 1, "depth": 2, "title": "Prerequisites", "anchor": "prerequisites", "start_char": 1130, "end_char": 1497, "estimated_token_count": 96, "token_estimator": "heuristic-v1", "text": "## Prerequisites\n\nBefore you begin, ensure you have:\n\n- [Polkadot SDK dependencies installed](/parachains/install-polkadot-sdk/){target=\\_blank}\n- A [Polkadot SDK Parchain Template](/parachains/launch-a-parachain/set-up-the-parachain-template/){target=\\_blank} set up locally\n- Basic familiarity with [FRAME concepts](/parachains/customize-runtime/){target=\\_blank}"} -{"page_id": "parachains-customize-runtime-pallet-development-create-a-pallet", "page_title": "Make a Custom Pallet", "index": 2, "depth": 2, "title": "Core Pallet Components", "anchor": "core-pallet-components", "start_char": 1497, "end_char": 2372, "estimated_token_count": 193, "token_estimator": "heuristic-v1", "text": "## Core Pallet Components\n\nAs you build your custom pallet, you'll work with these key sections:\n\n- **Imports and dependencies**: Bring in necessary FRAME libraries and external modules.\n- **Runtime configuration trait**: Specify types and constants for pallet-runtime interaction.\n- **Runtime events**: Define signals that communicate state changes.\n- **Runtime errors**: Define error types returned from dispatchable calls.\n- **Runtime storage**: Declare on-chain storage items for your pallet's state.\n- **Genesis configuration**: Set initial blockchain state.\n- **Dispatchable functions (extrinsics)**: Create callable functions for user interactions.\n\nFor additional macros beyond those covered here, refer to the [pallet_macros](https://paritytech.github.io/polkadot-sdk/master/frame_support/pallet_macros/index.html){target=\\_blank} section of the Polkadot SDK Docs."} -{"page_id": "parachains-customize-runtime-pallet-development-create-a-pallet", "page_title": "Make a Custom Pallet", "index": 3, "depth": 2, "title": "Create the Pallet Project", "anchor": "create-the-pallet-project", "start_char": 2372, "end_char": 3111, "estimated_token_count": 180, "token_estimator": "heuristic-v1", "text": "## Create the Pallet Project\n\nBegin by creating a new Rust library project for your custom pallet within the [Polkadot SDK Parachain Template](https://github.com/paritytech/polkadot-sdk-parachain-template){target=\\_blank}:\n\n1. Navigate to the root directory of your parachain template:\n\n ```bash\n cd polkadot-sdk-parachain-template\n ```\n\n2. Navigate to the `pallets` directory:\n\n ```bash\n cd pallets\n ```\n\n3. Create a new Rust library project:\n\n ```bash\n cargo new --lib pallet-custom\n ```\n\n4. Enter the new project directory:\n\n ```bash\n cd pallet-custom\n ```\n\n5. Verify the project structure. It should look like:\n\n ```\n pallet-custom/\n ├── Cargo.toml\n └── src/\n └── lib.rs\n ```"} -{"page_id": "parachains-customize-runtime-pallet-development-create-a-pallet", "page_title": "Make a Custom Pallet", "index": 4, "depth": 2, "title": "Configure Dependencies", "anchor": "configure-dependencies", "start_char": 3111, "end_char": 4892, "estimated_token_count": 386, "token_estimator": "heuristic-v1", "text": "## Configure Dependencies\n\nTo integrate your custom pallet into the Polkadot SDK-based runtime, configure the `Cargo.toml` file with the required dependencies. Since your pallet exists within the parachain template workspace, you'll use workspace inheritance to maintain version consistency.\n\n1. Open `Cargo.toml` and replace its contents with:\n\n ```toml title=\"pallet-custom/Cargo.toml\"\n [package]\n name = \"pallet-custom\"\n description = \"A custom counter pallet for demonstration purposes.\"\n version = \"0.1.0\"\n license = \"Unlicense\"\n authors.workspace = true\n homepage.workspace = true\n repository.workspace = true\n edition.workspace = true\n publish = false\n\n [package.metadata.docs.rs]\n targets = [\"x86_64-unknown-linux-gnu\"]\n\n [dependencies]\n codec = { features = [\"derive\"], workspace = true }\n scale-info = { features = [\"derive\"], workspace = true }\n frame = { features = [\"experimental\", \"runtime\"], workspace = true }\n\n [features]\n default = [\"std\"]\n std = [\n \"codec/std\",\n \"scale-info/std\",\n \"frame/std\",\n ]\n ```\n\n !!!note \"Version Management\"\n The parachain template uses workspace inheritance to maintain consistent dependency versions across all packages. The actual versions are defined in the root `Cargo.toml` file, ensuring compatibility throughout the project. By using `workspace = true`, your pallet automatically inherits the correct versions.\n\n2. The parachain template already includes `pallets/*` in the workspace members, so your new pallet is automatically recognized. Verify this by checking the root `Cargo.toml`:\n\n ```toml title=\"Cargo.toml\"\n [workspace.members]\n members = [\n \"node\",\n \"pallets/*\",\n \"runtime\",\n ]\n ```"} -{"page_id": "parachains-customize-runtime-pallet-development-create-a-pallet", "page_title": "Make a Custom Pallet", "index": 5, "depth": 2, "title": "Initialize the Pallet Structure", "anchor": "initialize-the-pallet-structure", "start_char": 4892, "end_char": 6071, "estimated_token_count": 269, "token_estimator": "heuristic-v1", "text": "## Initialize the Pallet Structure\n\nWith dependencies configured, set up the basic scaffold that will hold your pallet's logic:\n\n1. Open `src/lib.rs` and delete all existing content.\n\n2. Add the initial scaffold structure using the unified `frame` dependency:\n\n ```rust title=\"src/lib.rs\"\n #![cfg_attr(not(feature = \"std\"), no_std)]\n\n pub use pallet::*;\n\n #[frame::pallet]\n pub mod pallet {\n use frame::prelude::*;\n\n #[pallet::pallet]\n pub struct Pallet(_);\n\n #[pallet::config]\n pub trait Config: frame_system::Config {\n // Configuration will be added here\n }\n\n #[pallet::storage]\n pub type CounterValue = StorageValue<_, u32, ValueQuery>;\n\n #[pallet::call]\n impl Pallet {\n // Dispatchable functions will be added here\n }\n }\n ```\n\n !!!note\n This setup starts with a minimal scaffold without events and errors. These will be added in the following sections after the `Config` trait is properly configured with the required `RuntimeEvent` type.\n\n3. Verify it compiles:\n\n ```bash\n cargo build --package pallet-custom\n ```"} -{"page_id": "parachains-customize-runtime-pallet-development-create-a-pallet", "page_title": "Make a Custom Pallet", "index": 6, "depth": 2, "title": "Configure the Pallet", "anchor": "configure-the-pallet", "start_char": 6071, "end_char": 7327, "estimated_token_count": 320, "token_estimator": "heuristic-v1", "text": "## Configure the Pallet\n\nThe [`Config`](https://paritytech.github.io/polkadot-sdk/master/frame_system/pallet/trait.Config.html){target=\\_blank} trait exposes configurable options and links your pallet to the runtime. All types and constants the pallet depends on must be declared here. These types are defined generically and become concrete when the pallet is instantiated at runtime.\n\nReplace the [`#[pallet::config]`](https://paritytech.github.io/polkadot-sdk/master/frame_support/pallet_macros/attr.config.html){target=\\_blank} section with:\n\n```rust title=\"src/lib.rs\"\n#[pallet::config]\npub trait Config: frame_system::Config {\n /// The overarching runtime event type.\n type RuntimeEvent: From> + IsType<::RuntimeEvent>;\n \n /// Maximum value the counter can reach.\n #[pallet::constant]\n type CounterMaxValue: Get;\n}\n```\n\n**Key configuration elements:**\n\n- **[`RuntimeEvent`](https://paritytech.github.io/polkadot-sdk/master/frame_system/pallet/trait.Config.html#associatedtype.RuntimeEvent){target=\\_blank}**: Required for the pallet to emit events that the runtime can process.\n- **`CounterMaxValue`**: A constant that sets an upper limit on counter values, configurable per runtime."} -{"page_id": "parachains-customize-runtime-pallet-development-create-a-pallet", "page_title": "Make a Custom Pallet", "index": 7, "depth": 2, "title": "Define Events", "anchor": "define-events", "start_char": 7327, "end_char": 8742, "estimated_token_count": 344, "token_estimator": "heuristic-v1", "text": "## Define Events\n\nEvents inform external entities (dApps, explorers, users) about significant runtime changes. Event details are included in the node's metadata, making them accessible to external tools.\n\nThe [`#[pallet::generate_deposit]`](https://paritytech.github.io/polkadot-sdk/master/frame_support/pallet_macros/attr.generate_deposit.html){target=\\_blank} macro automatically generates a `deposit_event` function that converts your pallet's events into the `RuntimeEvent` type and deposits them via [`frame_system::Pallet::deposit_event`](https://paritytech.github.io/polkadot-sdk/master/frame_system/pallet/struct.Pallet.html#method.deposit_event){target=\\_blank}.\n\nAdd the [`#[pallet::event]`](https://paritytech.github.io/polkadot-sdk/master/frame_support/pallet_macros/attr.event.html){target=\\_blank} section after the `Config` trait:\n\n```rust title=\"src/lib.rs\"\n#[pallet::event]\n#[pallet::generate_deposit(pub(super) fn deposit_event)]\npub enum Event {\n /// Counter value was explicitly set. [new_value]\n CounterValueSet { \n new_value: u32 \n },\n /// Counter was incremented. [new_value, who, amount]\n CounterIncremented {\n new_value: u32,\n who: T::AccountId,\n amount: u32,\n },\n /// Counter was decremented. [new_value, who, amount]\n CounterDecremented {\n new_value: u32,\n who: T::AccountId,\n amount: u32,\n },\n}\n```"} -{"page_id": "parachains-customize-runtime-pallet-development-create-a-pallet", "page_title": "Make a Custom Pallet", "index": 8, "depth": 2, "title": "Define Errors", "anchor": "define-errors", "start_char": 8742, "end_char": 9646, "estimated_token_count": 221, "token_estimator": "heuristic-v1", "text": "## Define Errors\n\nErrors indicate when and why a call fails. Use informative names and descriptions, as error documentation is included in the node's metadata.\n\nError types must implement the [`TypeInfo`](https://paritytech.github.io/polkadot-sdk/master/frame_support/pallet_prelude/trait.TypeInfo.html){target=\\_blank} trait, and runtime errors can be up to 4 bytes in size.\n\nAdd the [`#[pallet::error]`](https://paritytech.github.io/polkadot-sdk/master/frame_support/pallet_macros/attr.error.html){target=\\_blank} section after the events:\n\n```rust title=\"src/lib.rs\"\n#[pallet::error]\npub enum Error {\n /// The counter value has not been set yet.\n NoneValue,\n /// Arithmetic operation would cause overflow.\n Overflow,\n /// Arithmetic operation would cause underflow.\n Underflow,\n /// The counter value would exceed the maximum allowed value.\n CounterMaxValueExceeded,\n}\n```"} -{"page_id": "parachains-customize-runtime-pallet-development-create-a-pallet", "page_title": "Make a Custom Pallet", "index": 9, "depth": 2, "title": "Add Storage Items", "anchor": "add-storage-items", "start_char": 9646, "end_char": 10760, "estimated_token_count": 283, "token_estimator": "heuristic-v1", "text": "## Add Storage Items\n\nStorage items persist state on-chain. This pallet uses two storage items:\n\n- **`CounterValue`**: Stores the current counter value.\n- **`UserInteractions`**: Tracks interaction counts per user account.\n\nThe initial scaffold already includes the `CounterValue` storage item. Now add the `UserInteractions` storage map after it:\n\n```rust title=\"src/lib.rs\"\n/// Tracks the number of interactions per user.\n#[pallet::storage]\npub type UserInteractions = StorageMap<_, Blake2_128Concat, T::AccountId, u32, ValueQuery>;\n```\n\nYour storage section should now look like this:\n\n```rust title=\"src/lib.rs\"\n/// The current value of the counter.\n#[pallet::storage]\npub type CounterValue = StorageValue<_, u32, ValueQuery>;\n\n/// Tracks the number of interactions per user.\n#[pallet::storage]\npub type UserInteractions = StorageMap<_, Blake2_128Concat, T::AccountId, u32, ValueQuery>;\n```\n\nFor more storage types and patterns, explore the [Polkadot SDK storage documentation](https://paritytech.github.io/polkadot-sdk/master/frame_support/storage/types/index.html){target=\\_blank}."} -{"page_id": "parachains-customize-runtime-pallet-development-create-a-pallet", "page_title": "Make a Custom Pallet", "index": 10, "depth": 2, "title": "Configure Genesis State", "anchor": "configure-genesis-state", "start_char": 10760, "end_char": 12586, "estimated_token_count": 419, "token_estimator": "heuristic-v1", "text": "## Configure Genesis State\n\nGenesis configuration allows you to set the initial state of your pallet when the blockchain first starts. This is essential for both production networks and testing environments. It is particularly useful for:\n\n- Setting initial parameter values.\n- Pre-allocating resources or accounts.\n- Establishing starting conditions for testing.\n- Configuring network-specific initial state.\n\nAdd the [`#[pallet::genesis_config]`](https://paritytech.github.io/polkadot-sdk/master/frame_support/pallet_macros/attr.genesis_config.html){target=\\_blank} and [`#[pallet::genesis_build]`](https://paritytech.github.io/polkadot-sdk/master/frame_support/pallet_macros/attr.genesis_build.html){target=\\_blank} sections after your storage items:\n\n```rust title=\"src/lib.rs\"\n#[pallet::genesis_config]\n#[derive(DefaultNoBound)]\npub struct GenesisConfig {\n /// Initial value for the counter\n pub initial_counter_value: u32,\n /// Pre-populated user interactions\n pub initial_user_interactions: Vec<(T::AccountId, u32)>,\n}\n\n#[pallet::genesis_build]\nimpl BuildGenesisConfig for GenesisConfig {\n fn build(&self) {\n // Set the initial counter value\n CounterValue::::put(self.initial_counter_value);\n \n // Set initial user interactions\n for (account, count) in &self.initial_user_interactions {\n UserInteractions::::insert(account, count);\n }\n }\n}\n```\n\n**Genesis configuration components:**\n\n- **`GenesisConfig` struct**: Defines what can be configured at genesis.\n- **`#[derive(DefaultNoBound)]`**: Provides sensible defaults (empty vec and 0 for the counter).\n- **`BuildGenesisConfig` implementation**: Executes the logic to set initial storage values.\n- **`build()` method**: Called once when the blockchain initializes."} -{"page_id": "parachains-customize-runtime-pallet-development-create-a-pallet", "page_title": "Make a Custom Pallet", "index": 11, "depth": 2, "title": "Implement Dispatchable Functions", "anchor": "implement-dispatchable-functions", "start_char": 12586, "end_char": 15998, "estimated_token_count": 753, "token_estimator": "heuristic-v1", "text": "## Implement Dispatchable Functions\n\nDispatchable functions (extrinsics) allow users to interact with your pallet and trigger state changes. Each function must:\n\n- Return a [`DispatchResult`](https://paritytech.github.io/polkadot-sdk/master/frame_support/dispatch/type.DispatchResult.html){target=\\_blank}.\n- Be annotated with a weight (computational cost).\n- Have an explicit call index for backward compatibility.\n\nReplace the [`#[pallet::call]`](https://paritytech.github.io/polkadot-sdk/master/frame_support/pallet_macros/attr.call.html){target=\\_blank} section with:\n\n```rust title=\"src/lib.rs\"\n#[pallet::call]\nimpl Pallet {\n /// Set the counter to a specific value. Root origin only.\n #[pallet::call_index(0)]\n #[pallet::weight(0)]\n pub fn set_counter_value(origin: OriginFor, new_value: u32) -> DispatchResult {\n // Ensure the caller is root\n ensure_root(origin)?;\n \n // Validate the new value doesn't exceed the maximum\n ensure!(\n new_value <= T::CounterMaxValue::get(),\n Error::::CounterMaxValueExceeded\n );\n \n // Update storage\n CounterValue::::put(new_value);\n \n // Emit event\n Self::deposit_event(Event::CounterValueSet { new_value });\n \n Ok(())\n }\n\n /// Increment the counter by a specified amount.\n #[pallet::call_index(1)]\n #[pallet::weight(0)]\n pub fn increment(origin: OriginFor, amount: u32) -> DispatchResult {\n // Ensure the caller is signed\n let who = ensure_signed(origin)?;\n \n // Get current counter value\n let current_value = CounterValue::::get();\n \n // Check for overflow\n let new_value = current_value\n .checked_add(amount)\n .ok_or(Error::::Overflow)?;\n \n // Ensure new value doesn't exceed maximum\n ensure!(\n new_value <= T::CounterMaxValue::get(),\n Error::::CounterMaxValueExceeded\n );\n \n // Update counter storage\n CounterValue::::put(new_value);\n \n // Track user interaction\n UserInteractions::::mutate(&who, |count| {\n *count = count.saturating_add(1);\n });\n \n // Emit event\n Self::deposit_event(Event::CounterIncremented {\n new_value,\n who,\n amount,\n });\n \n Ok(())\n }\n\n /// Decrement the counter by a specified amount.\n #[pallet::call_index(2)]\n #[pallet::weight(0)]\n pub fn decrement(origin: OriginFor, amount: u32) -> DispatchResult {\n // Ensure the caller is signed\n let who = ensure_signed(origin)?;\n \n // Get current counter value\n let current_value = CounterValue::::get();\n \n // Check for underflow\n let new_value = current_value\n .checked_sub(amount)\n .ok_or(Error::::Underflow)?;\n \n // Update counter storage\n CounterValue::::put(new_value);\n \n // Track user interaction\n UserInteractions::::mutate(&who, |count| {\n *count = count.saturating_add(1);\n });\n \n // Emit event\n Self::deposit_event(Event::CounterDecremented {\n new_value,\n who,\n amount,\n });\n \n Ok(())\n }\n}\n```"} -{"page_id": "parachains-customize-runtime-pallet-development-create-a-pallet", "page_title": "Make a Custom Pallet", "index": 12, "depth": 3, "title": "Dispatchable Function Details", "anchor": "dispatchable-function-details", "start_char": 15998, "end_char": 16937, "estimated_token_count": 222, "token_estimator": "heuristic-v1", "text": "### Dispatchable Function Details\n\n???+ interface \"`set_counter_value`\"\n\n - **Access**: Root origin only (privileged operations)\n - **Purpose**: Set counter to a specific value\n - **Validations**: New value must not exceed `CounterMaxValue`\n - **State changes**: Updates `CounterValue` storage\n - **Events**: Emits `CounterValueSet`\n\n??? interface \"`increment`\"\n\n - **Access**: Any signed account\n - **Purpose**: Increase counter by specified amount\n - **Validations**: Checks for overflow and max value compliance\n - **State changes**: Updates `CounterValue` and `UserInteractions`\n - **Events**: Emits `CounterIncremented`\n\n??? interface \"`decrement`\"\n\n - **Access**: Any signed account\n - **Purpose**: Decrease counter by specified amount\n - **Validations**: Checks for underflow\n - **State changes**: Updates `CounterValue` and `UserInteractions`\n - **Events**: Emits `CounterDecremented`"} -{"page_id": "parachains-customize-runtime-pallet-development-create-a-pallet", "page_title": "Make a Custom Pallet", "index": 13, "depth": 2, "title": "Verify Pallet Compilation", "anchor": "verify-pallet-compilation", "start_char": 16937, "end_char": 21105, "estimated_token_count": 924, "token_estimator": "heuristic-v1", "text": "## Verify Pallet Compilation\n\nBefore proceeding, ensure your pallet compiles without errors:\n\n```bash\ncargo build --package pallet-custom\n```\n\nIf you encounter errors, carefully review the code against this guide. Once the build completes successfully, your custom pallet is ready for integration.\n\n??? code \"Complete Pallet Implementation\"\n \n ```rust title=\"src/lib.rs\"\n #![cfg_attr(not(feature = \"std\"), no_std)]\n\n pub use pallet::*;\n\n #[frame::pallet]\n pub mod pallet {\n use frame::prelude::*;\n\n #[pallet::pallet]\n pub struct Pallet(_);\n\n #[pallet::config]\n pub trait Config: frame_system::Config {\n type RuntimeEvent: From> + IsType<::RuntimeEvent>;\n \n #[pallet::constant]\n type CounterMaxValue: Get;\n }\n\n #[pallet::event]\n #[pallet::generate_deposit(pub(super) fn deposit_event)]\n pub enum Event {\n CounterValueSet { new_value: u32 },\n CounterIncremented { new_value: u32, who: T::AccountId, amount: u32 },\n CounterDecremented { new_value: u32, who: T::AccountId, amount: u32 },\n }\n\n #[pallet::error]\n pub enum Error {\n NoneValue,\n Overflow,\n Underflow,\n CounterMaxValueExceeded,\n }\n\n #[pallet::storage]\n pub type CounterValue = StorageValue<_, u32, ValueQuery>;\n\n #[pallet::storage]\n pub type UserInteractions = StorageMap<_, Blake2_128Concat, T::AccountId, u32, ValueQuery>;\n\n #[pallet::genesis_config]\n #[derive(DefaultNoBound)]\n pub struct GenesisConfig {\n pub initial_counter_value: u32,\n pub initial_user_interactions: Vec<(T::AccountId, u32)>,\n }\n\n #[pallet::genesis_build]\n impl BuildGenesisConfig for GenesisConfig {\n fn build(&self) {\n CounterValue::::put(self.initial_counter_value);\n for (account, count) in &self.initial_user_interactions {\n UserInteractions::::insert(account, count);\n }\n }\n }\n\n #[pallet::call]\n impl Pallet {\n #[pallet::call_index(0)]\n #[pallet::weight(0)]\n pub fn set_counter_value(origin: OriginFor, new_value: u32) -> DispatchResult {\n ensure_root(origin)?;\n ensure!(new_value <= T::CounterMaxValue::get(), Error::::CounterMaxValueExceeded);\n CounterValue::::put(new_value);\n Self::deposit_event(Event::CounterValueSet { new_value });\n Ok(())\n }\n\n #[pallet::call_index(1)]\n #[pallet::weight(0)]\n pub fn increment(origin: OriginFor, amount: u32) -> DispatchResult {\n let who = ensure_signed(origin)?;\n let current_value = CounterValue::::get();\n let new_value = current_value.checked_add(amount).ok_or(Error::::Overflow)?;\n ensure!(new_value <= T::CounterMaxValue::get(), Error::::CounterMaxValueExceeded);\n CounterValue::::put(new_value);\n UserInteractions::::mutate(&who, |count| *count = count.saturating_add(1));\n Self::deposit_event(Event::CounterIncremented { new_value, who, amount });\n Ok(())\n }\n\n #[pallet::call_index(2)]\n #[pallet::weight(0)]\n pub fn decrement(origin: OriginFor, amount: u32) -> DispatchResult {\n let who = ensure_signed(origin)?;\n let current_value = CounterValue::::get();\n let new_value = current_value.checked_sub(amount).ok_or(Error::::Underflow)?;\n CounterValue::::put(new_value);\n UserInteractions::::mutate(&who, |count| *count = count.saturating_add(1));\n Self::deposit_event(Event::CounterDecremented { new_value, who, amount });\n Ok(())\n }\n }\n }\n ```"} -{"page_id": "parachains-customize-runtime-pallet-development-create-a-pallet", "page_title": "Make a Custom Pallet", "index": 14, "depth": 2, "title": "Add the Pallet to Your Runtime", "anchor": "add-the-pallet-to-your-runtime", "start_char": 21105, "end_char": 21223, "estimated_token_count": 23, "token_estimator": "heuristic-v1", "text": "## Add the Pallet to Your Runtime\n\nNow that your custom pallet is complete, integrate it into the parachain runtime."} -{"page_id": "parachains-customize-runtime-pallet-development-create-a-pallet", "page_title": "Make a Custom Pallet", "index": 15, "depth": 3, "title": "Add Runtime Dependency", "anchor": "add-runtime-dependency", "start_char": 21223, "end_char": 21803, "estimated_token_count": 153, "token_estimator": "heuristic-v1", "text": "### Add Runtime Dependency\n\n1. In the `runtime/Cargo.toml`, add your custom pallet to the `[dependencies]` section:\n\n ```toml title=\"runtime/Cargo.toml\"\n [dependencies]\n # Local dependencies\n pallet-custom = { path = \"../pallets/pallet-custom\", default-features = false }\n \n # ... other dependencies\n ```\n\n2. Enable the `std` feature by adding it to the `[features]` section:\n\n ```toml title=\"runtime/Cargo.toml\"\n [features]\n default = [\"std\"]\n std = [\n \"codec/std\",\n \"pallet-custom/std\",\n # ... other features\n ]\n ```"} -{"page_id": "parachains-customize-runtime-pallet-development-create-a-pallet", "page_title": "Make a Custom Pallet", "index": 16, "depth": 3, "title": "Implement the Config Trait", "anchor": "implement-the-config-trait", "start_char": 21803, "end_char": 22372, "estimated_token_count": 143, "token_estimator": "heuristic-v1", "text": "### Implement the Config Trait\n\nAt the end of the `runtime/src/configs/mod.rs` file, add the implementation: \n\n```rust title=\"runtime/src/configs/mod.rs\"\n/// Configure the custom counter pallet\nimpl pallet_custom::Config for Runtime {\n type RuntimeEvent = RuntimeEvent;\n type CounterMaxValue = ConstU32<1000>;\n}\n```\n\nThis configuration:\n\n- Links the pallet's events to the runtime's event system\n- Sets a maximum counter value of 1000 using [`ConstU32`](https://paritytech.github.io/polkadot-sdk/master/frame_support/traits/struct.ConstU32.html){target=\\_blank}"} -{"page_id": "parachains-customize-runtime-pallet-development-create-a-pallet", "page_title": "Make a Custom Pallet", "index": 17, "depth": 3, "title": "Add to Runtime Construct", "anchor": "add-to-runtime-construct", "start_char": 22372, "end_char": 23374, "estimated_token_count": 214, "token_estimator": "heuristic-v1", "text": "### Add to Runtime Construct\n\nIn the `runtime/src/lib.rs` file, locate the [`#[frame_support::runtime]`](https://paritytech.github.io/polkadot-sdk/master/frame_support/attr.runtime.html){target=\\_blank} section and add your pallet with a unique `pallet_index`:\n\n```rust title=\"runtime/src/lib.rs\"\n#[frame_support::runtime]\nmod runtime {\n #[runtime::runtime]\n #[runtime::derive(\n RuntimeCall,\n RuntimeEvent,\n RuntimeError,\n RuntimeOrigin,\n RuntimeTask,\n RuntimeFreezeReason,\n RuntimeHoldReason,\n RuntimeSlashReason,\n RuntimeLockId,\n RuntimeViewFunction\n )]\n pub struct Runtime;\n\n #[runtime::pallet_index(0)]\n pub type System = frame_system;\n\n // ... other pallets\n\n #[runtime::pallet_index(51)]\n pub type CustomPallet = pallet_custom;\n}\n```\n\n!!!warning\n Each pallet must have a unique index. Duplicate indices will cause compilation errors. Choose an index that doesn't conflict with existing pallets."} -{"page_id": "parachains-customize-runtime-pallet-development-create-a-pallet", "page_title": "Make a Custom Pallet", "index": 18, "depth": 3, "title": "Configure Genesis for Your Runtime", "anchor": "configure-genesis-for-your-runtime", "start_char": 23374, "end_char": 23855, "estimated_token_count": 99, "token_estimator": "heuristic-v1", "text": "### Configure Genesis for Your Runtime\n\nTo set initial values for your pallet when the chain starts, you'll need to configure the genesis in your chain specification. This is typically done in the `node/src/chain_spec.rs` file or when generating the chain specification.\n\nFor development and testing, you can use the default values provided by the `#[derive(DefaultNoBound)]` macro. For production networks, you'll want to set these values in your chain specification explicitly."} -{"page_id": "parachains-customize-runtime-pallet-development-create-a-pallet", "page_title": "Make a Custom Pallet", "index": 19, "depth": 3, "title": "Verify Runtime Compilation", "anchor": "verify-runtime-compilation", "start_char": 23855, "end_char": 24078, "estimated_token_count": 41, "token_estimator": "heuristic-v1", "text": "### Verify Runtime Compilation\n\nCompile the runtime to ensure everything is configured correctly:\n\n```bash\ncargo build --release\n```\n\nThis command validates all pallet configurations and prepares the build for deployment."} -{"page_id": "parachains-customize-runtime-pallet-development-create-a-pallet", "page_title": "Make a Custom Pallet", "index": 20, "depth": 2, "title": "Run Your Chain Locally", "anchor": "run-your-chain-locally", "start_char": 24078, "end_char": 24266, "estimated_token_count": 47, "token_estimator": "heuristic-v1", "text": "## Run Your Chain Locally\n\nLaunch your parachain locally to test the new pallet functionality using the [Polkadot Omni Node](https://crates.io/crates/polkadot-omni-node){target=\\_blank}."} -{"page_id": "parachains-customize-runtime-pallet-development-create-a-pallet", "page_title": "Make a Custom Pallet", "index": 21, "depth": 3, "title": "Generate a Chain Specification", "anchor": "generate-a-chain-specification", "start_char": 24266, "end_char": 24675, "estimated_token_count": 92, "token_estimator": "heuristic-v1", "text": "### Generate a Chain Specification\n\nCreate a chain specification file with the updated runtime:\n\n```bash\nchain-spec-builder create -t development \\\n--relay-chain paseo \\\n--para-id 1000 \\\n--runtime ./target/release/wbuild/parachain-template-runtime/parachain_template_runtime.compact.compressed.wasm \\\nnamed-preset development\n```\n\nThis command generates a `chain_spec.json` that includes your custom pallet."} -{"page_id": "parachains-customize-runtime-pallet-development-create-a-pallet", "page_title": "Make a Custom Pallet", "index": 22, "depth": 3, "title": "Start the Parachain Node", "anchor": "start-the-parachain-node", "start_char": 24675, "end_char": 24858, "estimated_token_count": 44, "token_estimator": "heuristic-v1", "text": "### Start the Parachain Node\n\nLaunch the parachain:\n\n```bash\npolkadot-omni-node --chain ./chain_spec.json --dev\n```\n\nVerify the node starts successfully and begins producing blocks."} -{"page_id": "parachains-customize-runtime-pallet-development-create-a-pallet", "page_title": "Make a Custom Pallet", "index": 23, "depth": 2, "title": "Interact with Your Pallet", "anchor": "interact-with-your-pallet", "start_char": 24858, "end_char": 25630, "estimated_token_count": 234, "token_estimator": "heuristic-v1", "text": "## Interact with Your Pallet\n\nUse the Polkadot.js Apps interface to test your pallet:\n\n1. Navigate to [Polkadot.js Apps](https://polkadot.js.org/apps/?rpc=ws%3A%2F%2F127.0.0.1%3A9944#/extrinsics){target=\\_blank}.\n\n2. Ensure you're connected to your local node at `ws://127.0.0.1:9944`.\n\n3. Go to **Developer** > **Extrinsics**.\n\n4. Locate **customPallet** in the pallet dropdown.\n\n5. You should see the available extrinsics:\n\n - **`increment(amount)`**: Increase the counter by a specified amount.\n - **`decrement(amount)`**: Decrease the counter by a specified amount.\n - **`setCounterValue(newValue)`**: Set counter to a specific value (requires sudo/root).\n\n![](/images/parachains/customize-runtime/pallet-development/create-a-pallet/create-a-pallet-01.webp)"} -{"page_id": "parachains-customize-runtime-pallet-development-create-a-pallet", "page_title": "Make a Custom Pallet", "index": 24, "depth": 2, "title": "Key Takeaways", "anchor": "key-takeaways", "start_char": 25630, "end_char": 26457, "estimated_token_count": 170, "token_estimator": "heuristic-v1", "text": "## Key Takeaways\n\nYou've successfully created and integrated a custom pallet into a Polkadot SDK-based runtime. You learned:\n\n- **Configuration**: Defined runtime-specific types and constants via the `Config` trait.\n- **Storage**: Implemented on-chain state using `StorageValue` and `StorageMap`.\n- **Events**: Created signals to communicate state changes to external systems.\n- **Errors**: Established clear error handling with descriptive error types.\n- **Genesis**: Configured initial blockchain state for both production and testing.\n- **Dispatchables**: Built callable functions with proper validation and access control.\n- **Integration**: Successfully added the pallet to a runtime and tested it locally.\n\nThese components form the foundation for developing sophisticated blockchain logic in Polkadot SDK-based chains."} -{"page_id": "parachains-customize-runtime-pallet-development-create-a-pallet", "page_title": "Make a Custom Pallet", "index": 25, "depth": 2, "title": "Where to Go Next", "anchor": "where-to-go-next", "start_char": 26457, "end_char": 26806, "estimated_token_count": 86, "token_estimator": "heuristic-v1", "text": "## Where to Go Next\n\n
\n\n- Guide __Mock Your Runtime__\n\n ---\n\n Learn to create a mock runtime environment for testing your pallet in isolation before integration.\n\n [:octicons-arrow-right-24: Continue](/parachains/customize-runtime/pallet-development/mock-runtime/)\n\n
"} -{"page_id": "parachains-customize-runtime-pallet-development-mock-runtime", "page_title": "Mock Your Runtime", "index": 0, "depth": 2, "title": "Introduction", "anchor": "introduction", "start_char": 21, "end_char": 784, "estimated_token_count": 146, "token_estimator": "heuristic-v1", "text": "## Introduction\n\nTesting is a critical part of pallet development. Before integrating your pallet into a full runtime, you need a way to test its functionality in isolation. A mock runtime provides a minimal, simulated blockchain environment where you can verify your pallet's logic without the overhead of running a full node.\n\nIn this guide, you'll learn how to create a mock runtime for the custom counter pallet built in the [Make a Custom Pallet](/parachains/customize-runtime/pallet-development/create-a-pallet/) guide. This mock runtime will enable you to write comprehensive unit tests that verify:\n\n- Dispatchable function behavior\n- Storage state changes\n- Event emission\n- Error handling\n- Access control and origin validation\n- Genesis configuration"} -{"page_id": "parachains-customize-runtime-pallet-development-mock-runtime", "page_title": "Mock Your Runtime", "index": 1, "depth": 2, "title": "Prerequisites", "anchor": "prerequisites", "start_char": 784, "end_char": 1141, "estimated_token_count": 94, "token_estimator": "heuristic-v1", "text": "## Prerequisites\n\nBefore you begin, ensure you have:\n\n- Completed the [Make a Custom Pallet](/parachains/customize-runtime/pallet-development/create-a-pallet/) guide\n- The custom counter pallet from that guide available in `pallets/pallet-custom`\n- Basic understanding of [Rust testing](https://doc.rust-lang.org/book/ch11-00-testing.html){target=\\_blank}"} -{"page_id": "parachains-customize-runtime-pallet-development-mock-runtime", "page_title": "Mock Your Runtime", "index": 2, "depth": 2, "title": "Understanding Mock Runtimes", "anchor": "understanding-mock-runtimes", "start_char": 1141, "end_char": 1733, "estimated_token_count": 111, "token_estimator": "heuristic-v1", "text": "## Understanding Mock Runtimes\n\nA mock runtime is a minimal implementation of the runtime environment that:\n\n- **Simulates blockchain state** - Provides storage and state management\n- **Implements required traits** - Satisfies your pallet's `Config` trait requirements\n- **Enables isolated testing** - Allows testing without external dependencies\n- **Supports genesis configuration** - Sets initial blockchain state for tests\n- **Speeds up development** - Provides instant feedback on code changes\n\nMock runtimes are used exclusively for testing and are never deployed to a live blockchain."} -{"page_id": "parachains-customize-runtime-pallet-development-mock-runtime", "page_title": "Mock Your Runtime", "index": 3, "depth": 2, "title": "Create the Mock Runtime Module", "anchor": "create-the-mock-runtime-module", "start_char": 1733, "end_char": 2448, "estimated_token_count": 189, "token_estimator": "heuristic-v1", "text": "## Create the Mock Runtime Module\n\nStart by creating a new module file within your pallet to house the mock runtime code.\n\n1. Navigate to your pallet directory:\n\n ```bash\n cd pallets/pallet-custom/src\n ```\n\n2. Create a new file named `mock.rs`:\n\n ```bash\n touch mock.rs\n ```\n\n3. Open `src/lib.rs` and add the mock module declaration at the top of the file, right after the `pub use pallet::*;` line:\n\n ```rust\n #![cfg_attr(not(feature = \"std\"), no_std)]\n\n pub use pallet::*;\n\n #[cfg(test)]\n mod mock;\n\n #[frame::pallet]\n pub mod pallet {\n // ... existing pallet code\n }\n ```\n\n The `#[cfg(test)]` attribute ensures this module is only compiled during testing."} -{"page_id": "parachains-customize-runtime-pallet-development-mock-runtime", "page_title": "Mock Your Runtime", "index": 4, "depth": 2, "title": "Set Up Basic Mock Infrastructure", "anchor": "set-up-basic-mock-infrastructure", "start_char": 2448, "end_char": 3290, "estimated_token_count": 199, "token_estimator": "heuristic-v1", "text": "## Set Up Basic Mock Infrastructure\n\nOpen `src/mock.rs` and add the foundational imports and type definitions:\n\n```rust\nuse crate as pallet_custom;\nuse frame::{\n deps::{\n frame_support::{derive_impl, traits::ConstU32},\n sp_io,\n sp_runtime::{traits::IdentityLookup, BuildStorage},\n },\n prelude::*,\n};\n\ntype Block = frame_system::mocking::MockBlock;\n\n// Configure a mock runtime to test the pallet.\nframe::deps::frame_support::construct_runtime!(\n pub enum Test\n {\n System: frame_system,\n CustomPallet: pallet_custom,\n }\n);\n```\n\n**Key components:**\n\n- **`construct_runtime!`** - Macro that builds a minimal runtime with only the pallets needed for testing\n- **`Test`** - The mock runtime type used in tests\n- **`Block`** - Type alias for the mock block type that the runtime will use"} -{"page_id": "parachains-customize-runtime-pallet-development-mock-runtime", "page_title": "Mock Your Runtime", "index": 5, "depth": 2, "title": "Implement frame_system Configuration", "anchor": "implement-frame_system-configuration", "start_char": 3290, "end_char": 4323, "estimated_token_count": 227, "token_estimator": "heuristic-v1", "text": "## Implement frame_system Configuration\n\nThe [`frame_system`](https://paritytech.github.io/polkadot-sdk/master/frame_system/index.html){target=\\_blank} pallet provides core blockchain functionality and is required by all other pallets. Configure it for the test environment:\n\n```rust\n#[derive_impl(frame_system::config_preludes::TestDefaultConfig)]\nimpl frame_system::Config for Test {\n type Block = Block;\n type AccountId = u64;\n type Lookup = IdentityLookup;\n}\n```\n\n**Simplified for testing:**\n\n- **`#[derive_impl]`** - Automatically provides sensible test defaults for most `frame_system::Config` types\n- **`AccountId = u64`** - Uses simple integers instead of cryptographic account IDs\n- **`Lookup = IdentityLookup`** - Direct account ID mapping (no address conversion)\n- **`Block = Block`** - Uses the mock block type we defined earlier\n\nThis approach is much more concise than manually specifying every configuration type, as the `TestDefaultConfig` preset provides appropriate defaults for testing."} -{"page_id": "parachains-customize-runtime-pallet-development-mock-runtime", "page_title": "Mock Your Runtime", "index": 6, "depth": 2, "title": "Implement Your Pallet's Configuration", "anchor": "implement-your-pallets-configuration", "start_char": 4323, "end_char": 4978, "estimated_token_count": 142, "token_estimator": "heuristic-v1", "text": "## Implement Your Pallet's Configuration\n\nNow implement the `Config` trait for your custom pallet. This must match the trait defined in your pallet's `lib.rs`:\n\n```rust\nimpl pallet_custom::Config for Test {\n type RuntimeEvent = RuntimeEvent;\n type CounterMaxValue = ConstU32<1000>;\n}\n```\n\n**Configuration details:**\n\n- **`RuntimeEvent`** - Connects your pallet's events to the mock runtime's event system\n- **`CounterMaxValue`** - Sets the maximum counter value to 1000, matching the production configuration\n\n!!!note\n The configuration here should mirror what you'll use in production unless you specifically need different values for testing."} -{"page_id": "parachains-customize-runtime-pallet-development-mock-runtime", "page_title": "Mock Your Runtime", "index": 7, "depth": 2, "title": "Configure Genesis Storage", "anchor": "configure-genesis-storage", "start_char": 4978, "end_char": 5258, "estimated_token_count": 47, "token_estimator": "heuristic-v1", "text": "## Configure Genesis Storage\n\nGenesis storage defines the initial state of your blockchain before any blocks are produced. Since your counter pallet includes genesis configuration (added in the previous guide), you can now set up test environments with different initial states."} -{"page_id": "parachains-customize-runtime-pallet-development-mock-runtime", "page_title": "Mock Your Runtime", "index": 8, "depth": 3, "title": "Basic Test Environment", "anchor": "basic-test-environment", "start_char": 5258, "end_char": 5873, "estimated_token_count": 132, "token_estimator": "heuristic-v1", "text": "### Basic Test Environment\n\nCreate a helper function for the default test environment:\n\n```rust\n// Build genesis storage according to the mock runtime.\npub fn new_test_ext() -> sp_io::TestExternalities {\n let mut t = frame_system::GenesisConfig::::default()\n .build_storage()\n .unwrap();\n\n pallet_custom::GenesisConfig:: {\n initial_counter_value: 0,\n initial_user_interactions: vec![],\n }\n .assimilate_storage(&mut t)\n .unwrap();\n\n t.into()\n}\n```\n\nThis function creates a clean blockchain state with an initial counter value of 0 and no user interactions."} -{"page_id": "parachains-customize-runtime-pallet-development-mock-runtime", "page_title": "Mock Your Runtime", "index": 9, "depth": 3, "title": "Custom Genesis Configurations", "anchor": "custom-genesis-configurations", "start_char": 5873, "end_char": 7562, "estimated_token_count": 364, "token_estimator": "heuristic-v1", "text": "### Custom Genesis Configurations\n\nFor testing specific scenarios, create additional helper functions with customized genesis states:\n\n```rust\n// Helper function to create a test externalities with a specific initial counter value\npub fn new_test_ext_with_counter(initial_value: u32) -> sp_io::TestExternalities {\n let mut t = frame_system::GenesisConfig::::default()\n .build_storage()\n .unwrap();\n\n pallet_custom::GenesisConfig:: {\n initial_counter_value: initial_value,\n initial_user_interactions: vec![],\n }\n .assimilate_storage(&mut t)\n .unwrap();\n\n t.into()\n}\n\n// Helper function to create a test externalities with initial user interactions\npub fn new_test_ext_with_interactions(\n initial_value: u32,\n interactions: Vec<(u64, u32)>,\n) -> sp_io::TestExternalities {\n let mut t = frame_system::GenesisConfig::::default()\n .build_storage()\n .unwrap();\n\n pallet_custom::GenesisConfig:: {\n initial_counter_value: initial_value,\n initial_user_interactions: interactions,\n }\n .assimilate_storage(&mut t)\n .unwrap();\n\n t.into()\n}\n```\n\n**Key methods:**\n\n- **[`BuildStorage::build_storage()`](https://paritytech.github.io/polkadot-sdk/master/sp_runtime/trait.BuildStorage.html#method.build_storage){target=\\_blank}** - Creates the initial storage state\n- **[`assimilate_storage`](https://paritytech.github.io/polkadot-sdk/master/sp_runtime/trait.BuildStorage.html#method.assimilate_storage){target=\\_blank}** - Merges pallet genesis config into the existing storage\n- **Multiple configurations** - You can chain multiple `assimilate_storage` calls for different pallets"} -{"page_id": "parachains-customize-runtime-pallet-development-mock-runtime", "page_title": "Mock Your Runtime", "index": 10, "depth": 2, "title": "Verify Mock Compilation", "anchor": "verify-mock-compilation", "start_char": 7562, "end_char": 10478, "estimated_token_count": 549, "token_estimator": "heuristic-v1", "text": "## Verify Mock Compilation\n\nBefore proceeding to write tests, ensure your mock runtime compiles correctly:\n\n```bash\ncargo test --package pallet-custom --lib\n```\n\nThis command compiles the test code (including the mock and genesis configuration) without running tests yet. Address any compilation errors before continuing.\n\n??? code \"Complete Mock Runtime\"\n\n Here's the complete `mock.rs` file for reference:\n\n ```rust\n use crate as pallet_custom;\n use frame::{\n deps::{\n frame_support::{derive_impl, traits::ConstU32},\n sp_io,\n sp_runtime::{traits::IdentityLookup, BuildStorage},\n },\n prelude::*,\n };\n\n type Block = frame_system::mocking::MockBlock;\n\n // Configure a mock runtime to test the pallet.\n frame::deps::frame_support::construct_runtime!(\n pub enum Test\n {\n System: frame_system,\n CustomPallet: pallet_custom,\n }\n );\n\n #[derive_impl(frame_system::config_preludes::TestDefaultConfig)]\n impl frame_system::Config for Test {\n type Block = Block;\n type AccountId = u64;\n type Lookup = IdentityLookup;\n }\n\n impl pallet_custom::Config for Test {\n type RuntimeEvent = RuntimeEvent;\n type CounterMaxValue = ConstU32<1000>;\n }\n\n // Build genesis storage according to the mock runtime.\n pub fn new_test_ext() -> sp_io::TestExternalities {\n let mut t = frame_system::GenesisConfig::::default()\n .build_storage()\n .unwrap();\n\n pallet_custom::GenesisConfig:: {\n initial_counter_value: 0,\n initial_user_interactions: vec![],\n }\n .assimilate_storage(&mut t)\n .unwrap();\n\n t.into()\n }\n\n // Helper function to create a test externalities with a specific initial counter value\n pub fn new_test_ext_with_counter(initial_value: u32) -> sp_io::TestExternalities {\n let mut t = frame_system::GenesisConfig::::default()\n .build_storage()\n .unwrap();\n\n pallet_custom::GenesisConfig:: {\n initial_counter_value: initial_value,\n initial_user_interactions: vec![],\n }\n .assimilate_storage(&mut t)\n .unwrap();\n\n t.into()\n }\n\n // Helper function to create a test externalities with initial user interactions\n pub fn new_test_ext_with_interactions(\n initial_value: u32,\n interactions: Vec<(u64, u32)>,\n ) -> sp_io::TestExternalities {\n let mut t = frame_system::GenesisConfig::::default()\n .build_storage()\n .unwrap();\n\n pallet_custom::GenesisConfig:: {\n initial_counter_value: initial_value,\n initial_user_interactions: interactions,\n }\n .assimilate_storage(&mut t)\n .unwrap();\n\n t.into()\n }\n ```"} -{"page_id": "parachains-customize-runtime-pallet-development-mock-runtime", "page_title": "Mock Your Runtime", "index": 11, "depth": 2, "title": "Key Takeaways", "anchor": "key-takeaways", "start_char": 10478, "end_char": 11284, "estimated_token_count": 147, "token_estimator": "heuristic-v1", "text": "## Key Takeaways\n\nYou've successfully created a mock runtime with genesis configuration for your custom pallet. You now have:\n\n- **Isolated testing environment** - Test your pallet without a full runtime\n- **Simplified configuration** - Minimal setup for rapid development iteration\n- **Genesis configuration** - Set initial blockchain state for different test scenarios\n- **Multiple test helpers** - Different genesis setups for various testing needs\n- **Foundation for unit tests** - Infrastructure to test all pallet functionality\n- **Fast feedback loop** - Instant compilation and test execution\n\nThe mock runtime with genesis configuration is essential for test-driven development, allowing you to verify logic under different initial conditions before integration into the actual parachain runtime."} -{"page_id": "parachains-customize-runtime-pallet-development-mock-runtime", "page_title": "Mock Your Runtime", "index": 12, "depth": 2, "title": "Where to Go Next", "anchor": "where-to-go-next", "start_char": 11284, "end_char": 11634, "estimated_token_count": 87, "token_estimator": "heuristic-v1", "text": "## Where to Go Next\n\n
\n\n- Guide __Pallet Unit Testing__\n\n ---\n\n Learn to write comprehensive unit tests for your pallet using the mock runtime you just created.\n\n [:octicons-arrow-right-24: Continue](/parachains/customize-runtime/pallet-development/pallet-testing/)\n\n
"} +{"page_id": "parachains-customize-runtime-pallet-development-create-a-pallet", "page_title": "Create a Custom Pallet", "index": 0, "depth": 2, "title": "Introduction", "anchor": "introduction", "start_char": 26, "end_char": 847, "estimated_token_count": 167, "token_estimator": "heuristic-v1", "text": "## Introduction\n\n[Framework for Runtime Aggregation of Modular Entities (FRAME)](https://paritytech.github.io/polkadot-sdk/master/polkadot_sdk_docs/polkadot_sdk/frame_runtime/index.html){target=\\_blank} provides a powerful set of tools for blockchain development through modular components called [pallets](https://paritytech.github.io/polkadot-sdk/master/polkadot_sdk_docs/polkadot_sdk/frame_runtime/pallet/index.html){target=\\_blank}. These Rust-based runtime modules allow you to build custom blockchain functionality with precision and flexibility. While FRAME includes a library of pre-built pallets, its true strength lies in creating custom pallets tailored to your specific needs.\n\nIn this guide, you'll learn how to build a custom counter pallet from scratch that demonstrates core pallet development concepts."} +{"page_id": "parachains-customize-runtime-pallet-development-create-a-pallet", "page_title": "Create a Custom Pallet", "index": 1, "depth": 2, "title": "Prerequisites", "anchor": "prerequisites", "start_char": 847, "end_char": 1217, "estimated_token_count": 99, "token_estimator": "heuristic-v1", "text": "## Prerequisites\n\nBefore you begin, ensure you have:\n\n- [Polkadot SDK dependencies installed](/parachains/install-polkadot-sdk/){target=\\_blank}.\n- A [Polkadot SDK Parchain Template](/parachains/launch-a-parachain/set-up-the-parachain-template/){target=\\_blank} set up locally.\n- Basic familiarity with [FRAME concepts](/parachains/customize-runtime/){target=\\_blank}."} +{"page_id": "parachains-customize-runtime-pallet-development-create-a-pallet", "page_title": "Create a Custom Pallet", "index": 2, "depth": 2, "title": "Core Pallet Components", "anchor": "core-pallet-components", "start_char": 1217, "end_char": 2092, "estimated_token_count": 193, "token_estimator": "heuristic-v1", "text": "## Core Pallet Components\n\nAs you build your custom pallet, you'll work with these key sections:\n\n- **Imports and dependencies**: Bring in necessary FRAME libraries and external modules.\n- **Runtime configuration trait**: Specify types and constants for pallet-runtime interaction.\n- **Runtime events**: Define signals that communicate state changes.\n- **Runtime errors**: Define error types returned from dispatchable calls.\n- **Runtime storage**: Declare on-chain storage items for your pallet's state.\n- **Genesis configuration**: Set initial blockchain state.\n- **Dispatchable functions (extrinsics)**: Create callable functions for user interactions.\n\nFor additional macros beyond those covered here, refer to the [pallet_macros](https://paritytech.github.io/polkadot-sdk/master/frame_support/pallet_macros/index.html){target=\\_blank} section of the Polkadot SDK Docs."} +{"page_id": "parachains-customize-runtime-pallet-development-create-a-pallet", "page_title": "Create a Custom Pallet", "index": 3, "depth": 2, "title": "Create the Pallet Project", "anchor": "create-the-pallet-project", "start_char": 2092, "end_char": 2831, "estimated_token_count": 180, "token_estimator": "heuristic-v1", "text": "## Create the Pallet Project\n\nBegin by creating a new Rust library project for your custom pallet within the [Polkadot SDK Parachain Template](https://github.com/paritytech/polkadot-sdk-parachain-template){target=\\_blank}:\n\n1. Navigate to the root directory of your parachain template:\n\n ```bash\n cd polkadot-sdk-parachain-template\n ```\n\n2. Navigate to the `pallets` directory:\n\n ```bash\n cd pallets\n ```\n\n3. Create a new Rust library project:\n\n ```bash\n cargo new --lib pallet-custom\n ```\n\n4. Enter the new project directory:\n\n ```bash\n cd pallet-custom\n ```\n\n5. Verify the project structure. It should look like:\n\n ```\n pallet-custom/\n ├── Cargo.toml\n └── src/\n └── lib.rs\n ```"} +{"page_id": "parachains-customize-runtime-pallet-development-create-a-pallet", "page_title": "Create a Custom Pallet", "index": 4, "depth": 2, "title": "Configure Dependencies", "anchor": "configure-dependencies", "start_char": 2831, "end_char": 4724, "estimated_token_count": 386, "token_estimator": "heuristic-v1", "text": "## Configure Dependencies\n\nTo integrate your custom pallet into the Polkadot SDK-based runtime, configure the `Cargo.toml` file with the required dependencies. Since your pallet exists within the parachain template workspace, you'll use workspace inheritance to maintain version consistency.\n\n1. Open `Cargo.toml` and replace its contents with:\n\n ```toml title=\"pallet-custom/Cargo.toml\"\n [package]\n name = \"pallet-custom\"\n description = \"A custom counter pallet for demonstration purposes.\"\n version = \"0.1.0\"\n license = \"Unlicense\"\n authors.workspace = true\n homepage.workspace = true\n repository.workspace = true\n edition.workspace = true\n publish = false\n\n [package.metadata.docs.rs]\n targets = [\"x86_64-unknown-linux-gnu\"]\n\n [dependencies]\n codec = { features = [\"derive\"], workspace = true }\n scale-info = { features = [\"derive\"], workspace = true }\n frame = { features = [\"experimental\", \"runtime\"], workspace = true }\n\n [features]\n default = [\"std\"]\n std = [\n \"codec/std\",\n \"scale-info/std\",\n \"frame/std\",\n ]\n ```\n\n !!!note \"Version Management\"\n The parachain template uses workspace inheritance to maintain consistent dependency versions across all packages. The actual versions are defined in the root `Cargo.toml` file, ensuring compatibility throughout the project. By using `workspace = true`, your pallet automatically inherits the correct versions.\n\n2. The parachain template already includes `pallets/*` in the workspace members, so your new pallet is automatically recognized. Verify this by checking the root `Cargo.toml`:\n\n ```toml title=\"Cargo.toml\"\n [workspace.members]\n members = [\n \"node\",\n \"pallets/*\",\n \"runtime\",\n ]\n ```"} +{"page_id": "parachains-customize-runtime-pallet-development-create-a-pallet", "page_title": "Create a Custom Pallet", "index": 5, "depth": 2, "title": "Initialize the Pallet Structure", "anchor": "initialize-the-pallet-structure", "start_char": 4724, "end_char": 5916, "estimated_token_count": 269, "token_estimator": "heuristic-v1", "text": "## Initialize the Pallet Structure\n\nWith dependencies configured, set up the basic scaffold that will hold your pallet's logic:\n\n1. Open `src/lib.rs` and delete all existing content.\n\n2. Add the initial scaffold structure using the unified `frame` dependency:\n\n ```rust title=\"src/lib.rs\"\n #![cfg_attr(not(feature = \"std\"), no_std)]\n\n pub use pallet::*;\n\n #[frame::pallet]\n pub mod pallet {\n use frame::prelude::*;\n\n #[pallet::pallet]\n pub struct Pallet(_);\n\n #[pallet::config]\n pub trait Config: frame_system::Config {\n // Configuration will be added here\n }\n\n #[pallet::storage]\n pub type CounterValue = StorageValue<_, u32, ValueQuery>;\n\n #[pallet::call]\n impl Pallet {\n // Dispatchable functions will be added here\n }\n }\n ```\n\n This setup starts with a minimal scaffold without events and errors. These will be added in the following sections after the `Config` trait is correctly configured with the required `RuntimeEvent` type.\n\n3. Verify it compiles using the following command:\n\n ```bash\n cargo build --package pallet-custom\n ```"} +{"page_id": "parachains-customize-runtime-pallet-development-create-a-pallet", "page_title": "Create a Custom Pallet", "index": 6, "depth": 2, "title": "Configure the Pallet", "anchor": "configure-the-pallet", "start_char": 5916, "end_char": 7187, "estimated_token_count": 319, "token_estimator": "heuristic-v1", "text": "## Configure the Pallet\n\nThe [`Config`](https://paritytech.github.io/polkadot-sdk/master/frame_system/pallet/trait.Config.html){target=\\_blank} trait exposes configurable options and links your pallet to the runtime. All types and constants the pallet depends on must be declared here. These types are defined generically and become concrete when the pallet is instantiated at runtime.\n\nReplace the [`#[pallet::config]`](https://paritytech.github.io/polkadot-sdk/master/frame_support/pallet_macros/attr.config.html){target=\\_blank} section with:\n\n```rust title=\"src/lib.rs\"\n#[pallet::config]\npub trait Config: frame_system::Config {\n /// The overarching runtime event type.\n type RuntimeEvent: From> + IsType<::RuntimeEvent>;\n\n /// Maximum value the counter can reach.\n #[pallet::constant]\n type CounterMaxValue: Get;\n}\n\n```\n\nKey configuration elements include the following:\n\n- **[`RuntimeEvent`](https://paritytech.github.io/polkadot-sdk/master/frame_system/pallet/trait.Config.html#associatedtype.RuntimeEvent){target=\\_blank}**: Required for the pallet to emit events that the runtime can process.\n- **`CounterMaxValue`**: A constant that sets an upper limit on counter values, configurable per runtime."} +{"page_id": "parachains-customize-runtime-pallet-development-create-a-pallet", "page_title": "Create a Custom Pallet", "index": 7, "depth": 2, "title": "Define Events", "anchor": "define-events", "start_char": 7187, "end_char": 8602, "estimated_token_count": 345, "token_estimator": "heuristic-v1", "text": "## Define Events\n\nEvents inform external entities (dApps, explorers, users) about significant runtime changes. Event details are included in the node's metadata, making them accessible to external tools.\n\nThe [`#[pallet::generate_deposit]`](https://paritytech.github.io/polkadot-sdk/master/frame_support/pallet_macros/attr.generate_deposit.html){target=\\_blank} macro automatically generates a `deposit_event` function that converts your pallet's events into the `RuntimeEvent` type and deposits them via [`frame_system::Pallet::deposit_event`](https://paritytech.github.io/polkadot-sdk/master/frame_system/pallet/struct.Pallet.html#method.deposit_event){target=\\_blank}.\n\nAdd the [`#[pallet::event]`](https://paritytech.github.io/polkadot-sdk/master/frame_support/pallet_macros/attr.event.html){target=\\_blank} section after the `Config` trait:\n\n```rust title=\"src/lib.rs\"\n#[pallet::event]\n#[pallet::generate_deposit(pub(super) fn deposit_event)]\npub enum Event {\n /// Counter value was explicitly set. [new_value]\n CounterValueSet {\n new_value: u32,\n },\n /// Counter was incremented. [new_value, who, amount]\n CounterIncremented {\n new_value: u32,\n who: T::AccountId,\n amount: u32,\n },\n /// Counter was decremented. [new_value, who, amount]\n CounterDecremented {\n new_value: u32,\n who: T::AccountId,\n amount: u32,\n },\n}\n\n```"} +{"page_id": "parachains-customize-runtime-pallet-development-create-a-pallet", "page_title": "Create a Custom Pallet", "index": 8, "depth": 2, "title": "Define Errors", "anchor": "define-errors", "start_char": 8602, "end_char": 9507, "estimated_token_count": 221, "token_estimator": "heuristic-v1", "text": "## Define Errors\n\nErrors indicate when and why a call fails. Use informative names and descriptions, as error documentation is included in the node's metadata.\n\nError types must implement the [`TypeInfo`](https://paritytech.github.io/polkadot-sdk/master/frame_support/pallet_prelude/trait.TypeInfo.html){target=\\_blank} trait, and runtime errors can be up to 4 bytes in size.\n\nAdd the [`#[pallet::error]`](https://paritytech.github.io/polkadot-sdk/master/frame_support/pallet_macros/attr.error.html){target=\\_blank} section after the events:\n\n```rust title=\"src/lib.rs\"\n#[pallet::error]\npub enum Error {\n /// The counter value has not been set yet.\n NoneValue,\n /// Arithmetic operation would cause overflow.\n Overflow,\n /// Arithmetic operation would cause underflow.\n Underflow,\n /// The counter value would exceed the maximum allowed value.\n CounterMaxValueExceeded,\n}\n\n```"} +{"page_id": "parachains-customize-runtime-pallet-development-create-a-pallet", "page_title": "Create a Custom Pallet", "index": 9, "depth": 2, "title": "Add Storage Items", "anchor": "add-storage-items", "start_char": 9507, "end_char": 10621, "estimated_token_count": 283, "token_estimator": "heuristic-v1", "text": "## Add Storage Items\n\nStorage items persist state on-chain. This pallet uses two storage items:\n\n- **`CounterValue`**: Stores the current counter value.\n- **`UserInteractions`**: Tracks interaction counts per user account.\n\nThe initial scaffold already includes the `CounterValue` storage item. Now add the `UserInteractions` storage map after it:\n\n```rust title=\"src/lib.rs\"\n/// Tracks the number of interactions per user.\n#[pallet::storage]\npub type UserInteractions = StorageMap<_, Blake2_128Concat, T::AccountId, u32, ValueQuery>;\n```\n\nYour storage section should now look like this:\n\n```rust title=\"src/lib.rs\"\n/// The current value of the counter.\n#[pallet::storage]\npub type CounterValue = StorageValue<_, u32, ValueQuery>;\n\n/// Tracks the number of interactions per user.\n#[pallet::storage]\npub type UserInteractions = StorageMap<_, Blake2_128Concat, T::AccountId, u32, ValueQuery>;\n```\n\nFor more storage types and patterns, explore the [Polkadot SDK storage documentation](https://paritytech.github.io/polkadot-sdk/master/frame_support/storage/types/index.html){target=\\_blank}."} +{"page_id": "parachains-customize-runtime-pallet-development-create-a-pallet", "page_title": "Create a Custom Pallet", "index": 10, "depth": 2, "title": "Configure Genesis State", "anchor": "configure-genesis-state", "start_char": 10621, "end_char": 12447, "estimated_token_count": 416, "token_estimator": "heuristic-v1", "text": "## Configure Genesis State\n\nGenesis configuration allows you to set the initial state of your pallet when the blockchain first starts and is essential for both production networks and testing environments. It is beneficial for:\n\n- Setting initial parameter values.\n- Pre-allocating resources or accounts.\n- Establishing starting conditions for testing.\n- Configuring network-specific initial state.\n\nAdd the [`#[pallet::genesis_config]`](https://paritytech.github.io/polkadot-sdk/master/frame_support/pallet_macros/attr.genesis_config.html){target=\\_blank} and [`#[pallet::genesis_build]`](https://paritytech.github.io/polkadot-sdk/master/frame_support/pallet_macros/attr.genesis_build.html){target=\\_blank} sections after your storage items:\n\n```rust title=\"src/lib.rs\"\n#[pallet::genesis_config]\n#[derive(DefaultNoBound)]\npub struct GenesisConfig {\n /// Initial value for the counter\n pub initial_counter_value: u32,\n /// Pre-populated user interactions\n pub initial_user_interactions: Vec<(T::AccountId, u32)>,\n}\n\n#[pallet::genesis_build]\nimpl BuildGenesisConfig for GenesisConfig {\n fn build(&self) {\n // Set the initial counter value\n CounterValue::::put(self.initial_counter_value);\n\n // Set initial user interactions\n for (account, count) in &self.initial_user_interactions {\n UserInteractions::::insert(account, count);\n }\n }\n}\n\n```\n\nGenesis configuration components include the following:\n\n- **`GenesisConfig` struct**: Defines what can be configured at genesis.\n- **`#[derive(DefaultNoBound)]`**: Provides sensible defaults (empty vec and 0 for the counter).\n- **`BuildGenesisConfig` implementation**: Executes the logic to set initial storage values.\n- **`build()` method**: Called once when the blockchain initializes."} +{"page_id": "parachains-customize-runtime-pallet-development-create-a-pallet", "page_title": "Create a Custom Pallet", "index": 11, "depth": 2, "title": "Implement Dispatchable Functions", "anchor": "implement-dispatchable-functions", "start_char": 12447, "end_char": 15604, "estimated_token_count": 753, "token_estimator": "heuristic-v1", "text": "## Implement Dispatchable Functions\n\nDispatchable functions (extrinsics) allow users to interact with your pallet and trigger state changes. Each function must:\n\n- Return a [`DispatchResult`](https://paritytech.github.io/polkadot-sdk/master/frame_support/dispatch/type.DispatchResult.html){target=\\_blank}.\n- Be annotated with a weight (computational cost).\n- Have an explicit call index for backward compatibility.\n\nReplace the [`#[pallet::call]`](https://paritytech.github.io/polkadot-sdk/master/frame_support/pallet_macros/attr.call.html){target=\\_blank} section with:\n\n```rust title=\"src/lib.rs\"\n#[pallet::call]\nimpl Pallet {\n /// Set the counter to a specific value. Root origin only.\n #[pallet::call_index(0)]\n #[pallet::weight(0)]\n pub fn set_counter_value(origin: OriginFor, new_value: u32) -> DispatchResult {\n // Ensure the caller is root\n ensure_root(origin)?;\n\n // Validate the new value doesn't exceed the maximum\n ensure!(new_value <= T::CounterMaxValue::get(), Error::::CounterMaxValueExceeded);\n\n // Update storage\n CounterValue::::put(new_value);\n\n // Emit event\n Self::deposit_event(Event::CounterValueSet { new_value });\n\n Ok(())\n }\n\n /// Increment the counter by a specified amount.\n #[pallet::call_index(1)]\n #[pallet::weight(0)]\n pub fn increment(origin: OriginFor, amount: u32) -> DispatchResult {\n // Ensure the caller is signed\n let who = ensure_signed(origin)?;\n\n // Get current counter value\n let current_value = CounterValue::::get();\n\n // Check for overflow\n let new_value = current_value.checked_add(amount).ok_or(Error::::Overflow)?;\n\n // Ensure new value doesn't exceed maximum\n ensure!(new_value <= T::CounterMaxValue::get(), Error::::CounterMaxValueExceeded);\n\n // Update counter storage\n CounterValue::::put(new_value);\n\n // Track user interaction\n UserInteractions::::mutate(&who, |count| {\n *count = count.saturating_add(1);\n });\n\n // Emit event\n Self::deposit_event(Event::CounterIncremented {\n new_value,\n who,\n amount,\n });\n\n Ok(())\n }\n\n /// Decrement the counter by a specified amount.\n #[pallet::call_index(2)]\n #[pallet::weight(0)]\n pub fn decrement(origin: OriginFor, amount: u32) -> DispatchResult {\n // Ensure the caller is signed\n let who = ensure_signed(origin)?;\n\n // Get current counter value\n let current_value = CounterValue::::get();\n\n // Check for underflow\n let new_value = current_value.checked_sub(amount).ok_or(Error::::Underflow)?;\n\n // Update counter storage\n CounterValue::::put(new_value);\n\n // Track user interaction\n UserInteractions::::mutate(&who, |count| {\n *count = count.saturating_add(1);\n });\n\n // Emit event\n Self::deposit_event(Event::CounterDecremented {\n new_value,\n who,\n amount,\n });\n\n Ok(())\n }\n}\n\n```"} +{"page_id": "parachains-customize-runtime-pallet-development-create-a-pallet", "page_title": "Create a Custom Pallet", "index": 12, "depth": 3, "title": "Dispatchable Function Details", "anchor": "dispatchable-function-details", "start_char": 15604, "end_char": 16558, "estimated_token_count": 237, "token_estimator": "heuristic-v1", "text": "### Dispatchable Function Details\n\n???+ interface \"`set_counter_value`\"\n\n - **Access**: Root origin only (privileged operations).\n - **Purpose**: Set counter to a specific value.\n - **Validations**: New value must not exceed `CounterMaxValue`.\n - **State changes**: Updates `CounterValue` storage.\n - **Events**: Emits `CounterValueSet`.\n\n??? interface \"`increment`\"\n\n - **Access**: Any signed account.\n - **Purpose**: Increase counter by specified amount.\n - **Validations**: Checks for overflow and max value compliance.\n - **State changes**: Updates `CounterValue` and `UserInteractions`.\n - **Events**: Emits `CounterIncremented`.\n\n??? interface \"`decrement`\"\n\n - **Access**: Any signed account.\n - **Purpose**: Decrease counter by specified amount.\n - **Validations**: Checks for underflow.\n - **State changes**: Updates `CounterValue` and `UserInteractions`.\n - **Events**: Emits `CounterDecremented`."} +{"page_id": "parachains-customize-runtime-pallet-development-create-a-pallet", "page_title": "Create a Custom Pallet", "index": 13, "depth": 2, "title": "Verify Pallet Compilation", "anchor": "verify-pallet-compilation", "start_char": 16558, "end_char": 21051, "estimated_token_count": 938, "token_estimator": "heuristic-v1", "text": "## Verify Pallet Compilation\n\nBefore proceeding, ensure your pallet compiles without errors by running the following command:\n\n```bash\ncargo build --package pallet-custom\n```\n\nIf you encounter errors, carefully review the code against this guide. Once the build completes successfully, your custom pallet is ready for integration.\n\n??? code \"Complete Pallet Implementation\"\n \n ```rust title=\"src/lib.rs\"\n #![cfg_attr(not(feature = \"std\"), no_std)]\n\n pub use pallet::*;\n\n #[frame::pallet]\n pub mod pallet {\n use frame::prelude::*;\n\n #[pallet::pallet]\n pub struct Pallet(_);\n\n #[pallet::config]\n pub trait Config: frame_system::Config {\n type RuntimeEvent: From> + IsType<::RuntimeEvent>;\n\n #[pallet::constant]\n type CounterMaxValue: Get;\n }\n\n #[pallet::event]\n #[pallet::generate_deposit(pub(super) fn deposit_event)]\n pub enum Event {\n CounterValueSet {\n new_value: u32,\n },\n CounterIncremented {\n new_value: u32,\n who: T::AccountId,\n amount: u32,\n },\n CounterDecremented {\n new_value: u32,\n who: T::AccountId,\n amount: u32,\n },\n }\n\n #[pallet::error]\n pub enum Error {\n NoneValue,\n Overflow,\n Underflow,\n CounterMaxValueExceeded,\n }\n\n #[pallet::storage]\n pub type CounterValue = StorageValue<_, u32, ValueQuery>;\n\n #[pallet::storage]\n pub type UserInteractions = StorageMap<\n _,\n Blake2_128Concat,\n T::AccountId,\n u32,\n ValueQuery\n >;\n\n #[pallet::genesis_config]\n #[derive(DefaultNoBound)]\n pub struct GenesisConfig {\n pub initial_counter_value: u32,\n pub initial_user_interactions: Vec<(T::AccountId, u32)>,\n }\n\n #[pallet::genesis_build]\n impl BuildGenesisConfig for GenesisConfig {\n fn build(&self) {\n CounterValue::::put(self.initial_counter_value);\n for (account, count) in &self.initial_user_interactions {\n UserInteractions::::insert(account, count);\n }\n }\n }\n\n #[pallet::call]\n impl Pallet {\n #[pallet::call_index(0)]\n #[pallet::weight(0)]\n pub fn set_counter_value(origin: OriginFor, new_value: u32) -> DispatchResult {\n ensure_root(origin)?;\n ensure!(new_value <= T::CounterMaxValue::get(), Error::::CounterMaxValueExceeded);\n CounterValue::::put(new_value);\n Self::deposit_event(Event::CounterValueSet { new_value });\n Ok(())\n }\n\n #[pallet::call_index(1)]\n #[pallet::weight(0)]\n pub fn increment(origin: OriginFor, amount: u32) -> DispatchResult {\n let who = ensure_signed(origin)?;\n let current_value = CounterValue::::get();\n let new_value = current_value.checked_add(amount).ok_or(Error::::Overflow)?;\n ensure!(new_value <= T::CounterMaxValue::get(), Error::::CounterMaxValueExceeded);\n CounterValue::::put(new_value);\n UserInteractions::::mutate(&who, |count| {\n *count = count.saturating_add(1);\n });\n Self::deposit_event(Event::CounterIncremented { new_value, who, amount });\n Ok(())\n }\n\n #[pallet::call_index(2)]\n #[pallet::weight(0)]\n pub fn decrement(origin: OriginFor, amount: u32) -> DispatchResult {\n let who = ensure_signed(origin)?;\n let current_value = CounterValue::::get();\n let new_value = current_value.checked_sub(amount).ok_or(Error::::Underflow)?;\n CounterValue::::put(new_value);\n UserInteractions::::mutate(&who, |count| {\n *count = count.saturating_add(1);\n });\n Self::deposit_event(Event::CounterDecremented { new_value, who, amount });\n Ok(())\n }\n }\n }\n\n ```"} +{"page_id": "parachains-customize-runtime-pallet-development-create-a-pallet", "page_title": "Create a Custom Pallet", "index": 14, "depth": 2, "title": "Add the Pallet to Your Runtime", "anchor": "add-the-pallet-to-your-runtime", "start_char": 21051, "end_char": 21177, "estimated_token_count": 25, "token_estimator": "heuristic-v1", "text": "## Add the Pallet to Your Runtime\n\nNow that your custom pallet is complete, you can integrate it into the parachain runtime."} +{"page_id": "parachains-customize-runtime-pallet-development-create-a-pallet", "page_title": "Create a Custom Pallet", "index": 15, "depth": 3, "title": "Add Runtime Dependency", "anchor": "add-runtime-dependency", "start_char": 21177, "end_char": 21753, "estimated_token_count": 150, "token_estimator": "heuristic-v1", "text": "### Add Runtime Dependency\n\n1. In the `runtime/Cargo.toml`, add your custom pallet to the `[dependencies]` section:\n\n ```toml title=\"runtime/Cargo.toml\"\n [dependencies]\n # Local dependencies\n pallet-custom = { path = \"../pallets/pallet-custom\", default-features = false }\n \n # Other dependencies\n ```\n\n2. Enable the `std` feature by adding it to the `[features]` section:\n\n ```toml title=\"runtime/Cargo.toml\"\n [features]\n default = [\"std\"]\n std = [\n \"codec/std\",\n \"pallet-custom/std\",\n # ... other features\n ]\n ```"} +{"page_id": "parachains-customize-runtime-pallet-development-create-a-pallet", "page_title": "Create a Custom Pallet", "index": 16, "depth": 3, "title": "Implement the Config Trait", "anchor": "implement-the-config-trait", "start_char": 21753, "end_char": 22324, "estimated_token_count": 145, "token_estimator": "heuristic-v1", "text": "### Implement the Config Trait\n\nAt the end of the `runtime/src/configs/mod.rs` file, add the implementation: \n\n```rust title=\"runtime/src/configs/mod.rs\"\n/// Configure the custom counter pallet\nimpl pallet_custom::Config for Runtime {\n type RuntimeEvent = RuntimeEvent;\n type CounterMaxValue = ConstU32<1000>;\n}\n```\n\nThis configuration:\n\n- Links the pallet's events to the runtime's event system.\n- Sets a maximum counter value of 1000 using [`ConstU32`](https://paritytech.github.io/polkadot-sdk/master/frame_support/traits/struct.ConstU32.html){target=\\_blank}."} +{"page_id": "parachains-customize-runtime-pallet-development-create-a-pallet", "page_title": "Create a Custom Pallet", "index": 17, "depth": 3, "title": "Add to Runtime Construct", "anchor": "add-to-runtime-construct", "start_char": 22324, "end_char": 23326, "estimated_token_count": 214, "token_estimator": "heuristic-v1", "text": "### Add to Runtime Construct\n\nIn the `runtime/src/lib.rs` file, locate the [`#[frame_support::runtime]`](https://paritytech.github.io/polkadot-sdk/master/frame_support/attr.runtime.html){target=\\_blank} section and add your pallet with a unique `pallet_index`:\n\n```rust title=\"runtime/src/lib.rs\"\n#[frame_support::runtime]\nmod runtime {\n #[runtime::runtime]\n #[runtime::derive(\n RuntimeCall,\n RuntimeEvent,\n RuntimeError,\n RuntimeOrigin,\n RuntimeTask,\n RuntimeFreezeReason,\n RuntimeHoldReason,\n RuntimeSlashReason,\n RuntimeLockId,\n RuntimeViewFunction\n )]\n pub struct Runtime;\n\n #[runtime::pallet_index(0)]\n pub type System = frame_system;\n\n // ... other pallets\n\n #[runtime::pallet_index(51)]\n pub type CustomPallet = pallet_custom;\n}\n```\n\n!!!warning\n Each pallet must have a unique index. Duplicate indices will cause compilation errors. Choose an index that doesn't conflict with existing pallets."} +{"page_id": "parachains-customize-runtime-pallet-development-create-a-pallet", "page_title": "Create a Custom Pallet", "index": 18, "depth": 3, "title": "Configure Genesis for Your Runtime", "anchor": "configure-genesis-for-your-runtime", "start_char": 23326, "end_char": 23824, "estimated_token_count": 100, "token_estimator": "heuristic-v1", "text": "### Configure Genesis for Your Runtime\n\nTo set initial values for your pallet when the chain starts, you'll need to configure the genesis in your chain specification. Genesis configuration is typically done in the `node/src/chain_spec.rs` file or when generating the chain specification.\n\nFor development and testing, you can use the default values provided by the `#[derive(DefaultNoBound)]` macro. For production networks, you'll want to explicitly set these values in your chain specification."} +{"page_id": "parachains-customize-runtime-pallet-development-create-a-pallet", "page_title": "Create a Custom Pallet", "index": 19, "depth": 3, "title": "Verify Runtime Compilation", "anchor": "verify-runtime-compilation", "start_char": 23824, "end_char": 24047, "estimated_token_count": 41, "token_estimator": "heuristic-v1", "text": "### Verify Runtime Compilation\n\nCompile the runtime to ensure everything is configured correctly:\n\n```bash\ncargo build --release\n```\n\nThis command validates all pallet configurations and prepares the build for deployment."} +{"page_id": "parachains-customize-runtime-pallet-development-create-a-pallet", "page_title": "Create a Custom Pallet", "index": 20, "depth": 2, "title": "Run Your Chain Locally", "anchor": "run-your-chain-locally", "start_char": 24047, "end_char": 24235, "estimated_token_count": 47, "token_estimator": "heuristic-v1", "text": "## Run Your Chain Locally\n\nLaunch your parachain locally to test the new pallet functionality using the [Polkadot Omni Node](https://crates.io/crates/polkadot-omni-node){target=\\_blank}."} +{"page_id": "parachains-customize-runtime-pallet-development-create-a-pallet", "page_title": "Create a Custom Pallet", "index": 21, "depth": 3, "title": "Generate a Chain Specification", "anchor": "generate-a-chain-specification", "start_char": 24235, "end_char": 24644, "estimated_token_count": 92, "token_estimator": "heuristic-v1", "text": "### Generate a Chain Specification\n\nCreate a chain specification file with the updated runtime:\n\n```bash\nchain-spec-builder create -t development \\\n--relay-chain paseo \\\n--para-id 1000 \\\n--runtime ./target/release/wbuild/parachain-template-runtime/parachain_template_runtime.compact.compressed.wasm \\\nnamed-preset development\n```\n\nThis command generates a `chain_spec.json` that includes your custom pallet."} +{"page_id": "parachains-customize-runtime-pallet-development-create-a-pallet", "page_title": "Create a Custom Pallet", "index": 22, "depth": 3, "title": "Start the Parachain Node", "anchor": "start-the-parachain-node", "start_char": 24644, "end_char": 24827, "estimated_token_count": 44, "token_estimator": "heuristic-v1", "text": "### Start the Parachain Node\n\nLaunch the parachain:\n\n```bash\npolkadot-omni-node --chain ./chain_spec.json --dev\n```\n\nVerify the node starts successfully and begins producing blocks."} +{"page_id": "parachains-customize-runtime-pallet-development-create-a-pallet", "page_title": "Create a Custom Pallet", "index": 23, "depth": 2, "title": "Interact with Your Pallet", "anchor": "interact-with-your-pallet", "start_char": 24827, "end_char": 25599, "estimated_token_count": 234, "token_estimator": "heuristic-v1", "text": "## Interact with Your Pallet\n\nUse the Polkadot.js Apps interface to test your pallet:\n\n1. Navigate to [Polkadot.js Apps](https://polkadot.js.org/apps/?rpc=ws%3A%2F%2F127.0.0.1%3A9944#/extrinsics){target=\\_blank}.\n\n2. Ensure you're connected to your local node at `ws://127.0.0.1:9944`.\n\n3. Go to **Developer** > **Extrinsics**.\n\n4. Locate **customPallet** in the pallet dropdown.\n\n5. You should see the available extrinsics:\n\n - **`increment(amount)`**: Increase the counter by a specified amount.\n - **`decrement(amount)`**: Decrease the counter by a specified amount.\n - **`setCounterValue(newValue)`**: Set counter to a specific value (requires sudo/root).\n\n![](/images/parachains/customize-runtime/pallet-development/create-a-pallet/create-a-pallet-01.webp)"} +{"page_id": "parachains-customize-runtime-pallet-development-create-a-pallet", "page_title": "Create a Custom Pallet", "index": 24, "depth": 2, "title": "Key Takeaways", "anchor": "key-takeaways", "start_char": 25599, "end_char": 26322, "estimated_token_count": 129, "token_estimator": "heuristic-v1", "text": "## Key Takeaways\n\nYou've successfully created and integrated a custom pallet into a Polkadot SDK-based runtime. You have now successfully:\n\n- Defined runtime-specific types and constants via the `Config` trait.\n- Implemented on-chain state using `StorageValue` and `StorageMap`.\n- Created signals to communicate state changes to external systems.\n- Established clear error handling with descriptive error types.\n- Configured initial blockchain state for both production and testing.\n- Built callable functions with proper validation and access control.\n- Added the pallet to a runtime and tested it locally.\n\nThese components form the foundation for developing sophisticated blockchain logic in Polkadot SDK-based chains."} +{"page_id": "parachains-customize-runtime-pallet-development-create-a-pallet", "page_title": "Create a Custom Pallet", "index": 25, "depth": 2, "title": "Where to Go Next", "anchor": "where-to-go-next", "start_char": 26322, "end_char": 26671, "estimated_token_count": 86, "token_estimator": "heuristic-v1", "text": "## Where to Go Next\n\n
\n\n- Guide __Mock Your Runtime__\n\n ---\n\n Learn to create a mock runtime environment for testing your pallet in isolation before integration.\n\n [:octicons-arrow-right-24: Continue](/parachains/customize-runtime/pallet-development/mock-runtime/)\n\n
"} +{"page_id": "parachains-customize-runtime-pallet-development-mock-runtime", "page_title": "Mock Your Runtime", "index": 0, "depth": 2, "title": "Introduction", "anchor": "introduction", "start_char": 21, "end_char": 806, "estimated_token_count": 158, "token_estimator": "heuristic-v1", "text": "## Introduction\n\nTesting is a critical part of pallet development. Before integrating your pallet into a full runtime, you need a way to test its functionality in isolation. A mock runtime provides a minimal, simulated blockchain environment where you can verify your pallet's logic without the overhead of running a full node.\n\nIn this guide, you'll learn how to create a mock runtime for the custom counter pallet built in the [Make a Custom Pallet](/parachains/customize-runtime/pallet-development/create-a-pallet/){target=\\_blank} guide. This mock runtime will enable you to write comprehensive unit tests that verify:\n\n- Dispatchable function behavior.\n- Storage state changes.\n- Event emission.\n- Error handling.\n- Access control and origin validation.\n- Genesis configuration."} +{"page_id": "parachains-customize-runtime-pallet-development-mock-runtime", "page_title": "Mock Your Runtime", "index": 1, "depth": 2, "title": "Prerequisites", "anchor": "prerequisites", "start_char": 806, "end_char": 1203, "estimated_token_count": 108, "token_estimator": "heuristic-v1", "text": "## Prerequisites\n\nBefore you begin, ensure you have:\n\n- Completed the [Make a Custom Pallet](/parachains/customize-runtime/pallet-development/create-a-pallet/){target=\\_blank} guide.\n- The custom counter pallet from the Make a Custom Pallet guide. Available in `pallets/pallet-custom`.\n- Basic understanding of [Rust testing](https://doc.rust-lang.org/book/ch11-00-testing.html){target=\\_blank}."} +{"page_id": "parachains-customize-runtime-pallet-development-mock-runtime", "page_title": "Mock Your Runtime", "index": 2, "depth": 2, "title": "Understand Mock Runtimes", "anchor": "understand-mock-runtimes", "start_char": 1203, "end_char": 1737, "estimated_token_count": 90, "token_estimator": "heuristic-v1", "text": "## Understand Mock Runtimes\n\nA mock runtime is a minimal implementation of the runtime environment that:\n\n- Simulates blockchain state to provide storage and state management.\n- Satisfies your pallet's `Config` trait requirements.\n- Allows isolated testing without external dependencies.\n- Supports genesis configuration to set initial blockchain state for tests.\n- Provides instant feedback on code changes for a faster development cycle.\n\nMock runtimes are used exclusively for testing and are never deployed to a live blockchain."} +{"page_id": "parachains-customize-runtime-pallet-development-mock-runtime", "page_title": "Mock Your Runtime", "index": 3, "depth": 2, "title": "Create the Mock Runtime Module", "anchor": "create-the-mock-runtime-module", "start_char": 1737, "end_char": 2478, "estimated_token_count": 200, "token_estimator": "heuristic-v1", "text": "## Create the Mock Runtime Module\n\nStart by creating a new module file within your pallet to house the mock runtime code.\n\n1. Navigate to your pallet directory:\n\n ```bash\n cd pallets/pallet-custom/src\n ```\n\n2. Create a new file named `mock.rs`:\n\n ```bash\n touch mock.rs\n ```\n\n3. Next, open `src/lib.rs` and add the mock module declaration at the top of the file, right after the `pub use pallet::*;` line:\n\n ```rust title=\"src/lib.rs\"\n #![cfg_attr(not(feature = \"std\"), no_std)]\n\n pub use pallet::*;\n\n #[cfg(test)]\n mod mock;\n\n #[frame::pallet]\n pub mod pallet {\n // ... existing pallet code\n }\n\n ```\n\n The `#[cfg(test)]` attribute ensures this module is only compiled during testing."} +{"page_id": "parachains-customize-runtime-pallet-development-mock-runtime", "page_title": "Mock Your Runtime", "index": 4, "depth": 2, "title": "Set Up Basic Mock", "anchor": "set-up-basic-mock", "start_char": 2478, "end_char": 3554, "estimated_token_count": 253, "token_estimator": "heuristic-v1", "text": "## Set Up Basic Mock\n\nOpen `src/mock.rs` and add the foundational imports and type definitions:\n\n```rust title=\"src/mock.rs\"\nuse crate as pallet_custom;\nuse frame::{\n deps::{\n frame_support::{ derive_impl, traits::ConstU32 },\n sp_io,\n sp_runtime::{ traits::IdentityLookup, BuildStorage },\n },\n prelude::*,\n};\n\ntype Block = frame_system::mocking::MockBlock;\n\n// Configure a mock runtime to test the pallet.\nframe::deps::frame_support::construct_runtime!(\n pub enum Test\n {\n System: frame_system,\n CustomPallet: pallet_custom,\n }\n );\n```\n\nThe preceding code includes the following key components: \n\n- **[`construct_runtime!`](https://paritytech.github.io/polkadot-sdk/master/polkadot_sdk_frame/runtime/apis/trait.ConstructRuntimeApi.html#tymethod.construct_runtime_api){target=\\_blank}**: Macro that builds a minimal runtime with only the pallets needed for testing.\n- **`Test`**: The mock runtime type used in tests.\n- **`Block`**: Type alias for the mock block type that the runtime will use."} +{"page_id": "parachains-customize-runtime-pallet-development-mock-runtime", "page_title": "Mock Your Runtime", "index": 5, "depth": 2, "title": "Implement Essential Configuration", "anchor": "implement-essential-configuration", "start_char": 3554, "end_char": 4653, "estimated_token_count": 243, "token_estimator": "heuristic-v1", "text": "## Implement Essential Configuration\n\nThe [`frame_system`](https://paritytech.github.io/polkadot-sdk/master/frame_system/index.html){target=\\_blank} pallet provides core blockchain functionality and is required by all other pallets. Configure it for the test environment as follows:\n\n```rust title=\"src/mock.rs\"\n#[derive_impl(frame_system::config_preludes::TestDefaultConfig)]\nimpl frame_system::Config for Test {\n type Block = Block;\n type AccountId = u64;\n type Lookup = IdentityLookup;\n}\n```\n\nThis simplified configuration for testing includes the following:\n\n- **`#[derive_impl]`**: Automatically provides sensible test defaults for most `frame_system::Config` types.\n- **`AccountId = u64`**: Uses simple integers instead of cryptographic account IDs.\n- **`Lookup = IdentityLookup`**: Direct account ID mapping (no address conversion).\n- **`Block = Block`**: Uses the mock block type we defined earlier.\n\nThis approach is much more concise than manually specifying every configuration type, as the `TestDefaultConfig` preset provides appropriate defaults for testing."} +{"page_id": "parachains-customize-runtime-pallet-development-mock-runtime", "page_title": "Mock Your Runtime", "index": 6, "depth": 2, "title": "Implement Your Pallet's Configuration", "anchor": "implement-your-pallets-configuration", "start_char": 4653, "end_char": 5328, "estimated_token_count": 149, "token_estimator": "heuristic-v1", "text": "## Implement Your Pallet's Configuration\n\nNow implement the `Config` trait for your custom pallet. This trait must match the one defined in your pallet's `src/lib.rs`:\n\n```rust title=\"src/mock.rs\"\nimpl pallet_custom::Config for Test {\n type RuntimeEvent = RuntimeEvent;\n type CounterMaxValue = ConstU32<1000>;\n}\n```\n\nConfiguration details include:\n\n- **`RuntimeEvent`**: Connects your pallet's events to the mock runtime's event system.\n- **`CounterMaxValue`**: Sets the maximum counter value to 1000, matching the production configuration.\n\nThe configuration here should mirror what you'll use in production unless you specifically need different values for testing."} +{"page_id": "parachains-customize-runtime-pallet-development-mock-runtime", "page_title": "Mock Your Runtime", "index": 7, "depth": 2, "title": "Configure Genesis Storage", "anchor": "configure-genesis-storage", "start_char": 5328, "end_char": 5612, "estimated_token_count": 48, "token_estimator": "heuristic-v1", "text": "## Configure Genesis Storage\n\nGenesis storage defines the initial state of your blockchain before any blocks are produced. Since your counter pallet includes the genesis configuration (added in the previous guide), you can now set up test environments with different initial states."} +{"page_id": "parachains-customize-runtime-pallet-development-mock-runtime", "page_title": "Mock Your Runtime", "index": 8, "depth": 3, "title": "Basic Test Environment", "anchor": "basic-test-environment", "start_char": 5612, "end_char": 6239, "estimated_token_count": 143, "token_estimator": "heuristic-v1", "text": "### Basic Test Environment\n\nCreate a helper function for the default test environment:\n\n```rust title=\"src/mock.rs\"\n// Build genesis storage according to the mock runtime.\npub fn new_test_ext() -> sp_io::TestExternalities {\n let mut t = frame_system::GenesisConfig::::default().build_storage().unwrap();\n\n (pallet_custom::GenesisConfig:: {\n initial_counter_value: 0,\n initial_user_interactions: vec![],\n })\n .assimilate_storage(&mut t)\n .unwrap();\n\n t.into()\n}\n```\n\nThis function creates a clean blockchain state with an initial counter value of 0 and no user interactions."} +{"page_id": "parachains-customize-runtime-pallet-development-mock-runtime", "page_title": "Mock Your Runtime", "index": 9, "depth": 3, "title": "Custom Genesis Configurations", "anchor": "custom-genesis-configurations", "start_char": 6239, "end_char": 7931, "estimated_token_count": 373, "token_estimator": "heuristic-v1", "text": "### Custom Genesis Configurations\n\nFor testing specific scenarios, create additional helper functions with customized genesis states:\n\n```rust title=\"src/mock.rs\"\n// Helper function to create a test externalities with a specific initial counter value\npub fn new_test_ext_with_counter(initial_value: u32) -> sp_io::TestExternalities {\n let mut t = frame_system::GenesisConfig::::default().build_storage().unwrap();\n\n (pallet_custom::GenesisConfig:: {\n initial_counter_value: initial_value,\n initial_user_interactions: vec![],\n })\n .assimilate_storage(&mut t)\n .unwrap();\n\n t.into()\n}\n\n// Helper function to create a test externalities with initial user interactions\npub fn new_test_ext_with_interactions(\n initial_value: u32,\n interactions: Vec<(u64, u32)>\n) -> sp_io::TestExternalities {\n let mut t = frame_system::GenesisConfig::::default().build_storage().unwrap();\n\n (pallet_custom::GenesisConfig:: {\n initial_counter_value: initial_value,\n initial_user_interactions: interactions,\n })\n .assimilate_storage(&mut t)\n .unwrap();\n\n t.into()\n}\n```\n\nKey methods used in this step include:\n\n- **[`BuildStorage::build_storage()`](https://paritytech.github.io/polkadot-sdk/master/sp_runtime/trait.BuildStorage.html#method.build_storage){target=\\_blank}**: Creates the initial storage state.\n- **[`assimilate_storage`](https://paritytech.github.io/polkadot-sdk/master/sp_runtime/trait.BuildStorage.html#method.assimilate_storage){target=\\_blank}**: Merges pallet genesis config into the existing storage.\n\nYou can chain multiple `assimilate_storage` calls to configure multiple pallets."} +{"page_id": "parachains-customize-runtime-pallet-development-mock-runtime", "page_title": "Mock Your Runtime", "index": 10, "depth": 2, "title": "Verify Mock Compilation", "anchor": "verify-mock-compilation", "start_char": 7931, "end_char": 10853, "estimated_token_count": 564, "token_estimator": "heuristic-v1", "text": "## Verify Mock Compilation\n\nBefore proceeding to write tests, ensure your mock runtime compiles correctly:\n\n```bash\ncargo test --package pallet-custom --lib\n```\n\nThis command compiles the test code (including the mock and genesis configuration) without running tests yet. Address any compilation errors before continuing.\n\n??? code \"Complete mock runtime script\"\n\n Here's the complete `mock.rs` file for reference:\n\n ```rust title=\"src/mock.rs\"\n use crate as pallet_custom;\n use frame::{\n deps::{\n frame_support::{ derive_impl, traits::ConstU32 },\n sp_io,\n sp_runtime::{ traits::IdentityLookup, BuildStorage },\n },\n prelude::*,\n };\n\n type Block = frame_system::mocking::MockBlock;\n\n // Configure a mock runtime to test the pallet.\n frame::deps::frame_support::construct_runtime!(\n pub enum Test\n {\n System: frame_system,\n CustomPallet: pallet_custom,\n }\n );\n\n #[derive_impl(frame_system::config_preludes::TestDefaultConfig)]\n impl frame_system::Config for Test {\n type Block = Block;\n type AccountId = u64;\n type Lookup = IdentityLookup;\n }\n\n impl pallet_custom::Config for Test {\n type RuntimeEvent = RuntimeEvent;\n type CounterMaxValue = ConstU32<1000>;\n }\n\n // Build genesis storage according to the mock runtime.\n pub fn new_test_ext() -> sp_io::TestExternalities {\n let mut t = frame_system::GenesisConfig::::default().build_storage().unwrap();\n\n (pallet_custom::GenesisConfig:: {\n initial_counter_value: 0,\n initial_user_interactions: vec![],\n })\n .assimilate_storage(&mut t)\n .unwrap();\n\n t.into()\n }\n\n // Helper function to create a test externalities with a specific initial counter value\n pub fn new_test_ext_with_counter(initial_value: u32) -> sp_io::TestExternalities {\n let mut t = frame_system::GenesisConfig::::default().build_storage().unwrap();\n\n (pallet_custom::GenesisConfig:: {\n initial_counter_value: initial_value,\n initial_user_interactions: vec![],\n })\n .assimilate_storage(&mut t)\n .unwrap();\n\n t.into()\n }\n\n // Helper function to create a test externalities with initial user interactions\n pub fn new_test_ext_with_interactions(\n initial_value: u32,\n interactions: Vec<(u64, u32)>\n ) -> sp_io::TestExternalities {\n let mut t = frame_system::GenesisConfig::::default().build_storage().unwrap();\n\n (pallet_custom::GenesisConfig:: {\n initial_counter_value: initial_value,\n initial_user_interactions: interactions,\n })\n .assimilate_storage(&mut t)\n .unwrap();\n\n t.into()\n }\n ```"} +{"page_id": "parachains-customize-runtime-pallet-development-mock-runtime", "page_title": "Mock Your Runtime", "index": 11, "depth": 2, "title": "Key Takeaways", "anchor": "key-takeaways", "start_char": 10853, "end_char": 11416, "estimated_token_count": 98, "token_estimator": "heuristic-v1", "text": "## Key Takeaways\n\nYou've successfully created a mock runtime with a genesis configuration for your custom pallet. You can now:\n\n- Test your pallet without a full runtime.\n- Set initial blockchain state for different test scenarios.\n- Create different genesis setups for various testing needs.\n- Use this minimal setup to test all pallet functionality.\n\nThe mock runtime with a genesis configuration is essential for test-driven development, enabling you to verify logic under different initial conditions before integrating it into the actual parachain runtime."} +{"page_id": "parachains-customize-runtime-pallet-development-mock-runtime", "page_title": "Mock Your Runtime", "index": 12, "depth": 2, "title": "Where to Go Next", "anchor": "where-to-go-next", "start_char": 11416, "end_char": 11766, "estimated_token_count": 87, "token_estimator": "heuristic-v1", "text": "## Where to Go Next\n\n
\n\n- Guide __Pallet Unit Testing__\n\n ---\n\n Learn to write comprehensive unit tests for your pallet using the mock runtime you just created.\n\n [:octicons-arrow-right-24: Continue](/parachains/customize-runtime/pallet-development/pallet-testing/)\n\n
"} {"page_id": "parachains-customize-runtime-pallet-development-pallet-testing", "page_title": "Pallet Testing", "index": 0, "depth": 2, "title": "Introduction", "anchor": "introduction", "start_char": 18, "end_char": 672, "estimated_token_count": 123, "token_estimator": "heuristic-v1", "text": "## Introduction\n\nUnit testing in the Polkadot SDK helps ensure that the functions provided by a pallet behave as expected. It also confirms that data and events associated with a pallet are processed correctly during interactions. The Polkadot SDK offers a set of APIs to create a test environment to simulate runtime and mock transaction execution for extrinsics and queries.\n\nTo begin unit testing, you must first set up a mock runtime that simulates blockchain behavior, incorporating the necessary pallets. For a deeper understanding, consult the [Mock Runtime](/parachains/customize-runtime/pallet-development/mock-runtime/){target=\\_blank} guide."} {"page_id": "parachains-customize-runtime-pallet-development-pallet-testing", "page_title": "Pallet Testing", "index": 1, "depth": 2, "title": "Writing Unit Tests", "anchor": "writing-unit-tests", "start_char": 672, "end_char": 2195, "estimated_token_count": 285, "token_estimator": "heuristic-v1", "text": "## Writing Unit Tests\n\nOnce the mock runtime is in place, the next step is to write unit tests that evaluate the functionality of your pallet. Unit tests allow you to test specific pallet features in isolation, ensuring that each function behaves correctly under various conditions. These tests typically reside in your pallet module's `test.rs` file.\n\nUnit tests in the Polkadot SDK use the Rust testing framework, and the mock runtime you've defined earlier will serve as the test environment. Below are the typical steps involved in writing unit tests for a pallet.\n\nThe tests confirm that:\n\n- **Pallets initialize correctly**: At the start of each test, the system should initialize with block number 0, and the pallets should be in their default states.\n- **Pallets modify each other's state**: The second test shows how one pallet can trigger changes in another pallet's internal state, confirming proper cross-pallet interactions.\n- **State transitions between blocks are seamless**: By simulating block transitions, the tests validate that the runtime responds correctly to changes in the block number.\n\nTesting pallet interactions within the runtime is critical for ensuring the blockchain behaves as expected under real-world conditions. Writing integration tests allows validation of how pallets function together, preventing issues that might arise when the system is fully assembled.\n\nThis approach provides a comprehensive view of the runtime's functionality, ensuring the blockchain is stable and reliable."} {"page_id": "parachains-customize-runtime-pallet-development-pallet-testing", "page_title": "Pallet Testing", "index": 2, "depth": 3, "title": "Test Initialization", "anchor": "test-initialization", "start_char": 2195, "end_char": 2507, "estimated_token_count": 68, "token_estimator": "heuristic-v1", "text": "### Test Initialization\n\nEach test starts by initializing the runtime environment, typically using the `new_test_ext()` function, which sets up the mock storage and environment.\n\n```rust\n#[test]\nfn test_pallet_functionality() {\n new_test_ext().execute_with(|| {\n // Test logic goes here\n });\n}\n```"} @@ -1454,12 +1454,13 @@ {"page_id": "smart-contracts-for-eth-devs-contract-deployment", "page_title": "Contract Deployment", "index": 9, "depth": 2, "title": "Gas Estimation vs Actual Consumption", "anchor": "gas-estimation-vs-actual-consumption", "start_char": 4457, "end_char": 5006, "estimated_token_count": 85, "token_estimator": "heuristic-v1", "text": "## Gas Estimation vs Actual Consumption\n\nBoth REVM and PolkaVM deployments may show significant differences between gas estimation and actual consumption. You might see estimates that are several times higher than the actual gas consumed (often around 30% of the estimate). This is normal behavior because pre-dispatch estimation cannot distinguish between computation weight and storage deposits, leading to conservative overestimation. Contract deployments are particularly affected as they consume significant storage deposits for code storage."} {"page_id": "smart-contracts-for-eth-devs-contract-deployment", "page_title": "Contract Deployment", "index": 10, "depth": 2, "title": "Deployment Comparison", "anchor": "deployment-comparison", "start_char": 5006, "end_char": 5561, "estimated_token_count": 158, "token_estimator": "heuristic-v1", "text": "## Deployment Comparison\n\n| Feature | REVM Backend | PolkaVM Backend |\n|:-------:|:-------------:|:----------------:|\n| **Deployment Model** | Single-step bundled | Two-step upload and instantiate |\n| **Factory Patterns** | Direct runtime creation | Requires pre-uploaded code |\n| **Code Bundling** | Bytecode in transaction | Code hash references |\n| **Runtime Codegen** | Fully supported | Not supported |\n| **Simple Contracts** | No modifications needed | No modifications needed |\n| **Assembly Creation** | Supported | Discouraged, limited support |"} {"page_id": "smart-contracts-for-eth-devs-contract-deployment", "page_title": "Contract Deployment", "index": 11, "depth": 2, "title": "Conclusion", "anchor": "conclusion", "start_char": 5561, "end_char": 5999, "estimated_token_count": 69, "token_estimator": "heuristic-v1", "text": "## Conclusion\n\nBoth backends support contract deployment effectively, with REVM offering drop-in Ethereum compatibility and PolkaVM providing a more structured two-step approach. For the majority of use cases—deploying standard contracts like tokens or applications—both backends work seamlessly. Advanced patterns like factory contracts may require adjustment for PolkaVM, but these adaptations are straightforward with proper planning."} -{"page_id": "smart-contracts-for-eth-devs-dual-vm-stack", "page_title": "PolkaVM Design", "index": 0, "depth": 2, "title": "Introduction", "anchor": "introduction", "start_char": 188, "end_char": 480, "estimated_token_count": 40, "token_estimator": "heuristic-v1", "text": "## Introduction\n\nThe Asset Hub smart contracts solution includes multiple components to ensure Ethereum compatibility and high performance. Its architecture allows for integration with current Ethereum tools, while its innovative virtual machine design enhances performance characteristics."} -{"page_id": "smart-contracts-for-eth-devs-dual-vm-stack", "page_title": "PolkaVM Design", "index": 1, "depth": 2, "title": "PolkaVM", "anchor": "polkavm", "start_char": 480, "end_char": 1366, "estimated_token_count": 172, "token_estimator": "heuristic-v1", "text": "## PolkaVM\n\n[**PolkaVM**](https://github.com/paritytech/polkavm){target=\\_blank} is a custom virtual machine optimized for performance with [RISC-V-based](https://en.wikipedia.org/wiki/RISC-V){target=\\_blank} architecture, supporting Solidity and additional high-performance languages. It serves as the core execution environment, integrated directly within the runtime. It features:\n\n- An efficient interpreter for immediate code execution.\n- A planned JIT compiler for optimized performance.\n- Dual-mode execution capability, allowing selection of the most appropriate backend for specific workloads.\n- Optimized performance for short-running contract calls through the interpreter.\n\nThe interpreter remains particularly beneficial for contracts with minimal code execution, as it eliminates JIT compilation overhead and enables immediate code execution through lazy interpretation."} -{"page_id": "smart-contracts-for-eth-devs-dual-vm-stack", "page_title": "PolkaVM Design", "index": 2, "depth": 2, "title": "Architecture", "anchor": "architecture", "start_char": 1366, "end_char": 1531, "estimated_token_count": 26, "token_estimator": "heuristic-v1", "text": "## Architecture\n\nThe smart contract solution consists of the following key components that work together to enable Ethereum compatibility on Polkadot-based chains."} -{"page_id": "smart-contracts-for-eth-devs-dual-vm-stack", "page_title": "PolkaVM Design", "index": 3, "depth": 3, "title": "Pallet Revive", "anchor": "pallet-revive", "start_char": 1531, "end_char": 2801, "estimated_token_count": 230, "token_estimator": "heuristic-v1", "text": "### Pallet Revive\n\n[**`pallet_revive`**](https://paritytech.github.io/polkadot-sdk/master/pallet_revive/index.html){target=\\_blank} is a runtime module that executes smart contracts by adding extrinsics, runtime APIs, and logic to convert Ethereum-style transactions into formats compatible with Polkadot SDK-based blockchains. It processes Ethereum-style transactions through the following workflow:\n\n```mermaid\nsequenceDiagram\n participant User as User/dApp\n participant Proxy as Ethereum JSON RPC Proxy\n participant Chain as Blockchain Node\n participant Pallet as pallet_revive\n \n User->>Proxy: Submit Ethereum Transaction\n Proxy->>Chain: Repackage as Polkadot Compatible Transaction\n Chain->>Pallet: Process Transaction\n Pallet->>Pallet: Decode Ethereum Transaction\n Pallet->>Pallet: Execute Contract via PolkaVM\n Pallet->>Chain: Return Results\n Chain->>Proxy: Forward Results\n Proxy->>User: Return Ethereum-compatible Response\n```\n\nThis proxy-based approach eliminates the need for node binary modifications, maintaining compatibility across different client implementations. Preserving the original Ethereum transaction payload simplifies adapting existing tools, which can continue processing familiar transaction formats."} -{"page_id": "smart-contracts-for-eth-devs-dual-vm-stack", "page_title": "PolkaVM Design", "index": 4, "depth": 3, "title": "PolkaVM Design Fundamentals", "anchor": "polkavm-design-fundamentals", "start_char": 2801, "end_char": 4302, "estimated_token_count": 258, "token_estimator": "heuristic-v1", "text": "### PolkaVM Design Fundamentals\n\nPolkaVM introduces two fundamental architectural differences compared to the Ethereum Virtual Machine (EVM):\n\n```mermaid\nflowchart TB\n subgraph \"EVM Architecture\"\n EVMStack[Stack-Based]\n EVM256[256-bit Word Size]\n end\n \n subgraph \"PolkaVM Architecture\"\n PVMReg[Register-Based]\n PVM64[64-bit Word Size]\n end\n```\n\n- **Register-based design**: PolkaVM utilizes a RISC-V register-based approach. This design:\n\n - Employs a finite set of registers for argument passing instead of an infinite stack.\n - Facilitates efficient translation to underlying hardware architectures.\n - Optimizes register allocation through careful register count selection.\n - Enables simple 1:1 mapping to x86-64 instruction sets.\n - Reduces compilation complexity through strategic register limitation.\n - Improves overall execution performance through hardware-aligned design.\n\n- **64-bit word size**: PolkaVM operates with a 64-bit word size. This design:\n\n - Enables direct hardware-supported arithmetic operations.\n - Maintains compatibility with Solidity's 256-bit operations through YUL translation.\n - Allows integration of performance-critical components written in lower-level languages.\n - Optimizes computation-intensive operations through native word size alignment.\n - Reduces overhead for operations not requiring extended precision.\n - Facilitates efficient integration with modern CPU architectures."} -{"page_id": "smart-contracts-for-eth-devs-dual-vm-stack", "page_title": "PolkaVM Design", "index": 5, "depth": 2, "title": "Compilation Process", "anchor": "compilation-process", "start_char": 4302, "end_char": 5334, "estimated_token_count": 268, "token_estimator": "heuristic-v1", "text": "## Compilation Process\n\nWhen compiling a Solidity smart contract, the code passes through the following stages:\n\n```mermaid\nflowchart LR\n Dev[Developer] --> |Solidity
Source
Code| Solc\n \n subgraph \"Compilation Process\"\n direction LR\n Solc[solc] --> |YUL
IR| Revive\n Revive[Revive Compiler] --> |LLVM
IR| LLVM\n LLVM[LLVM
Optimizer] --> |RISC-V ELF
Shared Object| PVMLinker\n end\n \n PVMLinker[PVM Linker] --> PVM[PVM Blob
with Metadata]\n```\n\nThe compilation process integrates several specialized components:\n\n1. **Solc**: The standard Ethereum Solidity compiler that translates Solidity source code to [YUL IR](https://docs.soliditylang.org/en/latest/yul.html){target=\\_blank}.\n2. **Revive Compiler**: Takes YUL IR and transforms it to [LLVM IR](https://llvm.org/){target=\\_blank}.\n3. **LLVM**: A compiler infrastructure that optimizes the code and generates RISC-V ELF objects.\n4. **PVM linker**: Links the RISC-V ELF object into a final PolkaVM blob with metadata."} +{"page_id": "smart-contracts-for-eth-devs-dual-vm-stack", "page_title": "Dual Virtual Machine Stack", "index": 0, "depth": 2, "title": "Introduction", "anchor": "introduction", "start_char": 200, "end_char": 921, "estimated_token_count": 118, "token_estimator": "heuristic-v1", "text": "## Introduction\n\nPolkadot's smart contract platform supports two distinct virtual machine (VM) architectures, providing developers with flexibility in selecting the optimal execution backend for their specific needs. This approach strikes a balance between immediate Ethereum compatibility and long-term innovation, enabling developers to deploy either unmodified (Ethereum Virtual Machine) EVM contracts using Rust Ethereum Virtual Machine (REVM) or optimize for higher performance using PolkaVM (PVM).\n\nBoth VM options share common infrastructure, including RPC interfaces, tooling support, and precompiles. The following sections compare architectures and guide you in selecting the best VM for your project's needs."} +{"page_id": "smart-contracts-for-eth-devs-dual-vm-stack", "page_title": "Dual Virtual Machine Stack", "index": 1, "depth": 2, "title": "Migrate from EVM", "anchor": "migrate-from-evm", "start_char": 921, "end_char": 1755, "estimated_token_count": 145, "token_estimator": "heuristic-v1", "text": "## Migrate from EVM\n\nThe [REVM backend](https://github.com/bluealloy/revm){target=\\_blank} integrates a complete Rust implementation of the EVM, enabling Solidity contracts to run unchanged on Polkadot's smart contract platform.\n\nREVM allows developers to use their existing Ethereum tooling and infrastructure to build on Polkadot. Choose REVM to:\n\n- Migrate existing Ethereum contracts without modifications.\n- Retain exact EVM behavior for audit tools. \n- Use developer tools that rely upon inspecting EVM bytecode.\n- Prioritize rapid deployment over optimization.\n- Work with established Ethereum infrastructure and tooling to build on Polkadot.\n\nREVM enables Ethereum developers to seamlessly migrate to Polkadot, achieving performance and fee improvements without modifying their existing contracts or developer tooling stack."} +{"page_id": "smart-contracts-for-eth-devs-dual-vm-stack", "page_title": "Dual Virtual Machine Stack", "index": 2, "depth": 2, "title": "Upgrade to PolkaVM", "anchor": "upgrade-to-polkavm", "start_char": 1755, "end_char": 2712, "estimated_token_count": 203, "token_estimator": "heuristic-v1", "text": "## Upgrade to PolkaVM\n\n[**PolkaVM**](https://github.com/paritytech/polkavm){target=\\_blank} is a custom virtual machine optimized for performance with [RISC-V-based](https://en.wikipedia.org/wiki/RISC-V){target=\\_blank} architecture, supporting Solidity and additional high-performance languages. It serves as the core execution environment, integrated directly within the runtime. Choose the PolkaVM for:\n\n- An efficient interpreter for immediate code execution.\n- A planned [Just In Time (JIT)](https://en.wikipedia.org/wiki/Just-in-time_compilation){target=\\_blank} compiler for optimized performance.\n- Dual-mode execution capability, allowing selection of the most appropriate backend for specific workloads.\n- Optimized performance for short-running contract calls through the interpreter.\n\nThe interpreter remains particularly beneficial for contracts with minimal code execution, as it enables immediate code execution through lazy interpretation."} +{"page_id": "smart-contracts-for-eth-devs-dual-vm-stack", "page_title": "Dual Virtual Machine Stack", "index": 3, "depth": 2, "title": "Architecture", "anchor": "architecture", "start_char": 2712, "end_char": 2844, "estimated_token_count": 21, "token_estimator": "heuristic-v1", "text": "## Architecture\n\nThe following key components of PolkaVM work together to enable Ethereum compatibility on Polkadot-based chains."} +{"page_id": "smart-contracts-for-eth-devs-dual-vm-stack", "page_title": "Dual Virtual Machine Stack", "index": 4, "depth": 3, "title": "Revive Pallet", "anchor": "revive-pallet", "start_char": 2844, "end_char": 4123, "estimated_token_count": 232, "token_estimator": "heuristic-v1", "text": "### Revive Pallet\n\n[**`pallet_revive`**](https://paritytech.github.io/polkadot-sdk/master/pallet_revive/index.html){target=\\_blank} is a runtime module that executes smart contracts by adding extrinsics, runtime APIs, and logic to convert Ethereum-style transactions into formats compatible with Polkadot SDK-based blockchains. It processes Ethereum-style transactions through the following workflow:\n\n```mermaid\nsequenceDiagram\n participant User as User/dApp\n participant Proxy as Ethereum JSON RPC Proxy\n participant Chain as Blockchain Node\n participant Pallet as pallet_revive\n \n User->>Proxy: Submit Ethereum Transaction\n Proxy->>Chain: Repackage as Polkadot Compatible Transaction\n Chain->>Pallet: Process Transaction\n Pallet->>Pallet: Decode Ethereum Transaction\n Pallet->>Pallet: Execute Contract via PolkaVM\n Pallet->>Chain: Return Results\n Chain->>Proxy: Forward Results\n Proxy->>User: Return Ethereum-compatible Response\n```\n\nThis proxy-based approach eliminates the need for node binary modifications, maintaining compatibility across different client implementations. Preserving the original Ethereum transaction payload simplifies the adaptation of existing tools, which can continue processing familiar transaction formats."} +{"page_id": "smart-contracts-for-eth-devs-dual-vm-stack", "page_title": "Dual Virtual Machine Stack", "index": 5, "depth": 3, "title": "PolkaVM Design Fundamentals", "anchor": "polkavm-design-fundamentals", "start_char": 4123, "end_char": 5067, "estimated_token_count": 185, "token_estimator": "heuristic-v1", "text": "### PolkaVM Design Fundamentals\n\nPolkaVM differs from the EVM in two key ways that make it faster, more hardware-efficient, and easier to extend:\n\n- **Register-based design**: Instead of a stack machine, PolkaVM uses a RISC-V–style register model. This design:\n\n - Uses a fixed set of registers to pass arguments, not an infinite stack.\n - Maps cleanly to real hardware like x86-64.\n - Simplifies compilation and boosts runtime efficiency.\n - Enables tighter control over register allocation and performance tuning.\n\n- **64-bit word size**: PolkaVM runs on a native 64-bit word size, aligning directly with modern CPUs. This design:\n\n - Executes arithmetic operations with direct hardware support.\n - Maintains compatibility with Solidity’s 256-bit types via YUL translation.\n - Accelerates computation-heavy workloads through native word alignment.\n - Integrates easily with low-level, performance-focused components."} +{"page_id": "smart-contracts-for-eth-devs-dual-vm-stack", "page_title": "Dual Virtual Machine Stack", "index": 6, "depth": 2, "title": "Where To Go Next", "anchor": "where-to-go-next", "start_char": 5067, "end_char": 5383, "estimated_token_count": 82, "token_estimator": "heuristic-v1", "text": "## Where To Go Next\n\n
\n\n- Learn __Contract Deployment__\n\n ---\n\n Learn how REVM and PVM compare for compiling and deploying smart contracts.\n\n [:octicons-arrow-right-24: Reference](/smart-contracts/for-eth-devs/contract-deployment/)\n\n
"} {"page_id": "smart-contracts-for-eth-devs-gas-model", "page_title": "Gas Model on the Polkadot Hub", "index": 0, "depth": 2, "title": "Overview", "anchor": "overview", "start_char": 13, "end_char": 290, "estimated_token_count": 49, "token_estimator": "heuristic-v1", "text": "## Overview\n\nThe Polkadot Hub implements a gas model that bridges Ethereum's familiar gas concept with Polkadot's more sophisticated resource metering system. This page explains how gas works in the Polkadot Hub and what developers need to know when building smart contracts."} {"page_id": "smart-contracts-for-eth-devs-gas-model", "page_title": "Gas Model on the Polkadot Hub", "index": 1, "depth": 2, "title": "Understanding Resources in the Polkadot Hub", "anchor": "understanding-resources-in-the-polkadot-hub", "start_char": 290, "end_char": 1290, "estimated_token_count": 189, "token_estimator": "heuristic-v1", "text": "## Understanding Resources in the Polkadot Hub\n\nUnlike Ethereum, which uses a single gas value to measure everything, the Polkadot Hub tracks three separate resources:\n\n- **`ref_time`**: Measures computational time. It is the closest equivalent to traditional gas and represents the amount of CPU time your contract execution consumes.\n- **`proof_size`**: Measures the amount of state data that validators need to verify. When your contract reads from storage or makes state queries, this metric tracks the size of the proofs needed to validate those operations.\n- **`storage_deposit`**: Is a native balance that gets temporarily locked when your contract creates new storage entries. This prevents state bloat by requiring contracts to pay for the storage they use. The deposit is returned when the storage is freed.\n\nFor Ethereum wallet compatibility, the Polkadot Hub's RPC layer automatically maps these three dimensions into a single gas value that wallets can understand and display to users."} {"page_id": "smart-contracts-for-eth-devs-gas-model", "page_title": "Gas Model on the Polkadot Hub", "index": 2, "depth": 2, "title": "Gas vs Weight", "anchor": "gas-vs-weight", "start_char": 1290, "end_char": 1706, "estimated_token_count": 80, "token_estimator": "heuristic-v1", "text": "## Gas vs Weight\n\nWhen you interact with the Polkadot Hub through an Ethereum wallet, you see familiar gas values. Under the hood, the runtime works with `weight` - a two-dimensional metric that combines `ref_time` and `proof_size`.\n\nThe system continuously translates between these representations: converting `weight` to gas when estimating costs, and converting gas back to `weight` when executing transactions."} diff --git a/llms.txt b/llms.txt index dbdec65d9..0388f51af 100644 --- a/llms.txt +++ b/llms.txt @@ -55,7 +55,7 @@ Docs: Basics - [Accounts in Asset Hub Smart Contracts](https://raw.githubusercontent.com/polkadot-developers/polkadot-docs/master/.ai/pages/smart-contracts-for-eth-devs-accounts.md): Bridges Ethereum's 20-byte addresses with Polkadot's 32-byte accounts, enabling seamless interaction while maintaining compatibility with Ethereum tooling. - [Transactions and Fees on Asset Hub](https://raw.githubusercontent.com/polkadot-developers/polkadot-docs/master/.ai/pages/smart-contracts-for-eth-devs-blocks-transactions-fees.md): Explore how Asset Hub smart contracts handle blocks, transactions, and fees with EVM compatibility, supporting various Ethereum transaction types. - [Contract Deployment](https://raw.githubusercontent.com/polkadot-developers/polkadot-docs/master/.ai/pages/smart-contracts-for-eth-devs-contract-deployment.md): Compare deployment flows for REVM and PVM-based smart contracts on the Polkadot Hub. Includes single-step REVM flows and PVM’s two-step deployment model. -- [PolkaVM Design](https://raw.githubusercontent.com/polkadot-developers/polkadot-docs/master/.ai/pages/smart-contracts-for-eth-devs-dual-vm-stack.md): Discover PolkaVM, a high-performance smart contract VM for Polkadot, enabling Ethereum compatibility via pallet_revive, Solidity support & optimized execution. +- [Dual Virtual Machine Stack](https://raw.githubusercontent.com/polkadot-developers/polkadot-docs/master/.ai/pages/smart-contracts-for-eth-devs-dual-vm-stack.md): Compare Polkadot’s dual smart contract VMs—REVM for EVM compatibility and PolkaVM for RISC-V performance, flexibility, and efficiency. - [Get Started with Smart Contracts](https://raw.githubusercontent.com/polkadot-developers/polkadot-docs/master/.ai/pages/smart-contracts-get-started.md): Practical examples for building and deploying smart contracts on Polkadot Hub, from connecting and tooling to deployment, integrations, and precompiles. - [Smart Contracts Overview](https://raw.githubusercontent.com/polkadot-developers/polkadot-docs/master/.ai/pages/smart-contracts-overview.md): Learn about smart contract development capabilities in the Polkadot ecosystem, either by leveraging Polkadot Hub or other alternatives. - [Build a Custom Pallet](https://raw.githubusercontent.com/polkadot-developers/polkadot-docs/master/.ai/pages/tutorials-polkadot-sdk-parachains-zero-to-hero-build-custom-pallet.md): Learn how to build a custom pallet for Polkadot SDK-based blockchains with this step-by-step guide. Create and configure a simple counter pallet from scratch. @@ -122,7 +122,7 @@ Docs: Parachains - [Add Smart Contract Functionality](https://raw.githubusercontent.com/polkadot-developers/polkadot-docs/master/.ai/pages/parachains-customize-runtime-add-smart-contract-functionality.md): Add smart contract capabilities to your Polkadot SDK-based blockchain. Explore EVM and Wasm integration for enhanced chain functionality. - [Add Pallets to the Runtime](https://raw.githubusercontent.com/polkadot-developers/polkadot-docs/master/.ai/pages/parachains-customize-runtime-pallet-development-add-pallet-to-runtime.md): Add pallets to your runtime for custom functionality. Learn to configure and integrate pallets in Polkadot SDK-based blockchains. - [Benchmarking FRAME Pallets](https://raw.githubusercontent.com/polkadot-developers/polkadot-docs/master/.ai/pages/parachains-customize-runtime-pallet-development-benchmark-pallet.md): Learn how to use FRAME's benchmarking framework to measure extrinsic execution costs and provide accurate weights for on-chain computations. -- [Make a Custom Pallet](https://raw.githubusercontent.com/polkadot-developers/polkadot-docs/master/.ai/pages/parachains-customize-runtime-pallet-development-create-a-pallet.md): Learn how to create custom pallets using FRAME, allowing for flexible, modular, and scalable blockchain development. Follow the step-by-step guide. +- [Create a Custom Pallet](https://raw.githubusercontent.com/polkadot-developers/polkadot-docs/master/.ai/pages/parachains-customize-runtime-pallet-development-create-a-pallet.md): Learn how to create custom pallets using FRAME, allowing for flexible, modular, and scalable blockchain development. Follow the step-by-step guide. - [Mock Your Runtime](https://raw.githubusercontent.com/polkadot-developers/polkadot-docs/master/.ai/pages/parachains-customize-runtime-pallet-development-mock-runtime.md): Learn how to create a mock runtime environment for testing your custom pallets in isolation, enabling comprehensive unit testing before runtime integration. - [Pallet Testing](https://raw.githubusercontent.com/polkadot-developers/polkadot-docs/master/.ai/pages/parachains-customize-runtime-pallet-development-pallet-testing.md): Learn how to efficiently test pallets in the Polkadot SDK, ensuring the reliability and security of your pallets operations. - [Overview of FRAME](https://raw.githubusercontent.com/polkadot-developers/polkadot-docs/master/.ai/pages/parachains-customize-runtime.md): Learn how Polkadot SDK’s FRAME framework simplifies blockchain development with modular pallets and support libraries for efficient runtime design. @@ -203,7 +203,7 @@ Docs: Polkadot Protocol - [People Chain](https://raw.githubusercontent.com/polkadot-developers/polkadot-docs/master/.ai/pages/reference-polkadot-hub-people-and-identity.md): Learn how People chain secures decentralized identity management, empowering users to control and verify digital identities without central authorities. - [Accounts in Asset Hub Smart Contracts](https://raw.githubusercontent.com/polkadot-developers/polkadot-docs/master/.ai/pages/smart-contracts-for-eth-devs-accounts.md): Bridges Ethereum's 20-byte addresses with Polkadot's 32-byte accounts, enabling seamless interaction while maintaining compatibility with Ethereum tooling. - [Transactions and Fees on Asset Hub](https://raw.githubusercontent.com/polkadot-developers/polkadot-docs/master/.ai/pages/smart-contracts-for-eth-devs-blocks-transactions-fees.md): Explore how Asset Hub smart contracts handle blocks, transactions, and fees with EVM compatibility, supporting various Ethereum transaction types. -- [PolkaVM Design](https://raw.githubusercontent.com/polkadot-developers/polkadot-docs/master/.ai/pages/smart-contracts-for-eth-devs-dual-vm-stack.md): Discover PolkaVM, a high-performance smart contract VM for Polkadot, enabling Ethereum compatibility via pallet_revive, Solidity support & optimized execution. +- [Dual Virtual Machine Stack](https://raw.githubusercontent.com/polkadot-developers/polkadot-docs/master/.ai/pages/smart-contracts-for-eth-devs-dual-vm-stack.md): Compare Polkadot’s dual smart contract VMs—REVM for EVM compatibility and PolkaVM for RISC-V performance, flexibility, and efficiency. Docs: Infrastructure - [Set Up a Bootnode](https://raw.githubusercontent.com/polkadot-developers/polkadot-docs/master/.ai/pages/nodes-and-validators-run-a-node-bootnode.md): Learn how to configure and run a bootnode for Polkadot, including P2P, WS, and secure WSS connections with network key management and proxies. diff --git a/smart-contracts/for-eth-devs/.nav.yml b/smart-contracts/for-eth-devs/.nav.yml index 7cabde08e..95842da4f 100644 --- a/smart-contracts/for-eth-devs/.nav.yml +++ b/smart-contracts/for-eth-devs/.nav.yml @@ -1,5 +1,4 @@ nav: -- 'Dual Virtual Machine Stack': dual-vm-stack.md - 'Accounts': accounts.md - 'Gas Model': gas-model.md - 'Contract Deployment': contract-deployment.md diff --git a/smart-contracts/for-eth-devs/dual-vm-stack.md b/smart-contracts/for-eth-devs/dual-vm-stack.md index fb747b7d7..6f23c4c4f 100644 --- a/smart-contracts/for-eth-devs/dual-vm-stack.md +++ b/smart-contracts/for-eth-devs/dual-vm-stack.md @@ -1,33 +1,49 @@ --- -title: PolkaVM Design -description: Discover PolkaVM, a high-performance smart contract VM for Polkadot, enabling Ethereum compatibility via pallet_revive, Solidity support & optimized execution. +title: Dual Virtual Machine Stack +description: Compare Polkadot’s dual smart contract VMs—REVM for EVM compatibility and PolkaVM for RISC-V performance, flexibility, and efficiency. categories: Basics, Polkadot Protocol --- -# PolkaVM Design +# Dual Virtual Machine Stack --8<-- 'text/smart-contracts/polkaVM-warning.md' ## Introduction -The Asset Hub smart contracts solution includes multiple components to ensure Ethereum compatibility and high performance. Its architecture allows for integration with current Ethereum tools, while its innovative virtual machine design enhances performance characteristics. +Polkadot's smart contract platform supports two distinct virtual machine (VM) architectures, providing developers with flexibility in selecting the optimal execution backend for their specific needs. This approach strikes a balance between immediate Ethereum compatibility and long-term innovation, enabling developers to deploy either unmodified (Ethereum Virtual Machine) EVM contracts using Rust Ethereum Virtual Machine (REVM) or optimize for higher performance using PolkaVM (PVM). -## PolkaVM +Both VM options share common infrastructure, including RPC interfaces, tooling support, and precompiles. The following sections compare architectures and guide you in selecting the best VM for your project's needs. -[**PolkaVM**](https://github.com/paritytech/polkavm){target=\_blank} is a custom virtual machine optimized for performance with [RISC-V-based](https://en.wikipedia.org/wiki/RISC-V){target=\_blank} architecture, supporting Solidity and additional high-performance languages. It serves as the core execution environment, integrated directly within the runtime. It features: +## Migrate from EVM + +The [REVM backend](https://github.com/bluealloy/revm){target=\_blank} integrates a complete Rust implementation of the EVM, enabling Solidity contracts to run unchanged on Polkadot's smart contract platform. + +REVM allows developers to use their existing Ethereum tooling and infrastructure to build on Polkadot. Choose REVM to: + +- Migrate existing Ethereum contracts without modifications. +- Retain exact EVM behavior for audit tools. +- Use developer tools that rely upon inspecting EVM bytecode. +- Prioritize rapid deployment over optimization. +- Work with established Ethereum infrastructure and tooling to build on Polkadot. + +REVM enables Ethereum developers to seamlessly migrate to Polkadot, achieving performance and fee improvements without modifying their existing contracts or developer tooling stack. + +## Upgrade to PolkaVM + +[**PolkaVM**](https://github.com/paritytech/polkavm){target=\_blank} is a custom virtual machine optimized for performance with [RISC-V-based](https://en.wikipedia.org/wiki/RISC-V){target=\_blank} architecture, supporting Solidity and additional high-performance languages. It serves as the core execution environment, integrated directly within the runtime. Choose the PolkaVM for: - An efficient interpreter for immediate code execution. -- A planned JIT compiler for optimized performance. +- A planned [Just In Time (JIT)](https://en.wikipedia.org/wiki/Just-in-time_compilation){target=\_blank} compiler for optimized performance. - Dual-mode execution capability, allowing selection of the most appropriate backend for specific workloads. - Optimized performance for short-running contract calls through the interpreter. -The interpreter remains particularly beneficial for contracts with minimal code execution, as it eliminates JIT compilation overhead and enables immediate code execution through lazy interpretation. +The interpreter remains particularly beneficial for contracts with minimal code execution, as it enables immediate code execution through lazy interpretation. ## Architecture -The smart contract solution consists of the following key components that work together to enable Ethereum compatibility on Polkadot-based chains. +The following key components of PolkaVM work together to enable Ethereum compatibility on Polkadot-based chains. -### Pallet Revive +### Revive Pallet [**`pallet_revive`**](https://paritytech.github.io/polkadot-sdk/master/pallet_revive/index.html){target=\_blank} is a runtime module that executes smart contracts by adding extrinsics, runtime APIs, and logic to convert Ethereum-style transactions into formats compatible with Polkadot SDK-based blockchains. It processes Ethereum-style transactions through the following workflow: @@ -48,64 +64,36 @@ sequenceDiagram Proxy->>User: Return Ethereum-compatible Response ``` -This proxy-based approach eliminates the need for node binary modifications, maintaining compatibility across different client implementations. Preserving the original Ethereum transaction payload simplifies adapting existing tools, which can continue processing familiar transaction formats. +This proxy-based approach eliminates the need for node binary modifications, maintaining compatibility across different client implementations. Preserving the original Ethereum transaction payload simplifies the adaptation of existing tools, which can continue processing familiar transaction formats. ### PolkaVM Design Fundamentals -PolkaVM introduces two fundamental architectural differences compared to the Ethereum Virtual Machine (EVM): +PolkaVM differs from the EVM in two key ways that make it faster, more hardware-efficient, and easier to extend: -```mermaid -flowchart TB - subgraph "EVM Architecture" - EVMStack[Stack-Based] - EVM256[256-bit Word Size] - end - - subgraph "PolkaVM Architecture" - PVMReg[Register-Based] - PVM64[64-bit Word Size] - end -``` +- **Register-based design**: Instead of a stack machine, PolkaVM uses a RISC-V–style register model. This design: -- **Register-based design**: PolkaVM utilizes a RISC-V register-based approach. This design: + - Uses a fixed set of registers to pass arguments, not an infinite stack. + - Maps cleanly to real hardware like x86-64. + - Simplifies compilation and boosts runtime efficiency. + - Enables tighter control over register allocation and performance tuning. - - Employs a finite set of registers for argument passing instead of an infinite stack. - - Facilitates efficient translation to underlying hardware architectures. - - Optimizes register allocation through careful register count selection. - - Enables simple 1:1 mapping to x86-64 instruction sets. - - Reduces compilation complexity through strategic register limitation. - - Improves overall execution performance through hardware-aligned design. +- **64-bit word size**: PolkaVM runs on a native 64-bit word size, aligning directly with modern CPUs. This design: -- **64-bit word size**: PolkaVM operates with a 64-bit word size. This design: + - Executes arithmetic operations with direct hardware support. + - Maintains compatibility with Solidity’s 256-bit types via YUL translation. + - Accelerates computation-heavy workloads through native word alignment. + - Integrates easily with low-level, performance-focused components. - - Enables direct hardware-supported arithmetic operations. - - Maintains compatibility with Solidity's 256-bit operations through YUL translation. - - Allows integration of performance-critical components written in lower-level languages. - - Optimizes computation-intensive operations through native word size alignment. - - Reduces overhead for operations not requiring extended precision. - - Facilitates efficient integration with modern CPU architectures. +## Where To Go Next -## Compilation Process +
-When compiling a Solidity smart contract, the code passes through the following stages: +- Learn __Contract Deployment__ -```mermaid -flowchart LR - Dev[Developer] --> |Solidity
Source
Code| Solc - - subgraph "Compilation Process" - direction LR - Solc[solc] --> |YUL
IR| Revive - Revive[Revive Compiler] --> |LLVM
IR| LLVM - LLVM[LLVM
Optimizer] --> |RISC-V ELF
Shared Object| PVMLinker - end - - PVMLinker[PVM Linker] --> PVM[PVM Blob
with Metadata] -``` + --- + + Learn how REVM and PVM compare for compiling and deploying smart contracts. -The compilation process integrates several specialized components: + [:octicons-arrow-right-24: Reference](/smart-contracts/for-eth-devs/contract-deployment/) -1. **Solc**: The standard Ethereum Solidity compiler that translates Solidity source code to [YUL IR](https://docs.soliditylang.org/en/latest/yul.html){target=\_blank}. -2. **Revive Compiler**: Takes YUL IR and transforms it to [LLVM IR](https://llvm.org/){target=\_blank}. -3. **LLVM**: A compiler infrastructure that optimizes the code and generates RISC-V ELF objects. -4. **PVM linker**: Links the RISC-V ELF object into a final PolkaVM blob with metadata. +