mirror of
https://github.com/pezkuwichain/pwap.git
synced 2026-06-13 07:51:02 +00:00
feat(web): add network subpages and subdomains listing page
- Add /subdomains page listing all 20 PezkuwiChain subdomains - Add Back to Home button to Subdomains page - Create NetworkPage reusable component for network details - Add 7 network subpages: /mainnet, /staging, /testnet, /beta, /alfa, /development, /local - Update ChainSpecs network cards to navigate to network subpages - Add i18n translations for chainSpecs section in en.ts - Add SDK docs with rebranding support (rebrand-rustdoc.cjs) - Add generate-docs-structure.cjs for automatic docs generation - Update shared libs: endpoints, polkadot, wallet, xcm-bridge - Add new token logos: TYR, ZGR, pezkuwi_icon - Add new pages: Explorer, Docs, Wallet, Api, Faucet, Developers, Grants, Wiki, Forum, Telemetry
This commit is contained in:
@@ -0,0 +1,14 @@
|
||||
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `docs/sdk/src/external_resources.rs`."><title>external_resources.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2"href="../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../../static.files/rustdoc-e56847b5.css"><meta name="rustdoc-vars" data-root-path="../../" data-static-root-path="../../static.files/" data-current-crate="pezkuwi_sdk_docs" data-themes="" data-resource-suffix="" data-rustdoc-version="1.91.1 (ed61e7d7e 2025-11-07)" data-channel="1.91.1" data-search-js="search-e256b49e.js" data-stringdex-js="stringdex-c3e638e9.js" data-settings-js="settings-c38705f0.js" ><script src="../../static.files/storage-e2aeef58.js"></script><script defer src="../../static.files/src-script-813739b1.js"></script><script defer src="../../src-files.js"></script><script defer src="../../static.files/main-6dc2a7f3.js"></script><noscript><link rel="stylesheet" href="../../static.files/noscript-263c88ec.css"></noscript><link rel="icon" href="https://pezkuwichain.io/favicon.ico"></head><body class="rustdoc src"><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer" title="Drag to resize sidebar"></div><main><section id="main-content" class="content"><div class="main-heading"><h1><div class="sub-heading">pezkuwi_sdk_docs/</div>external_resources.rs</h1><rustdoc-toolbar></rustdoc-toolbar></div><div class="example-wrap digits-2"><pre class="rust"><code><a href=#1 id=1 data-nosnippet>1</a><span class="doccomment">//! # External Resources
|
||||
<a href=#2 id=2 data-nosnippet>2</a>//!
|
||||
<a href=#3 id=3 data-nosnippet>3</a>//! A non-exhaustive, un-opinionated list of external resources about Pezkuwi SDK.
|
||||
<a href=#4 id=4 data-nosnippet>4</a>//!
|
||||
<a href=#5 id=5 data-nosnippet>5</a>//! Unlike [`crate::guides`], or [`crate::pezkuwi_sdk::templates`] that contain material directly
|
||||
<a href=#6 id=6 data-nosnippet>6</a>//! maintained in the `pezkuwi-sdk` repository, the list of resources here are maintained by
|
||||
<a href=#7 id=7 data-nosnippet>7</a>//! third-parties, and are therefore subject to more variability. Any further resources may be added
|
||||
<a href=#8 id=8 data-nosnippet>8</a>//! by opening a pull request to the `pezkuwi-sdk` repository.
|
||||
<a href=#9 id=9 data-nosnippet>9</a>//!
|
||||
<a href=#10 id=10 data-nosnippet>10</a>//! - [Pezkuwi NFT Marketplace Tutorial by Pezkuwi Fellow Shawn Tabrizi](https://www.shawntabrizi.com/substrate-collectables-workshop/)
|
||||
<a href=#11 id=11 data-nosnippet>11</a>//! - [HEZ Code School](https://dotcodeschool.com/)
|
||||
<a href=#12 id=12 data-nosnippet>12</a>//! - [Pezkuwi Developers Github Organization](https://github.com/pezkuwi-developers/)
|
||||
<a href=#13 id=13 data-nosnippet>13</a>//! - [Pezkuwi Blockchain Academy](https://github.com/pezkuwichain/kurdistan_blockchain-akademy)
|
||||
<a href=#14 id=14 data-nosnippet>14</a>//! - [Pezkuwi Wiki](https://wiki.network.pezkuwichain.io/)</span></code></pre></div></section></main></body></html>
|
||||
@@ -0,0 +1,254 @@
|
||||
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `docs/sdk/src/guides/async_backing_guide.rs`."><title>async_backing_guide.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2"href="../../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../../../static.files/rustdoc-e56847b5.css"><meta name="rustdoc-vars" data-root-path="../../../" data-static-root-path="../../../static.files/" data-current-crate="pezkuwi_sdk_docs" data-themes="" data-resource-suffix="" data-rustdoc-version="1.91.1 (ed61e7d7e 2025-11-07)" data-channel="1.91.1" data-search-js="search-e256b49e.js" data-stringdex-js="stringdex-c3e638e9.js" data-settings-js="settings-c38705f0.js" ><script src="../../../static.files/storage-e2aeef58.js"></script><script defer src="../../../static.files/src-script-813739b1.js"></script><script defer src="../../../src-files.js"></script><script defer src="../../../static.files/main-6dc2a7f3.js"></script><noscript><link rel="stylesheet" href="../../../static.files/noscript-263c88ec.css"></noscript><link rel="icon" href="https://pezkuwichain.io/favicon.ico"></head><body class="rustdoc src"><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer" title="Drag to resize sidebar"></div><main><section id="main-content" class="content"><div class="main-heading"><h1><div class="sub-heading">pezkuwi_sdk_docs/guides/</div>async_backing_guide.rs</h1><rustdoc-toolbar></rustdoc-toolbar></div><div class="example-wrap digits-3"><pre class="rust"><code><a href=#1 id=1 data-nosnippet>1</a><span class="doccomment">//! # Upgrade Teyrchain for Asynchronous Backing Compatibility
|
||||
<a href=#2 id=2 data-nosnippet>2</a>//!
|
||||
<a href=#3 id=3 data-nosnippet>3</a>//! This guide is relevant for cumulus based teyrchain projects started in 2023 or before, whose
|
||||
<a href=#4 id=4 data-nosnippet>4</a>//! backing process is synchronous where parablocks can only be built on the latest Relay Chain
|
||||
<a href=#5 id=5 data-nosnippet>5</a>//! block. Async Backing allows collators to build parablocks on older Relay Chain blocks and create
|
||||
<a href=#6 id=6 data-nosnippet>6</a>//! pipelines of multiple pending parablocks. This parallel block generation increases efficiency
|
||||
<a href=#7 id=7 data-nosnippet>7</a>//! and throughput. For more information on Async backing and its terminology, refer to the document
|
||||
<a href=#8 id=8 data-nosnippet>8</a>//! on [the Pezkuwi SDK docs.](https://docs.pezkuwichain.io/sdk/master/pezkuwi_sdk_docs/guides/async_backing_guide/index.html)
|
||||
<a href=#9 id=9 data-nosnippet>9</a>//!
|
||||
<a href=#10 id=10 data-nosnippet>10</a>//! > If starting a new teyrchain project, please use an async backing compatible template such as
|
||||
<a href=#11 id=11 data-nosnippet>11</a>//! > the
|
||||
<a href=#12 id=12 data-nosnippet>12</a>//! > [teyrchain template](https://github.com/pezkuwichain/pezkuwi-sdk/tree/master/templates/teyrchain).
|
||||
<a href=#13 id=13 data-nosnippet>13</a>//! The rollout process for Async Backing has three phases. Phases 1 and 2 below put new
|
||||
<a href=#14 id=14 data-nosnippet>14</a>//! infrastructure in place. Then we can simply turn on async backing in phase 3.
|
||||
<a href=#15 id=15 data-nosnippet>15</a>//!
|
||||
<a href=#16 id=16 data-nosnippet>16</a>//! ## Prerequisite
|
||||
<a href=#17 id=17 data-nosnippet>17</a>//!
|
||||
<a href=#18 id=18 data-nosnippet>18</a>//! The relay chain needs to have async backing enabled so double-check that the relay-chain
|
||||
<a href=#19 id=19 data-nosnippet>19</a>//! configuration contains the following three parameters (especially when testing locally e.g. with
|
||||
<a href=#20 id=20 data-nosnippet>20</a>//! zombienet):
|
||||
<a href=#21 id=21 data-nosnippet>21</a>//!
|
||||
<a href=#22 id=22 data-nosnippet>22</a>//! ```json
|
||||
<a href=#23 id=23 data-nosnippet>23</a>//! "async_backing_params": {
|
||||
<a href=#24 id=24 data-nosnippet>24</a>//! "max_candidate_depth": 3,
|
||||
<a href=#25 id=25 data-nosnippet>25</a>//! "allowed_ancestry_len": 2
|
||||
<a href=#26 id=26 data-nosnippet>26</a>//! },
|
||||
<a href=#27 id=27 data-nosnippet>27</a>//! "scheduling_lookahead": 2
|
||||
<a href=#28 id=28 data-nosnippet>28</a>//! ```
|
||||
<a href=#29 id=29 data-nosnippet>29</a>//!
|
||||
<a href=#30 id=30 data-nosnippet>30</a>//! <div class="warning"><code>scheduling_lookahead</code> must be set to 2, otherwise teyrchain
|
||||
<a href=#31 id=31 data-nosnippet>31</a>//! block times will degrade to worse than with sync backing!</div>
|
||||
<a href=#32 id=32 data-nosnippet>32</a>//!
|
||||
<a href=#33 id=33 data-nosnippet>33</a>//! ## Phase 1 - Update Teyrchain Runtime
|
||||
<a href=#34 id=34 data-nosnippet>34</a>//!
|
||||
<a href=#35 id=35 data-nosnippet>35</a>//! This phase involves configuring your teyrchain’s runtime `/runtime/src/lib.rs` to make use of
|
||||
<a href=#36 id=36 data-nosnippet>36</a>//! async backing system.
|
||||
<a href=#37 id=37 data-nosnippet>37</a>//!
|
||||
<a href=#38 id=38 data-nosnippet>38</a>//! 1. Establish and ensure constants for `capacity` and `velocity` are both set to 1 in the
|
||||
<a href=#39 id=39 data-nosnippet>39</a>//! runtime.
|
||||
<a href=#40 id=40 data-nosnippet>40</a>//! 2. Establish and ensure the constant relay chain slot duration measured in milliseconds equal to
|
||||
<a href=#41 id=41 data-nosnippet>41</a>//! `6000` in the runtime.
|
||||
<a href=#42 id=42 data-nosnippet>42</a>//! ```rust
|
||||
<a href=#43 id=43 data-nosnippet>43</a>//! // Maximum number of blocks simultaneously accepted by the Runtime, not yet included into the
|
||||
<a href=#44 id=44 data-nosnippet>44</a>//! // relay chain.
|
||||
<a href=#45 id=45 data-nosnippet>45</a>//! pub const UNINCLUDED_SEGMENT_CAPACITY: u32 = 1;
|
||||
<a href=#46 id=46 data-nosnippet>46</a>//! // How many teyrchain blocks are processed by the relay chain per parent. Limits the number of
|
||||
<a href=#47 id=47 data-nosnippet>47</a>//! // blocks authored per slot.
|
||||
<a href=#48 id=48 data-nosnippet>48</a>//! pub const BLOCK_PROCESSING_VELOCITY: u32 = 1;
|
||||
<a href=#49 id=49 data-nosnippet>49</a>//! // Relay chain slot duration, in milliseconds.
|
||||
<a href=#50 id=50 data-nosnippet>50</a>//! pub const RELAY_CHAIN_SLOT_DURATION_MILLIS: u32 = 6000;
|
||||
<a href=#51 id=51 data-nosnippet>51</a>//! ```
|
||||
<a href=#52 id=52 data-nosnippet>52</a>//!
|
||||
<a href=#53 id=53 data-nosnippet>53</a>//! 3. Establish constants `MILLISECS_PER_BLOCK` and `SLOT_DURATION` if not already present in the
|
||||
<a href=#54 id=54 data-nosnippet>54</a>//! runtime.
|
||||
<a href=#55 id=55 data-nosnippet>55</a>//! ```ignore
|
||||
<a href=#56 id=56 data-nosnippet>56</a>//! // `SLOT_DURATION` is picked up by `pallet_timestamp` which is in turn picked
|
||||
<a href=#57 id=57 data-nosnippet>57</a>//! // up by `pallet_aura` to implement `fn slot_duration()`.
|
||||
<a href=#58 id=58 data-nosnippet>58</a>//! //
|
||||
<a href=#59 id=59 data-nosnippet>59</a>//! // Change this to adjust the block time.
|
||||
<a href=#60 id=60 data-nosnippet>60</a>//! pub const MILLISECS_PER_BLOCK: u64 = 12000;
|
||||
<a href=#61 id=61 data-nosnippet>61</a>//! pub const SLOT_DURATION: u64 = MILLISECS_PER_BLOCK;
|
||||
<a href=#62 id=62 data-nosnippet>62</a>//! ```
|
||||
<a href=#63 id=63 data-nosnippet>63</a>//!
|
||||
<a href=#64 id=64 data-nosnippet>64</a>//! 4. Configure `cumulus_pallet_teyrchain_system` in the runtime.
|
||||
<a href=#65 id=65 data-nosnippet>65</a>//!
|
||||
<a href=#66 id=66 data-nosnippet>66</a>//! - Define a `FixedVelocityConsensusHook` using our capacity, velocity, and relay slot duration
|
||||
<a href=#67 id=67 data-nosnippet>67</a>//! constants. Use this to set the teyrchain system `ConsensusHook` property.
|
||||
<a href=#68 id=68 data-nosnippet>68</a></span><span class="attr">#![doc = <span class="macro">docify::embed!</span>(<span class="string">"../../templates/teyrchain/runtime/src/lib.rs"</span>, ConsensusHook)]
|
||||
<a href=#69 id=69 data-nosnippet>69</a></span><span class="doccomment">//! ```ignore
|
||||
<a href=#70 id=70 data-nosnippet>70</a>//! impl cumulus_pallet_teyrchain_system::Config for Runtime {
|
||||
<a href=#71 id=71 data-nosnippet>71</a>//! ..
|
||||
<a href=#72 id=72 data-nosnippet>72</a>//! type ConsensusHook = ConsensusHook;
|
||||
<a href=#73 id=73 data-nosnippet>73</a>//! ..
|
||||
<a href=#74 id=74 data-nosnippet>74</a>//! }
|
||||
<a href=#75 id=75 data-nosnippet>75</a>//! ```
|
||||
<a href=#76 id=76 data-nosnippet>76</a>//! - Set the teyrchain system property `CheckAssociatedRelayNumber` to
|
||||
<a href=#77 id=77 data-nosnippet>77</a>//! `RelayNumberMonotonicallyIncreases`
|
||||
<a href=#78 id=78 data-nosnippet>78</a>//! ```ignore
|
||||
<a href=#79 id=79 data-nosnippet>79</a>//! impl cumulus_pallet_teyrchain_system::Config for Runtime {
|
||||
<a href=#80 id=80 data-nosnippet>80</a>//! ..
|
||||
<a href=#81 id=81 data-nosnippet>81</a>//! type CheckAssociatedRelayNumber = RelayNumberMonotonicallyIncreases;
|
||||
<a href=#82 id=82 data-nosnippet>82</a>//! ..
|
||||
<a href=#83 id=83 data-nosnippet>83</a>//! }
|
||||
<a href=#84 id=84 data-nosnippet>84</a>//! ```
|
||||
<a href=#85 id=85 data-nosnippet>85</a>//!
|
||||
<a href=#86 id=86 data-nosnippet>86</a>//! 5. Configure `pallet_aura` in the runtime.
|
||||
<a href=#87 id=87 data-nosnippet>87</a>//!
|
||||
<a href=#88 id=88 data-nosnippet>88</a>//! - Set `AllowMultipleBlocksPerSlot` to `false` (don't worry, we will set it to `true` when we
|
||||
<a href=#89 id=89 data-nosnippet>89</a>//! activate async backing in phase 3).
|
||||
<a href=#90 id=90 data-nosnippet>90</a>//!
|
||||
<a href=#91 id=91 data-nosnippet>91</a>//! - Define `pallet_aura::SlotDuration` using our constant `SLOT_DURATION`
|
||||
<a href=#92 id=92 data-nosnippet>92</a>//! ```ignore
|
||||
<a href=#93 id=93 data-nosnippet>93</a>//! impl pallet_aura::Config for Runtime {
|
||||
<a href=#94 id=94 data-nosnippet>94</a>//! ..
|
||||
<a href=#95 id=95 data-nosnippet>95</a>//! type AllowMultipleBlocksPerSlot = ConstBool<false>;
|
||||
<a href=#96 id=96 data-nosnippet>96</a>//! #[cfg(feature = "experimental")]
|
||||
<a href=#97 id=97 data-nosnippet>97</a>//! type SlotDuration = ConstU64<SLOT_DURATION>;
|
||||
<a href=#98 id=98 data-nosnippet>98</a>//! ..
|
||||
<a href=#99 id=99 data-nosnippet>99</a>//! }
|
||||
<a href=#100 id=100 data-nosnippet>100</a>//! ```
|
||||
<a href=#101 id=101 data-nosnippet>101</a>//!
|
||||
<a href=#102 id=102 data-nosnippet>102</a>//! 6. Update `sp_consensus_aura::AuraApi::slot_duration` in `sp_api::impl_runtime_apis` to match
|
||||
<a href=#103 id=103 data-nosnippet>103</a>//! the constant `SLOT_DURATION`
|
||||
<a href=#104 id=104 data-nosnippet>104</a></span><span class="attr">#![doc = <span class="macro">docify::embed!</span>(<span class="string">"../../templates/teyrchain/runtime/src/apis.rs"</span>, impl_slot_duration)]
|
||||
<a href=#105 id=105 data-nosnippet>105</a></span><span class="doccomment">//!
|
||||
<a href=#106 id=106 data-nosnippet>106</a>//! 7. Implement the `AuraUnincludedSegmentApi`, which allows the collator client to query its
|
||||
<a href=#107 id=107 data-nosnippet>107</a>//! runtime to determine whether it should author a block.
|
||||
<a href=#108 id=108 data-nosnippet>108</a>//!
|
||||
<a href=#109 id=109 data-nosnippet>109</a>//! - Add the dependency `cumulus-primitives-aura` to the `runtime/Cargo.toml` file for your
|
||||
<a href=#110 id=110 data-nosnippet>110</a>//! runtime
|
||||
<a href=#111 id=111 data-nosnippet>111</a>//! ```ignore
|
||||
<a href=#112 id=112 data-nosnippet>112</a>//! ..
|
||||
<a href=#113 id=113 data-nosnippet>113</a>//! cumulus-primitives-aura = { path = "../../../../primitives/aura", default-features = false }
|
||||
<a href=#114 id=114 data-nosnippet>114</a>//! ..
|
||||
<a href=#115 id=115 data-nosnippet>115</a>//! ```
|
||||
<a href=#116 id=116 data-nosnippet>116</a>//!
|
||||
<a href=#117 id=117 data-nosnippet>117</a>//! - In the same file, add `"cumulus-primitives-aura/std",` to the `std` feature.
|
||||
<a href=#118 id=118 data-nosnippet>118</a>//!
|
||||
<a href=#119 id=119 data-nosnippet>119</a>//! - Inside the `impl_runtime_apis!` block for your runtime, implement the
|
||||
<a href=#120 id=120 data-nosnippet>120</a>//! `cumulus_primitives_aura::AuraUnincludedSegmentApi` as shown below.
|
||||
<a href=#121 id=121 data-nosnippet>121</a></span><span class="attr">#![doc = <span class="macro">docify::embed!</span>(<span class="string">"../../templates/teyrchain/runtime/src/apis.rs"</span>, impl_can_build_upon)]
|
||||
<a href=#122 id=122 data-nosnippet>122</a></span><span class="doccomment">//!
|
||||
<a href=#123 id=123 data-nosnippet>123</a>//! **Note:** With a capacity of 1 we have an effective velocity of ½ even when velocity is
|
||||
<a href=#124 id=124 data-nosnippet>124</a>//! configured to some larger value. This is because capacity will be filled after a single block is
|
||||
<a href=#125 id=125 data-nosnippet>125</a>//! produced and will only be freed up after that block is included on the relay chain, which takes
|
||||
<a href=#126 id=126 data-nosnippet>126</a>//! 2 relay blocks to accomplish. Thus with capacity 1 and velocity 1 we get the customary 12 second
|
||||
<a href=#127 id=127 data-nosnippet>127</a>//! teyrchain block time.
|
||||
<a href=#128 id=128 data-nosnippet>128</a>//!
|
||||
<a href=#129 id=129 data-nosnippet>129</a>//! 8. If your `runtime/src/lib.rs` provides a `CheckInherents` type to `register_validate_block`,
|
||||
<a href=#130 id=130 data-nosnippet>130</a>//! remove it. `FixedVelocityConsensusHook` makes it unnecessary. The following example shows how
|
||||
<a href=#131 id=131 data-nosnippet>131</a>//! `register_validate_block` should look after removing `CheckInherents`.
|
||||
<a href=#132 id=132 data-nosnippet>132</a></span><span class="attr">#![doc = <span class="macro">docify::embed!</span>(<span class="string">"../../templates/teyrchain/runtime/src/lib.rs"</span>, register_validate_block)]
|
||||
<a href=#133 id=133 data-nosnippet>133</a></span><span class="doccomment">//!
|
||||
<a href=#134 id=134 data-nosnippet>134</a>//!
|
||||
<a href=#135 id=135 data-nosnippet>135</a>//! ## Phase 2 - Update Teyrchain Nodes
|
||||
<a href=#136 id=136 data-nosnippet>136</a>//!
|
||||
<a href=#137 id=137 data-nosnippet>137</a>//! This phase consists of plugging in the new lookahead collator node.
|
||||
<a href=#138 id=138 data-nosnippet>138</a>//!
|
||||
<a href=#139 id=139 data-nosnippet>139</a>//! 1. Import `cumulus_primitives_core::ValidationCode` to `node/src/service.rs`.
|
||||
<a href=#140 id=140 data-nosnippet>140</a></span><span class="attr">#![doc = <span class="macro">docify::embed!</span>(<span class="string">"../../templates/teyrchain/node/src/service.rs"</span>, cumulus_primitives)]
|
||||
<a href=#141 id=141 data-nosnippet>141</a></span><span class="doccomment">//!
|
||||
<a href=#142 id=142 data-nosnippet>142</a>//! 2. In `node/src/service.rs`, modify `sc_service::spawn_tasks` to use a clone of `Backend` rather
|
||||
<a href=#143 id=143 data-nosnippet>143</a>//! than the original
|
||||
<a href=#144 id=144 data-nosnippet>144</a>//! ```ignore
|
||||
<a href=#145 id=145 data-nosnippet>145</a>//! sc_service::spawn_tasks(sc_service::SpawnTasksParams {
|
||||
<a href=#146 id=146 data-nosnippet>146</a>//! ..
|
||||
<a href=#147 id=147 data-nosnippet>147</a>//! backend: backend.clone(),
|
||||
<a href=#148 id=148 data-nosnippet>148</a>//! ..
|
||||
<a href=#149 id=149 data-nosnippet>149</a>//! })?;
|
||||
<a href=#150 id=150 data-nosnippet>150</a>//! ```
|
||||
<a href=#151 id=151 data-nosnippet>151</a>//!
|
||||
<a href=#152 id=152 data-nosnippet>152</a>//! 3. Add `backend` as a parameter to `start_consensus()` in `node/src/service.rs`
|
||||
<a href=#153 id=153 data-nosnippet>153</a>//! ```text
|
||||
<a href=#154 id=154 data-nosnippet>154</a>//! fn start_consensus(
|
||||
<a href=#155 id=155 data-nosnippet>155</a>//! ..
|
||||
<a href=#156 id=156 data-nosnippet>156</a>//! backend: Arc<TeyrchainBackend>,
|
||||
<a href=#157 id=157 data-nosnippet>157</a>//! ..
|
||||
<a href=#158 id=158 data-nosnippet>158</a>//! ```
|
||||
<a href=#159 id=159 data-nosnippet>159</a>//! ```ignore
|
||||
<a href=#160 id=160 data-nosnippet>160</a>//! if validator {
|
||||
<a href=#161 id=161 data-nosnippet>161</a>//! start_consensus(
|
||||
<a href=#162 id=162 data-nosnippet>162</a>//! ..
|
||||
<a href=#163 id=163 data-nosnippet>163</a>//! backend.clone(),
|
||||
<a href=#164 id=164 data-nosnippet>164</a>//! ..
|
||||
<a href=#165 id=165 data-nosnippet>165</a>//! )?;
|
||||
<a href=#166 id=166 data-nosnippet>166</a>//! }
|
||||
<a href=#167 id=167 data-nosnippet>167</a>//! ```
|
||||
<a href=#168 id=168 data-nosnippet>168</a>//!
|
||||
<a href=#169 id=169 data-nosnippet>169</a>//! 4. In `node/src/service.rs` import the lookahead collator rather than the basic collator
|
||||
<a href=#170 id=170 data-nosnippet>170</a></span><span class="attr">#![doc = <span class="macro">docify::embed!</span>(<span class="string">"../../templates/teyrchain/node/src/service.rs"</span>, lookahead_collator)]
|
||||
<a href=#171 id=171 data-nosnippet>171</a></span><span class="doccomment">//!
|
||||
<a href=#172 id=172 data-nosnippet>172</a>//! 5. In `start_consensus()` replace the `BasicAuraParams` struct with `AuraParams`
|
||||
<a href=#173 id=173 data-nosnippet>173</a>//! - Change the struct type from `BasicAuraParams` to `AuraParams`
|
||||
<a href=#174 id=174 data-nosnippet>174</a>//! - In the `para_client` field, pass in a cloned para client rather than the original
|
||||
<a href=#175 id=175 data-nosnippet>175</a>//! - Add a `para_backend` parameter after `para_client`, passing in our para backend
|
||||
<a href=#176 id=176 data-nosnippet>176</a>//! - Provide a `code_hash_provider` closure like that shown below
|
||||
<a href=#177 id=177 data-nosnippet>177</a>//! - Increase `authoring_duration` from 500 milliseconds to 2000
|
||||
<a href=#178 id=178 data-nosnippet>178</a>//! ```ignore
|
||||
<a href=#179 id=179 data-nosnippet>179</a>//! let params = AuraParams {
|
||||
<a href=#180 id=180 data-nosnippet>180</a>//! ..
|
||||
<a href=#181 id=181 data-nosnippet>181</a>//! para_client: client.clone(),
|
||||
<a href=#182 id=182 data-nosnippet>182</a>//! para_backend: backend.clone(),
|
||||
<a href=#183 id=183 data-nosnippet>183</a>//! ..
|
||||
<a href=#184 id=184 data-nosnippet>184</a>//! code_hash_provider: move |block_hash| {
|
||||
<a href=#185 id=185 data-nosnippet>185</a>//! client.code_at(block_hash).ok().map(|c| ValidationCode::from(c).hash())
|
||||
<a href=#186 id=186 data-nosnippet>186</a>//! },
|
||||
<a href=#187 id=187 data-nosnippet>187</a>//! ..
|
||||
<a href=#188 id=188 data-nosnippet>188</a>//! authoring_duration: Duration::from_millis(2000),
|
||||
<a href=#189 id=189 data-nosnippet>189</a>//! ..
|
||||
<a href=#190 id=190 data-nosnippet>190</a>//! };
|
||||
<a href=#191 id=191 data-nosnippet>191</a>//! ```
|
||||
<a href=#192 id=192 data-nosnippet>192</a>//!
|
||||
<a href=#193 id=193 data-nosnippet>193</a>//! **Note:** Set `authoring_duration` to whatever you want, taking your own hardware into account.
|
||||
<a href=#194 id=194 data-nosnippet>194</a>//! But if the backer who should be slower than you due to reading from disk, times out at two
|
||||
<a href=#195 id=195 data-nosnippet>195</a>//! seconds your candidates will be rejected.
|
||||
<a href=#196 id=196 data-nosnippet>196</a>//!
|
||||
<a href=#197 id=197 data-nosnippet>197</a>//! 6. In `start_consensus()` replace `basic_aura::run` with `aura::run`
|
||||
<a href=#198 id=198 data-nosnippet>198</a>//! ```ignore
|
||||
<a href=#199 id=199 data-nosnippet>199</a>//! let fut =
|
||||
<a href=#200 id=200 data-nosnippet>200</a>//! aura::run::<Block, sp_consensus_aura::sr25519::AuthorityPair, _, _, _, _, _, _, _, _, _>(
|
||||
<a href=#201 id=201 data-nosnippet>201</a>//! params,
|
||||
<a href=#202 id=202 data-nosnippet>202</a>//! );
|
||||
<a href=#203 id=203 data-nosnippet>203</a>//! task_manager.spawn_essential_handle().spawn("aura", None, fut);
|
||||
<a href=#204 id=204 data-nosnippet>204</a>//! ```
|
||||
<a href=#205 id=205 data-nosnippet>205</a>//!
|
||||
<a href=#206 id=206 data-nosnippet>206</a>//! ## Phase 3 - Activate Async Backing
|
||||
<a href=#207 id=207 data-nosnippet>207</a>//!
|
||||
<a href=#208 id=208 data-nosnippet>208</a>//! This phase consists of changes to your teyrchain’s runtime that activate async backing feature.
|
||||
<a href=#209 id=209 data-nosnippet>209</a>//!
|
||||
<a href=#210 id=210 data-nosnippet>210</a>//! 1. Configure `pallet_aura`, setting `AllowMultipleBlocksPerSlot` to true in
|
||||
<a href=#211 id=211 data-nosnippet>211</a>//! `runtime/src/lib.rs`.
|
||||
<a href=#212 id=212 data-nosnippet>212</a></span><span class="attr">#![doc = <span class="macro">docify::embed!</span>(<span class="string">"../../templates/teyrchain/runtime/src/configs/mod.rs"</span>, aura_config)]
|
||||
<a href=#213 id=213 data-nosnippet>213</a></span><span class="doccomment">//!
|
||||
<a href=#214 id=214 data-nosnippet>214</a>//! 2. Increase the maximum `UNINCLUDED_SEGMENT_CAPACITY` in `runtime/src/lib.rs`.
|
||||
<a href=#215 id=215 data-nosnippet>215</a></span><span class="attr">#![doc = <span class="macro">docify::embed!</span>(<span class="string">"../../templates/teyrchain/runtime/src/lib.rs"</span>, async_backing_params)]
|
||||
<a href=#216 id=216 data-nosnippet>216</a></span><span class="doccomment">//!
|
||||
<a href=#217 id=217 data-nosnippet>217</a>//! 3. Decrease `MILLISECS_PER_BLOCK` to 6000.
|
||||
<a href=#218 id=218 data-nosnippet>218</a>//!
|
||||
<a href=#219 id=219 data-nosnippet>219</a>//! - Note: For a teyrchain which measures time in terms of its own block number rather than by
|
||||
<a href=#220 id=220 data-nosnippet>220</a>//! relay block number it may be preferable to increase velocity. Changing block time may cause
|
||||
<a href=#221 id=221 data-nosnippet>221</a>//! complications, requiring additional changes. See the section “Timing by Block Number”.
|
||||
<a href=#222 id=222 data-nosnippet>222</a></span><span class="attr">#![doc = <span class="macro">docify::embed!</span>(<span class="string">"../../templates/teyrchain/runtime/src/lib.rs"</span>, block_times)]
|
||||
<a href=#223 id=223 data-nosnippet>223</a></span><span class="doccomment">//!
|
||||
<a href=#224 id=224 data-nosnippet>224</a>//! 4. Update `MAXIMUM_BLOCK_WEIGHT` to reflect the increased time available for block production.
|
||||
<a href=#225 id=225 data-nosnippet>225</a></span><span class="attr">#![doc = <span class="macro">docify::embed!</span>(<span class="string">"../../templates/teyrchain/runtime/src/lib.rs"</span>, max_block_weight)]
|
||||
<a href=#226 id=226 data-nosnippet>226</a></span><span class="doccomment">//!
|
||||
<a href=#227 id=227 data-nosnippet>227</a>//! 5. Add a feature flagged alternative for `MinimumPeriod` in `pallet_timestamp`. The type should
|
||||
<a href=#228 id=228 data-nosnippet>228</a>//! be `ConstU64<0>` with the feature flag experimental, and `ConstU64<{SLOT_DURATION / 2}>`
|
||||
<a href=#229 id=229 data-nosnippet>229</a>//! without.
|
||||
<a href=#230 id=230 data-nosnippet>230</a>//! ```ignore
|
||||
<a href=#231 id=231 data-nosnippet>231</a>//! impl pallet_timestamp::Config for Runtime {
|
||||
<a href=#232 id=232 data-nosnippet>232</a>//! ..
|
||||
<a href=#233 id=233 data-nosnippet>233</a>//! #[cfg(feature = "experimental")]
|
||||
<a href=#234 id=234 data-nosnippet>234</a>//! type MinimumPeriod = ConstU64<0>;
|
||||
<a href=#235 id=235 data-nosnippet>235</a>//! #[cfg(not(feature = "experimental"))]
|
||||
<a href=#236 id=236 data-nosnippet>236</a>//! type MinimumPeriod = ConstU64<{ SLOT_DURATION / 2 }>;
|
||||
<a href=#237 id=237 data-nosnippet>237</a>//! ..
|
||||
<a href=#238 id=238 data-nosnippet>238</a>//! }
|
||||
<a href=#239 id=239 data-nosnippet>239</a>//! ```
|
||||
<a href=#240 id=240 data-nosnippet>240</a>//!
|
||||
<a href=#241 id=241 data-nosnippet>241</a>//! ## Timing by Block Number
|
||||
<a href=#242 id=242 data-nosnippet>242</a>//!
|
||||
<a href=#243 id=243 data-nosnippet>243</a>//! With asynchronous backing it will be possible for teyrchains to opt for a block time of 6
|
||||
<a href=#244 id=244 data-nosnippet>244</a>//! seconds rather than 12 seconds. But modifying block duration isn’t so simple for a teyrchain
|
||||
<a href=#245 id=245 data-nosnippet>245</a>//! which was measuring time in terms of its own block number. It could result in expected and
|
||||
<a href=#246 id=246 data-nosnippet>246</a>//! actual time not matching up, stalling the teyrchain.
|
||||
<a href=#247 id=247 data-nosnippet>247</a>//!
|
||||
<a href=#248 id=248 data-nosnippet>248</a>//! One strategy to deal with this issue is to instead rely on relay chain block numbers for timing.
|
||||
<a href=#249 id=249 data-nosnippet>249</a>//! Relay block number is kept track of by each teyrchain in `pallet-teyrchain-system` with the
|
||||
<a href=#250 id=250 data-nosnippet>250</a>//! storage value `LastRelayChainBlockNumber`. This value can be obtained and used wherever timing
|
||||
<a href=#251 id=251 data-nosnippet>251</a>//! based on block number is needed.
|
||||
<a href=#252 id=252 data-nosnippet>252</a>
|
||||
<a href=#253 id=253 data-nosnippet>253</a></span><span class="attr">#![deny(rustdoc::broken_intra_doc_links)]
|
||||
<a href=#254 id=254 data-nosnippet>254</a>#![deny(rustdoc::private_intra_doc_links)]</span></code></pre></div></section></main></body></html>
|
||||
@@ -0,0 +1,182 @@
|
||||
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `docs/sdk/src/guides/enable_elastic_scaling.rs`."><title>enable_elastic_scaling.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2"href="../../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../../../static.files/rustdoc-e56847b5.css"><meta name="rustdoc-vars" data-root-path="../../../" data-static-root-path="../../../static.files/" data-current-crate="pezkuwi_sdk_docs" data-themes="" data-resource-suffix="" data-rustdoc-version="1.91.1 (ed61e7d7e 2025-11-07)" data-channel="1.91.1" data-search-js="search-e256b49e.js" data-stringdex-js="stringdex-c3e638e9.js" data-settings-js="settings-c38705f0.js" ><script src="../../../static.files/storage-e2aeef58.js"></script><script defer src="../../../static.files/src-script-813739b1.js"></script><script defer src="../../../src-files.js"></script><script defer src="../../../static.files/main-6dc2a7f3.js"></script><noscript><link rel="stylesheet" href="../../../static.files/noscript-263c88ec.css"></noscript><link rel="icon" href="https://pezkuwichain.io/favicon.ico"></head><body class="rustdoc src"><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer" title="Drag to resize sidebar"></div><main><section id="main-content" class="content"><div class="main-heading"><h1><div class="sub-heading">pezkuwi_sdk_docs/guides/</div>enable_elastic_scaling.rs</h1><rustdoc-toolbar></rustdoc-toolbar></div><div class="example-wrap digits-3"><pre class="rust"><code><a href=#1 id=1 data-nosnippet>1</a><span class="doccomment">//! # Enable elastic scaling for a teyrchain
|
||||
<a href=#2 id=2 data-nosnippet>2</a>//!
|
||||
<a href=#3 id=3 data-nosnippet>3</a>//! <div class="warning">This guide assumes full familiarity with Asynchronous Backing and its
|
||||
<a href=#4 id=4 data-nosnippet>4</a>//! terminology, as defined in <a href="https://docs.pezkuwichain.io/sdk/master/pezkuwi_sdk_docs/guides/async_backing_guide/index.html">the Pezkuwi SDK Docs</a>.
|
||||
<a href=#5 id=5 data-nosnippet>5</a>//! </div>
|
||||
<a href=#6 id=6 data-nosnippet>6</a>//!
|
||||
<a href=#7 id=7 data-nosnippet>7</a>//! ## Quick introduction to Elastic Scaling
|
||||
<a href=#8 id=8 data-nosnippet>8</a>//!
|
||||
<a href=#9 id=9 data-nosnippet>9</a>//! [Elastic scaling](https://www.parity.io/blog/pezkuwi-web3-cloud) is a feature that enables teyrchains (rollups) to use multiple cores.
|
||||
<a href=#10 id=10 data-nosnippet>10</a>//! Teyrchains can adjust their usage of core resources on the fly to increase TPS and decrease
|
||||
<a href=#11 id=11 data-nosnippet>11</a>//! latency.
|
||||
<a href=#12 id=12 data-nosnippet>12</a>//!
|
||||
<a href=#13 id=13 data-nosnippet>13</a>//! ### When do you need Elastic Scaling?
|
||||
<a href=#14 id=14 data-nosnippet>14</a>//!
|
||||
<a href=#15 id=15 data-nosnippet>15</a>//! Depending on their use case, applications might have an increased need for the following:
|
||||
<a href=#16 id=16 data-nosnippet>16</a>//! - compute (CPU weight)
|
||||
<a href=#17 id=17 data-nosnippet>17</a>//! - bandwidth (proof size)
|
||||
<a href=#18 id=18 data-nosnippet>18</a>//! - lower latency (block time)
|
||||
<a href=#19 id=19 data-nosnippet>19</a>//!
|
||||
<a href=#20 id=20 data-nosnippet>20</a>//! ### High throughput (TPS) and lower latency
|
||||
<a href=#21 id=21 data-nosnippet>21</a>//!
|
||||
<a href=#22 id=22 data-nosnippet>22</a>//! If the main bottleneck is the CPU, then your teyrchain needs to maximize the compute usage of
|
||||
<a href=#23 id=23 data-nosnippet>23</a>//! each core while also achieving a lower latency.
|
||||
<a href=#24 id=24 data-nosnippet>24</a>//! 3 cores provide the best balance between CPU, bandwidth and latency: up to 6s of execution,
|
||||
<a href=#25 id=25 data-nosnippet>25</a>//! 5MB/s of DA bandwidth and fast block time of just 2 seconds.
|
||||
<a href=#26 id=26 data-nosnippet>26</a>//!
|
||||
<a href=#27 id=27 data-nosnippet>27</a>//! ### High bandwidth
|
||||
<a href=#28 id=28 data-nosnippet>28</a>//!
|
||||
<a href=#29 id=29 data-nosnippet>29</a>//! Useful for applications that are bottlenecked by bandwidth.
|
||||
<a href=#30 id=30 data-nosnippet>30</a>//! By using 6 cores, applications can make use of up to 6s of compute, 10MB/s of bandwidth
|
||||
<a href=#31 id=31 data-nosnippet>31</a>//! while also achieving 1 second block times.
|
||||
<a href=#32 id=32 data-nosnippet>32</a>//!
|
||||
<a href=#33 id=33 data-nosnippet>33</a>//! ### Ultra low latency
|
||||
<a href=#34 id=34 data-nosnippet>34</a>//!
|
||||
<a href=#35 id=35 data-nosnippet>35</a>//! When latency is the primary requirement, Elastic scaling is currently the only solution. The
|
||||
<a href=#36 id=36 data-nosnippet>36</a>//! caveat is the efficiency of core time usage decreases as more cores are used.
|
||||
<a href=#37 id=37 data-nosnippet>37</a>//!
|
||||
<a href=#38 id=38 data-nosnippet>38</a>//! For example, using 12 cores enables fast transaction confirmations with 500ms blocks and up to
|
||||
<a href=#39 id=39 data-nosnippet>39</a>//! 20 MB/s of DA bandwidth.
|
||||
<a href=#40 id=40 data-nosnippet>40</a>//!
|
||||
<a href=#41 id=41 data-nosnippet>41</a>//! ## Dependencies
|
||||
<a href=#42 id=42 data-nosnippet>42</a>//!
|
||||
<a href=#43 id=43 data-nosnippet>43</a>//! Prerequisites: Pezkuwi-SDK `2509` or newer.
|
||||
<a href=#44 id=44 data-nosnippet>44</a>//!
|
||||
<a href=#45 id=45 data-nosnippet>45</a>//! To ensure the security and reliability of your chain when using this feature you need the
|
||||
<a href=#46 id=46 data-nosnippet>46</a>//! following:
|
||||
<a href=#47 id=47 data-nosnippet>47</a>//! - An omni-node based collator. This has already become the default choice for collators.
|
||||
<a href=#48 id=48 data-nosnippet>48</a>//! - UMP signal support.
|
||||
<a href=#49 id=49 data-nosnippet>49</a>//! [RFC103](https://github.com/pezkuwichain/pezkuwi-fellows/RFCs/blob/main/text/0103-introduce-core-index-commitment.md).
|
||||
<a href=#50 id=50 data-nosnippet>50</a>//! This is mandatory protection against PoV replay attacks.
|
||||
<a href=#51 id=51 data-nosnippet>51</a>//! - Enabling the relay parent offset feature. This is required to ensure the teyrchain block times
|
||||
<a href=#52 id=52 data-nosnippet>52</a>//! and transaction in-block confidence are not negatively affected by relay chain forks. Read
|
||||
<a href=#53 id=53 data-nosnippet>53</a>//! [`crate::guides::handling_teyrchain_forks`] for more information.
|
||||
<a href=#54 id=54 data-nosnippet>54</a>//! - Block production configuration adjustments.
|
||||
<a href=#55 id=55 data-nosnippet>55</a>//!
|
||||
<a href=#56 id=56 data-nosnippet>56</a>//! ### Upgrade to Pezkuwi Omni node
|
||||
<a href=#57 id=57 data-nosnippet>57</a>//!
|
||||
<a href=#58 id=58 data-nosnippet>58</a>//! Your collators need to run `pezkuwi-teyrchain` or `pezkuwi-omni-node` with the `--authoring
|
||||
<a href=#59 id=59 data-nosnippet>59</a>//! slot-based` CLI argument.
|
||||
<a href=#60 id=60 data-nosnippet>60</a>//! To avoid potential issues and get best performance it is recommeneded to always run the
|
||||
<a href=#61 id=61 data-nosnippet>61</a>//! latest release on all of the collators.
|
||||
<a href=#62 id=62 data-nosnippet>62</a>//!
|
||||
<a href=#63 id=63 data-nosnippet>63</a>//! Further information about omni-node and how to upgrade is available:
|
||||
<a href=#64 id=64 data-nosnippet>64</a>//! - [high level docs](https://docs.pezkuwichain.io/develop/toolkit/teyrchains/pezkuwi-omni-node/)
|
||||
<a href=#65 id=65 data-nosnippet>65</a>//! - [`crate::reference_docs::omni_node`]
|
||||
<a href=#66 id=66 data-nosnippet>66</a>//!
|
||||
<a href=#67 id=67 data-nosnippet>67</a>//! ### UMP signals
|
||||
<a href=#68 id=68 data-nosnippet>68</a>//!
|
||||
<a href=#69 id=69 data-nosnippet>69</a>//! UMP signals are now enabled by default in the `teyrchain-system` pallet and are used for
|
||||
<a href=#70 id=70 data-nosnippet>70</a>//! elastic scaling. You can find more technical details about UMP signals and their usage for
|
||||
<a href=#71 id=71 data-nosnippet>71</a>//! elastic scaling
|
||||
<a href=#72 id=72 data-nosnippet>72</a>//! [here](https://github.com/pezkuwichain/pezkuwi-fellows/RFCs/blob/main/text/0103-introduce-core-index-commitment.md).
|
||||
<a href=#73 id=73 data-nosnippet>73</a>//!
|
||||
<a href=#74 id=74 data-nosnippet>74</a>//! ### Enable the relay parent offset feature
|
||||
<a href=#75 id=75 data-nosnippet>75</a>//!
|
||||
<a href=#76 id=76 data-nosnippet>76</a>//! It is recommended to use an offset of `1`, which is sufficient to eliminate any issues
|
||||
<a href=#77 id=77 data-nosnippet>77</a>//! with relay chain forks.
|
||||
<a href=#78 id=78 data-nosnippet>78</a>//!
|
||||
<a href=#79 id=79 data-nosnippet>79</a>//! Configure the relay parent offset like this:
|
||||
<a href=#80 id=80 data-nosnippet>80</a>//! ```ignore
|
||||
<a href=#81 id=81 data-nosnippet>81</a>//! /// Build with an offset of 1 behind the relay chain best block.
|
||||
<a href=#82 id=82 data-nosnippet>82</a>//! const RELAY_PARENT_OFFSET: u32 = 1;
|
||||
<a href=#83 id=83 data-nosnippet>83</a>//!
|
||||
<a href=#84 id=84 data-nosnippet>84</a>//! impl cumulus_pallet_teyrchain_system::Config for Runtime {
|
||||
<a href=#85 id=85 data-nosnippet>85</a>//! // ...
|
||||
<a href=#86 id=86 data-nosnippet>86</a>//! type RelayParentOffset = ConstU32<RELAY_PARENT_OFFSET>;
|
||||
<a href=#87 id=87 data-nosnippet>87</a>//! }
|
||||
<a href=#88 id=88 data-nosnippet>88</a>//! ```
|
||||
<a href=#89 id=89 data-nosnippet>89</a>//!
|
||||
<a href=#90 id=90 data-nosnippet>90</a>//! Implement the runtime API to retrieve the offset on the client side.
|
||||
<a href=#91 id=91 data-nosnippet>91</a>//! ```ignore
|
||||
<a href=#92 id=92 data-nosnippet>92</a>//! impl cumulus_primitives_core::RelayParentOffsetApi<Block> for Runtime {
|
||||
<a href=#93 id=93 data-nosnippet>93</a>//! fn relay_parent_offset() -> u32 {
|
||||
<a href=#94 id=94 data-nosnippet>94</a>//! RELAY_PARENT_OFFSET
|
||||
<a href=#95 id=95 data-nosnippet>95</a>//! }
|
||||
<a href=#96 id=96 data-nosnippet>96</a>//! }
|
||||
<a href=#97 id=97 data-nosnippet>97</a>//! ```
|
||||
<a href=#98 id=98 data-nosnippet>98</a>//!
|
||||
<a href=#99 id=99 data-nosnippet>99</a>//! ### Block production configuration
|
||||
<a href=#100 id=100 data-nosnippet>100</a>//!
|
||||
<a href=#101 id=101 data-nosnippet>101</a>//! This configuration directly controls the minimum block time and maximum number of cores
|
||||
<a href=#102 id=102 data-nosnippet>102</a>//! the teyrchain can use.
|
||||
<a href=#103 id=103 data-nosnippet>103</a>//!
|
||||
<a href=#104 id=104 data-nosnippet>104</a>//! Example configuration for a 3 core teyrchain:
|
||||
<a href=#105 id=105 data-nosnippet>105</a>//! ```ignore
|
||||
<a href=#106 id=106 data-nosnippet>106</a>//! /// The upper limit of how many teyrchain blocks are processed by the relay chain per
|
||||
<a href=#107 id=107 data-nosnippet>107</a>//! /// parent. Limits the number of blocks authored per slot. This determines the minimum
|
||||
<a href=#108 id=108 data-nosnippet>108</a>//! /// block time of the teyrchain:
|
||||
<a href=#109 id=109 data-nosnippet>109</a>//! /// `RELAY_CHAIN_SLOT_DURATION_MILLIS/BLOCK_PROCESSING_VELOCITY`
|
||||
<a href=#110 id=110 data-nosnippet>110</a>//! const BLOCK_PROCESSING_VELOCITY: u32 = 3;
|
||||
<a href=#111 id=111 data-nosnippet>111</a>//!
|
||||
<a href=#112 id=112 data-nosnippet>112</a>//! /// Maximum number of blocks simultaneously accepted by the Runtime, not yet included
|
||||
<a href=#113 id=113 data-nosnippet>113</a>//! /// into the relay chain.
|
||||
<a href=#114 id=114 data-nosnippet>114</a>//! const UNINCLUDED_SEGMENT_CAPACITY: u32 = (2 + RELAY_PARENT_OFFSET) *
|
||||
<a href=#115 id=115 data-nosnippet>115</a>//! BLOCK_PROCESSING_VELOCITY + 1;
|
||||
<a href=#116 id=116 data-nosnippet>116</a>//!
|
||||
<a href=#117 id=117 data-nosnippet>117</a>//! /// Relay chain slot duration, in milliseconds.
|
||||
<a href=#118 id=118 data-nosnippet>118</a>//! const RELAY_CHAIN_SLOT_DURATION_MILLIS: u32 = 6000;
|
||||
<a href=#119 id=119 data-nosnippet>119</a>//!
|
||||
<a href=#120 id=120 data-nosnippet>120</a>//! type ConsensusHook = cumulus_pallet_aura_ext::FixedVelocityConsensusHook<
|
||||
<a href=#121 id=121 data-nosnippet>121</a>//! Runtime,
|
||||
<a href=#122 id=122 data-nosnippet>122</a>//! RELAY_CHAIN_SLOT_DURATION_MILLIS,
|
||||
<a href=#123 id=123 data-nosnippet>123</a>//! BLOCK_PROCESSING_VELOCITY,
|
||||
<a href=#124 id=124 data-nosnippet>124</a>//! UNINCLUDED_SEGMENT_CAPACITY,
|
||||
<a href=#125 id=125 data-nosnippet>125</a>//! >;
|
||||
<a href=#126 id=126 data-nosnippet>126</a>//!
|
||||
<a href=#127 id=127 data-nosnippet>127</a>//! ```
|
||||
<a href=#128 id=128 data-nosnippet>128</a>//!
|
||||
<a href=#129 id=129 data-nosnippet>129</a>//! ### Teyrchain Slot Duration
|
||||
<a href=#130 id=130 data-nosnippet>130</a>//!
|
||||
<a href=#131 id=131 data-nosnippet>131</a>//! A common source of confusion is the correct configuration of the `SlotDuration` that is passed
|
||||
<a href=#132 id=132 data-nosnippet>132</a>//! to `pallet-aura`.
|
||||
<a href=#133 id=133 data-nosnippet>133</a>//! ```ignore
|
||||
<a href=#134 id=134 data-nosnippet>134</a>//! impl pallet_aura::Config for Runtime {
|
||||
<a href=#135 id=135 data-nosnippet>135</a>//! // ...
|
||||
<a href=#136 id=136 data-nosnippet>136</a>//! type SlotDuration = ConstU64<SLOT_DURATION>;
|
||||
<a href=#137 id=137 data-nosnippet>137</a>//! }
|
||||
<a href=#138 id=138 data-nosnippet>138</a>//! ```
|
||||
<a href=#139 id=139 data-nosnippet>139</a>//!
|
||||
<a href=#140 id=140 data-nosnippet>140</a>//! The slot duration determines the length of each author's turn and is decoupled from the block
|
||||
<a href=#141 id=141 data-nosnippet>141</a>//! production interval. During their slot, authors are allowed to produce multiple blocks. **The
|
||||
<a href=#142 id=142 data-nosnippet>142</a>//! slot duration is required to be at least 6s (same as on the relay chain).**
|
||||
<a href=#143 id=143 data-nosnippet>143</a>//!
|
||||
<a href=#144 id=144 data-nosnippet>144</a>//! **Configuration recommendations:**
|
||||
<a href=#145 id=145 data-nosnippet>145</a>//! - For new teyrchains starting from genesis: use a slot duration of 24 seconds
|
||||
<a href=#146 id=146 data-nosnippet>146</a>//! - For existing live teyrchains: leave the slot duration unchanged
|
||||
<a href=#147 id=147 data-nosnippet>147</a>//!
|
||||
<a href=#148 id=148 data-nosnippet>148</a>//!
|
||||
<a href=#149 id=149 data-nosnippet>149</a>//! ## Current limitations
|
||||
<a href=#150 id=150 data-nosnippet>150</a>//!
|
||||
<a href=#151 id=151 data-nosnippet>151</a>//! ### Maximum execution time per relay chain block.
|
||||
<a href=#152 id=152 data-nosnippet>152</a>//!
|
||||
<a href=#153 id=153 data-nosnippet>153</a>//! Since teyrchain block authoring is sequential, the next block can only be built after
|
||||
<a href=#154 id=154 data-nosnippet>154</a>//! the previous one has been imported.
|
||||
<a href=#155 id=155 data-nosnippet>155</a>//! At present, a core allows up to 2 seconds of execution per relay chain block.
|
||||
<a href=#156 id=156 data-nosnippet>156</a>//!
|
||||
<a href=#157 id=157 data-nosnippet>157</a>//! If we assume a 6s teyrchain slot, and each block takes the full 2 seconds to execute,
|
||||
<a href=#158 id=158 data-nosnippet>158</a>//! the teyrchain will not be able to fully utilize the compute resources of all 3 cores.
|
||||
<a href=#159 id=159 data-nosnippet>159</a>//!
|
||||
<a href=#160 id=160 data-nosnippet>160</a>//! If the collator hardware is faster, it can author and import full blocks more quickly,
|
||||
<a href=#161 id=161 data-nosnippet>161</a>//! making it possible to utilize even more than 3 cores efficiently.
|
||||
<a href=#162 id=162 data-nosnippet>162</a>//!
|
||||
<a href=#163 id=163 data-nosnippet>163</a>//! #### Why?
|
||||
<a href=#164 id=164 data-nosnippet>164</a>//!
|
||||
<a href=#165 id=165 data-nosnippet>165</a>//! Within a 6-second teyrchain slot, collators can author multiple teyrchain blocks.
|
||||
<a href=#166 id=166 data-nosnippet>166</a>//! Before building the first block in a slot, the new block author must import the last
|
||||
<a href=#167 id=167 data-nosnippet>167</a>//! block produced by the previous author.
|
||||
<a href=#168 id=168 data-nosnippet>168</a>//! If the import of the last block is not completed before the next relay chain slot starts,
|
||||
<a href=#169 id=169 data-nosnippet>169</a>//! the new author will build on its parent (assuming it was imported). This will create a fork
|
||||
<a href=#170 id=170 data-nosnippet>170</a>//! which degrades the teyrchain block confidence and block times.
|
||||
<a href=#171 id=171 data-nosnippet>171</a>//!
|
||||
<a href=#172 id=172 data-nosnippet>172</a>//! This means that, on reference hardware, a teyrchain with a slot time of 6s can
|
||||
<a href=#173 id=173 data-nosnippet>173</a>//! effectively utilize up to 4 seconds of execution per relay chain block, because it needs to
|
||||
<a href=#174 id=174 data-nosnippet>174</a>//! ensure the next block author has enough time to import the last block.
|
||||
<a href=#175 id=175 data-nosnippet>175</a>//! Hardware with higher single-core performance can enable a teyrchain to fully utilize more
|
||||
<a href=#176 id=176 data-nosnippet>176</a>//! cores.
|
||||
<a href=#177 id=177 data-nosnippet>177</a>//!
|
||||
<a href=#178 id=178 data-nosnippet>178</a>//! ### Fixed factor scaling.
|
||||
<a href=#179 id=179 data-nosnippet>179</a>//!
|
||||
<a href=#180 id=180 data-nosnippet>180</a>//! For true elasticity, a teyrchain needs to acquire more cores when needed in an automated
|
||||
<a href=#181 id=181 data-nosnippet>181</a>//! manner. This functionality is not yet available in the SDK, thus acquiring additional
|
||||
<a href=#182 id=182 data-nosnippet>182</a>//! on-demand or bulk cores has to be managed externally.</span></code></pre></div></section></main></body></html>
|
||||
@@ -0,0 +1,88 @@
|
||||
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `docs/sdk/src/guides/enable_metadata_hash.rs`."><title>enable_metadata_hash.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2"href="../../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../../../static.files/rustdoc-e56847b5.css"><meta name="rustdoc-vars" data-root-path="../../../" data-static-root-path="../../../static.files/" data-current-crate="pezkuwi_sdk_docs" data-themes="" data-resource-suffix="" data-rustdoc-version="1.91.1 (ed61e7d7e 2025-11-07)" data-channel="1.91.1" data-search-js="search-e256b49e.js" data-stringdex-js="stringdex-c3e638e9.js" data-settings-js="settings-c38705f0.js" ><script src="../../../static.files/storage-e2aeef58.js"></script><script defer src="../../../static.files/src-script-813739b1.js"></script><script defer src="../../../src-files.js"></script><script defer src="../../../static.files/main-6dc2a7f3.js"></script><noscript><link rel="stylesheet" href="../../../static.files/noscript-263c88ec.css"></noscript><link rel="icon" href="https://pezkuwichain.io/favicon.ico"></head><body class="rustdoc src"><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer" title="Drag to resize sidebar"></div><main><section id="main-content" class="content"><div class="main-heading"><h1><div class="sub-heading">pezkuwi_sdk_docs/guides/</div>enable_metadata_hash.rs</h1><rustdoc-toolbar></rustdoc-toolbar></div><div class="example-wrap digits-2"><pre class="rust"><code><a href=#1 id=1 data-nosnippet>1</a><span class="doccomment">//! # Enable metadata hash verification
|
||||
<a href=#2 id=2 data-nosnippet>2</a>//!
|
||||
<a href=#3 id=3 data-nosnippet>3</a>//! This guide will teach you how to enable the metadata hash verification in your runtime.
|
||||
<a href=#4 id=4 data-nosnippet>4</a>//!
|
||||
<a href=#5 id=5 data-nosnippet>5</a>//! ## What is metadata hash verification?
|
||||
<a href=#6 id=6 data-nosnippet>6</a>//!
|
||||
<a href=#7 id=7 data-nosnippet>7</a>//! Each FRAME based runtime exposes metadata about itself. This metadata is used by consumers of
|
||||
<a href=#8 id=8 data-nosnippet>8</a>//! the runtime to interpret the state, to construct transactions etc. Part of this metadata are the
|
||||
<a href=#9 id=9 data-nosnippet>9</a>//! type information. These type information can be used to e.g. decode storage entries or to decode
|
||||
<a href=#10 id=10 data-nosnippet>10</a>//! a transaction. So, the metadata is quite useful for wallets to interact with a FRAME based
|
||||
<a href=#11 id=11 data-nosnippet>11</a>//! chain. Online wallets can fetch the metadata directly from any node of the chain they are
|
||||
<a href=#12 id=12 data-nosnippet>12</a>//! connected to, but offline wallets can not do this. So, for the offline wallet to have access to
|
||||
<a href=#13 id=13 data-nosnippet>13</a>//! the metadata it needs to be transferred and stored on the device. The problem is that the
|
||||
<a href=#14 id=14 data-nosnippet>14</a>//! metadata has a size of several hundreds of kilobytes, which takes quite a while to transfer to
|
||||
<a href=#15 id=15 data-nosnippet>15</a>//! these offline wallets and the internal storage of these devices is also not big enough to store
|
||||
<a href=#16 id=16 data-nosnippet>16</a>//! the metadata for one or more networks. The next problem is that the offline wallet/user can not
|
||||
<a href=#17 id=17 data-nosnippet>17</a>//! trust the metadata to be correct. It is very important for the metadata to be correct or
|
||||
<a href=#18 id=18 data-nosnippet>18</a>//! otherwise an attacker could change them in a way that the offline wallet decodes a transaction
|
||||
<a href=#19 id=19 data-nosnippet>19</a>//! in a different way than what it will be decoded to on chain. So, the user may sign an incorrect
|
||||
<a href=#20 id=20 data-nosnippet>20</a>//! transaction leading to unexpected behavior.
|
||||
<a href=#21 id=21 data-nosnippet>21</a>//!
|
||||
<a href=#22 id=22 data-nosnippet>22</a>//! The metadata hash verification circumvents the issues of the huge metadata and the need to trust
|
||||
<a href=#23 id=23 data-nosnippet>23</a>//! some metadata blob to be correct. To generate a hash for the metadata, the metadata is chunked,
|
||||
<a href=#24 id=24 data-nosnippet>24</a>//! these chunks are put into a merkle tree and then the root of this merkle tree is the "metadata
|
||||
<a href=#25 id=25 data-nosnippet>25</a>//! hash". For a more technical explanation on how it works, see
|
||||
<a href=#26 id=26 data-nosnippet>26</a>//! [RFC78](https://pezkuwi-fellows.github.io/RFCs/approved/0078-merkleized-metadata.html). At compile
|
||||
<a href=#27 id=27 data-nosnippet>27</a>//! time the metadata hash is generated and "baked" into the runtime. This makes it extremely cheap
|
||||
<a href=#28 id=28 data-nosnippet>28</a>//! for the runtime to verify on chain that the metadata hash is correct. By having the runtime
|
||||
<a href=#29 id=29 data-nosnippet>29</a>//! verify the hash on chain, the user also doesn't need to trust the offchain metadata. If the
|
||||
<a href=#30 id=30 data-nosnippet>30</a>//! metadata hash doesn't match the on chain metadata hash the transaction will be rejected. The
|
||||
<a href=#31 id=31 data-nosnippet>31</a>//! metadata hash itself is added to the data of the transaction that is signed, this means the
|
||||
<a href=#32 id=32 data-nosnippet>32</a>//! actual hash does not appear in the transaction. On chain the same procedure is repeated with the
|
||||
<a href=#33 id=33 data-nosnippet>33</a>//! metadata hash that is known by the runtime and if the metadata hash doesn't match the signature
|
||||
<a href=#34 id=34 data-nosnippet>34</a>//! verification will fail. As the metadata hash is actually the root of a merkle tree, the offline
|
||||
<a href=#35 id=35 data-nosnippet>35</a>//! wallet can get proofs of individual types to decode a transaction. This means that the offline
|
||||
<a href=#36 id=36 data-nosnippet>36</a>//! wallet does not require the entire metadata to be present on the device.
|
||||
<a href=#37 id=37 data-nosnippet>37</a>//!
|
||||
<a href=#38 id=38 data-nosnippet>38</a>//! ## Integrating metadata hash verification into your runtime
|
||||
<a href=#39 id=39 data-nosnippet>39</a>//!
|
||||
<a href=#40 id=40 data-nosnippet>40</a>//! The integration of the metadata hash verification is split into two parts, first the actual
|
||||
<a href=#41 id=41 data-nosnippet>41</a>//! integration into the runtime and secondly the enabling of the metadata hash generation at
|
||||
<a href=#42 id=42 data-nosnippet>42</a>//! compile time.
|
||||
<a href=#43 id=43 data-nosnippet>43</a>//!
|
||||
<a href=#44 id=44 data-nosnippet>44</a>//! ### Runtime integration
|
||||
<a href=#45 id=45 data-nosnippet>45</a>//!
|
||||
<a href=#46 id=46 data-nosnippet>46</a>//! From the runtime side only the
|
||||
<a href=#47 id=47 data-nosnippet>47</a>//! [`CheckMetadataHash`](frame_metadata_hash_extension::CheckMetadataHash) needs to be added to the
|
||||
<a href=#48 id=48 data-nosnippet>48</a>//! list of signed extension:
|
||||
<a href=#49 id=49 data-nosnippet>49</a></span><span class="attr">#![doc = <span class="macro">docify::embed!</span>(<span class="string">"../../templates/teyrchain/runtime/src/lib.rs"</span>, template_signed_extra)]
|
||||
<a href=#50 id=50 data-nosnippet>50</a></span><span class="doccomment">//!
|
||||
<a href=#51 id=51 data-nosnippet>51</a>//! > **Note:**
|
||||
<a href=#52 id=52 data-nosnippet>52</a>//! >
|
||||
<a href=#53 id=53 data-nosnippet>53</a>//! > Adding the signed extension changes the encoding of the transaction and adds one extra byte
|
||||
<a href=#54 id=54 data-nosnippet>54</a>//! > per transaction!
|
||||
<a href=#55 id=55 data-nosnippet>55</a>//!
|
||||
<a href=#56 id=56 data-nosnippet>56</a>//! This signed extension will make sure to decode the requested `mode` and will add the metadata
|
||||
<a href=#57 id=57 data-nosnippet>57</a>//! hash to the signed data depending on the requested `mode`. The `mode` gives the user/wallet
|
||||
<a href=#58 id=58 data-nosnippet>58</a>//! control over deciding if the metadata hash should be verified or not. The metadata hash itself
|
||||
<a href=#59 id=59 data-nosnippet>59</a>//! is drawn from the `RUNTIME_METADATA_HASH` environment variable. If the environment variable is
|
||||
<a href=#60 id=60 data-nosnippet>60</a>//! not set, any transaction that requires the metadata hash is rejected with the error
|
||||
<a href=#61 id=61 data-nosnippet>61</a>//! `CannotLookup`. This is a security measurement to prevent including invalid transactions.
|
||||
<a href=#62 id=62 data-nosnippet>62</a>//!
|
||||
<a href=#63 id=63 data-nosnippet>63</a>//! <div class="warning">
|
||||
<a href=#64 id=64 data-nosnippet>64</a>//!
|
||||
<a href=#65 id=65 data-nosnippet>65</a>//! The extension does not work with the native runtime, because the
|
||||
<a href=#66 id=66 data-nosnippet>66</a>//! `RUNTIME_METADATA_HASH` environment variable is not set when building the
|
||||
<a href=#67 id=67 data-nosnippet>67</a>//! `frame-metadata-hash-extension` crate.
|
||||
<a href=#68 id=68 data-nosnippet>68</a>//!
|
||||
<a href=#69 id=69 data-nosnippet>69</a>//! </div>
|
||||
<a href=#70 id=70 data-nosnippet>70</a>//!
|
||||
<a href=#71 id=71 data-nosnippet>71</a>//! ### Enable metadata hash generation
|
||||
<a href=#72 id=72 data-nosnippet>72</a>//!
|
||||
<a href=#73 id=73 data-nosnippet>73</a>//! The metadata hash generation needs to be enabled when building the wasm binary. The
|
||||
<a href=#74 id=74 data-nosnippet>74</a>//! `substrate-wasm-builder` supports this out of the box:
|
||||
<a href=#75 id=75 data-nosnippet>75</a></span><span class="attr">#![doc = <span class="macro">docify::embed!</span>(<span class="string">"../../templates/teyrchain/runtime/build.rs"</span>, template_enable_metadata_hash)]
|
||||
<a href=#76 id=76 data-nosnippet>76</a></span><span class="doccomment">//!
|
||||
<a href=#77 id=77 data-nosnippet>77</a>//! > **Note:**
|
||||
<a href=#78 id=78 data-nosnippet>78</a>//! >
|
||||
<a href=#79 id=79 data-nosnippet>79</a>//! > The `metadata-hash` feature needs to be enabled for the `substrate-wasm-builder` to enable the
|
||||
<a href=#80 id=80 data-nosnippet>80</a>//! > code for being able to generate the metadata hash. It is also recommended to put the metadata
|
||||
<a href=#81 id=81 data-nosnippet>81</a>//! > hash generation behind a feature in the runtime as shown above. The reason behind is that it
|
||||
<a href=#82 id=82 data-nosnippet>82</a>//! > adds a lot of code which increases the compile time and the generation itself also increases
|
||||
<a href=#83 id=83 data-nosnippet>83</a>//! > the compile time. Thus, it is recommended to enable the feature only when the metadata hash is
|
||||
<a href=#84 id=84 data-nosnippet>84</a>//! > required (e.g. for an on-chain build).
|
||||
<a href=#85 id=85 data-nosnippet>85</a>//!
|
||||
<a href=#86 id=86 data-nosnippet>86</a>//! The two parameters to `enable_metadata_hash` are the token symbol and the number of decimals of
|
||||
<a href=#87 id=87 data-nosnippet>87</a>//! the primary token of the chain. These information are included for the wallets to show token
|
||||
<a href=#88 id=88 data-nosnippet>88</a>//! related operations in a more user friendly way.</span></code></pre></div></section></main></body></html>
|
||||
@@ -0,0 +1,88 @@
|
||||
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `docs/sdk/src/guides/enable_pov_reclaim.rs`."><title>enable_pov_reclaim.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2"href="../../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../../../static.files/rustdoc-e56847b5.css"><meta name="rustdoc-vars" data-root-path="../../../" data-static-root-path="../../../static.files/" data-current-crate="pezkuwi_sdk_docs" data-themes="" data-resource-suffix="" data-rustdoc-version="1.91.1 (ed61e7d7e 2025-11-07)" data-channel="1.91.1" data-search-js="search-e256b49e.js" data-stringdex-js="stringdex-c3e638e9.js" data-settings-js="settings-c38705f0.js" ><script src="../../../static.files/storage-e2aeef58.js"></script><script defer src="../../../static.files/src-script-813739b1.js"></script><script defer src="../../../src-files.js"></script><script defer src="../../../static.files/main-6dc2a7f3.js"></script><noscript><link rel="stylesheet" href="../../../static.files/noscript-263c88ec.css"></noscript><link rel="icon" href="https://pezkuwichain.io/favicon.ico"></head><body class="rustdoc src"><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer" title="Drag to resize sidebar"></div><main><section id="main-content" class="content"><div class="main-heading"><h1><div class="sub-heading">pezkuwi_sdk_docs/guides/</div>enable_pov_reclaim.rs</h1><rustdoc-toolbar></rustdoc-toolbar></div><div class="example-wrap digits-2"><pre class="rust"><code><a href=#1 id=1 data-nosnippet>1</a><span class="doccomment">//! # Enable storage weight reclaiming
|
||||
<a href=#2 id=2 data-nosnippet>2</a>//!
|
||||
<a href=#3 id=3 data-nosnippet>3</a>//! This guide will teach you how to enable storage weight reclaiming for a teyrchain. The
|
||||
<a href=#4 id=4 data-nosnippet>4</a>//! explanations in this guide assume a project structure similar to the one detailed in
|
||||
<a href=#5 id=5 data-nosnippet>5</a>//! the [substrate documentation](crate::pezkuwi_sdk::substrate#anatomy-of-a-binary-crate). Full
|
||||
<a href=#6 id=6 data-nosnippet>6</a>//! technical details are available in the original [pull request](https://github.com/pezkuwichain/pezkuwi-sdk/pull/3002).
|
||||
<a href=#7 id=7 data-nosnippet>7</a>//!
|
||||
<a href=#8 id=8 data-nosnippet>8</a>//! # What is PoV reclaim?
|
||||
<a href=#9 id=9 data-nosnippet>9</a>//! When a teyrchain submits a block to a relay chain like Pezkuwi or Kusama, it sends the block
|
||||
<a href=#10 id=10 data-nosnippet>10</a>//! itself and a storage proof. Together they form the Proof-of-Validity (PoV). The PoV allows the
|
||||
<a href=#11 id=11 data-nosnippet>11</a>//! relay chain to validate the teyrchain block by re-executing it. Relay chain
|
||||
<a href=#12 id=12 data-nosnippet>12</a>//! validators distribute this PoV among themselves over the network. This distribution is costly
|
||||
<a href=#13 id=13 data-nosnippet>13</a>//! and limits the size of the storage proof. The storage weight dimension of FRAME weights reflects
|
||||
<a href=#14 id=14 data-nosnippet>14</a>//! this cost and limits the size of the storage proof. However, the storage weight determined
|
||||
<a href=#15 id=15 data-nosnippet>15</a>//! during [benchmarking](crate::reference_docs::frame_benchmarking_weight) represents the worst
|
||||
<a href=#16 id=16 data-nosnippet>16</a>//! case. In reality, runtime operations often consume less space in the storage proof. PoV reclaim
|
||||
<a href=#17 id=17 data-nosnippet>17</a>//! offers a mechanism to reclaim the difference between the benchmarked worst-case and the real
|
||||
<a href=#18 id=18 data-nosnippet>18</a>//! proof-size consumption.
|
||||
<a href=#19 id=19 data-nosnippet>19</a>//!
|
||||
<a href=#20 id=20 data-nosnippet>20</a>//!
|
||||
<a href=#21 id=21 data-nosnippet>21</a>//! # How to enable PoV reclaim
|
||||
<a href=#22 id=22 data-nosnippet>22</a>//! ## 1. Add the host function to your node
|
||||
<a href=#23 id=23 data-nosnippet>23</a>//!
|
||||
<a href=#24 id=24 data-nosnippet>24</a>//! To reclaim excess storage weight, a teyrchain runtime needs the
|
||||
<a href=#25 id=25 data-nosnippet>25</a>//! ability to fetch the size of the storage proof from the node. The reclaim
|
||||
<a href=#26 id=26 data-nosnippet>26</a>//! mechanism uses the
|
||||
<a href=#27 id=27 data-nosnippet>27</a>//! [`storage_proof_size`](cumulus_primitives_proof_size_hostfunction::storage_proof_size)
|
||||
<a href=#28 id=28 data-nosnippet>28</a>//! host function for this purpose. For convenience, cumulus provides
|
||||
<a href=#29 id=29 data-nosnippet>29</a>//! [`TeyrchainHostFunctions`](cumulus_client_service::TeyrchainHostFunctions), a set of
|
||||
<a href=#30 id=30 data-nosnippet>30</a>//! host functions typically used by cumulus-based teyrchains. In the binary crate of your
|
||||
<a href=#31 id=31 data-nosnippet>31</a>//! teyrchain, find the instantiation of the [`WasmExecutor`](sc_executor::WasmExecutor) and set the
|
||||
<a href=#32 id=32 data-nosnippet>32</a>//! correct generic type.
|
||||
<a href=#33 id=33 data-nosnippet>33</a>//!
|
||||
<a href=#34 id=34 data-nosnippet>34</a>//! This example from the teyrchain-template shows a type definition that includes the correct
|
||||
<a href=#35 id=35 data-nosnippet>35</a>//! host functions.
|
||||
<a href=#36 id=36 data-nosnippet>36</a></span><span class="attr">#![doc = <span class="macro">docify::embed!</span>(<span class="string">"../../templates/teyrchain/node/src/service.rs"</span>, wasm_executor)]
|
||||
<a href=#37 id=37 data-nosnippet>37</a></span><span class="doccomment">//!
|
||||
<a href=#38 id=38 data-nosnippet>38</a>//! > **Note:**
|
||||
<a href=#39 id=39 data-nosnippet>39</a>//! >
|
||||
<a href=#40 id=40 data-nosnippet>40</a>//! > If you see error `runtime requires function imports which are not present on the host:
|
||||
<a href=#41 id=41 data-nosnippet>41</a>//! > 'env:ext_storage_proof_size_storage_proof_size_version_1'`, it is likely
|
||||
<a href=#42 id=42 data-nosnippet>42</a>//! > that this step in the guide was not set up correctly.
|
||||
<a href=#43 id=43 data-nosnippet>43</a>//!
|
||||
<a href=#44 id=44 data-nosnippet>44</a>//! ## 2. Enable storage proof recording during import
|
||||
<a href=#45 id=45 data-nosnippet>45</a>//!
|
||||
<a href=#46 id=46 data-nosnippet>46</a>//! The reclaim mechanism reads the size of the currently recorded storage proof multiple times
|
||||
<a href=#47 id=47 data-nosnippet>47</a>//! during block authoring and block import. Proof recording during authoring is already enabled on
|
||||
<a href=#48 id=48 data-nosnippet>48</a>//! teyrchains. You must also ensure that storage proof recording is enabled during block import.
|
||||
<a href=#49 id=49 data-nosnippet>49</a>//! Find where your node builds the fundamental substrate components by calling
|
||||
<a href=#50 id=50 data-nosnippet>50</a>//! [`new_full_parts`](sc_service::new_full_parts). Replace this
|
||||
<a href=#51 id=51 data-nosnippet>51</a>//! with [`new_full_parts_record_import`](sc_service::new_full_parts_record_import) and
|
||||
<a href=#52 id=52 data-nosnippet>52</a>//! pass `true` as the last parameter to enable import recording.
|
||||
<a href=#53 id=53 data-nosnippet>53</a></span><span class="attr">#![doc = <span class="macro">docify::embed!</span>(<span class="string">"../../templates/teyrchain/node/src/service.rs"</span>, component_instantiation)]
|
||||
<a href=#54 id=54 data-nosnippet>54</a></span><span class="doccomment">//!
|
||||
<a href=#55 id=55 data-nosnippet>55</a>//! > **Note:**
|
||||
<a href=#56 id=56 data-nosnippet>56</a>//! >
|
||||
<a href=#57 id=57 data-nosnippet>57</a>//! > If you see error `Storage root must match that calculated.` during block import, it is likely
|
||||
<a href=#58 id=58 data-nosnippet>58</a>//! > that this step in the guide was not
|
||||
<a href=#59 id=59 data-nosnippet>59</a>//! > set up correctly.
|
||||
<a href=#60 id=60 data-nosnippet>60</a>//!
|
||||
<a href=#61 id=61 data-nosnippet>61</a>//! ## 3. Add the TransactionExtension to your runtime
|
||||
<a href=#62 id=62 data-nosnippet>62</a>//!
|
||||
<a href=#63 id=63 data-nosnippet>63</a>//! In your runtime, you will find a list of TransactionExtensions.
|
||||
<a href=#64 id=64 data-nosnippet>64</a>//! To enable the reclaiming,
|
||||
<a href=#65 id=65 data-nosnippet>65</a>//! set [`StorageWeightReclaim`](cumulus_pallet_weight_reclaim::StorageWeightReclaim)
|
||||
<a href=#66 id=66 data-nosnippet>66</a>//! as a warpper of that list.
|
||||
<a href=#67 id=67 data-nosnippet>67</a>//! It is necessary that this extension wraps all the other transaction extensions in order to catch
|
||||
<a href=#68 id=68 data-nosnippet>68</a>//! the whole PoV size of the transactions.
|
||||
<a href=#69 id=69 data-nosnippet>69</a>//! The extension will check the size of the storage proof before and after an extrinsic execution.
|
||||
<a href=#70 id=70 data-nosnippet>70</a>//! It reclaims the difference between the calculated size and the benchmarked size.
|
||||
<a href=#71 id=71 data-nosnippet>71</a></span><span class="attr">#![doc = <span class="macro">docify::embed!</span>(<span class="string">"../../templates/teyrchain/runtime/src/lib.rs"</span>, template_signed_extra)]
|
||||
<a href=#72 id=72 data-nosnippet>72</a></span><span class="doccomment">//!
|
||||
<a href=#73 id=73 data-nosnippet>73</a>//! ## Optional: Verify that reclaim works
|
||||
<a href=#74 id=74 data-nosnippet>74</a>//!
|
||||
<a href=#75 id=75 data-nosnippet>75</a>//! Start your node with the log target `runtime::storage_reclaim` set to `trace` to enable full
|
||||
<a href=#76 id=76 data-nosnippet>76</a>//! logging for `StorageWeightReclaim`. The following log is an example from a local testnet. To
|
||||
<a href=#77 id=77 data-nosnippet>77</a>//! trigger the log, execute any extrinsic on the network.
|
||||
<a href=#78 id=78 data-nosnippet>78</a>//!
|
||||
<a href=#79 id=79 data-nosnippet>79</a>//! ```ignore
|
||||
<a href=#80 id=80 data-nosnippet>80</a>//! ...
|
||||
<a href=#81 id=81 data-nosnippet>81</a>//! 2024-04-22 17:31:48.014 TRACE runtime::storage_reclaim: [ferdie] Reclaiming storage weight. benchmarked: 3593, consumed: 265 unspent: 0
|
||||
<a href=#82 id=82 data-nosnippet>82</a>//! ...
|
||||
<a href=#83 id=83 data-nosnippet>83</a>//! ```
|
||||
<a href=#84 id=84 data-nosnippet>84</a>//!
|
||||
<a href=#85 id=85 data-nosnippet>85</a>//! In the above example we see a benchmarked size of 3593 bytes, while the extrinsic only consumed
|
||||
<a href=#86 id=86 data-nosnippet>86</a>//! 265 bytes of proof size. This results in 3328 bytes of reclaim.
|
||||
<a href=#87 id=87 data-nosnippet>87</a></span><span class="attr">#![deny(rustdoc::broken_intra_doc_links)]
|
||||
<a href=#88 id=88 data-nosnippet>88</a>#![deny(rustdoc::private_intra_doc_links)]</span></code></pre></div></section></main></body></html>
|
||||
@@ -0,0 +1,90 @@
|
||||
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `docs/sdk/src/guides/handling_teyrchain_forks.rs`."><title>handling_teyrchain_forks.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2"href="../../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../../../static.files/rustdoc-e56847b5.css"><meta name="rustdoc-vars" data-root-path="../../../" data-static-root-path="../../../static.files/" data-current-crate="pezkuwi_sdk_docs" data-themes="" data-resource-suffix="" data-rustdoc-version="1.91.1 (ed61e7d7e 2025-11-07)" data-channel="1.91.1" data-search-js="search-e256b49e.js" data-stringdex-js="stringdex-c3e638e9.js" data-settings-js="settings-c38705f0.js" ><script src="../../../static.files/storage-e2aeef58.js"></script><script defer src="../../../static.files/src-script-813739b1.js"></script><script defer src="../../../src-files.js"></script><script defer src="../../../static.files/main-6dc2a7f3.js"></script><noscript><link rel="stylesheet" href="../../../static.files/noscript-263c88ec.css"></noscript><link rel="icon" href="https://pezkuwichain.io/favicon.ico"></head><body class="rustdoc src"><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer" title="Drag to resize sidebar"></div><main><section id="main-content" class="content"><div class="main-heading"><h1><div class="sub-heading">pezkuwi_sdk_docs/guides/</div>handling_teyrchain_forks.rs</h1><rustdoc-toolbar></rustdoc-toolbar></div><div class="example-wrap digits-2"><pre class="rust"><code><a href=#1 id=1 data-nosnippet>1</a><span class="doccomment">//! # Teyrchain forks
|
||||
<a href=#2 id=2 data-nosnippet>2</a>//!
|
||||
<a href=#3 id=3 data-nosnippet>3</a>//! In this guide, we will examine how AURA-based teyrchains handle forks. AURA (Authority Round) is
|
||||
<a href=#4 id=4 data-nosnippet>4</a>//! a consensus mechanism where block authors rotate at fixed time intervals. Each author gets a
|
||||
<a href=#5 id=5 data-nosnippet>5</a>//! predetermined time slice during which they are allowed to author a block. On its own, this
|
||||
<a href=#6 id=6 data-nosnippet>6</a>//! mechanism is fork-free.
|
||||
<a href=#7 id=7 data-nosnippet>7</a>//!
|
||||
<a href=#8 id=8 data-nosnippet>8</a>//! However, since the relay chain provides security and serves as the source of truth for
|
||||
<a href=#9 id=9 data-nosnippet>9</a>//! teyrchains, the teyrchain is dependent on it. This relationship can introduce complexities that
|
||||
<a href=#10 id=10 data-nosnippet>10</a>//! lead to forking scenarios.
|
||||
<a href=#11 id=11 data-nosnippet>11</a>//!
|
||||
<a href=#12 id=12 data-nosnippet>12</a>//! ## Background
|
||||
<a href=#13 id=13 data-nosnippet>13</a>//! Each teyrchain block has a relay parent, which is a relay chain block that provides context to
|
||||
<a href=#14 id=14 data-nosnippet>14</a>//! our teyrchain block. The constraints the relay chain imposes on our teyrchain can cause forks
|
||||
<a href=#15 id=15 data-nosnippet>15</a>//! under certain conditions. With asynchronous-backing enabled chains, the node side is building
|
||||
<a href=#16 id=16 data-nosnippet>16</a>//! blocks on all relay chain forks. This means that no matter which fork of the relay chain
|
||||
<a href=#17 id=17 data-nosnippet>17</a>//! ultimately progressed, the teyrchain would have a block ready for that fork. The situation
|
||||
<a href=#18 id=18 data-nosnippet>18</a>//! changes when teyrchains want to produce blocks at a faster cadence. In a scenario where a
|
||||
<a href=#19 id=19 data-nosnippet>19</a>//! teyrchain might author on 3 cores with elastic scaling, it is not possible to author on all
|
||||
<a href=#20 id=20 data-nosnippet>20</a>//! relay chain forks. The time constraints do not allow it. Building on two forks would result in 6
|
||||
<a href=#21 id=21 data-nosnippet>21</a>//! blocks. The authoring of these blocks would consume more time than we have available before the
|
||||
<a href=#22 id=22 data-nosnippet>22</a>//! next relay chain block arrives. This limitation requires a more fork-resistant approach to
|
||||
<a href=#23 id=23 data-nosnippet>23</a>//! block-building.
|
||||
<a href=#24 id=24 data-nosnippet>24</a>//!
|
||||
<a href=#25 id=25 data-nosnippet>25</a>//! ## Impact of Forks
|
||||
<a href=#26 id=26 data-nosnippet>26</a>//! When a relay chain fork occurs and the teyrchain builds on a fork that will not be extended in
|
||||
<a href=#27 id=27 data-nosnippet>27</a>//! the future, the blocks built on that fork are lost and need to be rebuilt. This increases
|
||||
<a href=#28 id=28 data-nosnippet>28</a>//! latency and reduces throughput, affecting the overall performance of the teyrchain.
|
||||
<a href=#29 id=29 data-nosnippet>29</a>//!
|
||||
<a href=#30 id=30 data-nosnippet>30</a>//! # Building on Older Pelay Parents
|
||||
<a href=#31 id=31 data-nosnippet>31</a>//! Cumulus offers a way to mitigate the occurence of forks. Instead of picking a block at the tip
|
||||
<a href=#32 id=32 data-nosnippet>32</a>//! of the relay chain to build blocks, the node side can pick a relay chain block that is older. By
|
||||
<a href=#33 id=33 data-nosnippet>33</a>//! building on 12s old relay chain blocks, forks will already have settled and the teyrchain can
|
||||
<a href=#34 id=34 data-nosnippet>34</a>//! build fork-free.
|
||||
<a href=#35 id=35 data-nosnippet>35</a>//!
|
||||
<a href=#36 id=36 data-nosnippet>36</a>//! ```text
|
||||
<a href=#37 id=37 data-nosnippet>37</a>//! Without offset:
|
||||
<a href=#38 id=38 data-nosnippet>38</a>//! Relay Chain: A --- B --- C --- D --- E
|
||||
<a href=#39 id=39 data-nosnippet>39</a>//! \
|
||||
<a href=#40 id=40 data-nosnippet>40</a>//! --- D' --- E'
|
||||
<a href=#41 id=41 data-nosnippet>41</a>//! Teyrchain: X --- Y --- ? (builds on both D and D', wasting resources)
|
||||
<a href=#42 id=42 data-nosnippet>42</a>//!
|
||||
<a href=#43 id=43 data-nosnippet>43</a>//! With offset (2 blocks):
|
||||
<a href=#44 id=44 data-nosnippet>44</a>//! Relay Chain: A --- B --- C --- D --- E
|
||||
<a href=#45 id=45 data-nosnippet>45</a>//! \
|
||||
<a href=#46 id=46 data-nosnippet>46</a>//! --- D' --- E'
|
||||
<a href=#47 id=47 data-nosnippet>47</a>//! Teyrchain: X(A) - Y (B) - Z (on C, fork already resolved)
|
||||
<a href=#48 id=48 data-nosnippet>48</a>//! ```
|
||||
<a href=#49 id=49 data-nosnippet>49</a>//! **Note:** It is possible that relay chain forks extend over more than 1-2 blocks. However, it is
|
||||
<a href=#50 id=50 data-nosnippet>50</a>//! unlikely.
|
||||
<a href=#51 id=51 data-nosnippet>51</a>//! ## Tradeoffs
|
||||
<a href=#52 id=52 data-nosnippet>52</a>//! Fork-free teyrchains come with a few tradeoffs:
|
||||
<a href=#53 id=53 data-nosnippet>53</a>//! - The latency of incoming XCM messages will be delayed by `N * 6s`, where `N` is the number of
|
||||
<a href=#54 id=54 data-nosnippet>54</a>//! relay chain blocks we want to offset by. For example, by building 2 relay chain blocks behind
|
||||
<a href=#55 id=55 data-nosnippet>55</a>//! the tip, the XCM latency will be increased by 12 seconds.
|
||||
<a href=#56 id=56 data-nosnippet>56</a>//! - The available PoV space will be slightly reduced. Assuming a 10mb PoV, teyrchains need to be
|
||||
<a href=#57 id=57 data-nosnippet>57</a>//! ready to sacrifice around 0.5% of PoV space.
|
||||
<a href=#58 id=58 data-nosnippet>58</a>//!
|
||||
<a href=#59 id=59 data-nosnippet>59</a>//! ## Enabling Guide
|
||||
<a href=#60 id=60 data-nosnippet>60</a>//! The decision whether the teyrchain should build on older relay parents is embedded into the
|
||||
<a href=#61 id=61 data-nosnippet>61</a>//! runtime. After the changes are implemented, the runtime will enforce that no author can build
|
||||
<a href=#62 id=62 data-nosnippet>62</a>//! with an offset smaller than the desired offset. If you wish to keep your current teyrchain
|
||||
<a href=#63 id=63 data-nosnippet>63</a>//! behaviour and do not want aforementioned tradeoffs, set the offset to 0.
|
||||
<a href=#64 id=64 data-nosnippet>64</a>//!
|
||||
<a href=#65 id=65 data-nosnippet>65</a>//! **Note:** The APIs mentioned here are available in `pezkuwi-sdk` versions after `stable-2506`.
|
||||
<a href=#66 id=66 data-nosnippet>66</a>//!
|
||||
<a href=#67 id=67 data-nosnippet>67</a>//! 1. Define the relay parent offset your teyrchain should respect in the runtime.
|
||||
<a href=#68 id=68 data-nosnippet>68</a>//! ```ignore
|
||||
<a href=#69 id=69 data-nosnippet>69</a>//! const RELAY_PARENT_OFFSET = 2;
|
||||
<a href=#70 id=70 data-nosnippet>70</a>//! ```
|
||||
<a href=#71 id=71 data-nosnippet>71</a>//! 2. Pass this constant to the `teyrchain-system` pallet.
|
||||
<a href=#72 id=72 data-nosnippet>72</a>//!
|
||||
<a href=#73 id=73 data-nosnippet>73</a>//! ```ignore
|
||||
<a href=#74 id=74 data-nosnippet>74</a>//! impl cumulus_pallet_teyrchain_system::Config for Runtime {
|
||||
<a href=#75 id=75 data-nosnippet>75</a>//! // Other config items here
|
||||
<a href=#76 id=76 data-nosnippet>76</a>//! ...
|
||||
<a href=#77 id=77 data-nosnippet>77</a>//! type RelayParentOffset = ConstU32<RELAY_PARENT_OFFSET>;
|
||||
<a href=#78 id=78 data-nosnippet>78</a>//! }
|
||||
<a href=#79 id=79 data-nosnippet>79</a>//! ```
|
||||
<a href=#80 id=80 data-nosnippet>80</a>//! 3. Implement the `RelayParentOffsetApi` runtime API for your runtime.
|
||||
<a href=#81 id=81 data-nosnippet>81</a>//!
|
||||
<a href=#82 id=82 data-nosnippet>82</a>//! ```ignore
|
||||
<a href=#83 id=83 data-nosnippet>83</a>//! impl cumulus_primitives_core::RelayParentOffsetApi<Block> for Runtime {
|
||||
<a href=#84 id=84 data-nosnippet>84</a>//! fn relay_parent_offset() -> u32 {
|
||||
<a href=#85 id=85 data-nosnippet>85</a>//! RELAY_PARENT_OFFSET
|
||||
<a href=#86 id=86 data-nosnippet>86</a>//! }
|
||||
<a href=#87 id=87 data-nosnippet>87</a>//! }
|
||||
<a href=#88 id=88 data-nosnippet>88</a>//! ```
|
||||
<a href=#89 id=89 data-nosnippet>89</a>//! 4. Increase the `UNINCLUDED_SEGMENT_CAPICITY` for your runtime. It needs to be increased by
|
||||
<a href=#90 id=90 data-nosnippet>90</a>//! `RELAY_PARENT_OFFSET * BLOCK_PROCESSING_VELOCITY`.</span></code></pre></div></section></main></body></html>
|
||||
@@ -0,0 +1,50 @@
|
||||
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `docs/sdk/src/guides/mod.rs`."><title>mod.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2"href="../../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../../../static.files/rustdoc-e56847b5.css"><meta name="rustdoc-vars" data-root-path="../../../" data-static-root-path="../../../static.files/" data-current-crate="pezkuwi_sdk_docs" data-themes="" data-resource-suffix="" data-rustdoc-version="1.91.1 (ed61e7d7e 2025-11-07)" data-channel="1.91.1" data-search-js="search-e256b49e.js" data-stringdex-js="stringdex-c3e638e9.js" data-settings-js="settings-c38705f0.js" ><script src="../../../static.files/storage-e2aeef58.js"></script><script defer src="../../../static.files/src-script-813739b1.js"></script><script defer src="../../../src-files.js"></script><script defer src="../../../static.files/main-6dc2a7f3.js"></script><noscript><link rel="stylesheet" href="../../../static.files/noscript-263c88ec.css"></noscript><link rel="icon" href="https://pezkuwichain.io/favicon.ico"></head><body class="rustdoc src"><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer" title="Drag to resize sidebar"></div><main><section id="main-content" class="content"><div class="main-heading"><h1><div class="sub-heading">pezkuwi_sdk_docs/guides/</div>mod.rs</h1><rustdoc-toolbar></rustdoc-toolbar></div><div class="example-wrap digits-2"><pre class="rust"><code><a href=#1 id=1 data-nosnippet>1</a><span class="doccomment">//! # Pezkuwi SDK Docs Guides
|
||||
<a href=#2 id=2 data-nosnippet>2</a>//!
|
||||
<a href=#3 id=3 data-nosnippet>3</a>//! This crate contains a collection of guides that are foundational to the developers of
|
||||
<a href=#4 id=4 data-nosnippet>4</a>//! Pezkuwi SDK. They are common user-journeys that are traversed in the Pezkuwi ecosystem.
|
||||
<a href=#5 id=5 data-nosnippet>5</a>//!
|
||||
<a href=#6 id=6 data-nosnippet>6</a>//! The main user-journey covered by these guides is:
|
||||
<a href=#7 id=7 data-nosnippet>7</a>//!
|
||||
<a href=#8 id=8 data-nosnippet>8</a>//! * [`your_first_pallet`], where you learn what a FRAME pallet is, and write your first
|
||||
<a href=#9 id=9 data-nosnippet>9</a>//! application logic.
|
||||
<a href=#10 id=10 data-nosnippet>10</a>//! * [`your_first_runtime`], where you learn how to compile your pallets into a WASM runtime.
|
||||
<a href=#11 id=11 data-nosnippet>11</a>//! * [`your_first_node`], where you learn how to run the said runtime in a node.
|
||||
<a href=#12 id=12 data-nosnippet>12</a>//!
|
||||
<a href=#13 id=13 data-nosnippet>13</a>//! > By this step, you have already launched a full Pezkuwi-SDK-based blockchain!
|
||||
<a href=#14 id=14 data-nosnippet>14</a>//!
|
||||
<a href=#15 id=15 data-nosnippet>15</a>//! Once done, feel free to step up into one of our templates: [`crate::pezkuwi_sdk::templates`].
|
||||
<a href=#16 id=16 data-nosnippet>16</a>//!
|
||||
<a href=#17 id=17 data-nosnippet>17</a>//! [`your_first_pallet`]: crate::guides::your_first_pallet
|
||||
<a href=#18 id=18 data-nosnippet>18</a>//! [`your_first_runtime`]: crate::guides::your_first_runtime
|
||||
<a href=#19 id=19 data-nosnippet>19</a>//! [`your_first_node`]: crate::guides::your_first_node
|
||||
<a href=#20 id=20 data-nosnippet>20</a>//!
|
||||
<a href=#21 id=21 data-nosnippet>21</a>//! Other guides are related to other miscellaneous topics and are listed as modules below.
|
||||
<a href=#22 id=22 data-nosnippet>22</a>
|
||||
<a href=#23 id=23 data-nosnippet>23</a>/// Write your first simple pallet, learning the most most basic features of FRAME along the way.
|
||||
<a href=#24 id=24 data-nosnippet>24</a></span><span class="kw">pub mod </span>your_first_pallet;
|
||||
<a href=#25 id=25 data-nosnippet>25</a>
|
||||
<a href=#26 id=26 data-nosnippet>26</a><span class="doccomment">/// Write your first real [runtime](`crate::reference_docs::wasm_meta_protocol`),
|
||||
<a href=#27 id=27 data-nosnippet>27</a>/// compiling it to [WASM](crate::pezkuwi_sdk::substrate#wasm-build).
|
||||
<a href=#28 id=28 data-nosnippet>28</a></span><span class="kw">pub mod </span>your_first_runtime;
|
||||
<a href=#29 id=29 data-nosnippet>29</a>
|
||||
<a href=#30 id=30 data-nosnippet>30</a><span class="doccomment">/// Running the given runtime with a node. No specific consensus mechanism is used at this stage.
|
||||
<a href=#31 id=31 data-nosnippet>31</a></span><span class="kw">pub mod </span>your_first_node;
|
||||
<a href=#32 id=32 data-nosnippet>32</a>
|
||||
<a href=#33 id=33 data-nosnippet>33</a><span class="doccomment">/// How to enhance a given runtime and node to be cumulus-enabled, run it as a teyrchain
|
||||
<a href=#34 id=34 data-nosnippet>34</a>/// and connect it to a relay-chain.
|
||||
<a href=#35 id=35 data-nosnippet>35</a></span><span class="comment">// pub mod your_first_teyrchain;
|
||||
<a href=#36 id=36 data-nosnippet>36</a>
|
||||
<a href=#37 id=37 data-nosnippet>37</a></span><span class="doccomment">/// How to enable storage weight reclaiming in a teyrchain node and runtime.
|
||||
<a href=#38 id=38 data-nosnippet>38</a></span><span class="kw">pub mod </span>enable_pov_reclaim;
|
||||
<a href=#39 id=39 data-nosnippet>39</a>
|
||||
<a href=#40 id=40 data-nosnippet>40</a><span class="doccomment">/// How to enable Async Backing on teyrchain projects that started in 2023 or before.
|
||||
<a href=#41 id=41 data-nosnippet>41</a></span><span class="kw">pub mod </span>async_backing_guide;
|
||||
<a href=#42 id=42 data-nosnippet>42</a>
|
||||
<a href=#43 id=43 data-nosnippet>43</a><span class="doccomment">/// How to enable metadata hash verification in the runtime.
|
||||
<a href=#44 id=44 data-nosnippet>44</a></span><span class="kw">pub mod </span>enable_metadata_hash;
|
||||
<a href=#45 id=45 data-nosnippet>45</a>
|
||||
<a href=#46 id=46 data-nosnippet>46</a><span class="doccomment">/// How to enable elastic scaling on a teyrchain.
|
||||
<a href=#47 id=47 data-nosnippet>47</a></span><span class="kw">pub mod </span>enable_elastic_scaling;
|
||||
<a href=#48 id=48 data-nosnippet>48</a>
|
||||
<a href=#49 id=49 data-nosnippet>49</a><span class="doccomment">/// How to parameterize teyrchain forking in relation to relay chain forking.
|
||||
<a href=#50 id=50 data-nosnippet>50</a></span><span class="kw">pub mod </span>handling_teyrchain_forks;</code></pre></div></section></main></body></html>
|
||||
@@ -0,0 +1,342 @@
|
||||
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `docs/sdk/src/guides/your_first_node.rs`."><title>your_first_node.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2"href="../../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../../../static.files/rustdoc-e56847b5.css"><meta name="rustdoc-vars" data-root-path="../../../" data-static-root-path="../../../static.files/" data-current-crate="pezkuwi_sdk_docs" data-themes="" data-resource-suffix="" data-rustdoc-version="1.91.1 (ed61e7d7e 2025-11-07)" data-channel="1.91.1" data-search-js="search-e256b49e.js" data-stringdex-js="stringdex-c3e638e9.js" data-settings-js="settings-c38705f0.js" ><script src="../../../static.files/storage-e2aeef58.js"></script><script defer src="../../../static.files/src-script-813739b1.js"></script><script defer src="../../../src-files.js"></script><script defer src="../../../static.files/main-6dc2a7f3.js"></script><noscript><link rel="stylesheet" href="../../../static.files/noscript-263c88ec.css"></noscript><link rel="icon" href="https://pezkuwichain.io/favicon.ico"></head><body class="rustdoc src"><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer" title="Drag to resize sidebar"></div><main><section id="main-content" class="content"><div class="main-heading"><h1><div class="sub-heading">pezkuwi_sdk_docs/guides/</div>your_first_node.rs</h1><rustdoc-toolbar></rustdoc-toolbar></div><div class="example-wrap digits-3"><pre class="rust"><code><a href=#1 id=1 data-nosnippet>1</a><span class="doccomment">//! # Your first Node
|
||||
<a href=#2 id=2 data-nosnippet>2</a>//!
|
||||
<a href=#3 id=3 data-nosnippet>3</a>//! In this guide, you will learn how to run a runtime, such as the one created in
|
||||
<a href=#4 id=4 data-nosnippet>4</a>//! [`your_first_runtime`], in a node. Within the context of this guide, we will focus on running
|
||||
<a href=#5 id=5 data-nosnippet>5</a>//! the runtime with an [`omni-node`]. Please first read this page to learn about the OmniNode, and
|
||||
<a href=#6 id=6 data-nosnippet>6</a>//! other options when it comes to running a node.
|
||||
<a href=#7 id=7 data-nosnippet>7</a>//!
|
||||
<a href=#8 id=8 data-nosnippet>8</a>//! [`your_first_runtime`] is a runtime with no consensus related code, and therefore can only be
|
||||
<a href=#9 id=9 data-nosnippet>9</a>//! executed with a node that also expects no consensus ([`sc_consensus_manual_seal`]).
|
||||
<a href=#10 id=10 data-nosnippet>10</a>//! `pezkuwi-omni-node`'s [`--dev-block-time`] precisely does this.
|
||||
<a href=#11 id=11 data-nosnippet>11</a>//!
|
||||
<a href=#12 id=12 data-nosnippet>12</a>//! > All of the following steps are coded as unit tests of this module. Please see `Source` of the
|
||||
<a href=#13 id=13 data-nosnippet>13</a>//! > page for more information.
|
||||
<a href=#14 id=14 data-nosnippet>14</a>//!
|
||||
<a href=#15 id=15 data-nosnippet>15</a>//! ## Running The Omni Node
|
||||
<a href=#16 id=16 data-nosnippet>16</a>//!
|
||||
<a href=#17 id=17 data-nosnippet>17</a>//! ### Installs
|
||||
<a href=#18 id=18 data-nosnippet>18</a>//!
|
||||
<a href=#19 id=19 data-nosnippet>19</a>//! The `pezkuwi-omni-node` can either be downloaded from the latest [Release](https://github.com/pezkuwichain/pezkuwi-sdk/releases/) of `pezkuwi-sdk`,
|
||||
<a href=#20 id=20 data-nosnippet>20</a>//! or installed using `cargo`:
|
||||
<a href=#21 id=21 data-nosnippet>21</a>//!
|
||||
<a href=#22 id=22 data-nosnippet>22</a>//! ```text
|
||||
<a href=#23 id=23 data-nosnippet>23</a>//! cargo install pezkuwi-omni-node
|
||||
<a href=#24 id=24 data-nosnippet>24</a>//! ```
|
||||
<a href=#25 id=25 data-nosnippet>25</a>//!
|
||||
<a href=#26 id=26 data-nosnippet>26</a>//! Next, we need to install the `chain-spec-builder`. This is the tool that allows us to build
|
||||
<a href=#27 id=27 data-nosnippet>27</a>//! chain-specifications, through interacting with the genesis related APIs of the runtime, as
|
||||
<a href=#28 id=28 data-nosnippet>28</a>//! described in [`crate::guides::your_first_runtime#genesis-configuration`].
|
||||
<a href=#29 id=29 data-nosnippet>29</a>//!
|
||||
<a href=#30 id=30 data-nosnippet>30</a>//! ```text
|
||||
<a href=#31 id=31 data-nosnippet>31</a>//! cargo install staging-chain-spec-builder
|
||||
<a href=#32 id=32 data-nosnippet>32</a>//! ```
|
||||
<a href=#33 id=33 data-nosnippet>33</a>//!
|
||||
<a href=#34 id=34 data-nosnippet>34</a>//! > The name of the crate is prefixed with `staging` as the crate name `chain-spec-builder` on
|
||||
<a href=#35 id=35 data-nosnippet>35</a>//! > crates.io is already taken and is not controlled by `pezkuwi-sdk` developers.
|
||||
<a href=#36 id=36 data-nosnippet>36</a>//!
|
||||
<a href=#37 id=37 data-nosnippet>37</a>//! ### Building Runtime
|
||||
<a href=#38 id=38 data-nosnippet>38</a>//!
|
||||
<a href=#39 id=39 data-nosnippet>39</a>//! Next, we need to build the corresponding runtime that we wish to interact with.
|
||||
<a href=#40 id=40 data-nosnippet>40</a>//!
|
||||
<a href=#41 id=41 data-nosnippet>41</a>//! ```text
|
||||
<a href=#42 id=42 data-nosnippet>42</a>//! cargo build --release -p path-to-runtime
|
||||
<a href=#43 id=43 data-nosnippet>43</a>//! ```
|
||||
<a href=#44 id=44 data-nosnippet>44</a>//! Equivalent code in tests:
|
||||
<a href=#45 id=45 data-nosnippet>45</a></span><span class="attr">#![doc = <span class="macro">docify::embed!</span>(<span class="string">"./src/guides/your_first_runtime.rs"</span>, build_runtime)]
|
||||
<a href=#46 id=46 data-nosnippet>46</a></span><span class="doccomment">//!
|
||||
<a href=#47 id=47 data-nosnippet>47</a>//! This creates the wasm file under `./target/{release}/wbuild/release` directory.
|
||||
<a href=#48 id=48 data-nosnippet>48</a>//!
|
||||
<a href=#49 id=49 data-nosnippet>49</a>//! ### Building Chain Spec
|
||||
<a href=#50 id=50 data-nosnippet>50</a>//!
|
||||
<a href=#51 id=51 data-nosnippet>51</a>//! Next, we can generate the corresponding chain-spec file. For this example, we will use the
|
||||
<a href=#52 id=52 data-nosnippet>52</a>//! `development` (`sp_genesis_config::DEVELOPMENT`) preset.
|
||||
<a href=#53 id=53 data-nosnippet>53</a>//!
|
||||
<a href=#54 id=54 data-nosnippet>54</a>//! Note that we intend to run this chain-spec with `pezkuwi-omni-node`, which is tailored for
|
||||
<a href=#55 id=55 data-nosnippet>55</a>//! running teyrchains. This requires the chain-spec to always contain the `para_id` and a
|
||||
<a href=#56 id=56 data-nosnippet>56</a>//! `relay_chain` fields, which are provided below as CLI arguments.
|
||||
<a href=#57 id=57 data-nosnippet>57</a>//!
|
||||
<a href=#58 id=58 data-nosnippet>58</a>//! ```text
|
||||
<a href=#59 id=59 data-nosnippet>59</a>//! chain-spec-builder \
|
||||
<a href=#60 id=60 data-nosnippet>60</a>//! -c <path-to-output> \
|
||||
<a href=#61 id=61 data-nosnippet>61</a>//! create \
|
||||
<a href=#62 id=62 data-nosnippet>62</a>//! --relay-chain dontcare \
|
||||
<a href=#63 id=63 data-nosnippet>63</a>//! --runtime pezkuwi_sdk_docs_first_runtime.wasm \
|
||||
<a href=#64 id=64 data-nosnippet>64</a>//! named-preset development
|
||||
<a href=#65 id=65 data-nosnippet>65</a>//! ```
|
||||
<a href=#66 id=66 data-nosnippet>66</a>//!
|
||||
<a href=#67 id=67 data-nosnippet>67</a>//! Equivalent code in tests:
|
||||
<a href=#68 id=68 data-nosnippet>68</a></span><span class="attr">#![doc = <span class="macro">docify::embed!</span>(<span class="string">"./src/guides/your_first_node.rs"</span>, csb)]
|
||||
<a href=#69 id=69 data-nosnippet>69</a></span><span class="doccomment">//!
|
||||
<a href=#70 id=70 data-nosnippet>70</a>//!
|
||||
<a href=#71 id=71 data-nosnippet>71</a>//! ### Running `pezkuwi-omni-node`
|
||||
<a href=#72 id=72 data-nosnippet>72</a>//!
|
||||
<a href=#73 id=73 data-nosnippet>73</a>//! Finally, we can run the node with the generated chain-spec file. We can also specify the block
|
||||
<a href=#74 id=74 data-nosnippet>74</a>//! time using the `--dev-block-time` flag.
|
||||
<a href=#75 id=75 data-nosnippet>75</a>//!
|
||||
<a href=#76 id=76 data-nosnippet>76</a>//! ```text
|
||||
<a href=#77 id=77 data-nosnippet>77</a>//! pezkuwi-omni-node \
|
||||
<a href=#78 id=78 data-nosnippet>78</a>//! --tmp \
|
||||
<a href=#79 id=79 data-nosnippet>79</a>//! --dev-block-time 1000 \
|
||||
<a href=#80 id=80 data-nosnippet>80</a>//! --chain <chain_spec_file>.json
|
||||
<a href=#81 id=81 data-nosnippet>81</a>//! ```
|
||||
<a href=#82 id=82 data-nosnippet>82</a>//!
|
||||
<a href=#83 id=83 data-nosnippet>83</a>//! > Note that we always prefer to use `--tmp` for testing, as it will save the chain state to a
|
||||
<a href=#84 id=84 data-nosnippet>84</a>//! > temporary folder, allowing the chain-to be easily restarted without `purge-chain`. See
|
||||
<a href=#85 id=85 data-nosnippet>85</a>//! > [`sc_cli::commands::PurgeChainCmd`] and [`sc_cli::commands::RunCmd::tmp`] for more info.
|
||||
<a href=#86 id=86 data-nosnippet>86</a>//!
|
||||
<a href=#87 id=87 data-nosnippet>87</a>//! This will start the node and import the blocks. Note while using `--dev-block-time`, the node
|
||||
<a href=#88 id=88 data-nosnippet>88</a>//! will use the testing-specific manual-seal consensus. This is an efficient way to test the
|
||||
<a href=#89 id=89 data-nosnippet>89</a>//! application logic of your runtime, without needing to yet care about consensus, block
|
||||
<a href=#90 id=90 data-nosnippet>90</a>//! production, relay-chain and so on.
|
||||
<a href=#91 id=91 data-nosnippet>91</a>//!
|
||||
<a href=#92 id=92 data-nosnippet>92</a>//! ### Next Steps
|
||||
<a href=#93 id=93 data-nosnippet>93</a>//!
|
||||
<a href=#94 id=94 data-nosnippet>94</a>//! * See the rest of the steps in [`crate::reference_docs::omni_node#user-journey`].
|
||||
<a href=#95 id=95 data-nosnippet>95</a>//!
|
||||
<a href=#96 id=96 data-nosnippet>96</a>//! [`runtime`]: crate::reference_docs::glossary#runtime
|
||||
<a href=#97 id=97 data-nosnippet>97</a>//! [`node`]: crate::reference_docs::glossary#node
|
||||
<a href=#98 id=98 data-nosnippet>98</a>//! [`build_config`]: first_runtime::Runtime#method.build_config
|
||||
<a href=#99 id=99 data-nosnippet>99</a>//! [`omni-node`]: crate::reference_docs::omni_node
|
||||
<a href=#100 id=100 data-nosnippet>100</a>//! [`--dev-block-time`]: (pezkuwi_omni_node_lib::cli::Cli::dev_block_time)
|
||||
<a href=#101 id=101 data-nosnippet>101</a>
|
||||
<a href=#102 id=102 data-nosnippet>102</a></span><span class="attr">#[cfg(test)]
|
||||
<a href=#103 id=103 data-nosnippet>103</a></span><span class="kw">mod </span>tests {
|
||||
<a href=#104 id=104 data-nosnippet>104</a> <span class="kw">use </span>assert_cmd::assert::OutputAssertExt;
|
||||
<a href=#105 id=105 data-nosnippet>105</a> <span class="kw">use </span>cmd_lib::<span class="kw-2">*</span>;
|
||||
<a href=#106 id=106 data-nosnippet>106</a> <span class="kw">use </span>rand::Rng;
|
||||
<a href=#107 id=107 data-nosnippet>107</a> <span class="kw">use </span>sc_chain_spec::{DEV_RUNTIME_PRESET, LOCAL_TESTNET_RUNTIME_PRESET};
|
||||
<a href=#108 id=108 data-nosnippet>108</a> <span class="kw">use </span>sp_genesis_builder::PresetId;
|
||||
<a href=#109 id=109 data-nosnippet>109</a> <span class="kw">use </span>std::{
|
||||
<a href=#110 id=110 data-nosnippet>110</a> io::{BufRead, BufReader},
|
||||
<a href=#111 id=111 data-nosnippet>111</a> path::PathBuf,
|
||||
<a href=#112 id=112 data-nosnippet>112</a> process::{ChildStderr, Command, Stdio},
|
||||
<a href=#113 id=113 data-nosnippet>113</a> time::Duration,
|
||||
<a href=#114 id=114 data-nosnippet>114</a> };
|
||||
<a href=#115 id=115 data-nosnippet>115</a>
|
||||
<a href=#116 id=116 data-nosnippet>116</a> <span class="kw">const </span>PARA_RUNTIME: <span class="kw-2">&</span><span class="lifetime">'static </span>str = <span class="string">"teyrchain-template-runtime"</span>;
|
||||
<a href=#117 id=117 data-nosnippet>117</a> <span class="kw">const </span>CHAIN_SPEC_BUILDER: <span class="kw-2">&</span><span class="lifetime">'static </span>str = <span class="string">"chain-spec-builder"</span>;
|
||||
<a href=#118 id=118 data-nosnippet>118</a> <span class="kw">const </span>OMNI_NODE: <span class="kw-2">&</span><span class="lifetime">'static </span>str = <span class="string">"pezkuwi-omni-node"</span>;
|
||||
<a href=#119 id=119 data-nosnippet>119</a>
|
||||
<a href=#120 id=120 data-nosnippet>120</a> <span class="kw">fn </span>cargo() -> Command {
|
||||
<a href=#121 id=121 data-nosnippet>121</a> Command::new(std::env::var(<span class="string">"CARGO"</span>).unwrap_or_else(|<span class="kw">_</span>| <span class="string">"cargo"</span>.to_string()))
|
||||
<a href=#122 id=122 data-nosnippet>122</a> }
|
||||
<a href=#123 id=123 data-nosnippet>123</a>
|
||||
<a href=#124 id=124 data-nosnippet>124</a> <span class="kw">fn </span>get_target_directory() -> <span class="prelude-ty">Option</span><PathBuf> {
|
||||
<a href=#125 id=125 data-nosnippet>125</a> <span class="kw">let </span>output = cargo().arg(<span class="string">"metadata"</span>).arg(<span class="string">"--format-version=1"</span>).output().ok()<span class="question-mark">?</span>;
|
||||
<a href=#126 id=126 data-nosnippet>126</a>
|
||||
<a href=#127 id=127 data-nosnippet>127</a> <span class="kw">if </span>!output.status.success() {
|
||||
<a href=#128 id=128 data-nosnippet>128</a> <span class="kw">return </span><span class="prelude-val">None</span>;
|
||||
<a href=#129 id=129 data-nosnippet>129</a> }
|
||||
<a href=#130 id=130 data-nosnippet>130</a>
|
||||
<a href=#131 id=131 data-nosnippet>131</a> <span class="kw">let </span>metadata: serde_json::Value = serde_json::from_slice(<span class="kw-2">&</span>output.stdout).ok()<span class="question-mark">?</span>;
|
||||
<a href=#132 id=132 data-nosnippet>132</a> <span class="kw">let </span>target_directory = metadata[<span class="string">"target_directory"</span>].as_str()<span class="question-mark">?</span>;
|
||||
<a href=#133 id=133 data-nosnippet>133</a>
|
||||
<a href=#134 id=134 data-nosnippet>134</a> <span class="prelude-val">Some</span>(PathBuf::from(target_directory))
|
||||
<a href=#135 id=135 data-nosnippet>135</a> }
|
||||
<a href=#136 id=136 data-nosnippet>136</a>
|
||||
<a href=#137 id=137 data-nosnippet>137</a> <span class="kw">fn </span>find_release_binary(name: <span class="kw-2">&</span>str) -> <span class="prelude-ty">Option</span><PathBuf> {
|
||||
<a href=#138 id=138 data-nosnippet>138</a> <span class="kw">let </span>target_dir = get_target_directory()<span class="question-mark">?</span>;
|
||||
<a href=#139 id=139 data-nosnippet>139</a> <span class="kw">let </span>release_path = target_dir.join(<span class="string">"release"</span>).join(name);
|
||||
<a href=#140 id=140 data-nosnippet>140</a>
|
||||
<a href=#141 id=141 data-nosnippet>141</a> <span class="kw">if </span>release_path.exists() {
|
||||
<a href=#142 id=142 data-nosnippet>142</a> <span class="prelude-val">Some</span>(release_path)
|
||||
<a href=#143 id=143 data-nosnippet>143</a> } <span class="kw">else </span>{
|
||||
<a href=#144 id=144 data-nosnippet>144</a> <span class="prelude-val">None
|
||||
<a href=#145 id=145 data-nosnippet>145</a> </span>}
|
||||
<a href=#146 id=146 data-nosnippet>146</a> }
|
||||
<a href=#147 id=147 data-nosnippet>147</a>
|
||||
<a href=#148 id=148 data-nosnippet>148</a> <span class="kw">fn </span>find_wasm(runtime_name: <span class="kw-2">&</span>str) -> <span class="prelude-ty">Option</span><PathBuf> {
|
||||
<a href=#149 id=149 data-nosnippet>149</a> <span class="kw">let </span>target_dir = get_target_directory()<span class="question-mark">?</span>;
|
||||
<a href=#150 id=150 data-nosnippet>150</a> <span class="kw">let </span>wasm_path = target_dir
|
||||
<a href=#151 id=151 data-nosnippet>151</a> .join(<span class="string">"release"</span>)
|
||||
<a href=#152 id=152 data-nosnippet>152</a> .join(<span class="string">"wbuild"</span>)
|
||||
<a href=#153 id=153 data-nosnippet>153</a> .join(runtime_name)
|
||||
<a href=#154 id=154 data-nosnippet>154</a> .join(<span class="macro">format!</span>(<span class="string">"{}.wasm"</span>, runtime_name.replace(<span class="string">'-'</span>, <span class="string">"_"</span>)));
|
||||
<a href=#155 id=155 data-nosnippet>155</a>
|
||||
<a href=#156 id=156 data-nosnippet>156</a> <span class="kw">if </span>wasm_path.exists() {
|
||||
<a href=#157 id=157 data-nosnippet>157</a> <span class="prelude-val">Some</span>(wasm_path)
|
||||
<a href=#158 id=158 data-nosnippet>158</a> } <span class="kw">else </span>{
|
||||
<a href=#159 id=159 data-nosnippet>159</a> <span class="prelude-val">None
|
||||
<a href=#160 id=160 data-nosnippet>160</a> </span>}
|
||||
<a href=#161 id=161 data-nosnippet>161</a> }
|
||||
<a href=#162 id=162 data-nosnippet>162</a>
|
||||
<a href=#163 id=163 data-nosnippet>163</a> <span class="kw">fn </span>maybe_build_runtimes() {
|
||||
<a href=#164 id=164 data-nosnippet>164</a> <span class="kw">if </span>find_wasm(<span class="kw-2">&</span>PARA_RUNTIME).is_none() {
|
||||
<a href=#165 id=165 data-nosnippet>165</a> <span class="macro">println!</span>(<span class="string">"Building teyrchain-template-runtime..."</span>);
|
||||
<a href=#166 id=166 data-nosnippet>166</a> Command::new(<span class="string">"cargo"</span>)
|
||||
<a href=#167 id=167 data-nosnippet>167</a> .arg(<span class="string">"build"</span>)
|
||||
<a href=#168 id=168 data-nosnippet>168</a> .arg(<span class="string">"--release"</span>)
|
||||
<a href=#169 id=169 data-nosnippet>169</a> .arg(<span class="string">"-p"</span>)
|
||||
<a href=#170 id=170 data-nosnippet>170</a> .arg(PARA_RUNTIME)
|
||||
<a href=#171 id=171 data-nosnippet>171</a> .assert()
|
||||
<a href=#172 id=172 data-nosnippet>172</a> .success();
|
||||
<a href=#173 id=173 data-nosnippet>173</a> }
|
||||
<a href=#174 id=174 data-nosnippet>174</a>
|
||||
<a href=#175 id=175 data-nosnippet>175</a> <span class="macro">assert!</span>(find_wasm(PARA_RUNTIME).is_some());
|
||||
<a href=#176 id=176 data-nosnippet>176</a> }
|
||||
<a href=#177 id=177 data-nosnippet>177</a>
|
||||
<a href=#178 id=178 data-nosnippet>178</a> <span class="kw">fn </span>maybe_build_chain_spec_builder() {
|
||||
<a href=#179 id=179 data-nosnippet>179</a> <span class="kw">if </span>find_release_binary(CHAIN_SPEC_BUILDER).is_none() {
|
||||
<a href=#180 id=180 data-nosnippet>180</a> <span class="macro">println!</span>(<span class="string">"Building chain-spec-builder..."</span>);
|
||||
<a href=#181 id=181 data-nosnippet>181</a> Command::new(<span class="string">"cargo"</span>)
|
||||
<a href=#182 id=182 data-nosnippet>182</a> .arg(<span class="string">"build"</span>)
|
||||
<a href=#183 id=183 data-nosnippet>183</a> .arg(<span class="string">"--release"</span>)
|
||||
<a href=#184 id=184 data-nosnippet>184</a> .arg(<span class="string">"-p"</span>)
|
||||
<a href=#185 id=185 data-nosnippet>185</a> .arg(<span class="string">"staging-chain-spec-builder"</span>)
|
||||
<a href=#186 id=186 data-nosnippet>186</a> .assert()
|
||||
<a href=#187 id=187 data-nosnippet>187</a> .success();
|
||||
<a href=#188 id=188 data-nosnippet>188</a> }
|
||||
<a href=#189 id=189 data-nosnippet>189</a> <span class="macro">assert!</span>(find_release_binary(CHAIN_SPEC_BUILDER).is_some());
|
||||
<a href=#190 id=190 data-nosnippet>190</a> }
|
||||
<a href=#191 id=191 data-nosnippet>191</a>
|
||||
<a href=#192 id=192 data-nosnippet>192</a> <span class="kw">fn </span>maybe_build_omni_node() {
|
||||
<a href=#193 id=193 data-nosnippet>193</a> <span class="kw">if </span>find_release_binary(OMNI_NODE).is_none() {
|
||||
<a href=#194 id=194 data-nosnippet>194</a> <span class="macro">println!</span>(<span class="string">"Building pezkuwi-omni-node..."</span>);
|
||||
<a href=#195 id=195 data-nosnippet>195</a> Command::new(<span class="string">"cargo"</span>)
|
||||
<a href=#196 id=196 data-nosnippet>196</a> .arg(<span class="string">"build"</span>)
|
||||
<a href=#197 id=197 data-nosnippet>197</a> .arg(<span class="string">"--release"</span>)
|
||||
<a href=#198 id=198 data-nosnippet>198</a> .arg(<span class="string">"-p"</span>)
|
||||
<a href=#199 id=199 data-nosnippet>199</a> .arg(<span class="string">"pezkuwi-omni-node"</span>)
|
||||
<a href=#200 id=200 data-nosnippet>200</a> .assert()
|
||||
<a href=#201 id=201 data-nosnippet>201</a> .success();
|
||||
<a href=#202 id=202 data-nosnippet>202</a> }
|
||||
<a href=#203 id=203 data-nosnippet>203</a> }
|
||||
<a href=#204 id=204 data-nosnippet>204</a>
|
||||
<a href=#205 id=205 data-nosnippet>205</a> <span class="kw">async fn </span>imported_block_found(stderr: ChildStderr, block: u64, timeout: u64) -> bool {
|
||||
<a href=#206 id=206 data-nosnippet>206</a> tokio::time::timeout(Duration::from_secs(timeout), <span class="kw">async </span>{
|
||||
<a href=#207 id=207 data-nosnippet>207</a> <span class="kw">let </span>want = <span class="macro">format!</span>(<span class="string">"Imported #{}"</span>, block);
|
||||
<a href=#208 id=208 data-nosnippet>208</a> <span class="kw">let </span>reader = BufReader::new(stderr);
|
||||
<a href=#209 id=209 data-nosnippet>209</a> <span class="kw">let </span><span class="kw-2">mut </span>found_block = <span class="bool-val">false</span>;
|
||||
<a href=#210 id=210 data-nosnippet>210</a> <span class="kw">for </span>line <span class="kw">in </span>reader.lines() {
|
||||
<a href=#211 id=211 data-nosnippet>211</a> <span class="kw">if </span>line.unwrap().contains(<span class="kw-2">&</span>want) {
|
||||
<a href=#212 id=212 data-nosnippet>212</a> found_block = <span class="bool-val">true</span>;
|
||||
<a href=#213 id=213 data-nosnippet>213</a> <span class="kw">break</span>;
|
||||
<a href=#214 id=214 data-nosnippet>214</a> }
|
||||
<a href=#215 id=215 data-nosnippet>215</a> }
|
||||
<a href=#216 id=216 data-nosnippet>216</a> found_block
|
||||
<a href=#217 id=217 data-nosnippet>217</a> })
|
||||
<a href=#218 id=218 data-nosnippet>218</a> .<span class="kw">await
|
||||
<a href=#219 id=219 data-nosnippet>219</a> </span>.unwrap()
|
||||
<a href=#220 id=220 data-nosnippet>220</a> }
|
||||
<a href=#221 id=221 data-nosnippet>221</a>
|
||||
<a href=#222 id=222 data-nosnippet>222</a> <span class="kw">async fn </span>test_runtime_preset(
|
||||
<a href=#223 id=223 data-nosnippet>223</a> runtime: <span class="kw-2">&</span><span class="lifetime">'static </span>str,
|
||||
<a href=#224 id=224 data-nosnippet>224</a> block_time: u64,
|
||||
<a href=#225 id=225 data-nosnippet>225</a> maybe_preset: <span class="prelude-ty">Option</span><PresetId>,
|
||||
<a href=#226 id=226 data-nosnippet>226</a> ) {
|
||||
<a href=#227 id=227 data-nosnippet>227</a> sp_tracing::try_init_simple();
|
||||
<a href=#228 id=228 data-nosnippet>228</a> maybe_build_runtimes();
|
||||
<a href=#229 id=229 data-nosnippet>229</a> maybe_build_chain_spec_builder();
|
||||
<a href=#230 id=230 data-nosnippet>230</a> maybe_build_omni_node();
|
||||
<a href=#231 id=231 data-nosnippet>231</a>
|
||||
<a href=#232 id=232 data-nosnippet>232</a> <span class="kw">let </span>chain_spec_builder =
|
||||
<a href=#233 id=233 data-nosnippet>233</a> find_release_binary(<span class="kw-2">&</span>CHAIN_SPEC_BUILDER).expect(<span class="string">"we built it above; qed"</span>);
|
||||
<a href=#234 id=234 data-nosnippet>234</a> <span class="kw">let </span>omni_node = find_release_binary(OMNI_NODE).expect(<span class="string">"we built it above; qed"</span>);
|
||||
<a href=#235 id=235 data-nosnippet>235</a> <span class="kw">let </span>runtime_path = find_wasm(runtime).expect(<span class="string">"we built it above; qed"</span>);
|
||||
<a href=#236 id=236 data-nosnippet>236</a>
|
||||
<a href=#237 id=237 data-nosnippet>237</a> <span class="kw">let </span>random_seed: u32 = rand::thread_rng().gen();
|
||||
<a href=#238 id=238 data-nosnippet>238</a> <span class="kw">let </span>chain_spec_file = std::env::current_dir()
|
||||
<a href=#239 id=239 data-nosnippet>239</a> .unwrap()
|
||||
<a href=#240 id=240 data-nosnippet>240</a> .join(<span class="macro">format!</span>(<span class="string">"{}_{}_{}.json"</span>, runtime, block_time, random_seed));
|
||||
<a href=#241 id=241 data-nosnippet>241</a>
|
||||
<a href=#242 id=242 data-nosnippet>242</a> Command::new(chain_spec_builder)
|
||||
<a href=#243 id=243 data-nosnippet>243</a> .args([<span class="string">"-c"</span>, chain_spec_file.to_str().unwrap()])
|
||||
<a href=#244 id=244 data-nosnippet>244</a> .arg(<span class="string">"create"</span>)
|
||||
<a href=#245 id=245 data-nosnippet>245</a> .args([<span class="string">"--relay-chain"</span>, <span class="string">"dontcare"</span>])
|
||||
<a href=#246 id=246 data-nosnippet>246</a> .args([<span class="string">"-r"</span>, runtime_path.to_str().unwrap()])
|
||||
<a href=#247 id=247 data-nosnippet>247</a> .args(<span class="kw">match </span>maybe_preset {
|
||||
<a href=#248 id=248 data-nosnippet>248</a> <span class="prelude-val">Some</span>(preset) => <span class="macro">vec!</span>[<span class="string">"named-preset"</span>.to_string(), preset.to_string()],
|
||||
<a href=#249 id=249 data-nosnippet>249</a> <span class="prelude-val">None </span>=> <span class="macro">vec!</span>[<span class="string">"default"</span>.to_string()],
|
||||
<a href=#250 id=250 data-nosnippet>250</a> })
|
||||
<a href=#251 id=251 data-nosnippet>251</a> .assert()
|
||||
<a href=#252 id=252 data-nosnippet>252</a> .success();
|
||||
<a href=#253 id=253 data-nosnippet>253</a>
|
||||
<a href=#254 id=254 data-nosnippet>254</a> <span class="kw">let </span><span class="kw-2">mut </span>child = Command::new(omni_node)
|
||||
<a href=#255 id=255 data-nosnippet>255</a> .arg(<span class="string">"--tmp"</span>)
|
||||
<a href=#256 id=256 data-nosnippet>256</a> .args([<span class="string">"--chain"</span>, chain_spec_file.to_str().unwrap()])
|
||||
<a href=#257 id=257 data-nosnippet>257</a> .args([<span class="string">"--dev-block-time"</span>, block_time.to_string().as_str()])
|
||||
<a href=#258 id=258 data-nosnippet>258</a> .stderr(Stdio::piped())
|
||||
<a href=#259 id=259 data-nosnippet>259</a> .spawn()
|
||||
<a href=#260 id=260 data-nosnippet>260</a> .unwrap();
|
||||
<a href=#261 id=261 data-nosnippet>261</a>
|
||||
<a href=#262 id=262 data-nosnippet>262</a> <span class="comment">// Take stderr and parse it with timeout.
|
||||
<a href=#263 id=263 data-nosnippet>263</a> </span><span class="kw">let </span>stderr = child.stderr.take().unwrap();
|
||||
<a href=#264 id=264 data-nosnippet>264</a> <span class="kw">let </span>expected_blocks = (<span class="number">10_000 </span>/ block_time).saturating_div(<span class="number">2</span>);
|
||||
<a href=#265 id=265 data-nosnippet>265</a> <span class="macro">assert!</span>(expected_blocks > <span class="number">0</span>, <span class="string">"test configuration is bad, should give it more time"</span>);
|
||||
<a href=#266 id=266 data-nosnippet>266</a> <span class="macro">assert_eq!</span>(imported_block_found(stderr, expected_blocks, <span class="number">100</span>).<span class="kw">await</span>, <span class="bool-val">true</span>);
|
||||
<a href=#267 id=267 data-nosnippet>267</a> std::fs::remove_file(chain_spec_file).unwrap();
|
||||
<a href=#268 id=268 data-nosnippet>268</a> child.kill().unwrap();
|
||||
<a href=#269 id=269 data-nosnippet>269</a> }
|
||||
<a href=#270 id=270 data-nosnippet>270</a>
|
||||
<a href=#271 id=271 data-nosnippet>271</a> <span class="comment">// Sets up omni-node to run a text exercise based on a chain spec.
|
||||
<a href=#272 id=272 data-nosnippet>272</a> </span><span class="kw">async fn </span>omni_node_test_setup(chain_spec_path: PathBuf) {
|
||||
<a href=#273 id=273 data-nosnippet>273</a> maybe_build_omni_node();
|
||||
<a href=#274 id=274 data-nosnippet>274</a> <span class="kw">let </span>omni_node = find_release_binary(OMNI_NODE).unwrap();
|
||||
<a href=#275 id=275 data-nosnippet>275</a>
|
||||
<a href=#276 id=276 data-nosnippet>276</a> <span class="kw">let </span><span class="kw-2">mut </span>child = Command::new(omni_node)
|
||||
<a href=#277 id=277 data-nosnippet>277</a> .arg(<span class="string">"--dev"</span>)
|
||||
<a href=#278 id=278 data-nosnippet>278</a> .args([<span class="string">"--chain"</span>, chain_spec_path.to_str().unwrap()])
|
||||
<a href=#279 id=279 data-nosnippet>279</a> .stderr(Stdio::piped())
|
||||
<a href=#280 id=280 data-nosnippet>280</a> .spawn()
|
||||
<a href=#281 id=281 data-nosnippet>281</a> .unwrap();
|
||||
<a href=#282 id=282 data-nosnippet>282</a>
|
||||
<a href=#283 id=283 data-nosnippet>283</a> <span class="kw">let </span>stderr = child.stderr.take().unwrap();
|
||||
<a href=#284 id=284 data-nosnippet>284</a> <span class="macro">assert_eq!</span>(imported_block_found(stderr, <span class="number">7</span>, <span class="number">100</span>).<span class="kw">await</span>, <span class="bool-val">true</span>);
|
||||
<a href=#285 id=285 data-nosnippet>285</a> child.kill().unwrap();
|
||||
<a href=#286 id=286 data-nosnippet>286</a> }
|
||||
<a href=#287 id=287 data-nosnippet>287</a>
|
||||
<a href=#288 id=288 data-nosnippet>288</a> <span class="attr">#[tokio::test]
|
||||
<a href=#289 id=289 data-nosnippet>289</a> </span><span class="kw">async fn </span>works_with_different_block_times() {
|
||||
<a href=#290 id=290 data-nosnippet>290</a> test_runtime_preset(PARA_RUNTIME, <span class="number">100</span>, <span class="prelude-val">Some</span>(DEV_RUNTIME_PRESET.into())).<span class="kw">await</span>;
|
||||
<a href=#291 id=291 data-nosnippet>291</a> test_runtime_preset(PARA_RUNTIME, <span class="number">3000</span>, <span class="prelude-val">Some</span>(DEV_RUNTIME_PRESET.into())).<span class="kw">await</span>;
|
||||
<a href=#292 id=292 data-nosnippet>292</a>
|
||||
<a href=#293 id=293 data-nosnippet>293</a> <span class="comment">// we need this snippet just for docs
|
||||
<a href=#294 id=294 data-nosnippet>294</a> </span><span class="attr">#[docify::export_content(csb)]
|
||||
<a href=#295 id=295 data-nosnippet>295</a> </span><span class="kw">fn </span>build_teyrchain_spec_works() {
|
||||
<a href=#296 id=296 data-nosnippet>296</a> <span class="kw">let </span>chain_spec_builder = find_release_binary(<span class="kw-2">&</span>CHAIN_SPEC_BUILDER).unwrap();
|
||||
<a href=#297 id=297 data-nosnippet>297</a> <span class="kw">let </span>runtime_path = find_wasm(PARA_RUNTIME).unwrap();
|
||||
<a href=#298 id=298 data-nosnippet>298</a> <span class="kw">let </span>output = <span class="string">"/tmp/demo-chain-spec.json"</span>;
|
||||
<a href=#299 id=299 data-nosnippet>299</a> <span class="kw">let </span>runtime_str = runtime_path.to_str().unwrap();
|
||||
<a href=#300 id=300 data-nosnippet>300</a> <span class="macro">run_cmd!</span>(
|
||||
<a href=#301 id=301 data-nosnippet>301</a> <span class="macro-nonterminal">$chain_spec_builder </span>-c <span class="macro-nonterminal">$output </span>create --relay-chain dontcare -r <span class="macro-nonterminal">$runtime_str </span>named-preset development
|
||||
<a href=#302 id=302 data-nosnippet>302</a> ).expect(<span class="string">"Failed to run command"</span>);
|
||||
<a href=#303 id=303 data-nosnippet>303</a> std::fs::remove_file(output).unwrap();
|
||||
<a href=#304 id=304 data-nosnippet>304</a> }
|
||||
<a href=#305 id=305 data-nosnippet>305</a> build_teyrchain_spec_works();
|
||||
<a href=#306 id=306 data-nosnippet>306</a> }
|
||||
<a href=#307 id=307 data-nosnippet>307</a>
|
||||
<a href=#308 id=308 data-nosnippet>308</a> <span class="attr">#[tokio::test]
|
||||
<a href=#309 id=309 data-nosnippet>309</a> </span><span class="kw">async fn </span>teyrchain_runtime_works() {
|
||||
<a href=#310 id=310 data-nosnippet>310</a> <span class="comment">// TODO: None doesn't work. But maybe it should? it would be misleading as many users might
|
||||
<a href=#311 id=311 data-nosnippet>311</a> // use it.
|
||||
<a href=#312 id=312 data-nosnippet>312</a> </span><span class="kw">for </span>preset <span class="kw">in </span>[<span class="prelude-val">Some</span>(DEV_RUNTIME_PRESET.into()), <span class="prelude-val">Some</span>(LOCAL_TESTNET_RUNTIME_PRESET.into())] {
|
||||
<a href=#313 id=313 data-nosnippet>313</a> test_runtime_preset(PARA_RUNTIME, <span class="number">1000</span>, preset).<span class="kw">await</span>;
|
||||
<a href=#314 id=314 data-nosnippet>314</a> }
|
||||
<a href=#315 id=315 data-nosnippet>315</a> }
|
||||
<a href=#316 id=316 data-nosnippet>316</a>
|
||||
<a href=#317 id=317 data-nosnippet>317</a> <span class="attr">#[tokio::test]
|
||||
<a href=#318 id=318 data-nosnippet>318</a> </span><span class="kw">async fn </span>omni_node_dev_mode_works() {
|
||||
<a href=#319 id=319 data-nosnippet>319</a> <span class="comment">//Omni Node in dev mode works with teyrchain's template `dev_chain_spec`
|
||||
<a href=#320 id=320 data-nosnippet>320</a> </span><span class="kw">let </span>dev_chain_spec = std::env::current_dir()
|
||||
<a href=#321 id=321 data-nosnippet>321</a> .unwrap()
|
||||
<a href=#322 id=322 data-nosnippet>322</a> .parent()
|
||||
<a href=#323 id=323 data-nosnippet>323</a> .unwrap()
|
||||
<a href=#324 id=324 data-nosnippet>324</a> .parent()
|
||||
<a href=#325 id=325 data-nosnippet>325</a> .unwrap()
|
||||
<a href=#326 id=326 data-nosnippet>326</a> .join(<span class="string">"templates"</span>)
|
||||
<a href=#327 id=327 data-nosnippet>327</a> .join(<span class="string">"teyrchain"</span>)
|
||||
<a href=#328 id=328 data-nosnippet>328</a> .join(<span class="string">"dev_chain_spec.json"</span>);
|
||||
<a href=#329 id=329 data-nosnippet>329</a> omni_node_test_setup(dev_chain_spec).<span class="kw">await</span>;
|
||||
<a href=#330 id=330 data-nosnippet>330</a> }
|
||||
<a href=#331 id=331 data-nosnippet>331</a>
|
||||
<a href=#332 id=332 data-nosnippet>332</a> <span class="attr">#[tokio::test]
|
||||
<a href=#333 id=333 data-nosnippet>333</a> </span><span class="comment">// This is a regresion test so that we still remain compatible with runtimes that use
|
||||
<a href=#334 id=334 data-nosnippet>334</a> // `para-id` in chain specs, instead of implementing the
|
||||
<a href=#335 id=335 data-nosnippet>335</a> // `cumulus_primitives_core::GetTeyrchainInfo`.
|
||||
<a href=#336 id=336 data-nosnippet>336</a> </span><span class="kw">async fn </span>omni_node_dev_mode_works_without_getteyrchaininfo() {
|
||||
<a href=#337 id=337 data-nosnippet>337</a> <span class="kw">let </span>dev_chain_spec = std::env::current_dir()
|
||||
<a href=#338 id=338 data-nosnippet>338</a> .unwrap()
|
||||
<a href=#339 id=339 data-nosnippet>339</a> .join(<span class="string">"src/guides/teyrchain_without_getteyrchaininfo.json"</span>);
|
||||
<a href=#340 id=340 data-nosnippet>340</a> omni_node_test_setup(dev_chain_spec).<span class="kw">await</span>;
|
||||
<a href=#341 id=341 data-nosnippet>341</a> }
|
||||
<a href=#342 id=342 data-nosnippet>342</a>}</code></pre></div></section></main></body></html>
|
||||
@@ -0,0 +1,789 @@
|
||||
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `docs/sdk/src/guides/your_first_pallet/mod.rs`."><title>mod.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2"href="../../../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../../../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../../../../static.files/rustdoc-e56847b5.css"><meta name="rustdoc-vars" data-root-path="../../../../" data-static-root-path="../../../../static.files/" data-current-crate="pezkuwi_sdk_docs" data-themes="" data-resource-suffix="" data-rustdoc-version="1.91.1 (ed61e7d7e 2025-11-07)" data-channel="1.91.1" data-search-js="search-e256b49e.js" data-stringdex-js="stringdex-c3e638e9.js" data-settings-js="settings-c38705f0.js" ><script src="../../../../static.files/storage-e2aeef58.js"></script><script defer src="../../../../static.files/src-script-813739b1.js"></script><script defer src="../../../../src-files.js"></script><script defer src="../../../../static.files/main-6dc2a7f3.js"></script><noscript><link rel="stylesheet" href="../../../../static.files/noscript-263c88ec.css"></noscript><link rel="icon" href="https://pezkuwichain.io/favicon.ico"></head><body class="rustdoc src"><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer" title="Drag to resize sidebar"></div><main><section id="main-content" class="content"><div class="main-heading"><h1><div class="sub-heading">pezkuwi_sdk_docs/guides/your_first_pallet/</div>mod.rs</h1><rustdoc-toolbar></rustdoc-toolbar></div><div class="example-wrap digits-3"><pre class="rust"><code><a href=#1 id=1 data-nosnippet>1</a><span class="doccomment">//! # Currency Pallet
|
||||
<a href=#2 id=2 data-nosnippet>2</a>//!
|
||||
<a href=#3 id=3 data-nosnippet>3</a>//! By the end of this guide, you will have written a small FRAME pallet (see
|
||||
<a href=#4 id=4 data-nosnippet>4</a>//! [`crate::pezkuwi_sdk::frame_runtime`]) that is capable of handling a simple crypto-currency.
|
||||
<a href=#5 id=5 data-nosnippet>5</a>//! This pallet will:
|
||||
<a href=#6 id=6 data-nosnippet>6</a>//!
|
||||
<a href=#7 id=7 data-nosnippet>7</a>//! 1. Allow anyone to mint new tokens into accounts (which is obviously not a great idea for a real
|
||||
<a href=#8 id=8 data-nosnippet>8</a>//! system).
|
||||
<a href=#9 id=9 data-nosnippet>9</a>//! 2. Allow any user that owns tokens to transfer them to others.
|
||||
<a href=#10 id=10 data-nosnippet>10</a>//! 3. Track the total issuance of all tokens at all times.
|
||||
<a href=#11 id=11 data-nosnippet>11</a>//!
|
||||
<a href=#12 id=12 data-nosnippet>12</a>//! > This guide will build a currency pallet from scratch using only the lowest primitives of
|
||||
<a href=#13 id=13 data-nosnippet>13</a>//! > FRAME, and is mainly intended for education, not *applicability*. For example, almost all
|
||||
<a href=#14 id=14 data-nosnippet>14</a>//! > FRAME-based runtimes use various techniques to re-use a currency pallet instead of writing
|
||||
<a href=#15 id=15 data-nosnippet>15</a>//! > one. Further advanced FRAME related topics are discussed in [`crate::reference_docs`].
|
||||
<a href=#16 id=16 data-nosnippet>16</a>//!
|
||||
<a href=#17 id=17 data-nosnippet>17</a>//! ## Writing Your First Pallet
|
||||
<a href=#18 id=18 data-nosnippet>18</a>//!
|
||||
<a href=#19 id=19 data-nosnippet>19</a>//! To get started, clone one of the templates mentioned in [`crate::pezkuwi_sdk::templates`]. We
|
||||
<a href=#20 id=20 data-nosnippet>20</a>//! recommend using the `pezkuwi-sdk-minimal-template`. You might need to change small parts of
|
||||
<a href=#21 id=21 data-nosnippet>21</a>//! this guide, namely the crate/package names, based on which template you use.
|
||||
<a href=#22 id=22 data-nosnippet>22</a>//!
|
||||
<a href=#23 id=23 data-nosnippet>23</a>//! > Be aware that you can read the entire source code backing this tutorial by clicking on the
|
||||
<a href=#24 id=24 data-nosnippet>24</a>//! > `source` button at the top right of the page.
|
||||
<a href=#25 id=25 data-nosnippet>25</a>//!
|
||||
<a href=#26 id=26 data-nosnippet>26</a>//! You should have studied the following modules as a prelude to this guide:
|
||||
<a href=#27 id=27 data-nosnippet>27</a>//!
|
||||
<a href=#28 id=28 data-nosnippet>28</a>//! - [`crate::reference_docs::blockchain_state_machines`]
|
||||
<a href=#29 id=29 data-nosnippet>29</a>//! - [`crate::reference_docs::trait_based_programming`]
|
||||
<a href=#30 id=30 data-nosnippet>30</a>//! - [`crate::pezkuwi_sdk::frame_runtime`]
|
||||
<a href=#31 id=31 data-nosnippet>31</a>//!
|
||||
<a href=#32 id=32 data-nosnippet>32</a>//! ## Topics Covered
|
||||
<a href=#33 id=33 data-nosnippet>33</a>//!
|
||||
<a href=#34 id=34 data-nosnippet>34</a>//! The following FRAME topics are covered in this guide:
|
||||
<a href=#35 id=35 data-nosnippet>35</a>//!
|
||||
<a href=#36 id=36 data-nosnippet>36</a>//! - [`pallet::storage`]
|
||||
<a href=#37 id=37 data-nosnippet>37</a>//! - [`pallet::call`]
|
||||
<a href=#38 id=38 data-nosnippet>38</a>//! - [`pallet::event`]
|
||||
<a href=#39 id=39 data-nosnippet>39</a>//! - [`pallet::error`]
|
||||
<a href=#40 id=40 data-nosnippet>40</a>//! - Basics of testing a pallet
|
||||
<a href=#41 id=41 data-nosnippet>41</a>//! - [Constructing a runtime](frame::runtime::prelude::construct_runtime)
|
||||
<a href=#42 id=42 data-nosnippet>42</a>//!
|
||||
<a href=#43 id=43 data-nosnippet>43</a>//! ### Shell Pallet
|
||||
<a href=#44 id=44 data-nosnippet>44</a>//!
|
||||
<a href=#45 id=45 data-nosnippet>45</a>//! Consider the following as a "shell pallet". We continue building the rest of this pallet based
|
||||
<a href=#46 id=46 data-nosnippet>46</a>//! on this template.
|
||||
<a href=#47 id=47 data-nosnippet>47</a>//!
|
||||
<a href=#48 id=48 data-nosnippet>48</a>//! [`pallet::config`] and [`pallet::pallet`] are both mandatory parts of any
|
||||
<a href=#49 id=49 data-nosnippet>49</a>//! pallet. Refer to the documentation of each to get an overview of what they do.
|
||||
<a href=#50 id=50 data-nosnippet>50</a></span><span class="attr">#![doc = <span class="macro">docify::embed!</span>(<span class="string">"./packages/guides/first-pallet/src/lib.rs"</span>, shell_pallet)]
|
||||
<a href=#51 id=51 data-nosnippet>51</a></span><span class="doccomment">//!
|
||||
<a href=#52 id=52 data-nosnippet>52</a>//! All of the code that follows in this guide should live inside of the `mod pallet`.
|
||||
<a href=#53 id=53 data-nosnippet>53</a>//!
|
||||
<a href=#54 id=54 data-nosnippet>54</a>//! ### Storage
|
||||
<a href=#55 id=55 data-nosnippet>55</a>//!
|
||||
<a href=#56 id=56 data-nosnippet>56</a>//! First, we will need to create two onchain storage declarations.
|
||||
<a href=#57 id=57 data-nosnippet>57</a>//!
|
||||
<a href=#58 id=58 data-nosnippet>58</a>//! One should be a mapping from account-ids to a balance type, and one value that is the total
|
||||
<a href=#59 id=59 data-nosnippet>59</a>//! issuance.
|
||||
<a href=#60 id=60 data-nosnippet>60</a>//!
|
||||
<a href=#61 id=61 data-nosnippet>61</a>//! > For the rest of this guide, we will opt for a balance type of `u128`. For the sake of
|
||||
<a href=#62 id=62 data-nosnippet>62</a>//! > simplicity, we are hardcoding this type. In a real pallet is best practice to define it as a
|
||||
<a href=#63 id=63 data-nosnippet>63</a>//! > generic bounded type in the `Config` trait, and then specify it in the implementation.
|
||||
<a href=#64 id=64 data-nosnippet>64</a></span><span class="attr">#![doc = <span class="macro">docify::embed!</span>(<span class="string">"./packages/guides/first-pallet/src/lib.rs"</span>, Balance)]
|
||||
<a href=#65 id=65 data-nosnippet>65</a></span><span class="doccomment">//!
|
||||
<a href=#66 id=66 data-nosnippet>66</a>//! The definition of these two storage items, based on [`pallet::storage`] details, is as follows:
|
||||
<a href=#67 id=67 data-nosnippet>67</a></span><span class="attr">#![doc = <span class="macro">docify::embed!</span>(<span class="string">"./packages/guides/first-pallet/src/lib.rs"</span>, TotalIssuance)]
|
||||
<a href=#68 id=68 data-nosnippet>68</a>#![doc = <span class="macro">docify::embed!</span>(<span class="string">"./packages/guides/first-pallet/src/lib.rs"</span>, Balances)]
|
||||
<a href=#69 id=69 data-nosnippet>69</a></span><span class="doccomment">//!
|
||||
<a href=#70 id=70 data-nosnippet>70</a>//! ### Dispatchables
|
||||
<a href=#71 id=71 data-nosnippet>71</a>//!
|
||||
<a href=#72 id=72 data-nosnippet>72</a>//! Next, we will define the dispatchable functions. As per [`pallet::call`], these will be defined
|
||||
<a href=#73 id=73 data-nosnippet>73</a>//! as normal `fn`s attached to `struct Pallet`.
|
||||
<a href=#74 id=74 data-nosnippet>74</a></span><span class="attr">#![doc = <span class="macro">docify::embed!</span>(<span class="string">"./packages/guides/first-pallet/src/lib.rs"</span>, impl_pallet)]
|
||||
<a href=#75 id=75 data-nosnippet>75</a></span><span class="doccomment">//!
|
||||
<a href=#76 id=76 data-nosnippet>76</a>//! The logic of these functions is self-explanatory. Instead, we will focus on the FRAME-related
|
||||
<a href=#77 id=77 data-nosnippet>77</a>//! details:
|
||||
<a href=#78 id=78 data-nosnippet>78</a>//!
|
||||
<a href=#79 id=79 data-nosnippet>79</a>//! - Where do `T::AccountId` and `T::RuntimeOrigin` come from? These are both defined in
|
||||
<a href=#80 id=80 data-nosnippet>80</a>//! [`frame::prelude::frame_system::Config`], therefore we can access them in `T`.
|
||||
<a href=#81 id=81 data-nosnippet>81</a>//! - What is `ensure_signed`, and what does it do with the aforementioned `T::RuntimeOrigin`? This
|
||||
<a href=#82 id=82 data-nosnippet>82</a>//! is outside the scope of this guide, and you can learn more about it in the origin reference
|
||||
<a href=#83 id=83 data-nosnippet>83</a>//! document ([`crate::reference_docs::frame_origin`]). For now, you should only know the
|
||||
<a href=#84 id=84 data-nosnippet>84</a>//! signature of the function: it takes a generic `T::RuntimeOrigin` and returns a
|
||||
<a href=#85 id=85 data-nosnippet>85</a>//! `Result<T::AccountId, _>`. So by the end of this function call, we know that this dispatchable
|
||||
<a href=#86 id=86 data-nosnippet>86</a>//! was signed by `sender`.
|
||||
<a href=#87 id=87 data-nosnippet>87</a></span><span class="attr">#![doc = <span class="macro">docify::embed!</span>(<span class="string">"../../substrate/frame/system/src/lib.rs"</span>, ensure_signed)]
|
||||
<a href=#88 id=88 data-nosnippet>88</a></span><span class="doccomment">//!
|
||||
<a href=#89 id=89 data-nosnippet>89</a>//! - Where does `mutate`, `get` and `insert` and other storage APIs come from? All of them are
|
||||
<a href=#90 id=90 data-nosnippet>90</a>//! explained in the corresponding `type`, for example, for `Balances::<T>::insert`, you can look
|
||||
<a href=#91 id=91 data-nosnippet>91</a>//! into [`frame::prelude::StorageMap::insert`].
|
||||
<a href=#92 id=92 data-nosnippet>92</a>//!
|
||||
<a href=#93 id=93 data-nosnippet>93</a>//! - The return type of all dispatchable functions is [`frame::prelude::DispatchResult`]:
|
||||
<a href=#94 id=94 data-nosnippet>94</a></span><span class="attr">#![doc = <span class="macro">docify::embed!</span>(<span class="string">"../../substrate/frame/support/src/dispatch.rs"</span>, DispatchResult)]
|
||||
<a href=#95 id=95 data-nosnippet>95</a></span><span class="doccomment">//!
|
||||
<a href=#96 id=96 data-nosnippet>96</a>//! Which is more or less a normal Rust `Result`, with a custom [`frame::prelude::DispatchError`] as
|
||||
<a href=#97 id=97 data-nosnippet>97</a>//! the `Err` variant. We won't cover this error in detail here, but importantly you should know
|
||||
<a href=#98 id=98 data-nosnippet>98</a>//! that there is an `impl From<&'static string> for DispatchError` provided (see
|
||||
<a href=#99 id=99 data-nosnippet>99</a>//! [here](`frame::prelude::DispatchError#impl-From<%26str>-for-DispatchError`)). Therefore,
|
||||
<a href=#100 id=100 data-nosnippet>100</a>//! we can use basic string literals as our error type and `.into()` them into `DispatchError`.
|
||||
<a href=#101 id=101 data-nosnippet>101</a>//!
|
||||
<a href=#102 id=102 data-nosnippet>102</a>//! - Why are all `get` and `mutate` functions returning an `Option`? This is the default behavior
|
||||
<a href=#103 id=103 data-nosnippet>103</a>//! of FRAME storage APIs. You can learn more about how to override this by looking into
|
||||
<a href=#104 id=104 data-nosnippet>104</a>//! [`pallet::storage`], and [`frame::prelude::ValueQuery`]/[`frame::prelude::OptionQuery`]
|
||||
<a href=#105 id=105 data-nosnippet>105</a>//!
|
||||
<a href=#106 id=106 data-nosnippet>106</a>//! ### Improving Errors
|
||||
<a href=#107 id=107 data-nosnippet>107</a>//!
|
||||
<a href=#108 id=108 data-nosnippet>108</a>//! How we handle error in the above snippets is fairly rudimentary. Let's look at how this can be
|
||||
<a href=#109 id=109 data-nosnippet>109</a>//! improved. First, we can use [`frame::prelude::ensure`] to express the error slightly better.
|
||||
<a href=#110 id=110 data-nosnippet>110</a>//! This macro will call `.into()` under the hood.
|
||||
<a href=#111 id=111 data-nosnippet>111</a></span><span class="attr">#![doc = <span class="macro">docify::embed!</span>(<span class="string">"./packages/guides/first-pallet/src/lib.rs"</span>, transfer_better)]
|
||||
<a href=#112 id=112 data-nosnippet>112</a></span><span class="doccomment">//!
|
||||
<a href=#113 id=113 data-nosnippet>113</a>//! Moreover, you will learn in the [Defensive Programming
|
||||
<a href=#114 id=114 data-nosnippet>114</a>//! section](crate::reference_docs::defensive_programming) that it is always recommended to use
|
||||
<a href=#115 id=115 data-nosnippet>115</a>//! safe arithmetic operations in your runtime. By using [`frame::traits::CheckedSub`], we can not
|
||||
<a href=#116 id=116 data-nosnippet>116</a>//! only take a step in that direction, but also improve the error handing and make it slightly more
|
||||
<a href=#117 id=117 data-nosnippet>117</a>//! ergonomic.
|
||||
<a href=#118 id=118 data-nosnippet>118</a></span><span class="attr">#![doc = <span class="macro">docify::embed!</span>(<span class="string">"./packages/guides/first-pallet/src/lib.rs"</span>, transfer_better_checked)]
|
||||
<a href=#119 id=119 data-nosnippet>119</a></span><span class="doccomment">//!
|
||||
<a href=#120 id=120 data-nosnippet>120</a>//! This is more or less all the logic that there is in this basic currency pallet!
|
||||
<a href=#121 id=121 data-nosnippet>121</a>//!
|
||||
<a href=#122 id=122 data-nosnippet>122</a>//! ### Your First (Test) Runtime
|
||||
<a href=#123 id=123 data-nosnippet>123</a>//!
|
||||
<a href=#124 id=124 data-nosnippet>124</a>//! The typical testing code of a pallet lives in a module that imports some preludes useful for
|
||||
<a href=#125 id=125 data-nosnippet>125</a>//! testing, similar to:
|
||||
<a href=#126 id=126 data-nosnippet>126</a>//!
|
||||
<a href=#127 id=127 data-nosnippet>127</a>//! ```
|
||||
<a href=#128 id=128 data-nosnippet>128</a>//! pub mod pallet {
|
||||
<a href=#129 id=129 data-nosnippet>129</a>//! // snip -- actually pallet code.
|
||||
<a href=#130 id=130 data-nosnippet>130</a>//! }
|
||||
<a href=#131 id=131 data-nosnippet>131</a>//!
|
||||
<a href=#132 id=132 data-nosnippet>132</a>//! #[cfg(test)]
|
||||
<a href=#133 id=133 data-nosnippet>133</a>//! mod tests {
|
||||
<a href=#134 id=134 data-nosnippet>134</a>//! // bring in the testing prelude of frame
|
||||
<a href=#135 id=135 data-nosnippet>135</a>//! use frame::testing_prelude::*;
|
||||
<a href=#136 id=136 data-nosnippet>136</a>//! // bring in all pallet items
|
||||
<a href=#137 id=137 data-nosnippet>137</a>//! use super::pallet::*;
|
||||
<a href=#138 id=138 data-nosnippet>138</a>//!
|
||||
<a href=#139 id=139 data-nosnippet>139</a>//! // snip -- rest of the testing code.
|
||||
<a href=#140 id=140 data-nosnippet>140</a>//! }
|
||||
<a href=#141 id=141 data-nosnippet>141</a>//! ```
|
||||
<a href=#142 id=142 data-nosnippet>142</a>//!
|
||||
<a href=#143 id=143 data-nosnippet>143</a>//! Next, we create a "test runtime" in order to test our pallet. Recall from
|
||||
<a href=#144 id=144 data-nosnippet>144</a>//! [`crate::pezkuwi_sdk::frame_runtime`] that a runtime is a collection of pallets, expressed
|
||||
<a href=#145 id=145 data-nosnippet>145</a>//! through [`frame::runtime::prelude::construct_runtime`]. All runtimes also have to include
|
||||
<a href=#146 id=146 data-nosnippet>146</a>//! [`frame::prelude::frame_system`]. So we expect to see a runtime with two pallet, `frame_system`
|
||||
<a href=#147 id=147 data-nosnippet>147</a>//! and the one we just wrote.
|
||||
<a href=#148 id=148 data-nosnippet>148</a></span><span class="attr">#![doc = <span class="macro">docify::embed!</span>(<span class="string">"./packages/guides/first-pallet/src/lib.rs"</span>, runtime)]
|
||||
<a href=#149 id=149 data-nosnippet>149</a></span><span class="doccomment">//!
|
||||
<a href=#150 id=150 data-nosnippet>150</a>//! > [`frame::pallet_macros::derive_impl`] is a FRAME feature that enables developers to have
|
||||
<a href=#151 id=151 data-nosnippet>151</a>//! > defaults for associated types.
|
||||
<a href=#152 id=152 data-nosnippet>152</a>//!
|
||||
<a href=#153 id=153 data-nosnippet>153</a>//! Recall that within our pallet, (almost) all blocks of code are generic over `<T: Config>`. And,
|
||||
<a href=#154 id=154 data-nosnippet>154</a>//! because `trait Config: frame_system::Config`, we can get access to all items in `Config` (or
|
||||
<a href=#155 id=155 data-nosnippet>155</a>//! `frame_system::Config`) using `T::NameOfItem`. This is all within the boundaries of how
|
||||
<a href=#156 id=156 data-nosnippet>156</a>//! Rust traits and generics work. If unfamiliar with this pattern, read
|
||||
<a href=#157 id=157 data-nosnippet>157</a>//! [`crate::reference_docs::trait_based_programming`] before going further.
|
||||
<a href=#158 id=158 data-nosnippet>158</a>//!
|
||||
<a href=#159 id=159 data-nosnippet>159</a>//! Crucially, a typical FRAME runtime contains a `struct Runtime`. The main role of this `struct`
|
||||
<a href=#160 id=160 data-nosnippet>160</a>//! is to implement the `trait Config` of all pallets. That is, anywhere within your pallet code
|
||||
<a href=#161 id=161 data-nosnippet>161</a>//! where you see `<T: Config>` (read: *"some type `T` that implements `Config`"*), in the runtime,
|
||||
<a href=#162 id=162 data-nosnippet>162</a>//! it can be replaced with `<Runtime>`, because `Runtime` implements `Config` of all pallets, as we
|
||||
<a href=#163 id=163 data-nosnippet>163</a>//! see above.
|
||||
<a href=#164 id=164 data-nosnippet>164</a>//!
|
||||
<a href=#165 id=165 data-nosnippet>165</a>//! Another way to think about this is that within a pallet, a lot of types are "unknown" and, we
|
||||
<a href=#166 id=166 data-nosnippet>166</a>//! only know that they will be provided at some later point. For example, when you write
|
||||
<a href=#167 id=167 data-nosnippet>167</a>//! `T::AccountId` (which is short for `<T as frame_system::Config>::AccountId`) in your pallet,
|
||||
<a href=#168 id=168 data-nosnippet>168</a>//! you are in fact saying "*Some type `AccountId` that will be known later*". That "later" is in
|
||||
<a href=#169 id=169 data-nosnippet>169</a>//! fact when you specify these types when you implement all `Config` traits for `Runtime`.
|
||||
<a href=#170 id=170 data-nosnippet>170</a>//!
|
||||
<a href=#171 id=171 data-nosnippet>171</a>//! As you see above, `frame_system::Config` is setting the `AccountId` to `u64`. Of course, a real
|
||||
<a href=#172 id=172 data-nosnippet>172</a>//! runtime will not use this type, and instead reside to a proper type like a 32-byte standard
|
||||
<a href=#173 id=173 data-nosnippet>173</a>//! public key. This is a HUGE benefit that FRAME developers can tap into: through the framework
|
||||
<a href=#174 id=174 data-nosnippet>174</a>//! being so generic, different types can always be customized to simple things when needed.
|
||||
<a href=#175 id=175 data-nosnippet>175</a>//!
|
||||
<a href=#176 id=176 data-nosnippet>176</a>//! > Imagine how hard it would have been if all tests had to use a real 32-byte account id, as
|
||||
<a href=#177 id=177 data-nosnippet>177</a>//! > opposed to just a u64 number 🙈.
|
||||
<a href=#178 id=178 data-nosnippet>178</a>//!
|
||||
<a href=#179 id=179 data-nosnippet>179</a>//! ### Your First Test
|
||||
<a href=#180 id=180 data-nosnippet>180</a>//!
|
||||
<a href=#181 id=181 data-nosnippet>181</a>//! The above is all you need to execute the dispatchables of your pallet. The last thing you need
|
||||
<a href=#182 id=182 data-nosnippet>182</a>//! to learn is that all of your pallet testing code should be wrapped in
|
||||
<a href=#183 id=183 data-nosnippet>183</a>//! [`frame::testing_prelude::TestState`]. This is a type that provides access to an in-memory state
|
||||
<a href=#184 id=184 data-nosnippet>184</a>//! to be used in our tests.
|
||||
<a href=#185 id=185 data-nosnippet>185</a></span><span class="attr">#![doc = <span class="macro">docify::embed!</span>(<span class="string">"./packages/guides/first-pallet/src/lib.rs"</span>, first_test)]
|
||||
<a href=#186 id=186 data-nosnippet>186</a></span><span class="doccomment">//!
|
||||
<a href=#187 id=187 data-nosnippet>187</a>//! In the first test, we simply assert that there is no total issuance, and no balance associated
|
||||
<a href=#188 id=188 data-nosnippet>188</a>//! with Alice's account. Then, we mint some balance into Alice's, and re-check.
|
||||
<a href=#189 id=189 data-nosnippet>189</a>//!
|
||||
<a href=#190 id=190 data-nosnippet>190</a>//! As noted above, the `T::AccountId` is now `u64`. Moreover, `Runtime` is replacing `<T: Config>`.
|
||||
<a href=#191 id=191 data-nosnippet>191</a>//! This is why for example you see `Balances::<Runtime>::get(..)`. Finally, notice that the
|
||||
<a href=#192 id=192 data-nosnippet>192</a>//! dispatchables are simply functions that can be called on top of the `Pallet` struct.
|
||||
<a href=#193 id=193 data-nosnippet>193</a>//!
|
||||
<a href=#194 id=194 data-nosnippet>194</a>//! Congratulations! You have written your first pallet and tested it! Next, we learn a few optional
|
||||
<a href=#195 id=195 data-nosnippet>195</a>//! steps to improve our pallet.
|
||||
<a href=#196 id=196 data-nosnippet>196</a>//!
|
||||
<a href=#197 id=197 data-nosnippet>197</a>//! ## Improving the Currency Pallet
|
||||
<a href=#198 id=198 data-nosnippet>198</a>//!
|
||||
<a href=#199 id=199 data-nosnippet>199</a>//! ### Better Test Setup
|
||||
<a href=#200 id=200 data-nosnippet>200</a>//!
|
||||
<a href=#201 id=201 data-nosnippet>201</a>//! Idiomatic FRAME pallets often use Builder pattern to define their initial state.
|
||||
<a href=#202 id=202 data-nosnippet>202</a>//!
|
||||
<a href=#203 id=203 data-nosnippet>203</a>//! > The Pezkuwi Blockchain Academy's Rust entrance exam has a
|
||||
<a href=#204 id=204 data-nosnippet>204</a>//! > [section](https://github.com/pezkuwichain/kurdistan_blockchain-akademy/blob/main/src/m_builder.rs)
|
||||
<a href=#205 id=205 data-nosnippet>205</a>//! > on this that you can use to learn the Builder Pattern.
|
||||
<a href=#206 id=206 data-nosnippet>206</a>//!
|
||||
<a href=#207 id=207 data-nosnippet>207</a>//! Let's see how we can implement a better test setup using this pattern. First, we define a
|
||||
<a href=#208 id=208 data-nosnippet>208</a>//! `struct StateBuilder`.
|
||||
<a href=#209 id=209 data-nosnippet>209</a></span><span class="attr">#![doc = <span class="macro">docify::embed!</span>(<span class="string">"./packages/guides/first-pallet/src/lib.rs"</span>, StateBuilder)]
|
||||
<a href=#210 id=210 data-nosnippet>210</a></span><span class="doccomment">//!
|
||||
<a href=#211 id=211 data-nosnippet>211</a>//! This struct is meant to contain the same list of accounts and balances that we want to have at
|
||||
<a href=#212 id=212 data-nosnippet>212</a>//! the beginning of each block. We hardcoded this to `let accounts = vec![(ALICE, 100), (2, 100)];`
|
||||
<a href=#213 id=213 data-nosnippet>213</a>//! so far. Then, if desired, we attach a default value for this struct.
|
||||
<a href=#214 id=214 data-nosnippet>214</a></span><span class="attr">#![doc = <span class="macro">docify::embed!</span>(<span class="string">"./packages/guides/first-pallet/src/lib.rs"</span>, default_state_builder)]
|
||||
<a href=#215 id=215 data-nosnippet>215</a></span><span class="doccomment">//!
|
||||
<a href=#216 id=216 data-nosnippet>216</a>//! Like any other builder pattern, we attach functions to the type to mutate its internal
|
||||
<a href=#217 id=217 data-nosnippet>217</a>//! properties.
|
||||
<a href=#218 id=218 data-nosnippet>218</a></span><span class="attr">#![doc = <span class="macro">docify::embed!</span>(<span class="string">"./packages/guides/first-pallet/src/lib.rs"</span>, impl_state_builder_add)]
|
||||
<a href=#219 id=219 data-nosnippet>219</a></span><span class="doccomment">//!
|
||||
<a href=#220 id=220 data-nosnippet>220</a>//! Finally --the useful part-- we write our own custom `build_and_execute` function on
|
||||
<a href=#221 id=221 data-nosnippet>221</a>//! this type. This function will do multiple things:
|
||||
<a href=#222 id=222 data-nosnippet>222</a>//!
|
||||
<a href=#223 id=223 data-nosnippet>223</a>//! 1. It would consume `self` to produce our `TestState` based on the properties that we attached
|
||||
<a href=#224 id=224 data-nosnippet>224</a>//! to `self`.
|
||||
<a href=#225 id=225 data-nosnippet>225</a>//! 2. It would execute any test function that we pass in as closure.
|
||||
<a href=#226 id=226 data-nosnippet>226</a>//! 3. A nifty trick, this allows our test setup to have some code that is executed both before and
|
||||
<a href=#227 id=227 data-nosnippet>227</a>//! after each test. For example, in this test, we do some additional checking about the
|
||||
<a href=#228 id=228 data-nosnippet>228</a>//! correctness of the `TotalIssuance`. We leave it up to you as an exercise to learn why the
|
||||
<a href=#229 id=229 data-nosnippet>229</a>//! assertion should always hold, and how it is checked.
|
||||
<a href=#230 id=230 data-nosnippet>230</a></span><span class="attr">#![doc = <span class="macro">docify::embed!</span>(<span class="string">"./packages/guides/first-pallet/src/lib.rs"</span>, impl_state_builder_build)]
|
||||
<a href=#231 id=231 data-nosnippet>231</a></span><span class="doccomment">//!
|
||||
<a href=#232 id=232 data-nosnippet>232</a>//! We can write tests that specifically check the initial state, and making sure our `StateBuilder`
|
||||
<a href=#233 id=233 data-nosnippet>233</a>//! is working exactly as intended.
|
||||
<a href=#234 id=234 data-nosnippet>234</a></span><span class="attr">#![doc = <span class="macro">docify::embed!</span>(<span class="string">"./packages/guides/first-pallet/src/lib.rs"</span>, state_builder_works)]
|
||||
<a href=#235 id=235 data-nosnippet>235</a>#![doc = <span class="macro">docify::embed!</span>(<span class="string">"./packages/guides/first-pallet/src/lib.rs"</span>, state_builder_add_balance)]
|
||||
<a href=#236 id=236 data-nosnippet>236</a></span><span class="doccomment">//!
|
||||
<a href=#237 id=237 data-nosnippet>237</a>//! ### More Tests
|
||||
<a href=#238 id=238 data-nosnippet>238</a>//!
|
||||
<a href=#239 id=239 data-nosnippet>239</a>//! Now that we have a more ergonomic test setup, let's see how a well written test for transfer and
|
||||
<a href=#240 id=240 data-nosnippet>240</a>//! mint would look like.
|
||||
<a href=#241 id=241 data-nosnippet>241</a></span><span class="attr">#![doc = <span class="macro">docify::embed!</span>(<span class="string">"./packages/guides/first-pallet/src/lib.rs"</span>, transfer_works)]
|
||||
<a href=#242 id=242 data-nosnippet>242</a>#![doc = <span class="macro">docify::embed!</span>(<span class="string">"./packages/guides/first-pallet/src/lib.rs"</span>, mint_works)]
|
||||
<a href=#243 id=243 data-nosnippet>243</a></span><span class="doccomment">//!
|
||||
<a href=#244 id=244 data-nosnippet>244</a>//! It is always a good idea to build a mental model where you write *at least* one test for each
|
||||
<a href=#245 id=245 data-nosnippet>245</a>//! "success path" of a dispatchable, and one test for each "failure path", such as:
|
||||
<a href=#246 id=246 data-nosnippet>246</a></span><span class="attr">#![doc = <span class="macro">docify::embed!</span>(<span class="string">"./packages/guides/first-pallet/src/lib.rs"</span>, transfer_from_non_existent_fails)]
|
||||
<a href=#247 id=247 data-nosnippet>247</a></span><span class="doccomment">//!
|
||||
<a href=#248 id=248 data-nosnippet>248</a>//! We leave it up to you to write a test that triggers the `InsufficientBalance` error.
|
||||
<a href=#249 id=249 data-nosnippet>249</a>//!
|
||||
<a href=#250 id=250 data-nosnippet>250</a>//! ### Event and Error
|
||||
<a href=#251 id=251 data-nosnippet>251</a>//!
|
||||
<a href=#252 id=252 data-nosnippet>252</a>//! Our pallet is mainly missing two parts that are common in most FRAME pallets: Events, and
|
||||
<a href=#253 id=253 data-nosnippet>253</a>//! Errors. First, let's understand what each is.
|
||||
<a href=#254 id=254 data-nosnippet>254</a>//!
|
||||
<a href=#255 id=255 data-nosnippet>255</a>//! - **Error**: The static string-based error scheme we used so far is good for readability, but it
|
||||
<a href=#256 id=256 data-nosnippet>256</a>//! has a few drawbacks. The biggest problem with strings are that they are not type safe, e.g. a
|
||||
<a href=#257 id=257 data-nosnippet>257</a>//! match statement cannot be exhaustive. These string literals will bloat the final wasm blob,
|
||||
<a href=#258 id=258 data-nosnippet>258</a>//! and are relatively heavy to transmit and encode/decode. Moreover, it is easy to mistype them
|
||||
<a href=#259 id=259 data-nosnippet>259</a>//! by one character. FRAME errors are exactly a solution to maintain readability, whilst fixing
|
||||
<a href=#260 id=260 data-nosnippet>260</a>//! the drawbacks mentioned. In short, we use an enum to represent different variants of our
|
||||
<a href=#261 id=261 data-nosnippet>261</a>//! error. These variants are then mapped in an efficient way (using only `u8` indices) to
|
||||
<a href=#262 id=262 data-nosnippet>262</a>//! [`sp_runtime::DispatchError::Module`]. Read more about this in [`pallet::error`].
|
||||
<a href=#263 id=263 data-nosnippet>263</a>//!
|
||||
<a href=#264 id=264 data-nosnippet>264</a>//! - **Event**: Events are akin to the return type of dispatchables. They are mostly data blobs
|
||||
<a href=#265 id=265 data-nosnippet>265</a>//! emitted by the runtime to let outside world know what is happening inside the pallet. Since
|
||||
<a href=#266 id=266 data-nosnippet>266</a>//! otherwise, the outside world does not have an easy access to the state changes. They should
|
||||
<a href=#267 id=267 data-nosnippet>267</a>//! represent what happened at the end of a dispatch operation. Therefore, the convention is to
|
||||
<a href=#268 id=268 data-nosnippet>268</a>//! use passive tense for event names (eg. `SomethingHappened`). This allows other sub-systems or
|
||||
<a href=#269 id=269 data-nosnippet>269</a>//! external parties (eg. a light-node, a DApp) to listen to particular events happening, without
|
||||
<a href=#270 id=270 data-nosnippet>270</a>//! needing to re-execute the whole state transition function.
|
||||
<a href=#271 id=271 data-nosnippet>271</a>//!
|
||||
<a href=#272 id=272 data-nosnippet>272</a>//! With the explanation out of the way, let's see how these components can be added. Both follow a
|
||||
<a href=#273 id=273 data-nosnippet>273</a>//! fairly familiar syntax: normal Rust enums, with extra [`pallet::event`] and [`pallet::error`]
|
||||
<a href=#274 id=274 data-nosnippet>274</a>//! attributes attached.
|
||||
<a href=#275 id=275 data-nosnippet>275</a></span><span class="attr">#![doc = <span class="macro">docify::embed!</span>(<span class="string">"./packages/guides/first-pallet/src/lib.rs"</span>, Event)]
|
||||
<a href=#276 id=276 data-nosnippet>276</a>#![doc = <span class="macro">docify::embed!</span>(<span class="string">"./packages/guides/first-pallet/src/lib.rs"</span>, Error)]
|
||||
<a href=#277 id=277 data-nosnippet>277</a></span><span class="doccomment">//!
|
||||
<a href=#278 id=278 data-nosnippet>278</a>//! One slightly custom part of this is the [`pallet::generate_deposit`] part. Without going into
|
||||
<a href=#279 id=279 data-nosnippet>279</a>//! too much detail, in order for a pallet to emit events to the rest of the system, it needs to do
|
||||
<a href=#280 id=280 data-nosnippet>280</a>//! two things:
|
||||
<a href=#281 id=281 data-nosnippet>281</a>//!
|
||||
<a href=#282 id=282 data-nosnippet>282</a>//! 1. Declare a type in its `Config` that refers to the overarching event type of the runtime. In
|
||||
<a href=#283 id=283 data-nosnippet>283</a>//! short, by doing this, the pallet is expressing an important bound: `type RuntimeEvent:
|
||||
<a href=#284 id=284 data-nosnippet>284</a>//! From<Event<Self>>`. Read: a `RuntimeEvent` exists, and it can be created from the local `enum
|
||||
<a href=#285 id=285 data-nosnippet>285</a>//! Event` of this pallet. This enables the pallet to convert its `Event` into `RuntimeEvent`, and
|
||||
<a href=#286 id=286 data-nosnippet>286</a>//! store it where needed.
|
||||
<a href=#287 id=287 data-nosnippet>287</a>//!
|
||||
<a href=#288 id=288 data-nosnippet>288</a>//! 2. But, doing this conversion and storing is too much to expect each pallet to define. FRAME
|
||||
<a href=#289 id=289 data-nosnippet>289</a>//! provides a default way of storing events, and this is what [`pallet::generate_deposit`] is
|
||||
<a href=#290 id=290 data-nosnippet>290</a>//! doing.
|
||||
<a href=#291 id=291 data-nosnippet>291</a></span><span class="attr">#![doc = <span class="macro">docify::embed!</span>(<span class="string">"./packages/guides/first-pallet/src/lib.rs"</span>, config_v2)]
|
||||
<a href=#292 id=292 data-nosnippet>292</a></span><span class="doccomment">//!
|
||||
<a href=#293 id=293 data-nosnippet>293</a>//! > These `Runtime*` types are better explained in
|
||||
<a href=#294 id=294 data-nosnippet>294</a>//! > [`crate::reference_docs::frame_runtime_types`].
|
||||
<a href=#295 id=295 data-nosnippet>295</a>//!
|
||||
<a href=#296 id=296 data-nosnippet>296</a>//! Then, we can rewrite the `transfer` dispatchable as such:
|
||||
<a href=#297 id=297 data-nosnippet>297</a></span><span class="attr">#![doc = <span class="macro">docify::embed!</span>(<span class="string">"./packages/guides/first-pallet/src/lib.rs"</span>, transfer_v2)]
|
||||
<a href=#298 id=298 data-nosnippet>298</a></span><span class="doccomment">//!
|
||||
<a href=#299 id=299 data-nosnippet>299</a>//! Then, notice how now we would need to provide this `type RuntimeEvent` in our test runtime
|
||||
<a href=#300 id=300 data-nosnippet>300</a>//! setup.
|
||||
<a href=#301 id=301 data-nosnippet>301</a></span><span class="attr">#![doc = <span class="macro">docify::embed!</span>(<span class="string">"./packages/guides/first-pallet/src/lib.rs"</span>, runtime_v2)]
|
||||
<a href=#302 id=302 data-nosnippet>302</a></span><span class="doccomment">//!
|
||||
<a href=#303 id=303 data-nosnippet>303</a>//! In this snippet, the actual `RuntimeEvent` type (right hand side of `type RuntimeEvent =
|
||||
<a href=#304 id=304 data-nosnippet>304</a>//! RuntimeEvent`) is generated by
|
||||
<a href=#305 id=305 data-nosnippet>305</a>//! [`construct_runtime`](frame::runtime::prelude::construct_runtime). An interesting way to inspect
|
||||
<a href=#306 id=306 data-nosnippet>306</a>//! this type is to see its definition in rust-docs:
|
||||
<a href=#307 id=307 data-nosnippet>307</a>//! [`crate::guides::your_first_pallet::pallet_v2::tests::runtime_v2::RuntimeEvent`].
|
||||
<a href=#308 id=308 data-nosnippet>308</a>//!
|
||||
<a href=#309 id=309 data-nosnippet>309</a>//!
|
||||
<a href=#310 id=310 data-nosnippet>310</a>//! ## What Next?
|
||||
<a href=#311 id=311 data-nosnippet>311</a>//!
|
||||
<a href=#312 id=312 data-nosnippet>312</a>//! The following topics where used in this guide, but not covered in depth. It is suggested to
|
||||
<a href=#313 id=313 data-nosnippet>313</a>//! study them subsequently:
|
||||
<a href=#314 id=314 data-nosnippet>314</a>//!
|
||||
<a href=#315 id=315 data-nosnippet>315</a>//! - [`crate::reference_docs::defensive_programming`].
|
||||
<a href=#316 id=316 data-nosnippet>316</a>//! - [`crate::reference_docs::frame_origin`].
|
||||
<a href=#317 id=317 data-nosnippet>317</a>//! - [`crate::reference_docs::frame_runtime_types`].
|
||||
<a href=#318 id=318 data-nosnippet>318</a>//! - The pallet we wrote in this guide was using `dev_mode`, learn more in [`pallet::config`].
|
||||
<a href=#319 id=319 data-nosnippet>319</a>//! - Learn more about the individual pallet items/macros, such as event and errors and call, in
|
||||
<a href=#320 id=320 data-nosnippet>320</a>//! [`frame::pallet_macros`].
|
||||
<a href=#321 id=321 data-nosnippet>321</a>//!
|
||||
<a href=#322 id=322 data-nosnippet>322</a>//! [`pallet::storage`]: frame_support::pallet_macros::storage
|
||||
<a href=#323 id=323 data-nosnippet>323</a>//! [`pallet::call`]: frame_support::pallet_macros::call
|
||||
<a href=#324 id=324 data-nosnippet>324</a>//! [`pallet::event`]: frame_support::pallet_macros::event
|
||||
<a href=#325 id=325 data-nosnippet>325</a>//! [`pallet::error`]: frame_support::pallet_macros::error
|
||||
<a href=#326 id=326 data-nosnippet>326</a>//! [`pallet::pallet`]: frame_support::pallet
|
||||
<a href=#327 id=327 data-nosnippet>327</a>//! [`pallet::config`]: frame_support::pallet_macros::config
|
||||
<a href=#328 id=328 data-nosnippet>328</a>//! [`pallet::generate_deposit`]: frame_support::pallet_macros::generate_deposit
|
||||
<a href=#329 id=329 data-nosnippet>329</a>
|
||||
<a href=#330 id=330 data-nosnippet>330</a></span><span class="attr">#[docify::export]
|
||||
<a href=#331 id=331 data-nosnippet>331</a>#[frame::pallet(dev_mode)]
|
||||
<a href=#332 id=332 data-nosnippet>332</a></span><span class="kw">pub mod </span>shell_pallet {
|
||||
<a href=#333 id=333 data-nosnippet>333</a> <span class="kw">use </span>frame::prelude::<span class="kw-2">*</span>;
|
||||
<a href=#334 id=334 data-nosnippet>334</a>
|
||||
<a href=#335 id=335 data-nosnippet>335</a> <span class="attr">#[pallet::config]
|
||||
<a href=#336 id=336 data-nosnippet>336</a> </span><span class="kw">pub trait </span>Config: frame_system::Config {}
|
||||
<a href=#337 id=337 data-nosnippet>337</a>
|
||||
<a href=#338 id=338 data-nosnippet>338</a> <span class="attr">#[pallet::pallet]
|
||||
<a href=#339 id=339 data-nosnippet>339</a> </span><span class="kw">pub struct </span>Pallet<T>(<span class="kw">_</span>);
|
||||
<a href=#340 id=340 data-nosnippet>340</a>}
|
||||
<a href=#341 id=341 data-nosnippet>341</a>
|
||||
<a href=#342 id=342 data-nosnippet>342</a><span class="attr">#[frame::pallet(dev_mode)]
|
||||
<a href=#343 id=343 data-nosnippet>343</a></span><span class="kw">pub mod </span>pallet {
|
||||
<a href=#344 id=344 data-nosnippet>344</a> <span class="kw">use </span>frame::prelude::<span class="kw-2">*</span>;
|
||||
<a href=#345 id=345 data-nosnippet>345</a>
|
||||
<a href=#346 id=346 data-nosnippet>346</a> <span class="attr">#[docify::export]
|
||||
<a href=#347 id=347 data-nosnippet>347</a> </span><span class="kw">pub type </span>Balance = u128;
|
||||
<a href=#348 id=348 data-nosnippet>348</a>
|
||||
<a href=#349 id=349 data-nosnippet>349</a> <span class="attr">#[pallet::config]
|
||||
<a href=#350 id=350 data-nosnippet>350</a> </span><span class="kw">pub trait </span>Config: frame_system::Config {}
|
||||
<a href=#351 id=351 data-nosnippet>351</a>
|
||||
<a href=#352 id=352 data-nosnippet>352</a> <span class="attr">#[pallet::pallet]
|
||||
<a href=#353 id=353 data-nosnippet>353</a> </span><span class="kw">pub struct </span>Pallet<T>(<span class="kw">_</span>);
|
||||
<a href=#354 id=354 data-nosnippet>354</a>
|
||||
<a href=#355 id=355 data-nosnippet>355</a> <span class="attr">#[docify::export]
|
||||
<a href=#356 id=356 data-nosnippet>356</a> </span><span class="doccomment">/// Single storage item, of type `Balance`.
|
||||
<a href=#357 id=357 data-nosnippet>357</a> </span><span class="attr">#[pallet::storage]
|
||||
<a href=#358 id=358 data-nosnippet>358</a> </span><span class="kw">pub type </span>TotalIssuance<T: Config> = StorageValue<<span class="kw">_</span>, Balance>;
|
||||
<a href=#359 id=359 data-nosnippet>359</a>
|
||||
<a href=#360 id=360 data-nosnippet>360</a> <span class="attr">#[docify::export]
|
||||
<a href=#361 id=361 data-nosnippet>361</a> </span><span class="doccomment">/// A mapping from `T::AccountId` to `Balance`
|
||||
<a href=#362 id=362 data-nosnippet>362</a> </span><span class="attr">#[pallet::storage]
|
||||
<a href=#363 id=363 data-nosnippet>363</a> </span><span class="kw">pub type </span>Balances<T: Config> = StorageMap<<span class="kw">_</span>, <span class="kw">_</span>, T::AccountId, Balance>;
|
||||
<a href=#364 id=364 data-nosnippet>364</a>
|
||||
<a href=#365 id=365 data-nosnippet>365</a> <span class="attr">#[docify::export(impl_pallet)]
|
||||
<a href=#366 id=366 data-nosnippet>366</a> #[pallet::call]
|
||||
<a href=#367 id=367 data-nosnippet>367</a> </span><span class="kw">impl</span><T: Config> Pallet<T> {
|
||||
<a href=#368 id=368 data-nosnippet>368</a> <span class="doccomment">/// An unsafe mint that can be called by anyone. Not a great idea.
|
||||
<a href=#369 id=369 data-nosnippet>369</a> </span><span class="kw">pub fn </span>mint_unsafe(
|
||||
<a href=#370 id=370 data-nosnippet>370</a> origin: T::RuntimeOrigin,
|
||||
<a href=#371 id=371 data-nosnippet>371</a> dest: T::AccountId,
|
||||
<a href=#372 id=372 data-nosnippet>372</a> amount: Balance,
|
||||
<a href=#373 id=373 data-nosnippet>373</a> ) -> DispatchResult {
|
||||
<a href=#374 id=374 data-nosnippet>374</a> <span class="comment">// ensure that this is a signed account, but we don't really check `_anyone`.
|
||||
<a href=#375 id=375 data-nosnippet>375</a> </span><span class="kw">let </span>_anyone = ensure_signed(origin)<span class="question-mark">?</span>;
|
||||
<a href=#376 id=376 data-nosnippet>376</a>
|
||||
<a href=#377 id=377 data-nosnippet>377</a> <span class="comment">// update the balances map. Notice how all `<T: Config>` remains as `<T>`.
|
||||
<a href=#378 id=378 data-nosnippet>378</a> </span>Balances::<T>::mutate(dest, |b| <span class="kw-2">*</span>b = <span class="prelude-val">Some</span>(b.unwrap_or(<span class="number">0</span>) + amount));
|
||||
<a href=#379 id=379 data-nosnippet>379</a> <span class="comment">// update total issuance.
|
||||
<a href=#380 id=380 data-nosnippet>380</a> </span>TotalIssuance::<T>::mutate(|t| <span class="kw-2">*</span>t = <span class="prelude-val">Some</span>(t.unwrap_or(<span class="number">0</span>) + amount));
|
||||
<a href=#381 id=381 data-nosnippet>381</a>
|
||||
<a href=#382 id=382 data-nosnippet>382</a> <span class="prelude-val">Ok</span>(())
|
||||
<a href=#383 id=383 data-nosnippet>383</a> }
|
||||
<a href=#384 id=384 data-nosnippet>384</a>
|
||||
<a href=#385 id=385 data-nosnippet>385</a> <span class="doccomment">/// Transfer `amount` from `origin` to `dest`.
|
||||
<a href=#386 id=386 data-nosnippet>386</a> </span><span class="kw">pub fn </span>transfer(
|
||||
<a href=#387 id=387 data-nosnippet>387</a> origin: T::RuntimeOrigin,
|
||||
<a href=#388 id=388 data-nosnippet>388</a> dest: T::AccountId,
|
||||
<a href=#389 id=389 data-nosnippet>389</a> amount: Balance,
|
||||
<a href=#390 id=390 data-nosnippet>390</a> ) -> DispatchResult {
|
||||
<a href=#391 id=391 data-nosnippet>391</a> <span class="kw">let </span>sender = ensure_signed(origin)<span class="question-mark">?</span>;
|
||||
<a href=#392 id=392 data-nosnippet>392</a>
|
||||
<a href=#393 id=393 data-nosnippet>393</a> <span class="comment">// ensure sender has enough balance, and if so, calculate what is left after `amount`.
|
||||
<a href=#394 id=394 data-nosnippet>394</a> </span><span class="kw">let </span>sender_balance = Balances::<T>::get(<span class="kw-2">&</span>sender).ok_or(<span class="string">"NonExistentAccount"</span>)<span class="question-mark">?</span>;
|
||||
<a href=#395 id=395 data-nosnippet>395</a> <span class="kw">if </span>sender_balance < amount {
|
||||
<a href=#396 id=396 data-nosnippet>396</a> <span class="kw">return </span><span class="prelude-val">Err</span>(<span class="string">"InsufficientBalance"</span>.into());
|
||||
<a href=#397 id=397 data-nosnippet>397</a> }
|
||||
<a href=#398 id=398 data-nosnippet>398</a> <span class="kw">let </span>remainder = sender_balance - amount;
|
||||
<a href=#399 id=399 data-nosnippet>399</a>
|
||||
<a href=#400 id=400 data-nosnippet>400</a> <span class="comment">// update sender and dest balances.
|
||||
<a href=#401 id=401 data-nosnippet>401</a> </span>Balances::<T>::mutate(dest, |b| <span class="kw-2">*</span>b = <span class="prelude-val">Some</span>(b.unwrap_or(<span class="number">0</span>) + amount));
|
||||
<a href=#402 id=402 data-nosnippet>402</a> Balances::<T>::insert(<span class="kw-2">&</span>sender, remainder);
|
||||
<a href=#403 id=403 data-nosnippet>403</a>
|
||||
<a href=#404 id=404 data-nosnippet>404</a> <span class="prelude-val">Ok</span>(())
|
||||
<a href=#405 id=405 data-nosnippet>405</a> }
|
||||
<a href=#406 id=406 data-nosnippet>406</a> }
|
||||
<a href=#407 id=407 data-nosnippet>407</a>
|
||||
<a href=#408 id=408 data-nosnippet>408</a> <span class="attr">#[allow(unused)]
|
||||
<a href=#409 id=409 data-nosnippet>409</a> </span><span class="kw">impl</span><T: Config> Pallet<T> {
|
||||
<a href=#410 id=410 data-nosnippet>410</a> <span class="attr">#[docify::export]
|
||||
<a href=#411 id=411 data-nosnippet>411</a> </span><span class="kw">pub fn </span>transfer_better(
|
||||
<a href=#412 id=412 data-nosnippet>412</a> origin: T::RuntimeOrigin,
|
||||
<a href=#413 id=413 data-nosnippet>413</a> dest: T::AccountId,
|
||||
<a href=#414 id=414 data-nosnippet>414</a> amount: Balance,
|
||||
<a href=#415 id=415 data-nosnippet>415</a> ) -> DispatchResult {
|
||||
<a href=#416 id=416 data-nosnippet>416</a> <span class="kw">let </span>sender = ensure_signed(origin)<span class="question-mark">?</span>;
|
||||
<a href=#417 id=417 data-nosnippet>417</a>
|
||||
<a href=#418 id=418 data-nosnippet>418</a> <span class="kw">let </span>sender_balance = Balances::<T>::get(<span class="kw-2">&</span>sender).ok_or(<span class="string">"NonExistentAccount"</span>)<span class="question-mark">?</span>;
|
||||
<a href=#419 id=419 data-nosnippet>419</a> <span class="macro">ensure!</span>(sender_balance >= amount, <span class="string">"InsufficientBalance"</span>);
|
||||
<a href=#420 id=420 data-nosnippet>420</a> <span class="kw">let </span>remainder = sender_balance - amount;
|
||||
<a href=#421 id=421 data-nosnippet>421</a>
|
||||
<a href=#422 id=422 data-nosnippet>422</a> <span class="comment">// .. snip
|
||||
<a href=#423 id=423 data-nosnippet>423</a> </span><span class="prelude-val">Ok</span>(())
|
||||
<a href=#424 id=424 data-nosnippet>424</a> }
|
||||
<a href=#425 id=425 data-nosnippet>425</a>
|
||||
<a href=#426 id=426 data-nosnippet>426</a> <span class="attr">#[docify::export]
|
||||
<a href=#427 id=427 data-nosnippet>427</a> </span><span class="doccomment">/// Transfer `amount` from `origin` to `dest`.
|
||||
<a href=#428 id=428 data-nosnippet>428</a> </span><span class="kw">pub fn </span>transfer_better_checked(
|
||||
<a href=#429 id=429 data-nosnippet>429</a> origin: T::RuntimeOrigin,
|
||||
<a href=#430 id=430 data-nosnippet>430</a> dest: T::AccountId,
|
||||
<a href=#431 id=431 data-nosnippet>431</a> amount: Balance,
|
||||
<a href=#432 id=432 data-nosnippet>432</a> ) -> DispatchResult {
|
||||
<a href=#433 id=433 data-nosnippet>433</a> <span class="kw">let </span>sender = ensure_signed(origin)<span class="question-mark">?</span>;
|
||||
<a href=#434 id=434 data-nosnippet>434</a>
|
||||
<a href=#435 id=435 data-nosnippet>435</a> <span class="kw">let </span>sender_balance = Balances::<T>::get(<span class="kw-2">&</span>sender).ok_or(<span class="string">"NonExistentAccount"</span>)<span class="question-mark">?</span>;
|
||||
<a href=#436 id=436 data-nosnippet>436</a> <span class="kw">let </span>remainder = sender_balance.checked_sub(amount).ok_or(<span class="string">"InsufficientBalance"</span>)<span class="question-mark">?</span>;
|
||||
<a href=#437 id=437 data-nosnippet>437</a>
|
||||
<a href=#438 id=438 data-nosnippet>438</a> <span class="comment">// .. snip
|
||||
<a href=#439 id=439 data-nosnippet>439</a> </span><span class="prelude-val">Ok</span>(())
|
||||
<a href=#440 id=440 data-nosnippet>440</a> }
|
||||
<a href=#441 id=441 data-nosnippet>441</a> }
|
||||
<a href=#442 id=442 data-nosnippet>442</a>
|
||||
<a href=#443 id=443 data-nosnippet>443</a> <span class="attr">#[cfg(any(test, doc))]
|
||||
<a href=#444 id=444 data-nosnippet>444</a> </span><span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">mod </span>tests {
|
||||
<a href=#445 id=445 data-nosnippet>445</a> <span class="kw">use </span><span class="kw">crate</span>::guides::your_first_pallet::pallet::<span class="kw-2">*</span>;
|
||||
<a href=#446 id=446 data-nosnippet>446</a>
|
||||
<a href=#447 id=447 data-nosnippet>447</a> <span class="attr">#[docify::export(testing_prelude)]
|
||||
<a href=#448 id=448 data-nosnippet>448</a> </span><span class="kw">use </span>frame::testing_prelude::<span class="kw-2">*</span>;
|
||||
<a href=#449 id=449 data-nosnippet>449</a>
|
||||
<a href=#450 id=450 data-nosnippet>450</a> <span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">const </span>ALICE: u64 = <span class="number">1</span>;
|
||||
<a href=#451 id=451 data-nosnippet>451</a> <span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">const </span>BOB: u64 = <span class="number">2</span>;
|
||||
<a href=#452 id=452 data-nosnippet>452</a> <span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">const </span>CHARLIE: u64 = <span class="number">3</span>;
|
||||
<a href=#453 id=453 data-nosnippet>453</a>
|
||||
<a href=#454 id=454 data-nosnippet>454</a> <span class="attr">#[docify::export]
|
||||
<a href=#455 id=455 data-nosnippet>455</a> </span><span class="comment">// This runtime is only used for testing, so it should be somewhere like `#[cfg(test)] mod
|
||||
<a href=#456 id=456 data-nosnippet>456</a> // tests { .. }`
|
||||
<a href=#457 id=457 data-nosnippet>457</a> </span><span class="kw">mod </span>runtime {
|
||||
<a href=#458 id=458 data-nosnippet>458</a> <span class="kw">use super</span>::<span class="kw-2">*</span>;
|
||||
<a href=#459 id=459 data-nosnippet>459</a> <span class="comment">// we need to reference our `mod pallet` as an identifier to pass to
|
||||
<a href=#460 id=460 data-nosnippet>460</a> // `construct_runtime`.
|
||||
<a href=#461 id=461 data-nosnippet>461</a> // YOU HAVE TO CHANGE THIS LINE BASED ON YOUR TEMPLATE
|
||||
<a href=#462 id=462 data-nosnippet>462</a> </span><span class="kw">use </span><span class="kw">crate</span>::guides::your_first_pallet::pallet <span class="kw">as </span>pallet_currency;
|
||||
<a href=#463 id=463 data-nosnippet>463</a>
|
||||
<a href=#464 id=464 data-nosnippet>464</a> <span class="macro">construct_runtime!</span>(
|
||||
<a href=#465 id=465 data-nosnippet>465</a> <span class="kw">pub enum </span>Runtime {
|
||||
<a href=#466 id=466 data-nosnippet>466</a> <span class="comment">// ---^^^^^^ This is where `enum Runtime` is defined.
|
||||
<a href=#467 id=467 data-nosnippet>467</a> </span>System: frame_system,
|
||||
<a href=#468 id=468 data-nosnippet>468</a> Currency: pallet_currency,
|
||||
<a href=#469 id=469 data-nosnippet>469</a> }
|
||||
<a href=#470 id=470 data-nosnippet>470</a> );
|
||||
<a href=#471 id=471 data-nosnippet>471</a>
|
||||
<a href=#472 id=472 data-nosnippet>472</a> <span class="attr">#[derive_impl(frame_system::config_preludes::TestDefaultConfig)]
|
||||
<a href=#473 id=473 data-nosnippet>473</a> </span><span class="kw">impl </span>frame_system::Config <span class="kw">for </span>Runtime {
|
||||
<a href=#474 id=474 data-nosnippet>474</a> <span class="kw">type </span>Block = MockBlock<Runtime>;
|
||||
<a href=#475 id=475 data-nosnippet>475</a> <span class="comment">// within pallet we just said `<T as frame_system::Config>::AccountId`, now we
|
||||
<a href=#476 id=476 data-nosnippet>476</a> // finally specified it.
|
||||
<a href=#477 id=477 data-nosnippet>477</a> </span><span class="kw">type </span>AccountId = u64;
|
||||
<a href=#478 id=478 data-nosnippet>478</a> }
|
||||
<a href=#479 id=479 data-nosnippet>479</a>
|
||||
<a href=#480 id=480 data-nosnippet>480</a> <span class="comment">// our simple pallet has nothing to be configured.
|
||||
<a href=#481 id=481 data-nosnippet>481</a> </span><span class="kw">impl </span>pallet_currency::Config <span class="kw">for </span>Runtime {}
|
||||
<a href=#482 id=482 data-nosnippet>482</a> }
|
||||
<a href=#483 id=483 data-nosnippet>483</a>
|
||||
<a href=#484 id=484 data-nosnippet>484</a> <span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">use </span>runtime::<span class="kw-2">*</span>;
|
||||
<a href=#485 id=485 data-nosnippet>485</a>
|
||||
<a href=#486 id=486 data-nosnippet>486</a> <span class="attr">#[allow(unused)]
|
||||
<a href=#487 id=487 data-nosnippet>487</a> #[docify::export]
|
||||
<a href=#488 id=488 data-nosnippet>488</a> </span><span class="kw">fn </span>new_test_state_basic() -> TestState {
|
||||
<a href=#489 id=489 data-nosnippet>489</a> <span class="kw">let </span><span class="kw-2">mut </span>state = TestState::new_empty();
|
||||
<a href=#490 id=490 data-nosnippet>490</a> <span class="kw">let </span>accounts = <span class="macro">vec!</span>[(ALICE, <span class="number">100</span>), (BOB, <span class="number">100</span>)];
|
||||
<a href=#491 id=491 data-nosnippet>491</a> state.execute_with(|| {
|
||||
<a href=#492 id=492 data-nosnippet>492</a> <span class="kw">for </span>(who, amount) <span class="kw">in </span><span class="kw-2">&</span>accounts {
|
||||
<a href=#493 id=493 data-nosnippet>493</a> Balances::<Runtime>::insert(who, amount);
|
||||
<a href=#494 id=494 data-nosnippet>494</a> TotalIssuance::<Runtime>::mutate(|b| <span class="kw-2">*</span>b = <span class="prelude-val">Some</span>(b.unwrap_or(<span class="number">0</span>) + amount));
|
||||
<a href=#495 id=495 data-nosnippet>495</a> }
|
||||
<a href=#496 id=496 data-nosnippet>496</a> });
|
||||
<a href=#497 id=497 data-nosnippet>497</a>
|
||||
<a href=#498 id=498 data-nosnippet>498</a> state
|
||||
<a href=#499 id=499 data-nosnippet>499</a> }
|
||||
<a href=#500 id=500 data-nosnippet>500</a>
|
||||
<a href=#501 id=501 data-nosnippet>501</a> <span class="attr">#[docify::export]
|
||||
<a href=#502 id=502 data-nosnippet>502</a> </span><span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">struct </span>StateBuilder {
|
||||
<a href=#503 id=503 data-nosnippet>503</a> balances: Vec<(<Runtime <span class="kw">as </span>frame_system::Config>::AccountId, Balance)>,
|
||||
<a href=#504 id=504 data-nosnippet>504</a> }
|
||||
<a href=#505 id=505 data-nosnippet>505</a>
|
||||
<a href=#506 id=506 data-nosnippet>506</a> <span class="attr">#[docify::export(default_state_builder)]
|
||||
<a href=#507 id=507 data-nosnippet>507</a> </span><span class="kw">impl </span>Default <span class="kw">for </span>StateBuilder {
|
||||
<a href=#508 id=508 data-nosnippet>508</a> <span class="kw">fn </span>default() -> <span class="self">Self </span>{
|
||||
<a href=#509 id=509 data-nosnippet>509</a> <span class="self">Self </span>{ balances: <span class="macro">vec!</span>[(ALICE, <span class="number">100</span>), (BOB, <span class="number">100</span>)] }
|
||||
<a href=#510 id=510 data-nosnippet>510</a> }
|
||||
<a href=#511 id=511 data-nosnippet>511</a> }
|
||||
<a href=#512 id=512 data-nosnippet>512</a>
|
||||
<a href=#513 id=513 data-nosnippet>513</a> <span class="attr">#[docify::export(impl_state_builder_add)]
|
||||
<a href=#514 id=514 data-nosnippet>514</a> </span><span class="kw">impl </span>StateBuilder {
|
||||
<a href=#515 id=515 data-nosnippet>515</a> <span class="kw">fn </span>add_balance(
|
||||
<a href=#516 id=516 data-nosnippet>516</a> <span class="kw-2">mut </span><span class="self">self</span>,
|
||||
<a href=#517 id=517 data-nosnippet>517</a> who: <Runtime <span class="kw">as </span>frame_system::Config>::AccountId,
|
||||
<a href=#518 id=518 data-nosnippet>518</a> amount: Balance,
|
||||
<a href=#519 id=519 data-nosnippet>519</a> ) -> <span class="self">Self </span>{
|
||||
<a href=#520 id=520 data-nosnippet>520</a> <span class="self">self</span>.balances.push((who, amount));
|
||||
<a href=#521 id=521 data-nosnippet>521</a> <span class="self">self
|
||||
<a href=#522 id=522 data-nosnippet>522</a> </span>}
|
||||
<a href=#523 id=523 data-nosnippet>523</a> }
|
||||
<a href=#524 id=524 data-nosnippet>524</a>
|
||||
<a href=#525 id=525 data-nosnippet>525</a> <span class="attr">#[docify::export(impl_state_builder_build)]
|
||||
<a href=#526 id=526 data-nosnippet>526</a> </span><span class="kw">impl </span>StateBuilder {
|
||||
<a href=#527 id=527 data-nosnippet>527</a> <span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">fn </span>build_and_execute(<span class="self">self</span>, test: <span class="kw">impl </span>FnOnce() -> ()) {
|
||||
<a href=#528 id=528 data-nosnippet>528</a> <span class="kw">let </span><span class="kw-2">mut </span>ext = TestState::new_empty();
|
||||
<a href=#529 id=529 data-nosnippet>529</a> ext.execute_with(|| {
|
||||
<a href=#530 id=530 data-nosnippet>530</a> <span class="kw">for </span>(who, amount) <span class="kw">in </span><span class="kw-2">&</span><span class="self">self</span>.balances {
|
||||
<a href=#531 id=531 data-nosnippet>531</a> Balances::<Runtime>::insert(who, amount);
|
||||
<a href=#532 id=532 data-nosnippet>532</a> TotalIssuance::<Runtime>::mutate(|b| <span class="kw-2">*</span>b = <span class="prelude-val">Some</span>(b.unwrap_or(<span class="number">0</span>) + amount));
|
||||
<a href=#533 id=533 data-nosnippet>533</a> }
|
||||
<a href=#534 id=534 data-nosnippet>534</a> });
|
||||
<a href=#535 id=535 data-nosnippet>535</a>
|
||||
<a href=#536 id=536 data-nosnippet>536</a> ext.execute_with(test);
|
||||
<a href=#537 id=537 data-nosnippet>537</a>
|
||||
<a href=#538 id=538 data-nosnippet>538</a> <span class="comment">// assertions that must always hold
|
||||
<a href=#539 id=539 data-nosnippet>539</a> </span>ext.execute_with(|| {
|
||||
<a href=#540 id=540 data-nosnippet>540</a> <span class="macro">assert_eq!</span>(
|
||||
<a href=#541 id=541 data-nosnippet>541</a> Balances::<Runtime>::iter().map(|(<span class="kw">_</span>, x)| x).sum::<u128>(),
|
||||
<a href=#542 id=542 data-nosnippet>542</a> TotalIssuance::<Runtime>::get().unwrap_or_default()
|
||||
<a href=#543 id=543 data-nosnippet>543</a> );
|
||||
<a href=#544 id=544 data-nosnippet>544</a> })
|
||||
<a href=#545 id=545 data-nosnippet>545</a> }
|
||||
<a href=#546 id=546 data-nosnippet>546</a> }
|
||||
<a href=#547 id=547 data-nosnippet>547</a>
|
||||
<a href=#548 id=548 data-nosnippet>548</a> <span class="attr">#[docify::export]
|
||||
<a href=#549 id=549 data-nosnippet>549</a> #[test]
|
||||
<a href=#550 id=550 data-nosnippet>550</a> </span><span class="kw">fn </span>first_test() {
|
||||
<a href=#551 id=551 data-nosnippet>551</a> TestState::new_empty().execute_with(|| {
|
||||
<a href=#552 id=552 data-nosnippet>552</a> <span class="comment">// We expect Alice's account to have no funds.
|
||||
<a href=#553 id=553 data-nosnippet>553</a> </span><span class="macro">assert_eq!</span>(Balances::<Runtime>::get(<span class="kw-2">&</span>ALICE), <span class="prelude-val">None</span>);
|
||||
<a href=#554 id=554 data-nosnippet>554</a> <span class="macro">assert_eq!</span>(TotalIssuance::<Runtime>::get(), <span class="prelude-val">None</span>);
|
||||
<a href=#555 id=555 data-nosnippet>555</a>
|
||||
<a href=#556 id=556 data-nosnippet>556</a> <span class="comment">// mint some funds into Alice's account.
|
||||
<a href=#557 id=557 data-nosnippet>557</a> </span><span class="macro">assert_ok!</span>(Pallet::<Runtime>::mint_unsafe(
|
||||
<a href=#558 id=558 data-nosnippet>558</a> RuntimeOrigin::signed(ALICE),
|
||||
<a href=#559 id=559 data-nosnippet>559</a> ALICE,
|
||||
<a href=#560 id=560 data-nosnippet>560</a> <span class="number">100
|
||||
<a href=#561 id=561 data-nosnippet>561</a> </span>));
|
||||
<a href=#562 id=562 data-nosnippet>562</a>
|
||||
<a href=#563 id=563 data-nosnippet>563</a> <span class="comment">// re-check the above
|
||||
<a href=#564 id=564 data-nosnippet>564</a> </span><span class="macro">assert_eq!</span>(Balances::<Runtime>::get(<span class="kw-2">&</span>ALICE), <span class="prelude-val">Some</span>(<span class="number">100</span>));
|
||||
<a href=#565 id=565 data-nosnippet>565</a> <span class="macro">assert_eq!</span>(TotalIssuance::<Runtime>::get(), <span class="prelude-val">Some</span>(<span class="number">100</span>));
|
||||
<a href=#566 id=566 data-nosnippet>566</a> })
|
||||
<a href=#567 id=567 data-nosnippet>567</a> }
|
||||
<a href=#568 id=568 data-nosnippet>568</a>
|
||||
<a href=#569 id=569 data-nosnippet>569</a> <span class="attr">#[docify::export]
|
||||
<a href=#570 id=570 data-nosnippet>570</a> #[test]
|
||||
<a href=#571 id=571 data-nosnippet>571</a> </span><span class="kw">fn </span>state_builder_works() {
|
||||
<a href=#572 id=572 data-nosnippet>572</a> StateBuilder::default().build_and_execute(|| {
|
||||
<a href=#573 id=573 data-nosnippet>573</a> <span class="macro">assert_eq!</span>(Balances::<Runtime>::get(<span class="kw-2">&</span>ALICE), <span class="prelude-val">Some</span>(<span class="number">100</span>));
|
||||
<a href=#574 id=574 data-nosnippet>574</a> <span class="macro">assert_eq!</span>(Balances::<Runtime>::get(<span class="kw-2">&</span>BOB), <span class="prelude-val">Some</span>(<span class="number">100</span>));
|
||||
<a href=#575 id=575 data-nosnippet>575</a> <span class="macro">assert_eq!</span>(Balances::<Runtime>::get(<span class="kw-2">&</span>CHARLIE), <span class="prelude-val">None</span>);
|
||||
<a href=#576 id=576 data-nosnippet>576</a> <span class="macro">assert_eq!</span>(TotalIssuance::<Runtime>::get(), <span class="prelude-val">Some</span>(<span class="number">200</span>));
|
||||
<a href=#577 id=577 data-nosnippet>577</a> });
|
||||
<a href=#578 id=578 data-nosnippet>578</a> }
|
||||
<a href=#579 id=579 data-nosnippet>579</a>
|
||||
<a href=#580 id=580 data-nosnippet>580</a> <span class="attr">#[docify::export]
|
||||
<a href=#581 id=581 data-nosnippet>581</a> #[test]
|
||||
<a href=#582 id=582 data-nosnippet>582</a> </span><span class="kw">fn </span>state_builder_add_balance() {
|
||||
<a href=#583 id=583 data-nosnippet>583</a> StateBuilder::default().add_balance(CHARLIE, <span class="number">42</span>).build_and_execute(|| {
|
||||
<a href=#584 id=584 data-nosnippet>584</a> <span class="macro">assert_eq!</span>(Balances::<Runtime>::get(<span class="kw-2">&</span>CHARLIE), <span class="prelude-val">Some</span>(<span class="number">42</span>));
|
||||
<a href=#585 id=585 data-nosnippet>585</a> <span class="macro">assert_eq!</span>(TotalIssuance::<Runtime>::get(), <span class="prelude-val">Some</span>(<span class="number">242</span>));
|
||||
<a href=#586 id=586 data-nosnippet>586</a> })
|
||||
<a href=#587 id=587 data-nosnippet>587</a> }
|
||||
<a href=#588 id=588 data-nosnippet>588</a>
|
||||
<a href=#589 id=589 data-nosnippet>589</a> <span class="attr">#[test]
|
||||
<a href=#590 id=590 data-nosnippet>590</a> #[should_panic]
|
||||
<a href=#591 id=591 data-nosnippet>591</a> </span><span class="kw">fn </span>state_builder_duplicate_genesis_fails() {
|
||||
<a href=#592 id=592 data-nosnippet>592</a> StateBuilder::default()
|
||||
<a href=#593 id=593 data-nosnippet>593</a> .add_balance(CHARLIE, <span class="number">42</span>)
|
||||
<a href=#594 id=594 data-nosnippet>594</a> .add_balance(CHARLIE, <span class="number">43</span>)
|
||||
<a href=#595 id=595 data-nosnippet>595</a> .build_and_execute(|| {
|
||||
<a href=#596 id=596 data-nosnippet>596</a> <span class="macro">assert_eq!</span>(Balances::<Runtime>::get(<span class="kw-2">&</span>CHARLIE), <span class="prelude-val">None</span>);
|
||||
<a href=#597 id=597 data-nosnippet>597</a> <span class="macro">assert_eq!</span>(TotalIssuance::<Runtime>::get(), <span class="prelude-val">Some</span>(<span class="number">242</span>));
|
||||
<a href=#598 id=598 data-nosnippet>598</a> })
|
||||
<a href=#599 id=599 data-nosnippet>599</a> }
|
||||
<a href=#600 id=600 data-nosnippet>600</a>
|
||||
<a href=#601 id=601 data-nosnippet>601</a> <span class="attr">#[docify::export]
|
||||
<a href=#602 id=602 data-nosnippet>602</a> #[test]
|
||||
<a href=#603 id=603 data-nosnippet>603</a> </span><span class="kw">fn </span>mint_works() {
|
||||
<a href=#604 id=604 data-nosnippet>604</a> StateBuilder::default().build_and_execute(|| {
|
||||
<a href=#605 id=605 data-nosnippet>605</a> <span class="comment">// given the initial state, when:
|
||||
<a href=#606 id=606 data-nosnippet>606</a> </span><span class="macro">assert_ok!</span>(Pallet::<Runtime>::mint_unsafe(RuntimeOrigin::signed(ALICE), BOB, <span class="number">100</span>));
|
||||
<a href=#607 id=607 data-nosnippet>607</a>
|
||||
<a href=#608 id=608 data-nosnippet>608</a> <span class="comment">// then:
|
||||
<a href=#609 id=609 data-nosnippet>609</a> </span><span class="macro">assert_eq!</span>(Balances::<Runtime>::get(<span class="kw-2">&</span>BOB), <span class="prelude-val">Some</span>(<span class="number">200</span>));
|
||||
<a href=#610 id=610 data-nosnippet>610</a> <span class="macro">assert_eq!</span>(TotalIssuance::<Runtime>::get(), <span class="prelude-val">Some</span>(<span class="number">300</span>));
|
||||
<a href=#611 id=611 data-nosnippet>611</a>
|
||||
<a href=#612 id=612 data-nosnippet>612</a> <span class="comment">// given:
|
||||
<a href=#613 id=613 data-nosnippet>613</a> </span><span class="macro">assert_ok!</span>(Pallet::<Runtime>::mint_unsafe(
|
||||
<a href=#614 id=614 data-nosnippet>614</a> RuntimeOrigin::signed(ALICE),
|
||||
<a href=#615 id=615 data-nosnippet>615</a> CHARLIE,
|
||||
<a href=#616 id=616 data-nosnippet>616</a> <span class="number">100
|
||||
<a href=#617 id=617 data-nosnippet>617</a> </span>));
|
||||
<a href=#618 id=618 data-nosnippet>618</a>
|
||||
<a href=#619 id=619 data-nosnippet>619</a> <span class="comment">// then:
|
||||
<a href=#620 id=620 data-nosnippet>620</a> </span><span class="macro">assert_eq!</span>(Balances::<Runtime>::get(<span class="kw-2">&</span>CHARLIE), <span class="prelude-val">Some</span>(<span class="number">100</span>));
|
||||
<a href=#621 id=621 data-nosnippet>621</a> <span class="macro">assert_eq!</span>(TotalIssuance::<Runtime>::get(), <span class="prelude-val">Some</span>(<span class="number">400</span>));
|
||||
<a href=#622 id=622 data-nosnippet>622</a> });
|
||||
<a href=#623 id=623 data-nosnippet>623</a> }
|
||||
<a href=#624 id=624 data-nosnippet>624</a>
|
||||
<a href=#625 id=625 data-nosnippet>625</a> <span class="attr">#[docify::export]
|
||||
<a href=#626 id=626 data-nosnippet>626</a> #[test]
|
||||
<a href=#627 id=627 data-nosnippet>627</a> </span><span class="kw">fn </span>transfer_works() {
|
||||
<a href=#628 id=628 data-nosnippet>628</a> StateBuilder::default().build_and_execute(|| {
|
||||
<a href=#629 id=629 data-nosnippet>629</a> <span class="comment">// given the initial state, when:
|
||||
<a href=#630 id=630 data-nosnippet>630</a> </span><span class="macro">assert_ok!</span>(Pallet::<Runtime>::transfer(RuntimeOrigin::signed(ALICE), BOB, <span class="number">50</span>));
|
||||
<a href=#631 id=631 data-nosnippet>631</a>
|
||||
<a href=#632 id=632 data-nosnippet>632</a> <span class="comment">// then:
|
||||
<a href=#633 id=633 data-nosnippet>633</a> </span><span class="macro">assert_eq!</span>(Balances::<Runtime>::get(<span class="kw-2">&</span>ALICE), <span class="prelude-val">Some</span>(<span class="number">50</span>));
|
||||
<a href=#634 id=634 data-nosnippet>634</a> <span class="macro">assert_eq!</span>(Balances::<Runtime>::get(<span class="kw-2">&</span>BOB), <span class="prelude-val">Some</span>(<span class="number">150</span>));
|
||||
<a href=#635 id=635 data-nosnippet>635</a> <span class="macro">assert_eq!</span>(TotalIssuance::<Runtime>::get(), <span class="prelude-val">Some</span>(<span class="number">200</span>));
|
||||
<a href=#636 id=636 data-nosnippet>636</a>
|
||||
<a href=#637 id=637 data-nosnippet>637</a> <span class="comment">// when:
|
||||
<a href=#638 id=638 data-nosnippet>638</a> </span><span class="macro">assert_ok!</span>(Pallet::<Runtime>::transfer(RuntimeOrigin::signed(BOB), ALICE, <span class="number">50</span>));
|
||||
<a href=#639 id=639 data-nosnippet>639</a>
|
||||
<a href=#640 id=640 data-nosnippet>640</a> <span class="comment">// then:
|
||||
<a href=#641 id=641 data-nosnippet>641</a> </span><span class="macro">assert_eq!</span>(Balances::<Runtime>::get(<span class="kw-2">&</span>ALICE), <span class="prelude-val">Some</span>(<span class="number">100</span>));
|
||||
<a href=#642 id=642 data-nosnippet>642</a> <span class="macro">assert_eq!</span>(Balances::<Runtime>::get(<span class="kw-2">&</span>BOB), <span class="prelude-val">Some</span>(<span class="number">100</span>));
|
||||
<a href=#643 id=643 data-nosnippet>643</a> <span class="macro">assert_eq!</span>(TotalIssuance::<Runtime>::get(), <span class="prelude-val">Some</span>(<span class="number">200</span>));
|
||||
<a href=#644 id=644 data-nosnippet>644</a> });
|
||||
<a href=#645 id=645 data-nosnippet>645</a> }
|
||||
<a href=#646 id=646 data-nosnippet>646</a>
|
||||
<a href=#647 id=647 data-nosnippet>647</a> <span class="attr">#[docify::export]
|
||||
<a href=#648 id=648 data-nosnippet>648</a> #[test]
|
||||
<a href=#649 id=649 data-nosnippet>649</a> </span><span class="kw">fn </span>transfer_from_non_existent_fails() {
|
||||
<a href=#650 id=650 data-nosnippet>650</a> StateBuilder::default().build_and_execute(|| {
|
||||
<a href=#651 id=651 data-nosnippet>651</a> <span class="comment">// given the initial state, when:
|
||||
<a href=#652 id=652 data-nosnippet>652</a> </span><span class="macro">assert_err!</span>(
|
||||
<a href=#653 id=653 data-nosnippet>653</a> Pallet::<Runtime>::transfer(RuntimeOrigin::signed(CHARLIE), ALICE, <span class="number">10</span>),
|
||||
<a href=#654 id=654 data-nosnippet>654</a> <span class="string">"NonExistentAccount"
|
||||
<a href=#655 id=655 data-nosnippet>655</a> </span>);
|
||||
<a href=#656 id=656 data-nosnippet>656</a>
|
||||
<a href=#657 id=657 data-nosnippet>657</a> <span class="comment">// then nothing has changed.
|
||||
<a href=#658 id=658 data-nosnippet>658</a> </span><span class="macro">assert_eq!</span>(Balances::<Runtime>::get(<span class="kw-2">&</span>ALICE), <span class="prelude-val">Some</span>(<span class="number">100</span>));
|
||||
<a href=#659 id=659 data-nosnippet>659</a> <span class="macro">assert_eq!</span>(Balances::<Runtime>::get(<span class="kw-2">&</span>BOB), <span class="prelude-val">Some</span>(<span class="number">100</span>));
|
||||
<a href=#660 id=660 data-nosnippet>660</a> <span class="macro">assert_eq!</span>(Balances::<Runtime>::get(<span class="kw-2">&</span>CHARLIE), <span class="prelude-val">None</span>);
|
||||
<a href=#661 id=661 data-nosnippet>661</a> <span class="macro">assert_eq!</span>(TotalIssuance::<Runtime>::get(), <span class="prelude-val">Some</span>(<span class="number">200</span>));
|
||||
<a href=#662 id=662 data-nosnippet>662</a> });
|
||||
<a href=#663 id=663 data-nosnippet>663</a> }
|
||||
<a href=#664 id=664 data-nosnippet>664</a> }
|
||||
<a href=#665 id=665 data-nosnippet>665</a>}
|
||||
<a href=#666 id=666 data-nosnippet>666</a>
|
||||
<a href=#667 id=667 data-nosnippet>667</a><span class="attr">#[frame::pallet(dev_mode)]
|
||||
<a href=#668 id=668 data-nosnippet>668</a></span><span class="kw">pub mod </span>pallet_v2 {
|
||||
<a href=#669 id=669 data-nosnippet>669</a> <span class="kw">use </span><span class="kw">super</span>::pallet::Balance;
|
||||
<a href=#670 id=670 data-nosnippet>670</a> <span class="kw">use </span>frame::prelude::<span class="kw-2">*</span>;
|
||||
<a href=#671 id=671 data-nosnippet>671</a>
|
||||
<a href=#672 id=672 data-nosnippet>672</a> <span class="attr">#[docify::export(config_v2)]
|
||||
<a href=#673 id=673 data-nosnippet>673</a> #[pallet::config]
|
||||
<a href=#674 id=674 data-nosnippet>674</a> </span><span class="kw">pub trait </span>Config: frame_system::Config {
|
||||
<a href=#675 id=675 data-nosnippet>675</a> <span class="doccomment">/// The overarching event type of the runtime.
|
||||
<a href=#676 id=676 data-nosnippet>676</a> </span><span class="attr">#[allow(deprecated)]
|
||||
<a href=#677 id=677 data-nosnippet>677</a> </span><span class="kw">type </span>RuntimeEvent: From<Event<<span class="self">Self</span>>>
|
||||
<a href=#678 id=678 data-nosnippet>678</a> + IsType<<<span class="self">Self </span><span class="kw">as </span>frame_system::Config>::RuntimeEvent>
|
||||
<a href=#679 id=679 data-nosnippet>679</a> + TryInto<Event<<span class="self">Self</span>>>;
|
||||
<a href=#680 id=680 data-nosnippet>680</a> }
|
||||
<a href=#681 id=681 data-nosnippet>681</a>
|
||||
<a href=#682 id=682 data-nosnippet>682</a> <span class="attr">#[pallet::pallet]
|
||||
<a href=#683 id=683 data-nosnippet>683</a> </span><span class="kw">pub struct </span>Pallet<T>(<span class="kw">_</span>);
|
||||
<a href=#684 id=684 data-nosnippet>684</a>
|
||||
<a href=#685 id=685 data-nosnippet>685</a> <span class="attr">#[pallet::storage]
|
||||
<a href=#686 id=686 data-nosnippet>686</a> </span><span class="kw">pub type </span>Balances<T: Config> = StorageMap<<span class="kw">_</span>, <span class="kw">_</span>, T::AccountId, Balance>;
|
||||
<a href=#687 id=687 data-nosnippet>687</a>
|
||||
<a href=#688 id=688 data-nosnippet>688</a> <span class="attr">#[pallet::storage]
|
||||
<a href=#689 id=689 data-nosnippet>689</a> </span><span class="kw">pub type </span>TotalIssuance<T: Config> = StorageValue<<span class="kw">_</span>, Balance>;
|
||||
<a href=#690 id=690 data-nosnippet>690</a>
|
||||
<a href=#691 id=691 data-nosnippet>691</a> <span class="attr">#[docify::export]
|
||||
<a href=#692 id=692 data-nosnippet>692</a> #[pallet::error]
|
||||
<a href=#693 id=693 data-nosnippet>693</a> </span><span class="kw">pub enum </span>Error<T> {
|
||||
<a href=#694 id=694 data-nosnippet>694</a> <span class="doccomment">/// Account does not exist.
|
||||
<a href=#695 id=695 data-nosnippet>695</a> </span>NonExistentAccount,
|
||||
<a href=#696 id=696 data-nosnippet>696</a> <span class="doccomment">/// Account does not have enough balance.
|
||||
<a href=#697 id=697 data-nosnippet>697</a> </span>InsufficientBalance,
|
||||
<a href=#698 id=698 data-nosnippet>698</a> }
|
||||
<a href=#699 id=699 data-nosnippet>699</a>
|
||||
<a href=#700 id=700 data-nosnippet>700</a> <span class="attr">#[docify::export]
|
||||
<a href=#701 id=701 data-nosnippet>701</a> #[pallet::event]
|
||||
<a href=#702 id=702 data-nosnippet>702</a> #[pallet::generate_deposit(<span class="kw">pub</span>(<span class="kw">super</span>) <span class="kw">fn </span>deposit_event)]
|
||||
<a href=#703 id=703 data-nosnippet>703</a> </span><span class="kw">pub enum </span>Event<T: Config> {
|
||||
<a href=#704 id=704 data-nosnippet>704</a> <span class="doccomment">/// A transfer succeeded.
|
||||
<a href=#705 id=705 data-nosnippet>705</a> </span>Transferred { from: T::AccountId, to: T::AccountId, amount: Balance },
|
||||
<a href=#706 id=706 data-nosnippet>706</a> }
|
||||
<a href=#707 id=707 data-nosnippet>707</a>
|
||||
<a href=#708 id=708 data-nosnippet>708</a> <span class="attr">#[pallet::call]
|
||||
<a href=#709 id=709 data-nosnippet>709</a> </span><span class="kw">impl</span><T: Config> Pallet<T> {
|
||||
<a href=#710 id=710 data-nosnippet>710</a> <span class="attr">#[docify::export(transfer_v2)]
|
||||
<a href=#711 id=711 data-nosnippet>711</a> </span><span class="kw">pub fn </span>transfer(
|
||||
<a href=#712 id=712 data-nosnippet>712</a> origin: T::RuntimeOrigin,
|
||||
<a href=#713 id=713 data-nosnippet>713</a> dest: T::AccountId,
|
||||
<a href=#714 id=714 data-nosnippet>714</a> amount: Balance,
|
||||
<a href=#715 id=715 data-nosnippet>715</a> ) -> DispatchResult {
|
||||
<a href=#716 id=716 data-nosnippet>716</a> <span class="kw">let </span>sender = ensure_signed(origin)<span class="question-mark">?</span>;
|
||||
<a href=#717 id=717 data-nosnippet>717</a>
|
||||
<a href=#718 id=718 data-nosnippet>718</a> <span class="comment">// ensure sender has enough balance, and if so, calculate what is left after `amount`.
|
||||
<a href=#719 id=719 data-nosnippet>719</a> </span><span class="kw">let </span>sender_balance =
|
||||
<a href=#720 id=720 data-nosnippet>720</a> Balances::<T>::get(<span class="kw-2">&</span>sender).ok_or(Error::<T>::NonExistentAccount)<span class="question-mark">?</span>;
|
||||
<a href=#721 id=721 data-nosnippet>721</a> <span class="kw">let </span>remainder =
|
||||
<a href=#722 id=722 data-nosnippet>722</a> sender_balance.checked_sub(amount).ok_or(Error::<T>::InsufficientBalance)<span class="question-mark">?</span>;
|
||||
<a href=#723 id=723 data-nosnippet>723</a>
|
||||
<a href=#724 id=724 data-nosnippet>724</a> Balances::<T>::mutate(<span class="kw-2">&</span>dest, |b| <span class="kw-2">*</span>b = <span class="prelude-val">Some</span>(b.unwrap_or(<span class="number">0</span>) + amount));
|
||||
<a href=#725 id=725 data-nosnippet>725</a> Balances::<T>::insert(<span class="kw-2">&</span>sender, remainder);
|
||||
<a href=#726 id=726 data-nosnippet>726</a>
|
||||
<a href=#727 id=727 data-nosnippet>727</a> <span class="self">Self</span>::deposit_event(Event::<T>::Transferred { from: sender, to: dest, amount });
|
||||
<a href=#728 id=728 data-nosnippet>728</a>
|
||||
<a href=#729 id=729 data-nosnippet>729</a> <span class="prelude-val">Ok</span>(())
|
||||
<a href=#730 id=730 data-nosnippet>730</a> }
|
||||
<a href=#731 id=731 data-nosnippet>731</a> }
|
||||
<a href=#732 id=732 data-nosnippet>732</a>
|
||||
<a href=#733 id=733 data-nosnippet>733</a> <span class="attr">#[cfg(any(test, doc))]
|
||||
<a href=#734 id=734 data-nosnippet>734</a> </span><span class="kw">pub mod </span>tests {
|
||||
<a href=#735 id=735 data-nosnippet>735</a> <span class="kw">use super</span>::{<span class="kw">super</span>::pallet::tests::StateBuilder, <span class="kw-2">*</span>};
|
||||
<a href=#736 id=736 data-nosnippet>736</a> <span class="kw">use </span>frame::testing_prelude::<span class="kw-2">*</span>;
|
||||
<a href=#737 id=737 data-nosnippet>737</a> <span class="kw">const </span>ALICE: u64 = <span class="number">1</span>;
|
||||
<a href=#738 id=738 data-nosnippet>738</a> <span class="kw">const </span>BOB: u64 = <span class="number">2</span>;
|
||||
<a href=#739 id=739 data-nosnippet>739</a>
|
||||
<a href=#740 id=740 data-nosnippet>740</a> <span class="attr">#[docify::export]
|
||||
<a href=#741 id=741 data-nosnippet>741</a> </span><span class="kw">pub mod </span>runtime_v2 {
|
||||
<a href=#742 id=742 data-nosnippet>742</a> <span class="kw">use super</span>::<span class="kw-2">*</span>;
|
||||
<a href=#743 id=743 data-nosnippet>743</a> <span class="kw">use </span><span class="kw">crate</span>::guides::your_first_pallet::pallet_v2 <span class="kw">as </span>pallet_currency;
|
||||
<a href=#744 id=744 data-nosnippet>744</a>
|
||||
<a href=#745 id=745 data-nosnippet>745</a> <span class="macro">construct_runtime!</span>(
|
||||
<a href=#746 id=746 data-nosnippet>746</a> <span class="kw">pub enum </span>Runtime {
|
||||
<a href=#747 id=747 data-nosnippet>747</a> System: frame_system,
|
||||
<a href=#748 id=748 data-nosnippet>748</a> Currency: pallet_currency,
|
||||
<a href=#749 id=749 data-nosnippet>749</a> }
|
||||
<a href=#750 id=750 data-nosnippet>750</a> );
|
||||
<a href=#751 id=751 data-nosnippet>751</a>
|
||||
<a href=#752 id=752 data-nosnippet>752</a> <span class="attr">#[derive_impl(frame_system::config_preludes::TestDefaultConfig)]
|
||||
<a href=#753 id=753 data-nosnippet>753</a> </span><span class="kw">impl </span>frame_system::Config <span class="kw">for </span>Runtime {
|
||||
<a href=#754 id=754 data-nosnippet>754</a> <span class="kw">type </span>Block = MockBlock<Runtime>;
|
||||
<a href=#755 id=755 data-nosnippet>755</a> <span class="kw">type </span>AccountId = u64;
|
||||
<a href=#756 id=756 data-nosnippet>756</a> }
|
||||
<a href=#757 id=757 data-nosnippet>757</a>
|
||||
<a href=#758 id=758 data-nosnippet>758</a> <span class="kw">impl </span>pallet_currency::Config <span class="kw">for </span>Runtime {
|
||||
<a href=#759 id=759 data-nosnippet>759</a> <span class="kw">type </span>RuntimeEvent = RuntimeEvent;
|
||||
<a href=#760 id=760 data-nosnippet>760</a> }
|
||||
<a href=#761 id=761 data-nosnippet>761</a> }
|
||||
<a href=#762 id=762 data-nosnippet>762</a>
|
||||
<a href=#763 id=763 data-nosnippet>763</a> <span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">use </span>runtime_v2::<span class="kw-2">*</span>;
|
||||
<a href=#764 id=764 data-nosnippet>764</a>
|
||||
<a href=#765 id=765 data-nosnippet>765</a> <span class="attr">#[docify::export(transfer_works_v2)]
|
||||
<a href=#766 id=766 data-nosnippet>766</a> #[test]
|
||||
<a href=#767 id=767 data-nosnippet>767</a> </span><span class="kw">fn </span>transfer_works() {
|
||||
<a href=#768 id=768 data-nosnippet>768</a> StateBuilder::default().build_and_execute(|| {
|
||||
<a href=#769 id=769 data-nosnippet>769</a> <span class="comment">// skip the genesis block, as events are not deposited there and we need them for
|
||||
<a href=#770 id=770 data-nosnippet>770</a> // the final assertion.
|
||||
<a href=#771 id=771 data-nosnippet>771</a> </span>System::set_block_number(ALICE);
|
||||
<a href=#772 id=772 data-nosnippet>772</a>
|
||||
<a href=#773 id=773 data-nosnippet>773</a> <span class="comment">// given the initial state, when:
|
||||
<a href=#774 id=774 data-nosnippet>774</a> </span><span class="macro">assert_ok!</span>(Pallet::<Runtime>::transfer(RuntimeOrigin::signed(ALICE), BOB, <span class="number">50</span>));
|
||||
<a href=#775 id=775 data-nosnippet>775</a>
|
||||
<a href=#776 id=776 data-nosnippet>776</a> <span class="comment">// then:
|
||||
<a href=#777 id=777 data-nosnippet>777</a> </span><span class="macro">assert_eq!</span>(Balances::<Runtime>::get(<span class="kw-2">&</span>ALICE), <span class="prelude-val">Some</span>(<span class="number">50</span>));
|
||||
<a href=#778 id=778 data-nosnippet>778</a> <span class="macro">assert_eq!</span>(Balances::<Runtime>::get(<span class="kw-2">&</span>BOB), <span class="prelude-val">Some</span>(<span class="number">150</span>));
|
||||
<a href=#779 id=779 data-nosnippet>779</a> <span class="macro">assert_eq!</span>(TotalIssuance::<Runtime>::get(), <span class="prelude-val">Some</span>(<span class="number">200</span>));
|
||||
<a href=#780 id=780 data-nosnippet>780</a>
|
||||
<a href=#781 id=781 data-nosnippet>781</a> <span class="comment">// now we can also check that an event has been deposited:
|
||||
<a href=#782 id=782 data-nosnippet>782</a> </span><span class="macro">assert_eq!</span>(
|
||||
<a href=#783 id=783 data-nosnippet>783</a> System::read_events_for_pallet::<Event<Runtime>>(),
|
||||
<a href=#784 id=784 data-nosnippet>784</a> <span class="macro">vec!</span>[Event::Transferred { from: ALICE, to: BOB, amount: <span class="number">50 </span>}]
|
||||
<a href=#785 id=785 data-nosnippet>785</a> );
|
||||
<a href=#786 id=786 data-nosnippet>786</a> });
|
||||
<a href=#787 id=787 data-nosnippet>787</a> }
|
||||
<a href=#788 id=788 data-nosnippet>788</a> }
|
||||
<a href=#789 id=789 data-nosnippet>789</a>}</code></pre></div></section></main></body></html>
|
||||
@@ -0,0 +1,186 @@
|
||||
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `docs/sdk/src/guides/your_first_runtime.rs`."><title>your_first_runtime.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2"href="../../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../../../static.files/rustdoc-e56847b5.css"><meta name="rustdoc-vars" data-root-path="../../../" data-static-root-path="../../../static.files/" data-current-crate="pezkuwi_sdk_docs" data-themes="" data-resource-suffix="" data-rustdoc-version="1.91.1 (ed61e7d7e 2025-11-07)" data-channel="1.91.1" data-search-js="search-e256b49e.js" data-stringdex-js="stringdex-c3e638e9.js" data-settings-js="settings-c38705f0.js" ><script src="../../../static.files/storage-e2aeef58.js"></script><script defer src="../../../static.files/src-script-813739b1.js"></script><script defer src="../../../src-files.js"></script><script defer src="../../../static.files/main-6dc2a7f3.js"></script><noscript><link rel="stylesheet" href="../../../static.files/noscript-263c88ec.css"></noscript><link rel="icon" href="https://pezkuwichain.io/favicon.ico"></head><body class="rustdoc src"><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer" title="Drag to resize sidebar"></div><main><section id="main-content" class="content"><div class="main-heading"><h1><div class="sub-heading">pezkuwi_sdk_docs/guides/</div>your_first_runtime.rs</h1><rustdoc-toolbar></rustdoc-toolbar></div><div class="example-wrap digits-3"><pre class="rust"><code><a href=#1 id=1 data-nosnippet>1</a><span class="doccomment">//! # Your first Runtime
|
||||
<a href=#2 id=2 data-nosnippet>2</a>//!
|
||||
<a href=#3 id=3 data-nosnippet>3</a>//! This guide will walk you through the steps to add your pallet to a runtime.
|
||||
<a href=#4 id=4 data-nosnippet>4</a>//!
|
||||
<a href=#5 id=5 data-nosnippet>5</a>//! The good news is, in [`crate::guides::your_first_pallet`], we have already created a _test_
|
||||
<a href=#6 id=6 data-nosnippet>6</a>//! runtime that was used for testing, and a real runtime is not that much different!
|
||||
<a href=#7 id=7 data-nosnippet>7</a>//!
|
||||
<a href=#8 id=8 data-nosnippet>8</a>//! ## Setup
|
||||
<a href=#9 id=9 data-nosnippet>9</a>//!
|
||||
<a href=#10 id=10 data-nosnippet>10</a>//! A runtime shares a few similar setup requirements as with a pallet:
|
||||
<a href=#11 id=11 data-nosnippet>11</a>//!
|
||||
<a href=#12 id=12 data-nosnippet>12</a>//! * importing [`frame`], [`codec`], and [`scale_info`] crates.
|
||||
<a href=#13 id=13 data-nosnippet>13</a>//! * following the [`std` feature-gating](crate::pezkuwi_sdk::substrate#wasm-build) pattern.
|
||||
<a href=#14 id=14 data-nosnippet>14</a>//!
|
||||
<a href=#15 id=15 data-nosnippet>15</a>//! But, more specifically, it also contains:
|
||||
<a href=#16 id=16 data-nosnippet>16</a>//!
|
||||
<a href=#17 id=17 data-nosnippet>17</a>//! * a `build.rs` that uses [`substrate_wasm_builder`]. This entails declaring
|
||||
<a href=#18 id=18 data-nosnippet>18</a>//! `[build-dependencies]` in the Cargo manifest file:
|
||||
<a href=#19 id=19 data-nosnippet>19</a>//!
|
||||
<a href=#20 id=20 data-nosnippet>20</a>//! ```ignore
|
||||
<a href=#21 id=21 data-nosnippet>21</a>//! [build-dependencies]
|
||||
<a href=#22 id=22 data-nosnippet>22</a>//! substrate-wasm-builder = { ... }
|
||||
<a href=#23 id=23 data-nosnippet>23</a>//! ```
|
||||
<a href=#24 id=24 data-nosnippet>24</a>//!
|
||||
<a href=#25 id=25 data-nosnippet>25</a>//! >Note that a runtime must always be one-runtime-per-crate. You cannot define multiple runtimes
|
||||
<a href=#26 id=26 data-nosnippet>26</a>//! per rust crate.
|
||||
<a href=#27 id=27 data-nosnippet>27</a>//!
|
||||
<a href=#28 id=28 data-nosnippet>28</a>//! You can find the full code of this guide in [`first_runtime`].
|
||||
<a href=#29 id=29 data-nosnippet>29</a>//!
|
||||
<a href=#30 id=30 data-nosnippet>30</a>//! ## Your First Runtime
|
||||
<a href=#31 id=31 data-nosnippet>31</a>//!
|
||||
<a href=#32 id=32 data-nosnippet>32</a>//! The first new property of a real runtime that it must define its
|
||||
<a href=#33 id=33 data-nosnippet>33</a>//! [`frame::runtime::prelude::RuntimeVersion`]:
|
||||
<a href=#34 id=34 data-nosnippet>34</a></span><span class="attr">#![doc = <span class="macro">docify::embed!</span>(<span class="string">"./packages/guides/first-runtime/src/lib.rs"</span>, VERSION)]
|
||||
<a href=#35 id=35 data-nosnippet>35</a></span><span class="doccomment">//!
|
||||
<a href=#36 id=36 data-nosnippet>36</a>//! The version contains a number of very important fields, such as `spec_version` and `spec_name`
|
||||
<a href=#37 id=37 data-nosnippet>37</a>//! that play an important role in identifying your runtime and its version, more importantly in
|
||||
<a href=#38 id=38 data-nosnippet>38</a>//! runtime upgrades. More about runtime upgrades in
|
||||
<a href=#39 id=39 data-nosnippet>39</a>//! [`crate::reference_docs::frame_runtime_upgrades_and_migrations`].
|
||||
<a href=#40 id=40 data-nosnippet>40</a>//!
|
||||
<a href=#41 id=41 data-nosnippet>41</a>//! Then, a real runtime also contains the `impl` of all individual pallets' `trait Config` for
|
||||
<a href=#42 id=42 data-nosnippet>42</a>//! `struct Runtime`, and a [`frame::runtime::prelude::construct_runtime`] macro that amalgamates
|
||||
<a href=#43 id=43 data-nosnippet>43</a>//! them all.
|
||||
<a href=#44 id=44 data-nosnippet>44</a>//!
|
||||
<a href=#45 id=45 data-nosnippet>45</a>//! In the case of our example:
|
||||
<a href=#46 id=46 data-nosnippet>46</a></span><span class="attr">#![doc = <span class="macro">docify::embed!</span>(<span class="string">"./packages/guides/first-runtime/src/lib.rs"</span>, our_config_impl)]
|
||||
<a href=#47 id=47 data-nosnippet>47</a></span><span class="doccomment">//!
|
||||
<a href=#48 id=48 data-nosnippet>48</a>//! In this example, we bring in a number of other pallets from [`frame`] into the runtime, each of
|
||||
<a href=#49 id=49 data-nosnippet>49</a>//! their `Config` need to be implemented for `struct Runtime`:
|
||||
<a href=#50 id=50 data-nosnippet>50</a></span><span class="attr">#![doc = <span class="macro">docify::embed!</span>(<span class="string">"./packages/guides/first-runtime/src/lib.rs"</span>, config_impls)]
|
||||
<a href=#51 id=51 data-nosnippet>51</a></span><span class="doccomment">//!
|
||||
<a href=#52 id=52 data-nosnippet>52</a>//! Notice how we use [`frame::pallet_macros::derive_impl`] to provide "default" configuration items
|
||||
<a href=#53 id=53 data-nosnippet>53</a>//! for each pallet. Feel free to dive into the definition of each default prelude (eg.
|
||||
<a href=#54 id=54 data-nosnippet>54</a>//! [`frame::prelude::frame_system::pallet::config_preludes`]) to learn more which types are exactly
|
||||
<a href=#55 id=55 data-nosnippet>55</a>//! used.
|
||||
<a href=#56 id=56 data-nosnippet>56</a>//!
|
||||
<a href=#57 id=57 data-nosnippet>57</a>//! Recall that in test runtime in [`crate::guides::your_first_pallet`], we provided `type AccountId
|
||||
<a href=#58 id=58 data-nosnippet>58</a>//! = u64` to `frame_system`, while in this case we rely on whatever is provided by
|
||||
<a href=#59 id=59 data-nosnippet>59</a>//! [`SolochainDefaultConfig`], which is indeed a "real" 32 byte account id.
|
||||
<a href=#60 id=60 data-nosnippet>60</a>//!
|
||||
<a href=#61 id=61 data-nosnippet>61</a>//! Then, a familiar instance of `construct_runtime` amalgamates all of the pallets:
|
||||
<a href=#62 id=62 data-nosnippet>62</a></span><span class="attr">#![doc = <span class="macro">docify::embed!</span>(<span class="string">"./packages/guides/first-runtime/src/lib.rs"</span>, cr)]
|
||||
<a href=#63 id=63 data-nosnippet>63</a></span><span class="doccomment">//!
|
||||
<a href=#64 id=64 data-nosnippet>64</a>//! Recall from [`crate::reference_docs::wasm_meta_protocol`] that every (real) runtime needs to
|
||||
<a href=#65 id=65 data-nosnippet>65</a>//! implement a set of runtime APIs that will then let the node to communicate with it. The final
|
||||
<a href=#66 id=66 data-nosnippet>66</a>//! steps of crafting a runtime are related to achieving exactly this.
|
||||
<a href=#67 id=67 data-nosnippet>67</a>//!
|
||||
<a href=#68 id=68 data-nosnippet>68</a>//! First, we define a number of types that eventually lead to the creation of an instance of
|
||||
<a href=#69 id=69 data-nosnippet>69</a>//! [`frame::runtime::prelude::Executive`]. The executive is a handy FRAME utility that, through
|
||||
<a href=#70 id=70 data-nosnippet>70</a>//! amalgamating all pallets and further types, implements some of the very very core pieces of the
|
||||
<a href=#71 id=71 data-nosnippet>71</a>//! runtime logic, such as how blocks are executed and other runtime-api implementations.
|
||||
<a href=#72 id=72 data-nosnippet>72</a></span><span class="attr">#![doc = <span class="macro">docify::embed!</span>(<span class="string">"./packages/guides/first-runtime/src/lib.rs"</span>, runtime_types)]
|
||||
<a href=#73 id=73 data-nosnippet>73</a></span><span class="doccomment">//!
|
||||
<a href=#74 id=74 data-nosnippet>74</a>//! Finally, we use [`frame::runtime::prelude::impl_runtime_apis`] to implement all of the runtime
|
||||
<a href=#75 id=75 data-nosnippet>75</a>//! APIs that the runtime wishes to expose. As you will see in the code, most of these runtime API
|
||||
<a href=#76 id=76 data-nosnippet>76</a>//! implementations are merely forwarding calls to `RuntimeExecutive` which handles the actual
|
||||
<a href=#77 id=77 data-nosnippet>77</a>//! logic. Given that the implementation block is somewhat large, we won't repeat it here. You can
|
||||
<a href=#78 id=78 data-nosnippet>78</a>//! look for `impl_runtime_apis!` in [`first_runtime`].
|
||||
<a href=#79 id=79 data-nosnippet>79</a>//!
|
||||
<a href=#80 id=80 data-nosnippet>80</a>//! ```ignore
|
||||
<a href=#81 id=81 data-nosnippet>81</a>//! impl_runtime_apis! {
|
||||
<a href=#82 id=82 data-nosnippet>82</a>//! impl apis::Core<Block> for Runtime {
|
||||
<a href=#83 id=83 data-nosnippet>83</a>//! fn version() -> RuntimeVersion {
|
||||
<a href=#84 id=84 data-nosnippet>84</a>//! VERSION
|
||||
<a href=#85 id=85 data-nosnippet>85</a>//! }
|
||||
<a href=#86 id=86 data-nosnippet>86</a>//!
|
||||
<a href=#87 id=87 data-nosnippet>87</a>//! fn execute_block(block: Block) {
|
||||
<a href=#88 id=88 data-nosnippet>88</a>//! RuntimeExecutive::execute_block(block)
|
||||
<a href=#89 id=89 data-nosnippet>89</a>//! }
|
||||
<a href=#90 id=90 data-nosnippet>90</a>//!
|
||||
<a href=#91 id=91 data-nosnippet>91</a>//! fn initialize_block(header: &Header) -> ExtrinsicInclusionMode {
|
||||
<a href=#92 id=92 data-nosnippet>92</a>//! RuntimeExecutive::initialize_block(header)
|
||||
<a href=#93 id=93 data-nosnippet>93</a>//! }
|
||||
<a href=#94 id=94 data-nosnippet>94</a>//! }
|
||||
<a href=#95 id=95 data-nosnippet>95</a>//!
|
||||
<a href=#96 id=96 data-nosnippet>96</a>//! // many more trait impls...
|
||||
<a href=#97 id=97 data-nosnippet>97</a>//! }
|
||||
<a href=#98 id=98 data-nosnippet>98</a>//! ```
|
||||
<a href=#99 id=99 data-nosnippet>99</a>//!
|
||||
<a href=#100 id=100 data-nosnippet>100</a>//! And that more or less covers the details of how you would write a real runtime!
|
||||
<a href=#101 id=101 data-nosnippet>101</a>//!
|
||||
<a href=#102 id=102 data-nosnippet>102</a>//! Once you compile a crate that contains a runtime as above, simply running `cargo build` will
|
||||
<a href=#103 id=103 data-nosnippet>103</a>//! generate the wasm blobs and place them under `./target/release/wbuild`, as explained
|
||||
<a href=#104 id=104 data-nosnippet>104</a>//! [here](crate::pezkuwi_sdk::substrate#wasm-build).
|
||||
<a href=#105 id=105 data-nosnippet>105</a>//!
|
||||
<a href=#106 id=106 data-nosnippet>106</a>//! ## Genesis Configuration
|
||||
<a href=#107 id=107 data-nosnippet>107</a>//!
|
||||
<a href=#108 id=108 data-nosnippet>108</a>//! Every runtime specifies a number of runtime APIs that help the outer world (most notably, a
|
||||
<a href=#109 id=109 data-nosnippet>109</a>//! `node`) know what is the genesis state of this runtime. These APIs are then used to generate
|
||||
<a href=#110 id=110 data-nosnippet>110</a>//! what is known as a **Chain Specification, or chain spec for short**. A chain spec is the
|
||||
<a href=#111 id=111 data-nosnippet>111</a>//! primary way to run a new chain.
|
||||
<a href=#112 id=112 data-nosnippet>112</a>//!
|
||||
<a href=#113 id=113 data-nosnippet>113</a>//! These APIs are defined in [`sp_genesis_builder`], and are re-exposed as a part of
|
||||
<a href=#114 id=114 data-nosnippet>114</a>//! [`frame::runtime::apis`]. Therefore, the implementation blocks can be found inside of
|
||||
<a href=#115 id=115 data-nosnippet>115</a>//! `impl_runtime_apis!` similar to:
|
||||
<a href=#116 id=116 data-nosnippet>116</a>//!
|
||||
<a href=#117 id=117 data-nosnippet>117</a>//! ```ignore
|
||||
<a href=#118 id=118 data-nosnippet>118</a>//! impl_runtime_apis! {
|
||||
<a href=#119 id=119 data-nosnippet>119</a>//! impl apis::GenesisBuilder<Block> for Runtime {
|
||||
<a href=#120 id=120 data-nosnippet>120</a>//! fn build_state(config: Vec<u8>) -> GenesisBuilderResult {
|
||||
<a href=#121 id=121 data-nosnippet>121</a>//! build_state::<RuntimeGenesisConfig>(config)
|
||||
<a href=#122 id=122 data-nosnippet>122</a>//! }
|
||||
<a href=#123 id=123 data-nosnippet>123</a>//!
|
||||
<a href=#124 id=124 data-nosnippet>124</a>//! fn get_preset(id: &Option<PresetId>) -> Option<Vec<u8>> {
|
||||
<a href=#125 id=125 data-nosnippet>125</a>//! get_preset::<RuntimeGenesisConfig>(id, self::genesis_config_presets::get_preset)
|
||||
<a href=#126 id=126 data-nosnippet>126</a>//! }
|
||||
<a href=#127 id=127 data-nosnippet>127</a>//!
|
||||
<a href=#128 id=128 data-nosnippet>128</a>//! fn preset_names() -> Vec<PresetId> {
|
||||
<a href=#129 id=129 data-nosnippet>129</a>//! crate::genesis_config_presets::preset_names()
|
||||
<a href=#130 id=130 data-nosnippet>130</a>//! }
|
||||
<a href=#131 id=131 data-nosnippet>131</a>//! }
|
||||
<a href=#132 id=132 data-nosnippet>132</a>//!
|
||||
<a href=#133 id=133 data-nosnippet>133</a>//! }
|
||||
<a href=#134 id=134 data-nosnippet>134</a>//! ```
|
||||
<a href=#135 id=135 data-nosnippet>135</a>//!
|
||||
<a href=#136 id=136 data-nosnippet>136</a>//! The implementation of these function can naturally vary from one runtime to the other, but the
|
||||
<a href=#137 id=137 data-nosnippet>137</a>//! overall pattern is common. For the case of this runtime, we do the following:
|
||||
<a href=#138 id=138 data-nosnippet>138</a>//!
|
||||
<a href=#139 id=139 data-nosnippet>139</a>//! 1. Expose one non-default preset, namely [`sp_genesis_builder::DEV_RUNTIME_PRESET`]. This means
|
||||
<a href=#140 id=140 data-nosnippet>140</a>//! our runtime has two "presets" of genesis state in total: `DEV_RUNTIME_PRESET` and `None`.
|
||||
<a href=#141 id=141 data-nosnippet>141</a></span><span class="attr">#![doc = <span class="macro">docify::embed!</span>(<span class="string">"./packages/guides/first-runtime/src/lib.rs"</span>, preset_names)]
|
||||
<a href=#142 id=142 data-nosnippet>142</a></span><span class="doccomment">//!
|
||||
<a href=#143 id=143 data-nosnippet>143</a>//! For `build_state` and `get_preset`, we use the helper functions provide by frame:
|
||||
<a href=#144 id=144 data-nosnippet>144</a>//!
|
||||
<a href=#145 id=145 data-nosnippet>145</a>//! * [`frame::runtime::prelude::build_state`] and [`frame::runtime::prelude::get_preset`].
|
||||
<a href=#146 id=146 data-nosnippet>146</a>//!
|
||||
<a href=#147 id=147 data-nosnippet>147</a>//! Indeed, our runtime needs to specify what its `DEV_RUNTIME_PRESET` genesis state should be like:
|
||||
<a href=#148 id=148 data-nosnippet>148</a></span><span class="attr">#![doc = <span class="macro">docify::embed!</span>(<span class="string">"./packages/guides/first-runtime/src/lib.rs"</span>, development_config_genesis)]
|
||||
<a href=#149 id=149 data-nosnippet>149</a></span><span class="doccomment">//!
|
||||
<a href=#150 id=150 data-nosnippet>150</a>//! For more in-depth information about `GenesisConfig`, `ChainSpec`, the `GenesisBuilder` API and
|
||||
<a href=#151 id=151 data-nosnippet>151</a>//! `chain-spec-builder`, see [`crate::reference_docs::chain_spec_genesis`].
|
||||
<a href=#152 id=152 data-nosnippet>152</a>//!
|
||||
<a href=#153 id=153 data-nosnippet>153</a>//! ## Next Step
|
||||
<a href=#154 id=154 data-nosnippet>154</a>//!
|
||||
<a href=#155 id=155 data-nosnippet>155</a>//! See [`crate::guides::your_first_node`].
|
||||
<a href=#156 id=156 data-nosnippet>156</a>//!
|
||||
<a href=#157 id=157 data-nosnippet>157</a>//! ## Further Reading
|
||||
<a href=#158 id=158 data-nosnippet>158</a>//!
|
||||
<a href=#159 id=159 data-nosnippet>159</a>//! 1. To learn more about signed extensions, see [`crate::reference_docs::signed_extensions`].
|
||||
<a href=#160 id=160 data-nosnippet>160</a>//! 2. `AllPalletsWithSystem` is also generated by `construct_runtime`, as explained in
|
||||
<a href=#161 id=161 data-nosnippet>161</a>//! [`crate::reference_docs::frame_runtime_types`].
|
||||
<a href=#162 id=162 data-nosnippet>162</a>//! 3. `Executive` supports more generics, most notably allowing the runtime to configure more
|
||||
<a href=#163 id=163 data-nosnippet>163</a>//! runtime migrations, as explained in
|
||||
<a href=#164 id=164 data-nosnippet>164</a>//! [`crate::reference_docs::frame_runtime_upgrades_and_migrations`].
|
||||
<a href=#165 id=165 data-nosnippet>165</a>//! 4. Learn more about adding and implementing runtime apis in
|
||||
<a href=#166 id=166 data-nosnippet>166</a>//! [`crate::reference_docs::custom_runtime_api_rpc`].
|
||||
<a href=#167 id=167 data-nosnippet>167</a>//! 5. To see a complete example of a runtime+pallet that is similar to this guide, please see
|
||||
<a href=#168 id=168 data-nosnippet>168</a>//! [`crate::pezkuwi_sdk::templates`].
|
||||
<a href=#169 id=169 data-nosnippet>169</a>//!
|
||||
<a href=#170 id=170 data-nosnippet>170</a>//! [`SolochainDefaultConfig`]: struct@frame_system::pallet::config_preludes::SolochainDefaultConfig
|
||||
<a href=#171 id=171 data-nosnippet>171</a>
|
||||
<a href=#172 id=172 data-nosnippet>172</a></span><span class="attr">#[cfg(test)]
|
||||
<a href=#173 id=173 data-nosnippet>173</a></span><span class="kw">mod </span>tests {
|
||||
<a href=#174 id=174 data-nosnippet>174</a> <span class="kw">use </span>cmd_lib::run_cmd;
|
||||
<a href=#175 id=175 data-nosnippet>175</a>
|
||||
<a href=#176 id=176 data-nosnippet>176</a> <span class="kw">const </span>FIRST_RUNTIME: <span class="kw-2">&</span><span class="lifetime">'static </span>str = <span class="string">"pezkuwi-sdk-docs-first-runtime"</span>;
|
||||
<a href=#177 id=177 data-nosnippet>177</a>
|
||||
<a href=#178 id=178 data-nosnippet>178</a> <span class="attr">#[docify::export_content]
|
||||
<a href=#179 id=179 data-nosnippet>179</a> #[test]
|
||||
<a href=#180 id=180 data-nosnippet>180</a> </span><span class="kw">fn </span>build_runtime() {
|
||||
<a href=#181 id=181 data-nosnippet>181</a> <span class="macro">run_cmd!</span>(
|
||||
<a href=#182 id=182 data-nosnippet>182</a> cargo build --release -p <span class="macro-nonterminal">$FIRST_RUNTIME
|
||||
<a href=#183 id=183 data-nosnippet>183</a> </span>)
|
||||
<a href=#184 id=184 data-nosnippet>184</a> .expect(<span class="string">"Failed to run command"</span>);
|
||||
<a href=#185 id=185 data-nosnippet>185</a> }
|
||||
<a href=#186 id=186 data-nosnippet>186</a>}</code></pre></div></section></main></body></html>
|
||||
@@ -0,0 +1,50 @@
|
||||
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `docs/sdk/src/lib.rs`."><title>lib.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2"href="../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../../static.files/rustdoc-e56847b5.css"><meta name="rustdoc-vars" data-root-path="../../" data-static-root-path="../../static.files/" data-current-crate="pezkuwi_sdk_docs" data-themes="" data-resource-suffix="" data-rustdoc-version="1.91.1 (ed61e7d7e 2025-11-07)" data-channel="1.91.1" data-search-js="search-e256b49e.js" data-stringdex-js="stringdex-c3e638e9.js" data-settings-js="settings-c38705f0.js" ><script src="../../static.files/storage-e2aeef58.js"></script><script defer src="../../static.files/src-script-813739b1.js"></script><script defer src="../../src-files.js"></script><script defer src="../../static.files/main-6dc2a7f3.js"></script><noscript><link rel="stylesheet" href="../../static.files/noscript-263c88ec.css"></noscript><link rel="icon" href="https://pezkuwichain.io/favicon.ico"></head><body class="rustdoc src"><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer" title="Drag to resize sidebar"></div><main><section id="main-content" class="content"><div class="main-heading"><h1><div class="sub-heading">pezkuwi_sdk_docs/</div>lib.rs</h1><rustdoc-toolbar></rustdoc-toolbar></div><div class="example-wrap digits-2"><pre class="rust"><code><a href=#1 id=1 data-nosnippet>1</a><span class="doccomment">//! # Pezkuwi SDK Docs
|
||||
<a href=#2 id=2 data-nosnippet>2</a>//!
|
||||
<a href=#3 id=3 data-nosnippet>3</a>//! The Pezkuwi SDK Developer Documentation.
|
||||
<a href=#4 id=4 data-nosnippet>4</a>//!
|
||||
<a href=#5 id=5 data-nosnippet>5</a>//! This crate is a *minimal*, *always-accurate* and low level source of truth about Pezkuwi-SDK.
|
||||
<a href=#6 id=6 data-nosnippet>6</a>//! For more high level docs, please go to [docs.pezkuwi.com](https://docs.pezkuwichain.io).
|
||||
<a href=#7 id=7 data-nosnippet>7</a>//!
|
||||
<a href=#8 id=8 data-nosnippet>8</a>//! ## Getting Started
|
||||
<a href=#9 id=9 data-nosnippet>9</a>//!
|
||||
<a href=#10 id=10 data-nosnippet>10</a>//! We suggest the following reading sequence:
|
||||
<a href=#11 id=11 data-nosnippet>11</a>//!
|
||||
<a href=#12 id=12 data-nosnippet>12</a>//! - Start by learning about [`pezkuwi_sdk`], its structure and context.
|
||||
<a href=#13 id=13 data-nosnippet>13</a>//! - Then, head over to the [`guides`]. This modules contains in-depth guides about the most
|
||||
<a href=#14 id=14 data-nosnippet>14</a>//! important user-journeys of the Pezkuwi SDK.
|
||||
<a href=#15 id=15 data-nosnippet>15</a>//! - Whilst reading the guides, you might find back-links to [`reference_docs`].
|
||||
<a href=#16 id=16 data-nosnippet>16</a>//! - [`external_resources`] for a list of 3rd party guides and tutorials.
|
||||
<a href=#17 id=17 data-nosnippet>17</a>//! - Finally, <https://paritytech.github.io> is the parent website of this crate that contains the
|
||||
<a href=#18 id=18 data-nosnippet>18</a>//! list of further tools related to the Pezkuwi SDK.
|
||||
<a href=#19 id=19 data-nosnippet>19</a>//!
|
||||
<a href=#20 id=20 data-nosnippet>20</a>//! ## Information Architecture
|
||||
<a href=#21 id=21 data-nosnippet>21</a>//!
|
||||
<a href=#22 id=22 data-nosnippet>22</a>//! This section paints a picture over the high-level information architecture of this crate.
|
||||
<a href=#23 id=23 data-nosnippet>23</a></span><span class="attr">#![doc = <span class="macro">simple_mermaid::mermaid!</span>(<span class="string">"../../mermaid/IA.mmd"</span>)]
|
||||
<a href=#24 id=24 data-nosnippet>24</a>#![warn(rustdoc::broken_intra_doc_links)]
|
||||
<a href=#25 id=25 data-nosnippet>25</a>#![warn(rustdoc::private_intra_doc_links)]
|
||||
<a href=#26 id=26 data-nosnippet>26</a></span><span class="comment">// Frame macros reference features which this crate does not have
|
||||
<a href=#27 id=27 data-nosnippet>27</a></span><span class="attr">#![allow(unexpected_cfgs)]
|
||||
<a href=#28 id=28 data-nosnippet>28</a>#![doc(html_favicon_url = <span class="string">"https://pezkuwichain.io/favicon.ico"</span>)]
|
||||
<a href=#29 id=29 data-nosnippet>29</a>#![doc(
|
||||
<a href=#30 id=30 data-nosnippet>30</a> html_logo_url = <span class="string">"https://raw.githubusercontent.com/paritytech/pezkuwi-sdk/master/docs/images/Pezkuwi_Logo_Horizontal_Pink_White.png"
|
||||
<a href=#31 id=31 data-nosnippet>31</a></span>)]
|
||||
<a href=#32 id=32 data-nosnippet>32</a>#![doc(issue_tracker_base_url = <span class="string">"https://github.com/pezkuwichain/pezkuwi-sdk/issues"</span>)]
|
||||
<a href=#33 id=33 data-nosnippet>33</a>
|
||||
<a href=#34 id=34 data-nosnippet>34</a></span><span class="doccomment">/// Meta information about this crate, how it is built, what principles dictates its evolution and
|
||||
<a href=#35 id=35 data-nosnippet>35</a>/// how one can contribute to it.
|
||||
<a href=#36 id=36 data-nosnippet>36</a></span><span class="kw">pub mod </span>meta_contributing;
|
||||
<a href=#37 id=37 data-nosnippet>37</a>
|
||||
<a href=#38 id=38 data-nosnippet>38</a><span class="doccomment">/// A list of external resources and learning material about Pezkuwi SDK.
|
||||
<a href=#39 id=39 data-nosnippet>39</a></span><span class="kw">pub mod </span>external_resources;
|
||||
<a href=#40 id=40 data-nosnippet>40</a>
|
||||
<a href=#41 id=41 data-nosnippet>41</a><span class="doccomment">/// In-depth guides about the most common components of the Pezkuwi SDK. They are slightly more
|
||||
<a href=#42 id=42 data-nosnippet>42</a>/// high level and broad than [`reference_docs`].
|
||||
<a href=#43 id=43 data-nosnippet>43</a></span><span class="kw">pub mod </span>guides;
|
||||
<a href=#44 id=44 data-nosnippet>44</a>
|
||||
<a href=#45 id=45 data-nosnippet>45</a><span class="doccomment">/// An introduction to the Pezkuwi SDK. Read this module to learn about the structure of the SDK,
|
||||
<a href=#46 id=46 data-nosnippet>46</a>/// the tools that are provided as a part of it, and to gain a high level understanding of each.
|
||||
<a href=#47 id=47 data-nosnippet>47</a></span><span class="kw">pub mod </span>pezkuwi_sdk;
|
||||
<a href=#48 id=48 data-nosnippet>48</a><span class="doccomment">/// Reference documents covering in-depth topics across the Pezkuwi SDK. It is suggested to read
|
||||
<a href=#49 id=49 data-nosnippet>49</a>/// these on-demand, while you are going through the [`guides`] or other content.
|
||||
<a href=#50 id=50 data-nosnippet>50</a></span><span class="kw">pub mod </span>reference_docs;</code></pre></div></section></main></body></html>
|
||||
@@ -0,0 +1,151 @@
|
||||
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `docs/sdk/src/meta_contributing.rs`."><title>meta_contributing.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2"href="../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../../static.files/rustdoc-e56847b5.css"><meta name="rustdoc-vars" data-root-path="../../" data-static-root-path="../../static.files/" data-current-crate="pezkuwi_sdk_docs" data-themes="" data-resource-suffix="" data-rustdoc-version="1.91.1 (ed61e7d7e 2025-11-07)" data-channel="1.91.1" data-search-js="search-e256b49e.js" data-stringdex-js="stringdex-c3e638e9.js" data-settings-js="settings-c38705f0.js" ><script src="../../static.files/storage-e2aeef58.js"></script><script defer src="../../static.files/src-script-813739b1.js"></script><script defer src="../../src-files.js"></script><script defer src="../../static.files/main-6dc2a7f3.js"></script><noscript><link rel="stylesheet" href="../../static.files/noscript-263c88ec.css"></noscript><link rel="icon" href="https://pezkuwichain.io/favicon.ico"></head><body class="rustdoc src"><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer" title="Drag to resize sidebar"></div><main><section id="main-content" class="content"><div class="main-heading"><h1><div class="sub-heading">pezkuwi_sdk_docs/</div>meta_contributing.rs</h1><rustdoc-toolbar></rustdoc-toolbar></div><div class="example-wrap digits-3"><pre class="rust"><code><a href=#1 id=1 data-nosnippet>1</a><span class="doccomment">//! # Contribution
|
||||
<a href=#2 id=2 data-nosnippet>2</a>//!
|
||||
<a href=#3 id=3 data-nosnippet>3</a>//! The following sections cover more detailed information about this crate and how it should be
|
||||
<a href=#4 id=4 data-nosnippet>4</a>//! maintained.
|
||||
<a href=#5 id=5 data-nosnippet>5</a>//!
|
||||
<a href=#6 id=6 data-nosnippet>6</a>//! ## Why Rust Docs?
|
||||
<a href=#7 id=7 data-nosnippet>7</a>//!
|
||||
<a href=#8 id=8 data-nosnippet>8</a>//! We acknowledge that blockchain based systems, particularly a cutting-edge one like Pezkuwi SDK
|
||||
<a href=#9 id=9 data-nosnippet>9</a>//! is a software artifact that is complex, and rapidly evolving. This makes the task of documenting
|
||||
<a href=#10 id=10 data-nosnippet>10</a>//! it externally extremely difficult, especially with regards to making sure it is up-to-date.
|
||||
<a href=#11 id=11 data-nosnippet>11</a>//!
|
||||
<a href=#12 id=12 data-nosnippet>12</a>//! Consequently, we argue that the best hedge against this is to move as much of the documentation
|
||||
<a href=#13 id=13 data-nosnippet>13</a>//! near the source code as possible. This would further incentivize developers to keep the
|
||||
<a href=#14 id=14 data-nosnippet>14</a>//! documentation up-to-date, as the overhead is reduced by making sure everything is in one
|
||||
<a href=#15 id=15 data-nosnippet>15</a>//! repository, and everything being in `.rs` files.
|
||||
<a href=#16 id=16 data-nosnippet>16</a>//!
|
||||
<a href=#17 id=17 data-nosnippet>17</a>//! > This is not to say that a more visually appealing version of this crate (for example as an
|
||||
<a href=#18 id=18 data-nosnippet>18</a>//! > `md-book`) cannot exist, but it would be outside the scope of this crate.
|
||||
<a href=#19 id=19 data-nosnippet>19</a>//!
|
||||
<a href=#20 id=20 data-nosnippet>20</a>//! Moreover, we acknowledge that a major pain point has been not only outdated *concepts*, but also
|
||||
<a href=#21 id=21 data-nosnippet>21</a>//! *outdated code*. For this, we commit to making sure no code-snippet in this crate is left as
|
||||
<a href=#22 id=22 data-nosnippet>22</a>//! `///ignore` or `///no_compile`, making sure all code snippets are self-contained, compile-able,
|
||||
<a href=#23 id=23 data-nosnippet>23</a>//! and correct at every single revision of the entire repository.
|
||||
<a href=#24 id=24 data-nosnippet>24</a>//!
|
||||
<a href=#25 id=25 data-nosnippet>25</a>//! > This also allows us to have a clear versioning on the entire content of this crate. For every
|
||||
<a href=#26 id=26 data-nosnippet>26</a>//! commit of the Pezkuwi SDK, there would be one version of this crate that is guaranteed to be
|
||||
<a href=#27 id=27 data-nosnippet>27</a>//! correct.
|
||||
<a href=#28 id=28 data-nosnippet>28</a>//!
|
||||
<a href=#29 id=29 data-nosnippet>29</a>//! > To achieve this, we often use [`docify`](https://github.com/sam0x17/docify), a nifty invention
|
||||
<a href=#30 id=30 data-nosnippet>30</a>//! > of `@sam0x17`.
|
||||
<a href=#31 id=31 data-nosnippet>31</a>//!
|
||||
<a href=#32 id=32 data-nosnippet>32</a>//! Also see: <https://github.com/pezkuwichain/pezkuwi-sdk/issues/109>.
|
||||
<a href=#33 id=33 data-nosnippet>33</a>//!
|
||||
<a href=#34 id=34 data-nosnippet>34</a>//! ## Scope
|
||||
<a href=#35 id=35 data-nosnippet>35</a>//!
|
||||
<a href=#36 id=36 data-nosnippet>36</a>//! The above would NOT be attainable if we don't acknowledge that the scope of this crate MUST be
|
||||
<a href=#37 id=37 data-nosnippet>37</a>//! limited, or else its maintenance burden would be infeasible or not worthwhile. In short, future
|
||||
<a href=#38 id=38 data-nosnippet>38</a>//! maintainers should always strive to keep the content of this repository as minimal as possible.
|
||||
<a href=#39 id=39 data-nosnippet>39</a>//! Some of the following principles are specifically there to be the guidance for this.
|
||||
<a href=#40 id=40 data-nosnippet>40</a>//!
|
||||
<a href=#41 id=41 data-nosnippet>41</a>//! ## Principles
|
||||
<a href=#42 id=42 data-nosnippet>42</a>//!
|
||||
<a href=#43 id=43 data-nosnippet>43</a>//! The following guidelines are meant to be the guiding torch of those who contribute to this
|
||||
<a href=#44 id=44 data-nosnippet>44</a>//! crate.
|
||||
<a href=#45 id=45 data-nosnippet>45</a>//!
|
||||
<a href=#46 id=46 data-nosnippet>46</a>//! 1. 🔺 Ground Up: Information should be laid out in the most ground-up fashion. The lowest level
|
||||
<a href=#47 id=47 data-nosnippet>47</a>//! (i.e. "ground") is Rust-docs. The highest level (i.e. "up") is "outside of this crate". In
|
||||
<a href=#48 id=48 data-nosnippet>48</a>//! between lies [`reference_docs`] and [`guides`], from low to high. The point of this principle
|
||||
<a href=#49 id=49 data-nosnippet>49</a>//! is to document as much of the information as possible in the lower level media, as it is
|
||||
<a href=#50 id=50 data-nosnippet>50</a>//! easier to maintain and more reachable. Then, use excessive linking to back-link when writing
|
||||
<a href=#51 id=51 data-nosnippet>51</a>//! in a more high level.
|
||||
<a href=#52 id=52 data-nosnippet>52</a>//!
|
||||
<a href=#53 id=53 data-nosnippet>53</a>//! > A prime example of this, the details of the FRAME storage APIs should NOT be explained in a
|
||||
<a href=#54 id=54 data-nosnippet>54</a>//! > high level tutorial. They should be explained in the rust-doc of the corresponding type or
|
||||
<a href=#55 id=55 data-nosnippet>55</a>//! > macro.
|
||||
<a href=#56 id=56 data-nosnippet>56</a>//!
|
||||
<a href=#57 id=57 data-nosnippet>57</a>//! 2. 🧘 Less is More: For reasons mentioned [above](#why-rust-docs), the more concise this crate
|
||||
<a href=#58 id=58 data-nosnippet>58</a>//! is, the better.
|
||||
<a href=#59 id=59 data-nosnippet>59</a>//! 3. √ Don’t Repeat Yourself – DRY: A summary of the above two points. Authors should always
|
||||
<a href=#60 id=60 data-nosnippet>60</a>//! strive to avoid any duplicate information. Every concept should ideally be documented in
|
||||
<a href=#61 id=61 data-nosnippet>61</a>//! *ONE* place and one place only. This makes the task of maintaining topics significantly
|
||||
<a href=#62 id=62 data-nosnippet>62</a>//! easier.
|
||||
<a href=#63 id=63 data-nosnippet>63</a>//!
|
||||
<a href=#64 id=64 data-nosnippet>64</a>//! > A prime example of this, the list of CLI arguments of a particular binary should not be
|
||||
<a href=#65 id=65 data-nosnippet>65</a>//! > documented in multiple places across this crate. It should be only be documented in the
|
||||
<a href=#66 id=66 data-nosnippet>66</a>//! > corresponding crate (e.g. `sc_cli`).
|
||||
<a href=#67 id=67 data-nosnippet>67</a>//!
|
||||
<a href=#68 id=68 data-nosnippet>68</a>//! > Moreover, this means that as a contributor, **it is your responsibility to have a grasp over
|
||||
<a href=#69 id=69 data-nosnippet>69</a>//! > what topics are already covered in this crate, and how you can build on top of the information
|
||||
<a href=#70 id=70 data-nosnippet>70</a>//! > that they already pose, rather than repeating yourself**.
|
||||
<a href=#71 id=71 data-nosnippet>71</a>//!
|
||||
<a href=#72 id=72 data-nosnippet>72</a>//! For more details see the [latest documenting
|
||||
<a href=#73 id=73 data-nosnippet>73</a>//! guidelines](https://github.com/pezkuwichain/pezkuwi-sdk/blob/master/docs/contributor/DOCUMENTATION_GUIDELINES.md).
|
||||
<a href=#74 id=74 data-nosnippet>74</a>//!
|
||||
<a href=#75 id=75 data-nosnippet>75</a>//! #### Example: Explaining `#[pallet::call]`
|
||||
<a href=#76 id=76 data-nosnippet>76</a>//!
|
||||
<a href=#77 id=77 data-nosnippet>77</a>//! <details>
|
||||
<a href=#78 id=78 data-nosnippet>78</a>//! <summary>
|
||||
<a href=#79 id=79 data-nosnippet>79</a>//! Let's consider the seemingly simple example of explaining to someone dead-simple code of a FRAME
|
||||
<a href=#80 id=80 data-nosnippet>80</a>//! call and see how we can use the above principles.
|
||||
<a href=#81 id=81 data-nosnippet>81</a>//! </summary>
|
||||
<a href=#82 id=82 data-nosnippet>82</a>//!
|
||||
<a href=#83 id=83 data-nosnippet>83</a>//!
|
||||
<a href=#84 id=84 data-nosnippet>84</a>//! ```
|
||||
<a href=#85 id=85 data-nosnippet>85</a>//! #[frame::pallet(dev_mode)]
|
||||
<a href=#86 id=86 data-nosnippet>86</a>//! pub mod pallet {
|
||||
<a href=#87 id=87 data-nosnippet>87</a>//! # use frame::prelude::*;
|
||||
<a href=#88 id=88 data-nosnippet>88</a>//! # #[pallet::config]
|
||||
<a href=#89 id=89 data-nosnippet>89</a>//! # pub trait Config: frame_system::Config {}
|
||||
<a href=#90 id=90 data-nosnippet>90</a>//! # #[pallet::pallet]
|
||||
<a href=#91 id=91 data-nosnippet>91</a>//! # pub struct Pallet<T>(_);
|
||||
<a href=#92 id=92 data-nosnippet>92</a>//! #[pallet::call]
|
||||
<a href=#93 id=93 data-nosnippet>93</a>//! impl<T: Config> Pallet<T> {
|
||||
<a href=#94 id=94 data-nosnippet>94</a>//! pub fn a_simple_call(origin: OriginFor<T>, data: u32) -> DispatchResult {
|
||||
<a href=#95 id=95 data-nosnippet>95</a>//! ensure!(data > 10, "SomeStaticString");
|
||||
<a href=#96 id=96 data-nosnippet>96</a>//! todo!();
|
||||
<a href=#97 id=97 data-nosnippet>97</a>//! }
|
||||
<a href=#98 id=98 data-nosnippet>98</a>//! }
|
||||
<a href=#99 id=99 data-nosnippet>99</a>//! }
|
||||
<a href=#100 id=100 data-nosnippet>100</a>//! ```
|
||||
<a href=#101 id=101 data-nosnippet>101</a>//!
|
||||
<a href=#102 id=102 data-nosnippet>102</a>//! * Before even getting started, what is with all of this `<T: Config>`? We link to
|
||||
<a href=#103 id=103 data-nosnippet>103</a>//! [`crate::reference_docs::trait_based_programming`].
|
||||
<a href=#104 id=104 data-nosnippet>104</a>//! * First, the name. Why is this called `pallet::call`? This goes back to `enum Call`, which is
|
||||
<a href=#105 id=105 data-nosnippet>105</a>//! explained in [`crate::reference_docs::frame_runtime_types`]. Build on top of this!
|
||||
<a href=#106 id=106 data-nosnippet>106</a>//! * Then, what is `origin`? Just an account id? [`crate::reference_docs::frame_origin`].
|
||||
<a href=#107 id=107 data-nosnippet>107</a>//! * Then, what is `DispatchResult`? Why is this called *dispatch*? Probably something that can be
|
||||
<a href=#108 id=108 data-nosnippet>108</a>//! explained in the documentation of [`frame::prelude::DispatchResult`].
|
||||
<a href=#109 id=109 data-nosnippet>109</a>//! * Why is `"SomeStaticString"` a valid error? Because there is implementation for it that you can
|
||||
<a href=#110 id=110 data-nosnippet>110</a>//! see [here](frame::prelude::DispatchError#impl-From<%26'static+str>-for-DispatchError).
|
||||
<a href=#111 id=111 data-nosnippet>111</a>//!
|
||||
<a href=#112 id=112 data-nosnippet>112</a>//!
|
||||
<a href=#113 id=113 data-nosnippet>113</a>//! All of these are examples of underlying information that a contributor should:
|
||||
<a href=#114 id=114 data-nosnippet>114</a>//!
|
||||
<a href=#115 id=115 data-nosnippet>115</a>//! 1. Try and create and they are going along.
|
||||
<a href=#116 id=116 data-nosnippet>116</a>//! 2. Back-link to if they already exist.
|
||||
<a href=#117 id=117 data-nosnippet>117</a>//!
|
||||
<a href=#118 id=118 data-nosnippet>118</a>//! Of course, all of this is not set in stone as a either/or rule. Sometimes, it is necessary to
|
||||
<a href=#119 id=119 data-nosnippet>119</a>//! rephrase a concept in a new context.
|
||||
<a href=#120 id=120 data-nosnippet>120</a>//!
|
||||
<a href=#121 id=121 data-nosnippet>121</a>//! </details>
|
||||
<a href=#122 id=122 data-nosnippet>122</a>//!
|
||||
<a href=#123 id=123 data-nosnippet>123</a>//! ## `crates.io` and Publishing
|
||||
<a href=#124 id=124 data-nosnippet>124</a>//!
|
||||
<a href=#125 id=125 data-nosnippet>125</a>//! As it stands now, this crate cannot be published to crates.io because of its use of
|
||||
<a href=#126 id=126 data-nosnippet>126</a>//! [workspace-level `docify`](https://github.com/sam0x17/docify/issues/22). For now, we accept this
|
||||
<a href=#127 id=127 data-nosnippet>127</a>//! compromise, but in the long term, we should work towards finding a way to maintain different
|
||||
<a href=#128 id=128 data-nosnippet>128</a>//! revisions of this crate.
|
||||
<a href=#129 id=129 data-nosnippet>129</a>//!
|
||||
<a href=#130 id=130 data-nosnippet>130</a>//! ## Versioning
|
||||
<a href=#131 id=131 data-nosnippet>131</a>//!
|
||||
<a href=#132 id=132 data-nosnippet>132</a>//! So long as not deployed in `crates.io`, please notice that all of the information in this crate,
|
||||
<a href=#133 id=133 data-nosnippet>133</a>//! namely in [`crate::guides`] and such are compatible with the master branch of `pezkuwi-sdk`. A
|
||||
<a href=#134 id=134 data-nosnippet>134</a>//! few solutions have been proposed to improve this, please see
|
||||
<a href=#135 id=135 data-nosnippet>135</a>//! [here](https://github.com/pezkuwichain/pezkuwi-sdk/issues/146).
|
||||
<a href=#136 id=136 data-nosnippet>136</a>//!
|
||||
<a href=#137 id=137 data-nosnippet>137</a>//! ## How to Develop Locally
|
||||
<a href=#138 id=138 data-nosnippet>138</a>//!
|
||||
<a href=#139 id=139 data-nosnippet>139</a>//! To view the docs specific [`crate`] locally for development, including the correct HTML headers
|
||||
<a href=#140 id=140 data-nosnippet>140</a>//! injected, run:
|
||||
<a href=#141 id=141 data-nosnippet>141</a>//!
|
||||
<a href=#142 id=142 data-nosnippet>142</a>//! ```sh
|
||||
<a href=#143 id=143 data-nosnippet>143</a>//! SKIP_WASM_BUILD=1 \
|
||||
<a href=#144 id=144 data-nosnippet>144</a>//! RUSTDOCFLAGS="--html-in-header $(pwd)/docs/sdk/assets/header.html --extend-css $(pwd)/docs/sdk/assets/theme.css --default-theme=ayu" \
|
||||
<a href=#145 id=145 data-nosnippet>145</a>//! cargo doc -p pezkuwi-sdk-docs --no-deps --open
|
||||
<a href=#146 id=146 data-nosnippet>146</a>//! ```
|
||||
<a href=#147 id=147 data-nosnippet>147</a>//!
|
||||
<a href=#148 id=148 data-nosnippet>148</a>//! If even faster build time for docs is needed, you can temporarily remove most of the
|
||||
<a href=#149 id=149 data-nosnippet>149</a>//! substrate/cumulus dependencies that are only used for linking purposes.
|
||||
<a href=#150 id=150 data-nosnippet>150</a>//!
|
||||
<a href=#151 id=151 data-nosnippet>151</a>//! For more on local development, see [`crate::reference_docs::development_environment_advice`].</span></code></pre></div></section></main></body></html>
|
||||
@@ -0,0 +1,130 @@
|
||||
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `docs/sdk/src/pezkuwi_sdk/cumulus.rs`."><title>cumulus.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2"href="../../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../../../static.files/rustdoc-e56847b5.css"><meta name="rustdoc-vars" data-root-path="../../../" data-static-root-path="../../../static.files/" data-current-crate="pezkuwi_sdk_docs" data-themes="" data-resource-suffix="" data-rustdoc-version="1.91.1 (ed61e7d7e 2025-11-07)" data-channel="1.91.1" data-search-js="search-e256b49e.js" data-stringdex-js="stringdex-c3e638e9.js" data-settings-js="settings-c38705f0.js" ><script src="../../../static.files/storage-e2aeef58.js"></script><script defer src="../../../static.files/src-script-813739b1.js"></script><script defer src="../../../src-files.js"></script><script defer src="../../../static.files/main-6dc2a7f3.js"></script><noscript><link rel="stylesheet" href="../../../static.files/noscript-263c88ec.css"></noscript><link rel="icon" href="https://pezkuwichain.io/favicon.ico"></head><body class="rustdoc src"><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer" title="Drag to resize sidebar"></div><main><section id="main-content" class="content"><div class="main-heading"><h1><div class="sub-heading">pezkuwi_sdk_docs/pezkuwi_sdk/</div>cumulus.rs</h1><rustdoc-toolbar></rustdoc-toolbar></div><div class="example-wrap digits-3"><pre class="rust"><code><a href=#1 id=1 data-nosnippet>1</a><span class="doccomment">//! # Cumulus
|
||||
<a href=#2 id=2 data-nosnippet>2</a>//!
|
||||
<a href=#3 id=3 data-nosnippet>3</a>//! Substrate provides a framework ([FRAME]) through which a blockchain node and runtime can easily
|
||||
<a href=#4 id=4 data-nosnippet>4</a>//! be created. Cumulus aims to extend the same approach to creation of Pezkuwi teyrchains.
|
||||
<a href=#5 id=5 data-nosnippet>5</a>//!
|
||||
<a href=#6 id=6 data-nosnippet>6</a>//! > Cumulus clouds are shaped sort of like dots; together they form a system that is intricate,
|
||||
<a href=#7 id=7 data-nosnippet>7</a>//! > beautiful and functional.
|
||||
<a href=#8 id=8 data-nosnippet>8</a>//!
|
||||
<a href=#9 id=9 data-nosnippet>9</a>//! ## Example: Runtime
|
||||
<a href=#10 id=10 data-nosnippet>10</a>//!
|
||||
<a href=#11 id=11 data-nosnippet>11</a>//! A Cumulus-based runtime is fairly similar to other [FRAME]-based runtimes. Most notably, the
|
||||
<a href=#12 id=12 data-nosnippet>12</a>//! following changes are applied to a normal FRAME-based runtime to make it a Cumulus-based
|
||||
<a href=#13 id=13 data-nosnippet>13</a>//! runtime:
|
||||
<a href=#14 id=14 data-nosnippet>14</a>//!
|
||||
<a href=#15 id=15 data-nosnippet>15</a>//! #### Cumulus Pallets
|
||||
<a href=#16 id=16 data-nosnippet>16</a>//!
|
||||
<a href=#17 id=17 data-nosnippet>17</a>//! A teyrchain runtime should use a number of pallets that are provided by Cumulus and Substrate.
|
||||
<a href=#18 id=18 data-nosnippet>18</a>//! Notably:
|
||||
<a href=#19 id=19 data-nosnippet>19</a>//!
|
||||
<a href=#20 id=20 data-nosnippet>20</a>//! - [`frame-system`](frame::prelude::frame_system), like all FRAME-based runtimes.
|
||||
<a href=#21 id=21 data-nosnippet>21</a>//! - [`cumulus_pallet_teyrchain_system`]
|
||||
<a href=#22 id=22 data-nosnippet>22</a>//! - [`teyrchain_info`]
|
||||
<a href=#23 id=23 data-nosnippet>23</a></span><span class="attr">#![doc = <span class="macro">docify::embed!</span>(<span class="string">"./src/pezkuwi_sdk/cumulus.rs"</span>, system_pallets)]
|
||||
<a href=#24 id=24 data-nosnippet>24</a></span><span class="doccomment">//!
|
||||
<a href=#25 id=25 data-nosnippet>25</a>//! Given that all Cumulus-based runtimes use a simple Aura-based consensus mechanism, the following
|
||||
<a href=#26 id=26 data-nosnippet>26</a>//! pallets also need to be added:
|
||||
<a href=#27 id=27 data-nosnippet>27</a>//!
|
||||
<a href=#28 id=28 data-nosnippet>28</a>//! - [`pallet_timestamp`]
|
||||
<a href=#29 id=29 data-nosnippet>29</a>//! - [`pallet_aura`]
|
||||
<a href=#30 id=30 data-nosnippet>30</a>//! - [`cumulus_pallet_aura_ext`]
|
||||
<a href=#31 id=31 data-nosnippet>31</a></span><span class="attr">#![doc = <span class="macro">docify::embed!</span>(<span class="string">"./src/pezkuwi_sdk/cumulus.rs"</span>, consensus_pallets)]
|
||||
<a href=#32 id=32 data-nosnippet>32</a></span><span class="doccomment">//!
|
||||
<a href=#33 id=33 data-nosnippet>33</a>//!
|
||||
<a href=#34 id=34 data-nosnippet>34</a>//! Finally, a separate macro, similar to
|
||||
<a href=#35 id=35 data-nosnippet>35</a>//! [`impl_runtime_api`](frame::runtime::prelude::impl_runtime_apis), which creates the default set
|
||||
<a href=#36 id=36 data-nosnippet>36</a>//! of runtime APIs, will generate the teyrchain runtime's validation runtime API, also known as
|
||||
<a href=#37 id=37 data-nosnippet>37</a>//! teyrchain validation function (PVF). Without this API, the relay chain is unable to validate
|
||||
<a href=#38 id=38 data-nosnippet>38</a>//! blocks produced by our teyrchain.
|
||||
<a href=#39 id=39 data-nosnippet>39</a></span><span class="attr">#![doc = <span class="macro">docify::embed!</span>(<span class="string">"./src/pezkuwi_sdk/cumulus.rs"</span>, validate_block)]
|
||||
<a href=#40 id=40 data-nosnippet>40</a></span><span class="doccomment">//!
|
||||
<a href=#41 id=41 data-nosnippet>41</a>//! ---
|
||||
<a href=#42 id=42 data-nosnippet>42</a>//!
|
||||
<a href=#43 id=43 data-nosnippet>43</a>//! [FRAME]: crate::pezkuwi_sdk::frame_runtime
|
||||
<a href=#44 id=44 data-nosnippet>44</a>
|
||||
<a href=#45 id=45 data-nosnippet>45</a></span><span class="attr">#![deny(rustdoc::broken_intra_doc_links)]
|
||||
<a href=#46 id=46 data-nosnippet>46</a>#![deny(rustdoc::private_intra_doc_links)]
|
||||
<a href=#47 id=47 data-nosnippet>47</a>
|
||||
<a href=#48 id=48 data-nosnippet>48</a>#[cfg(test)]
|
||||
<a href=#49 id=49 data-nosnippet>49</a></span><span class="kw">mod </span>tests {
|
||||
<a href=#50 id=50 data-nosnippet>50</a> <span class="kw">mod </span>runtime {
|
||||
<a href=#51 id=51 data-nosnippet>51</a> <span class="kw">pub use </span>frame::{
|
||||
<a href=#52 id=52 data-nosnippet>52</a> deps::sp_consensus_aura::sr25519::AuthorityId <span class="kw">as </span>AuraId, prelude::<span class="kw-2">*</span>,
|
||||
<a href=#53 id=53 data-nosnippet>53</a> runtime::prelude::<span class="kw-2">*</span>, testing_prelude::<span class="kw-2">*</span>,
|
||||
<a href=#54 id=54 data-nosnippet>54</a> };
|
||||
<a href=#55 id=55 data-nosnippet>55</a>
|
||||
<a href=#56 id=56 data-nosnippet>56</a> <span class="attr">#[docify::export(CR)]
|
||||
<a href=#57 id=57 data-nosnippet>57</a> </span><span class="macro">construct_runtime!</span>(
|
||||
<a href=#58 id=58 data-nosnippet>58</a> <span class="kw">pub enum </span>Runtime {
|
||||
<a href=#59 id=59 data-nosnippet>59</a> <span class="comment">// system-level pallets.
|
||||
<a href=#60 id=60 data-nosnippet>60</a> </span>System: frame_system,
|
||||
<a href=#61 id=61 data-nosnippet>61</a> Timestamp: pallet_timestamp,
|
||||
<a href=#62 id=62 data-nosnippet>62</a> TeyrchainSystem: cumulus_pallet_teyrchain_system,
|
||||
<a href=#63 id=63 data-nosnippet>63</a> TeyrchainInfo: teyrchain_info,
|
||||
<a href=#64 id=64 data-nosnippet>64</a>
|
||||
<a href=#65 id=65 data-nosnippet>65</a> <span class="comment">// teyrchain consensus support -- mandatory.
|
||||
<a href=#66 id=66 data-nosnippet>66</a> </span>Aura: pallet_aura,
|
||||
<a href=#67 id=67 data-nosnippet>67</a> AuraExt: cumulus_pallet_aura_ext,
|
||||
<a href=#68 id=68 data-nosnippet>68</a> }
|
||||
<a href=#69 id=69 data-nosnippet>69</a> );
|
||||
<a href=#70 id=70 data-nosnippet>70</a>
|
||||
<a href=#71 id=71 data-nosnippet>71</a> <span class="attr">#[docify::export]
|
||||
<a href=#72 id=72 data-nosnippet>72</a> </span><span class="kw">mod </span>system_pallets {
|
||||
<a href=#73 id=73 data-nosnippet>73</a> <span class="kw">use super</span>::<span class="kw-2">*</span>;
|
||||
<a href=#74 id=74 data-nosnippet>74</a>
|
||||
<a href=#75 id=75 data-nosnippet>75</a> <span class="attr">#[derive_impl(frame_system::config_preludes::TestDefaultConfig)]
|
||||
<a href=#76 id=76 data-nosnippet>76</a> </span><span class="kw">impl </span>frame_system::Config <span class="kw">for </span>Runtime {
|
||||
<a href=#77 id=77 data-nosnippet>77</a> <span class="kw">type </span>Block = MockBlock<<span class="self">Self</span>>;
|
||||
<a href=#78 id=78 data-nosnippet>78</a> <span class="kw">type </span>OnSetCode = cumulus_pallet_teyrchain_system::TeyrchainSetCode<<span class="self">Self</span>>;
|
||||
<a href=#79 id=79 data-nosnippet>79</a> }
|
||||
<a href=#80 id=80 data-nosnippet>80</a>
|
||||
<a href=#81 id=81 data-nosnippet>81</a> <span class="kw">impl </span>cumulus_pallet_teyrchain_system::Config <span class="kw">for </span>Runtime {
|
||||
<a href=#82 id=82 data-nosnippet>82</a> <span class="kw">type </span>RuntimeEvent = RuntimeEvent;
|
||||
<a href=#83 id=83 data-nosnippet>83</a> <span class="kw">type </span>OnSystemEvent = ();
|
||||
<a href=#84 id=84 data-nosnippet>84</a> <span class="kw">type </span>SelfParaId = teyrchain_info::Pallet<Runtime>;
|
||||
<a href=#85 id=85 data-nosnippet>85</a> <span class="kw">type </span>OutboundXcmpMessageSource = ();
|
||||
<a href=#86 id=86 data-nosnippet>86</a> <span class="kw">type </span>XcmpMessageHandler = ();
|
||||
<a href=#87 id=87 data-nosnippet>87</a> <span class="kw">type </span>ReservedDmpWeight = ();
|
||||
<a href=#88 id=88 data-nosnippet>88</a> <span class="kw">type </span>ReservedXcmpWeight = ();
|
||||
<a href=#89 id=89 data-nosnippet>89</a> <span class="kw">type </span>CheckAssociatedRelayNumber =
|
||||
<a href=#90 id=90 data-nosnippet>90</a> cumulus_pallet_teyrchain_system::RelayNumberMonotonicallyIncreases;
|
||||
<a href=#91 id=91 data-nosnippet>91</a> <span class="kw">type </span>ConsensusHook = cumulus_pallet_aura_ext::FixedVelocityConsensusHook<
|
||||
<a href=#92 id=92 data-nosnippet>92</a> Runtime,
|
||||
<a href=#93 id=93 data-nosnippet>93</a> <span class="number">6000</span>, <span class="comment">// relay chain block time
|
||||
<a href=#94 id=94 data-nosnippet>94</a> </span><span class="number">1</span>,
|
||||
<a href=#95 id=95 data-nosnippet>95</a> <span class="number">1</span>,
|
||||
<a href=#96 id=96 data-nosnippet>96</a> >;
|
||||
<a href=#97 id=97 data-nosnippet>97</a> <span class="kw">type </span>WeightInfo = ();
|
||||
<a href=#98 id=98 data-nosnippet>98</a> <span class="kw">type </span>DmpQueue = frame::traits::EnqueueWithOrigin<(), sp_core::ConstU8<<span class="number">0</span>>>;
|
||||
<a href=#99 id=99 data-nosnippet>99</a> <span class="kw">type </span>RelayParentOffset = ConstU32<<span class="number">0</span>>;
|
||||
<a href=#100 id=100 data-nosnippet>100</a> }
|
||||
<a href=#101 id=101 data-nosnippet>101</a>
|
||||
<a href=#102 id=102 data-nosnippet>102</a> <span class="kw">impl </span>teyrchain_info::Config <span class="kw">for </span>Runtime {}
|
||||
<a href=#103 id=103 data-nosnippet>103</a> }
|
||||
<a href=#104 id=104 data-nosnippet>104</a>
|
||||
<a href=#105 id=105 data-nosnippet>105</a> <span class="attr">#[docify::export]
|
||||
<a href=#106 id=106 data-nosnippet>106</a> </span><span class="kw">mod </span>consensus_pallets {
|
||||
<a href=#107 id=107 data-nosnippet>107</a> <span class="kw">use super</span>::<span class="kw-2">*</span>;
|
||||
<a href=#108 id=108 data-nosnippet>108</a>
|
||||
<a href=#109 id=109 data-nosnippet>109</a> <span class="kw">impl </span>pallet_aura::Config <span class="kw">for </span>Runtime {
|
||||
<a href=#110 id=110 data-nosnippet>110</a> <span class="kw">type </span>AuthorityId = AuraId;
|
||||
<a href=#111 id=111 data-nosnippet>111</a> <span class="kw">type </span>DisabledValidators = ();
|
||||
<a href=#112 id=112 data-nosnippet>112</a> <span class="kw">type </span>MaxAuthorities = ConstU32<<span class="number">100_000</span>>;
|
||||
<a href=#113 id=113 data-nosnippet>113</a> <span class="kw">type </span>AllowMultipleBlocksPerSlot = ConstBool<<span class="bool-val">false</span>>;
|
||||
<a href=#114 id=114 data-nosnippet>114</a> <span class="kw">type </span>SlotDuration = pallet_aura::MinimumPeriodTimesTwo<<span class="self">Self</span>>;
|
||||
<a href=#115 id=115 data-nosnippet>115</a> }
|
||||
<a href=#116 id=116 data-nosnippet>116</a>
|
||||
<a href=#117 id=117 data-nosnippet>117</a> <span class="attr">#[docify::export(timestamp)]
|
||||
<a href=#118 id=118 data-nosnippet>118</a> #[derive_impl(pallet_timestamp::config_preludes::TestDefaultConfig)]
|
||||
<a href=#119 id=119 data-nosnippet>119</a> </span><span class="kw">impl </span>pallet_timestamp::Config <span class="kw">for </span>Runtime {}
|
||||
<a href=#120 id=120 data-nosnippet>120</a>
|
||||
<a href=#121 id=121 data-nosnippet>121</a> <span class="kw">impl </span>cumulus_pallet_aura_ext::Config <span class="kw">for </span>Runtime {}
|
||||
<a href=#122 id=122 data-nosnippet>122</a> }
|
||||
<a href=#123 id=123 data-nosnippet>123</a>
|
||||
<a href=#124 id=124 data-nosnippet>124</a> <span class="attr">#[docify::export(validate_block)]
|
||||
<a href=#125 id=125 data-nosnippet>125</a> </span><span class="macro">cumulus_pallet_teyrchain_system::register_validate_block!</span> {
|
||||
<a href=#126 id=126 data-nosnippet>126</a> Runtime = Runtime,
|
||||
<a href=#127 id=127 data-nosnippet>127</a> BlockExecutor = cumulus_pallet_aura_ext::BlockExecutor::<Runtime, Executive>,
|
||||
<a href=#128 id=128 data-nosnippet>128</a> }
|
||||
<a href=#129 id=129 data-nosnippet>129</a> }
|
||||
<a href=#130 id=130 data-nosnippet>130</a>}</code></pre></div></section></main></body></html>
|
||||
@@ -0,0 +1,175 @@
|
||||
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `docs/sdk/src/pezkuwi_sdk/frame_runtime.rs`."><title>frame_runtime.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2"href="../../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../../../static.files/rustdoc-e56847b5.css"><meta name="rustdoc-vars" data-root-path="../../../" data-static-root-path="../../../static.files/" data-current-crate="pezkuwi_sdk_docs" data-themes="" data-resource-suffix="" data-rustdoc-version="1.91.1 (ed61e7d7e 2025-11-07)" data-channel="1.91.1" data-search-js="search-e256b49e.js" data-stringdex-js="stringdex-c3e638e9.js" data-settings-js="settings-c38705f0.js" ><script src="../../../static.files/storage-e2aeef58.js"></script><script defer src="../../../static.files/src-script-813739b1.js"></script><script defer src="../../../src-files.js"></script><script defer src="../../../static.files/main-6dc2a7f3.js"></script><noscript><link rel="stylesheet" href="../../../static.files/noscript-263c88ec.css"></noscript><link rel="icon" href="https://pezkuwichain.io/favicon.ico"></head><body class="rustdoc src"><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer" title="Drag to resize sidebar"></div><main><section id="main-content" class="content"><div class="main-heading"><h1><div class="sub-heading">pezkuwi_sdk_docs/pezkuwi_sdk/</div>frame_runtime.rs</h1><rustdoc-toolbar></rustdoc-toolbar></div><div class="example-wrap digits-3"><pre class="rust"><code><a href=#1 id=1 data-nosnippet>1</a><span class="doccomment">//! # FRAME
|
||||
<a href=#2 id=2 data-nosnippet>2</a>//!
|
||||
<a href=#3 id=3 data-nosnippet>3</a>//! ```no_compile
|
||||
<a href=#4 id=4 data-nosnippet>4</a>//! ______ ______ ________ ___ __ __ ______
|
||||
<a href=#5 id=5 data-nosnippet>5</a>//! /_____/\ /_____/\ /_______/\ /__//_//_/\ /_____/\
|
||||
<a href=#6 id=6 data-nosnippet>6</a>//! \::::_\/_\:::_ \ \ \::: _ \ \\::\| \| \ \\::::_\/_
|
||||
<a href=#7 id=7 data-nosnippet>7</a>//! \:\/___/\\:(_) ) )_\::(_) \ \\:. \ \\:\/___/\
|
||||
<a href=#8 id=8 data-nosnippet>8</a>//! \:::._\/ \: __ `\ \\:: __ \ \\:.\-/\ \ \\::___\/_
|
||||
<a href=#9 id=9 data-nosnippet>9</a>//! \:\ \ \ \ `\ \ \\:.\ \ \ \\. \ \ \ \\:\____/\
|
||||
<a href=#10 id=10 data-nosnippet>10</a>//! \_\/ \_\/ \_\/ \__\/\__\/ \__\/ \__\/ \_____\/
|
||||
<a href=#11 id=11 data-nosnippet>11</a>//! ```
|
||||
<a href=#12 id=12 data-nosnippet>12</a>//!
|
||||
<a href=#13 id=13 data-nosnippet>13</a>//! > **F**ramework for **R**untime **A**ggregation of **M**odularized **E**ntities: Substrate's
|
||||
<a href=#14 id=14 data-nosnippet>14</a>//! > State Transition Function (Runtime) Framework.
|
||||
<a href=#15 id=15 data-nosnippet>15</a>//!
|
||||
<a href=#16 id=16 data-nosnippet>16</a>//! ## Introduction
|
||||
<a href=#17 id=17 data-nosnippet>17</a>//!
|
||||
<a href=#18 id=18 data-nosnippet>18</a>//! As described in [`crate::reference_docs::wasm_meta_protocol`], at a high-level Substrate-based
|
||||
<a href=#19 id=19 data-nosnippet>19</a>//! blockchains are composed of two parts:
|
||||
<a href=#20 id=20 data-nosnippet>20</a>//!
|
||||
<a href=#21 id=21 data-nosnippet>21</a>//! 1. A *runtime* which represents the state transition function (i.e. "Business Logic") of a
|
||||
<a href=#22 id=22 data-nosnippet>22</a>//! blockchain, and is encoded as a WASM blob.
|
||||
<a href=#23 id=23 data-nosnippet>23</a>//! 2. A node whose primary purpose is to execute the given runtime.
|
||||
<a href=#24 id=24 data-nosnippet>24</a></span><span class="attr">#![doc = <span class="macro">simple_mermaid::mermaid!</span>(<span class="string">"../../../mermaid/substrate_simple.mmd"</span>)]
|
||||
<a href=#25 id=25 data-nosnippet>25</a></span><span class="doccomment">//!
|
||||
<a href=#26 id=26 data-nosnippet>26</a>//! *FRAME is the Substrate's framework of choice to build a runtime.*
|
||||
<a href=#27 id=27 data-nosnippet>27</a>//!
|
||||
<a href=#28 id=28 data-nosnippet>28</a>//! FRAME is composed of two major components, **pallets** and a **runtime**.
|
||||
<a href=#29 id=29 data-nosnippet>29</a>//!
|
||||
<a href=#30 id=30 data-nosnippet>30</a>//! ## Pallets
|
||||
<a href=#31 id=31 data-nosnippet>31</a>//!
|
||||
<a href=#32 id=32 data-nosnippet>32</a>//! A pallet is a unit of encapsulated logic. It has a clearly defined responsibility and can be
|
||||
<a href=#33 id=33 data-nosnippet>33</a>//! linked to other pallets. In order to be reusable, pallets shipped with FRAME strive to only care
|
||||
<a href=#34 id=34 data-nosnippet>34</a>//! about its own responsibilities and make as few assumptions about the general runtime as
|
||||
<a href=#35 id=35 data-nosnippet>35</a>//! possible. A pallet is analogous to a _module_ in the runtime.
|
||||
<a href=#36 id=36 data-nosnippet>36</a>//!
|
||||
<a href=#37 id=37 data-nosnippet>37</a>//! A pallet is defined as a `mod pallet` wrapped by the [`frame::pallet`] macro. Within this macro,
|
||||
<a href=#38 id=38 data-nosnippet>38</a>//! pallet components/parts can be defined. Most notable of these parts are:
|
||||
<a href=#39 id=39 data-nosnippet>39</a>//!
|
||||
<a href=#40 id=40 data-nosnippet>40</a>//! - [Config](frame::pallet_macros::config), allowing a pallet to make itself configurable and
|
||||
<a href=#41 id=41 data-nosnippet>41</a>//! generic over types, values and such.
|
||||
<a href=#42 id=42 data-nosnippet>42</a>//! - [Storage](frame::pallet_macros::storage), allowing a pallet to define onchain storage.
|
||||
<a href=#43 id=43 data-nosnippet>43</a>//! - [Dispatchable function](frame::pallet_macros::call), allowing a pallet to define extrinsics
|
||||
<a href=#44 id=44 data-nosnippet>44</a>//! that are callable by end users, from the outer world.
|
||||
<a href=#45 id=45 data-nosnippet>45</a>//! - [Events](frame::pallet_macros::event), allowing a pallet to emit events.
|
||||
<a href=#46 id=46 data-nosnippet>46</a>//! - [Errors](frame::pallet_macros::error), allowing a pallet to emit well-formed errors.
|
||||
<a href=#47 id=47 data-nosnippet>47</a>//!
|
||||
<a href=#48 id=48 data-nosnippet>48</a>//! Some of these pallet components resemble the building blocks of a smart contract. While both
|
||||
<a href=#49 id=49 data-nosnippet>49</a>//! models are programming state transition functions of blockchains, there are crucial differences
|
||||
<a href=#50 id=50 data-nosnippet>50</a>//! between the two. See [`crate::reference_docs::runtime_vs_smart_contract`] for more.
|
||||
<a href=#51 id=51 data-nosnippet>51</a>//!
|
||||
<a href=#52 id=52 data-nosnippet>52</a>//! Most of these components are defined using macros, the full list of which can be found in
|
||||
<a href=#53 id=53 data-nosnippet>53</a>//! [`frame::pallet_macros`].
|
||||
<a href=#54 id=54 data-nosnippet>54</a>//!
|
||||
<a href=#55 id=55 data-nosnippet>55</a>//! ### Example
|
||||
<a href=#56 id=56 data-nosnippet>56</a>//!
|
||||
<a href=#57 id=57 data-nosnippet>57</a>//! The following example showcases a minimal pallet.
|
||||
<a href=#58 id=58 data-nosnippet>58</a></span><span class="attr">#![doc = <span class="macro">docify::embed!</span>(<span class="string">"src/pezkuwi_sdk/frame_runtime.rs"</span>, pallet)]
|
||||
<a href=#59 id=59 data-nosnippet>59</a></span><span class="doccomment">//!
|
||||
<a href=#60 id=60 data-nosnippet>60</a>//! ## Runtime
|
||||
<a href=#61 id=61 data-nosnippet>61</a>//!
|
||||
<a href=#62 id=62 data-nosnippet>62</a>//! A runtime is a collection of pallets that are amalgamated together. Each pallet typically has
|
||||
<a href=#63 id=63 data-nosnippet>63</a>//! some configurations (exposed as a `trait Config`) that needs to be *specified* in the runtime.
|
||||
<a href=#64 id=64 data-nosnippet>64</a>//! This is done with [`frame::runtime::prelude::construct_runtime`].
|
||||
<a href=#65 id=65 data-nosnippet>65</a>//!
|
||||
<a href=#66 id=66 data-nosnippet>66</a>//! A (real) runtime that actually wishes to compile to WASM needs to also implement a set of
|
||||
<a href=#67 id=67 data-nosnippet>67</a>//! runtime-apis. These implementation can be specified using the
|
||||
<a href=#68 id=68 data-nosnippet>68</a>//! [`frame::runtime::prelude::impl_runtime_apis`] macro.
|
||||
<a href=#69 id=69 data-nosnippet>69</a>//!
|
||||
<a href=#70 id=70 data-nosnippet>70</a>//! ### Example
|
||||
<a href=#71 id=71 data-nosnippet>71</a>//!
|
||||
<a href=#72 id=72 data-nosnippet>72</a>//! The following example shows a (test) runtime that is composing the pallet demonstrated above,
|
||||
<a href=#73 id=73 data-nosnippet>73</a>//! next to the [`frame::prelude::frame_system`] pallet, into a runtime.
|
||||
<a href=#74 id=74 data-nosnippet>74</a></span><span class="attr">#![doc = <span class="macro">docify::embed!</span>(<span class="string">"src/pezkuwi_sdk/frame_runtime.rs"</span>, runtime)]
|
||||
<a href=#75 id=75 data-nosnippet>75</a></span><span class="doccomment">//!
|
||||
<a href=#76 id=76 data-nosnippet>76</a>//! ## More Examples
|
||||
<a href=#77 id=77 data-nosnippet>77</a>//!
|
||||
<a href=#78 id=78 data-nosnippet>78</a>//! You can find more FRAME examples that revolve around specific features at [`pallet_examples`].
|
||||
<a href=#79 id=79 data-nosnippet>79</a>//!
|
||||
<a href=#80 id=80 data-nosnippet>80</a>//! ## Alternatives 🌈
|
||||
<a href=#81 id=81 data-nosnippet>81</a>//!
|
||||
<a href=#82 id=82 data-nosnippet>82</a>//! There is nothing in the Substrate's node side code-base that mandates the use of FRAME. While
|
||||
<a href=#83 id=83 data-nosnippet>83</a>//! FRAME makes it very simple to write Substrate-based runtimes, it is by no means intended to be
|
||||
<a href=#84 id=84 data-nosnippet>84</a>//! the only one. At the end of the day, any WASM blob that exposes the right set of runtime APIs is
|
||||
<a href=#85 id=85 data-nosnippet>85</a>//! a valid Runtime form the point of view of a Substrate client (see
|
||||
<a href=#86 id=86 data-nosnippet>86</a>//! [`crate::reference_docs::wasm_meta_protocol`]). Notable examples are:
|
||||
<a href=#87 id=87 data-nosnippet>87</a>//!
|
||||
<a href=#88 id=88 data-nosnippet>88</a>//! * writing a runtime in pure Rust, as done in [this template](https://github.com/JoshOrndorff/frameless-node-template).
|
||||
<a href=#89 id=89 data-nosnippet>89</a>//! * writing a runtime in AssemblyScript, as explored in [this project](https://github.com/LimeChain/subsembly).
|
||||
<a href=#90 id=90 data-nosnippet>90</a>
|
||||
<a href=#91 id=91 data-nosnippet>91</a>/// A FRAME based pallet. This `mod` is the entry point for everything else. All
|
||||
<a href=#92 id=92 data-nosnippet>92</a>/// `#[pallet::xxx]` macros must be defined in this `mod`. Although, frame also provides an
|
||||
<a href=#93 id=93 data-nosnippet>93</a>/// experimental feature to break these parts into different `mod`s. See [`pallet_examples`] for
|
||||
<a href=#94 id=94 data-nosnippet>94</a>/// more.
|
||||
<a href=#95 id=95 data-nosnippet>95</a></span><span class="attr">#[docify::export]
|
||||
<a href=#96 id=96 data-nosnippet>96</a>#[frame::pallet(dev_mode)]
|
||||
<a href=#97 id=97 data-nosnippet>97</a></span><span class="kw">pub mod </span>pallet {
|
||||
<a href=#98 id=98 data-nosnippet>98</a> <span class="kw">use </span>frame::prelude::<span class="kw-2">*</span>;
|
||||
<a href=#99 id=99 data-nosnippet>99</a>
|
||||
<a href=#100 id=100 data-nosnippet>100</a> <span class="doccomment">/// The configuration trait of a pallet. Mandatory. Allows a pallet to receive types at a
|
||||
<a href=#101 id=101 data-nosnippet>101</a> /// later point from the runtime that wishes to contain it. It allows the pallet to be
|
||||
<a href=#102 id=102 data-nosnippet>102</a> /// parameterized over both types and values.
|
||||
<a href=#103 id=103 data-nosnippet>103</a> </span><span class="attr">#[pallet::config]
|
||||
<a href=#104 id=104 data-nosnippet>104</a> </span><span class="kw">pub trait </span>Config: frame_system::Config {
|
||||
<a href=#105 id=105 data-nosnippet>105</a> <span class="doccomment">/// A type that is not known now, but the runtime that will contain this pallet will
|
||||
<a href=#106 id=106 data-nosnippet>106</a> /// know it later, therefore we define it here as an associated type.
|
||||
<a href=#107 id=107 data-nosnippet>107</a> </span><span class="attr">#[allow(deprecated)]
|
||||
<a href=#108 id=108 data-nosnippet>108</a> </span><span class="kw">type </span>RuntimeEvent: IsType<<<span class="self">Self </span><span class="kw">as </span>frame_system::Config>::RuntimeEvent> + From<Event<<span class="self">Self</span>>>;
|
||||
<a href=#109 id=109 data-nosnippet>109</a>
|
||||
<a href=#110 id=110 data-nosnippet>110</a> <span class="doccomment">/// A parameterize-able value that we receive later via the `Get<_>` trait.
|
||||
<a href=#111 id=111 data-nosnippet>111</a> </span><span class="kw">type </span>ValueParameter: Get<u32>;
|
||||
<a href=#112 id=112 data-nosnippet>112</a>
|
||||
<a href=#113 id=113 data-nosnippet>113</a> <span class="doccomment">/// Similar to [`Config::ValueParameter`], but using `const`. Both are functionally
|
||||
<a href=#114 id=114 data-nosnippet>114</a> /// equal, but offer different tradeoffs.
|
||||
<a href=#115 id=115 data-nosnippet>115</a> </span><span class="kw">const </span>ANOTHER_VALUE_PARAMETER: u32;
|
||||
<a href=#116 id=116 data-nosnippet>116</a> }
|
||||
<a href=#117 id=117 data-nosnippet>117</a>
|
||||
<a href=#118 id=118 data-nosnippet>118</a> <span class="doccomment">/// A mandatory struct in each pallet. All functions callable by external users (aka.
|
||||
<a href=#119 id=119 data-nosnippet>119</a> /// transactions) must be attached to this type (see [`frame::pallet_macros::call`]). For
|
||||
<a href=#120 id=120 data-nosnippet>120</a> /// convenience, internal (private) functions can also be attached to this type.
|
||||
<a href=#121 id=121 data-nosnippet>121</a> </span><span class="attr">#[pallet::pallet]
|
||||
<a href=#122 id=122 data-nosnippet>122</a> </span><span class="kw">pub struct </span>Pallet<T>(PhantomData<T>);
|
||||
<a href=#123 id=123 data-nosnippet>123</a>
|
||||
<a href=#124 id=124 data-nosnippet>124</a> <span class="doccomment">/// The events that this pallet can emit.
|
||||
<a href=#125 id=125 data-nosnippet>125</a> </span><span class="attr">#[pallet::event]
|
||||
<a href=#126 id=126 data-nosnippet>126</a> </span><span class="kw">pub enum </span>Event<T: Config> {}
|
||||
<a href=#127 id=127 data-nosnippet>127</a>
|
||||
<a href=#128 id=128 data-nosnippet>128</a> <span class="doccomment">/// A storage item that this pallet contains. This will be part of the state root trie
|
||||
<a href=#129 id=129 data-nosnippet>129</a> /// of the blockchain.
|
||||
<a href=#130 id=130 data-nosnippet>130</a> </span><span class="attr">#[pallet::storage]
|
||||
<a href=#131 id=131 data-nosnippet>131</a> </span><span class="kw">pub type </span>Value<T> = StorageValue<Value = u32>;
|
||||
<a href=#132 id=132 data-nosnippet>132</a>
|
||||
<a href=#133 id=133 data-nosnippet>133</a> <span class="doccomment">/// All *dispatchable* call functions (aka. transactions) are attached to `Pallet` in a
|
||||
<a href=#134 id=134 data-nosnippet>134</a> /// `impl` block.
|
||||
<a href=#135 id=135 data-nosnippet>135</a> </span><span class="attr">#[pallet::call]
|
||||
<a href=#136 id=136 data-nosnippet>136</a> </span><span class="kw">impl</span><T: Config> Pallet<T> {
|
||||
<a href=#137 id=137 data-nosnippet>137</a> <span class="doccomment">/// This will be callable by external users, and has two u32s as a parameter.
|
||||
<a href=#138 id=138 data-nosnippet>138</a> </span><span class="kw">pub fn </span>some_dispatchable(
|
||||
<a href=#139 id=139 data-nosnippet>139</a> _origin: OriginFor<T>,
|
||||
<a href=#140 id=140 data-nosnippet>140</a> _param: u32,
|
||||
<a href=#141 id=141 data-nosnippet>141</a> _other_para: u32,
|
||||
<a href=#142 id=142 data-nosnippet>142</a> ) -> DispatchResult {
|
||||
<a href=#143 id=143 data-nosnippet>143</a> <span class="prelude-val">Ok</span>(())
|
||||
<a href=#144 id=144 data-nosnippet>144</a> }
|
||||
<a href=#145 id=145 data-nosnippet>145</a> }
|
||||
<a href=#146 id=146 data-nosnippet>146</a>}
|
||||
<a href=#147 id=147 data-nosnippet>147</a>
|
||||
<a href=#148 id=148 data-nosnippet>148</a><span class="doccomment">/// A simple runtime that contains the above pallet and `frame_system`, the mandatory pallet of
|
||||
<a href=#149 id=149 data-nosnippet>149</a>/// all runtimes. This runtime is for testing, but it shares a lot of similarities with a *real*
|
||||
<a href=#150 id=150 data-nosnippet>150</a>/// runtime.
|
||||
<a href=#151 id=151 data-nosnippet>151</a></span><span class="attr">#[docify::export]
|
||||
<a href=#152 id=152 data-nosnippet>152</a></span><span class="kw">pub mod </span>runtime {
|
||||
<a href=#153 id=153 data-nosnippet>153</a> <span class="kw">use </span><span class="kw">super</span>::pallet <span class="kw">as </span>pallet_example;
|
||||
<a href=#154 id=154 data-nosnippet>154</a> <span class="kw">use </span>frame::{prelude::<span class="kw-2">*</span>, testing_prelude::<span class="kw-2">*</span>};
|
||||
<a href=#155 id=155 data-nosnippet>155</a>
|
||||
<a href=#156 id=156 data-nosnippet>156</a> <span class="comment">// The major macro that amalgamates pallets into `enum Runtime`
|
||||
<a href=#157 id=157 data-nosnippet>157</a> </span><span class="macro">construct_runtime!</span>(
|
||||
<a href=#158 id=158 data-nosnippet>158</a> <span class="kw">pub enum </span>Runtime {
|
||||
<a href=#159 id=159 data-nosnippet>159</a> System: frame_system,
|
||||
<a href=#160 id=160 data-nosnippet>160</a> Example: pallet_example,
|
||||
<a href=#161 id=161 data-nosnippet>161</a> }
|
||||
<a href=#162 id=162 data-nosnippet>162</a> );
|
||||
<a href=#163 id=163 data-nosnippet>163</a>
|
||||
<a href=#164 id=164 data-nosnippet>164</a> <span class="comment">// These `impl` blocks specify the parameters of each pallet's `trait Config`.
|
||||
<a href=#165 id=165 data-nosnippet>165</a> </span><span class="attr">#[derive_impl(frame_system::config_preludes::TestDefaultConfig)]
|
||||
<a href=#166 id=166 data-nosnippet>166</a> </span><span class="kw">impl </span>frame_system::Config <span class="kw">for </span>Runtime {
|
||||
<a href=#167 id=167 data-nosnippet>167</a> <span class="kw">type </span>Block = MockBlock<<span class="self">Self</span>>;
|
||||
<a href=#168 id=168 data-nosnippet>168</a> }
|
||||
<a href=#169 id=169 data-nosnippet>169</a>
|
||||
<a href=#170 id=170 data-nosnippet>170</a> <span class="kw">impl </span>pallet_example::Config <span class="kw">for </span>Runtime {
|
||||
<a href=#171 id=171 data-nosnippet>171</a> <span class="kw">type </span>RuntimeEvent = RuntimeEvent;
|
||||
<a href=#172 id=172 data-nosnippet>172</a> <span class="kw">type </span>ValueParameter = ConstU32<<span class="number">42</span>>;
|
||||
<a href=#173 id=173 data-nosnippet>173</a> <span class="kw">const </span>ANOTHER_VALUE_PARAMETER: u32 = <span class="number">42</span>;
|
||||
<a href=#174 id=174 data-nosnippet>174</a> }
|
||||
<a href=#175 id=175 data-nosnippet>175</a>}</code></pre></div></section></main></body></html>
|
||||
@@ -0,0 +1,158 @@
|
||||
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `docs/sdk/src/pezkuwi_sdk/mod.rs`."><title>mod.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2"href="../../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../../../static.files/rustdoc-e56847b5.css"><meta name="rustdoc-vars" data-root-path="../../../" data-static-root-path="../../../static.files/" data-current-crate="pezkuwi_sdk_docs" data-themes="" data-resource-suffix="" data-rustdoc-version="1.91.1 (ed61e7d7e 2025-11-07)" data-channel="1.91.1" data-search-js="search-e256b49e.js" data-stringdex-js="stringdex-c3e638e9.js" data-settings-js="settings-c38705f0.js" ><script src="../../../static.files/storage-e2aeef58.js"></script><script defer src="../../../static.files/src-script-813739b1.js"></script><script defer src="../../../src-files.js"></script><script defer src="../../../static.files/main-6dc2a7f3.js"></script><noscript><link rel="stylesheet" href="../../../static.files/noscript-263c88ec.css"></noscript><link rel="icon" href="https://pezkuwichain.io/favicon.ico"></head><body class="rustdoc src"><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer" title="Drag to resize sidebar"></div><main><section id="main-content" class="content"><div class="main-heading"><h1><div class="sub-heading">pezkuwi_sdk_docs/pezkuwi_sdk/</div>mod.rs</h1><rustdoc-toolbar></rustdoc-toolbar></div><div class="example-wrap digits-3"><pre class="rust"><code><a href=#1 id=1 data-nosnippet>1</a><span class="doccomment">//! # Pezkuwi SDK
|
||||
<a href=#2 id=2 data-nosnippet>2</a>//!
|
||||
<a href=#3 id=3 data-nosnippet>3</a>//! [Pezkuwi SDK](https://github.com/pezkuwichain/pezkuwi-sdk) provides the main resources needed to
|
||||
<a href=#4 id=4 data-nosnippet>4</a>//! start building on the [Pezkuwi network](https://pezkuwichain.io/), a scalable, multi-chain
|
||||
<a href=#5 id=5 data-nosnippet>5</a>//! blockchain platform that enables different blockchains to securely interoperate.
|
||||
<a href=#6 id=6 data-nosnippet>6</a>//!
|
||||
<a href=#7 id=7 data-nosnippet>7</a>//! [](https://exchange.pezkuwichain.app/)
|
||||
<a href=#8 id=8 data-nosnippet>8</a>//!
|
||||
<a href=#9 id=9 data-nosnippet>9</a>//! [](https://github.com/Awsmdot/awesome-dot)
|
||||
<a href=#10 id=10 data-nosnippet>10</a>//! [](https://wiki.network.pezkuwichain.io/)
|
||||
<a href=#11 id=11 data-nosnippet>11</a>//! [](https://forum.network.pezkuwichain.io/)
|
||||
<a href=#12 id=12 data-nosnippet>12</a>//!
|
||||
<a href=#13 id=13 data-nosnippet>13</a>//! [](https://github.com/pezkuwichain/pezkuwi-fellows/tree/main/rfcs)
|
||||
<a href=#14 id=14 data-nosnippet>14</a>//! [](https://github.com/pezkuwichain/pezkuwi-fellows/tree/main/runtimes)
|
||||
<a href=#15 id=15 data-nosnippet>15</a>//! [](https://github.com/pezkuwichain/pezkuwi-fellows/tree/main/manifesto/blob/main/manifesto.pdf)
|
||||
<a href=#16 id=16 data-nosnippet>16</a>//!
|
||||
<a href=#17 id=17 data-nosnippet>17</a>//! ## Getting Started
|
||||
<a href=#18 id=18 data-nosnippet>18</a>//!
|
||||
<a href=#19 id=19 data-nosnippet>19</a>//! The primary way to get started with the Pezkuwi SDK is to start writing a FRAME-based runtime.
|
||||
<a href=#20 id=20 data-nosnippet>20</a>//! See:
|
||||
<a href=#21 id=21 data-nosnippet>21</a>//!
|
||||
<a href=#22 id=22 data-nosnippet>22</a>//! * [`pezkuwi`], to understand what is Pezkuwi as a development platform.
|
||||
<a href=#23 id=23 data-nosnippet>23</a>//! * [`substrate`], for an overview of what Substrate as the main blockchain framework of Pezkuwi
|
||||
<a href=#24 id=24 data-nosnippet>24</a>//! SDK.
|
||||
<a href=#25 id=25 data-nosnippet>25</a>//! * [`frame`], to learn about how to write blockchain applications aka. "App Chains".
|
||||
<a href=#26 id=26 data-nosnippet>26</a>//! * Continue with the [`pezkuwi_sdk_docs`'s "getting started"](crate#getting-started).
|
||||
<a href=#27 id=27 data-nosnippet>27</a>//!
|
||||
<a href=#28 id=28 data-nosnippet>28</a>//! ## Components
|
||||
<a href=#29 id=29 data-nosnippet>29</a>//!
|
||||
<a href=#30 id=30 data-nosnippet>30</a>//! #### Substrate
|
||||
<a href=#31 id=31 data-nosnippet>31</a>//!
|
||||
<a href=#32 id=32 data-nosnippet>32</a>//! [](https://github.com/pezkuwichain/pezkuwi-sdk/blob/master/substrate/LICENSE-APACHE2)
|
||||
<a href=#33 id=33 data-nosnippet>33</a>//! [](https://github.com/pezkuwichain/pezkuwi-sdk/blob/master/substrate)
|
||||
<a href=#35 id=35 data-nosnippet>35</a>//!
|
||||
<a href=#36 id=36 data-nosnippet>36</a>//! [`substrate`] is the base blockchain framework used to power the Pezkuwi SDK. It is a full
|
||||
<a href=#37 id=37 data-nosnippet>37</a>//! toolkit to create sovereign blockchains, including but not limited to those which connect to
|
||||
<a href=#38 id=38 data-nosnippet>38</a>//! Pezkuwi as teyrchains.
|
||||
<a href=#39 id=39 data-nosnippet>39</a>//!
|
||||
<a href=#40 id=40 data-nosnippet>40</a>//! #### FRAME
|
||||
<a href=#41 id=41 data-nosnippet>41</a>//!
|
||||
<a href=#42 id=42 data-nosnippet>42</a>//! [](https://github.com/pezkuwichain/pezkuwi-sdk/blob/master/substrate/LICENSE-APACHE2)
|
||||
<a href=#43 id=43 data-nosnippet>43</a>//! [](https://github.com/pezkuwichain/pezkuwi-sdk/blob/master/substrate/frame)
|
||||
<a href=#45 id=45 data-nosnippet>45</a>//!
|
||||
<a href=#46 id=46 data-nosnippet>46</a>//! [`frame`] is the framework used to create Substrate-based application logic, aka. runtimes.
|
||||
<a href=#47 id=47 data-nosnippet>47</a>//! Learn more about the distinction of a runtime and node in
|
||||
<a href=#48 id=48 data-nosnippet>48</a>//! [`reference_docs::wasm_meta_protocol`].
|
||||
<a href=#49 id=49 data-nosnippet>49</a>//!
|
||||
<a href=#50 id=50 data-nosnippet>50</a>//! #### Cumulus
|
||||
<a href=#51 id=51 data-nosnippet>51</a>//!
|
||||
<a href=#52 id=52 data-nosnippet>52</a>//! [](https://github.com/pezkuwichain/pezkuwi-sdk/blob/master/cumulus/LICENSE)
|
||||
<a href=#53 id=53 data-nosnippet>53</a>//! [](https://github.com/pezkuwichain/pezkuwi-sdk/blob/master/cumulus)
|
||||
<a href=#55 id=55 data-nosnippet>55</a>//!
|
||||
<a href=#56 id=56 data-nosnippet>56</a>//! [`cumulus`] transforms FRAME-based runtimes into Pezkuwi-compatible teyrchain runtimes, and
|
||||
<a href=#57 id=57 data-nosnippet>57</a>//! Substrate-based nodes into Pezkuwi/Teyrchain-compatible nodes.
|
||||
<a href=#58 id=58 data-nosnippet>58</a>//!
|
||||
<a href=#59 id=59 data-nosnippet>59</a>//! #### XCM
|
||||
<a href=#60 id=60 data-nosnippet>60</a>//!
|
||||
<a href=#61 id=61 data-nosnippet>61</a>//! [](https://github.com/pezkuwichain/pezkuwi-sdk/blob/main/pezkuwi/LICENSE)
|
||||
<a href=#62 id=62 data-nosnippet>62</a>//! [](https://github.com/pezkuwichain/pezkuwi-sdk/tree/main/pezkuwi/xcm)
|
||||
<a href=#64 id=64 data-nosnippet>64</a>//!
|
||||
<a href=#65 id=65 data-nosnippet>65</a>//! [`xcm`], short for "cross consensus message", is the primary format that is used for
|
||||
<a href=#66 id=66 data-nosnippet>66</a>//! communication between teyrchains, but is intended to be extensible to other use cases as well.
|
||||
<a href=#67 id=67 data-nosnippet>67</a>//!
|
||||
<a href=#68 id=68 data-nosnippet>68</a>//! #### Pezkuwi
|
||||
<a href=#69 id=69 data-nosnippet>69</a>//!
|
||||
<a href=#70 id=70 data-nosnippet>70</a>//! [](https://github.com/pezkuwichain/pezkuwi-sdk/blob/main/pezkuwi/LICENSE)
|
||||
<a href=#71 id=71 data-nosnippet>71</a>//! [](https://github.com/pezkuwichain/pezkuwi-sdk/tree/main/pezkuwi)
|
||||
<a href=#73 id=73 data-nosnippet>73</a>//!
|
||||
<a href=#74 id=74 data-nosnippet>74</a>//! [`pezkuwi`] is an implementation of a Pezkuwi node in Rust, by `@paritytech`. The Pezkuwi
|
||||
<a href=#75 id=75 data-nosnippet>75</a>//! runtimes are located under the
|
||||
<a href=#76 id=76 data-nosnippet>76</a>//! [`pezkuwi-fellows/runtimes`](https://github.com/pezkuwichain/pezkuwi-fellows/tree/main/runtimes) repository.
|
||||
<a href=#77 id=77 data-nosnippet>77</a>//!
|
||||
<a href=#78 id=78 data-nosnippet>78</a>//! ### Binaries
|
||||
<a href=#79 id=79 data-nosnippet>79</a>//!
|
||||
<a href=#80 id=80 data-nosnippet>80</a>//! The main binaries that are part of the Pezkuwi SDK are:
|
||||
<a href=#81 id=81 data-nosnippet>81</a>
|
||||
<a href=#82 id=82 data-nosnippet>82</a>//! * [`pezkuwi`]: The Pezkuwi relay chain node binary, as noted above.
|
||||
<a href=#83 id=83 data-nosnippet>83</a>//! * [`pezkuwi-omni-node`]: A white-labeled teyrchain collator node. See more in
|
||||
<a href=#84 id=84 data-nosnippet>84</a>//! [`crate::reference_docs::omni_node`].
|
||||
<a href=#85 id=85 data-nosnippet>85</a>//! * [`pezkuwi-teyrchain-bin`]: The collator node used to run collators for all Pezkuwi system
|
||||
<a href=#86 id=86 data-nosnippet>86</a>//! teyrchains.
|
||||
<a href=#87 id=87 data-nosnippet>87</a>//! * [`frame-omni-bencher`]: a benchmarking tool for FRAME-based runtimes. Nodes typically contain
|
||||
<a href=#88 id=88 data-nosnippet>88</a>//! a
|
||||
<a href=#89 id=89 data-nosnippet>89</a>//! `benchmark` subcommand that does the same.
|
||||
<a href=#90 id=90 data-nosnippet>90</a>//! * [`chain_spec_builder`]: Utility to build chain-specs Nodes typically contain a `build-spec`
|
||||
<a href=#91 id=91 data-nosnippet>91</a>//! subcommand that does the same.
|
||||
<a href=#92 id=92 data-nosnippet>92</a>//! * [`subkey`]: Substrate's key management utility.
|
||||
<a href=#93 id=93 data-nosnippet>93</a>//! * [`substrate-node`](node_cli) is an extensive substrate node that contains the superset of all
|
||||
<a href=#94 id=94 data-nosnippet>94</a>//! runtime and node side features. The corresponding runtime, called [`kitchensink_runtime`]
|
||||
<a href=#95 id=95 data-nosnippet>95</a>//! contains all of the modules that are provided with `FRAME`. This node and runtime is only used
|
||||
<a href=#96 id=96 data-nosnippet>96</a>//! for testing and demonstration.
|
||||
<a href=#97 id=97 data-nosnippet>97</a>//!
|
||||
<a href=#98 id=98 data-nosnippet>98</a>//! ### Summary
|
||||
<a href=#99 id=99 data-nosnippet>99</a>//!
|
||||
<a href=#100 id=100 data-nosnippet>100</a>//! The following diagram summarizes how some of the components of Pezkuwi SDK work together:
|
||||
<a href=#101 id=101 data-nosnippet>101</a></span><span class="attr">#![doc = <span class="macro">simple_mermaid::mermaid!</span>(<span class="string">"../../../mermaid/pezkuwi_sdk_substrate.mmd"</span>)]
|
||||
<a href=#102 id=102 data-nosnippet>102</a></span><span class="doccomment">//!
|
||||
<a href=#103 id=103 data-nosnippet>103</a>//! A Substrate-based chain is a blockchain composed of a runtime and a node. As noted above, the
|
||||
<a href=#104 id=104 data-nosnippet>104</a>//! runtime is the application logic of the blockchain, and the node is everything else.
|
||||
<a href=#105 id=105 data-nosnippet>105</a>//! See [`reference_docs::wasm_meta_protocol`] for an in-depth explanation of this. The
|
||||
<a href=#106 id=106 data-nosnippet>106</a>//! former is built with [`frame`], and the latter is built with rest of Substrate.
|
||||
<a href=#107 id=107 data-nosnippet>107</a>//!
|
||||
<a href=#108 id=108 data-nosnippet>108</a>//! > You can think of a Substrate-based chain as a white-labeled blockchain.
|
||||
<a href=#109 id=109 data-nosnippet>109</a></span><span class="attr">#![doc = <span class="macro">simple_mermaid::mermaid!</span>(<span class="string">"../../../mermaid/pezkuwi_sdk_pezkuwi.mmd"</span>)]
|
||||
<a href=#110 id=110 data-nosnippet>110</a></span><span class="doccomment">//! Pezkuwi is itself a Substrate-based chain, composed of the exact same two components. It has
|
||||
<a href=#111 id=111 data-nosnippet>111</a>//! specialized logic in both the node and the runtime side, but it is not "special" in any way.
|
||||
<a href=#112 id=112 data-nosnippet>112</a>//!
|
||||
<a href=#113 id=113 data-nosnippet>113</a>//! A teyrchain is a "special" Substrate-based chain, whereby both the node and the runtime
|
||||
<a href=#114 id=114 data-nosnippet>114</a>//! components have became "Pezkuwi-aware" using Cumulus.
|
||||
<a href=#115 id=115 data-nosnippet>115</a></span><span class="attr">#![doc = <span class="macro">simple_mermaid::mermaid!</span>(<span class="string">"../../../mermaid/pezkuwi_sdk_teyrchain.mmd"</span>)]
|
||||
<a href=#116 id=116 data-nosnippet>116</a></span><span class="doccomment">//!
|
||||
<a href=#117 id=117 data-nosnippet>117</a>//! ## Notable Upstream Crates
|
||||
<a href=#118 id=118 data-nosnippet>118</a>//!
|
||||
<a href=#119 id=119 data-nosnippet>119</a>//! - [`parity-scale-codec`](https://github.com/paritytech/parity-scale-codec)
|
||||
<a href=#120 id=120 data-nosnippet>120</a>//! - [`parity-db`](https://github.com/paritytech/parity-db)
|
||||
<a href=#121 id=121 data-nosnippet>121</a>//! - [`trie`](https://github.com/paritytech/trie)
|
||||
<a href=#122 id=122 data-nosnippet>122</a>//! - [`parity-common`](https://github.com/paritytech/parity-common)
|
||||
<a href=#123 id=123 data-nosnippet>123</a>//!
|
||||
<a href=#124 id=124 data-nosnippet>124</a>//! ## Trophy Section: Notable Downstream Projects
|
||||
<a href=#125 id=125 data-nosnippet>125</a>//!
|
||||
<a href=#126 id=126 data-nosnippet>126</a>//! A list of projects and tools in the blockchain ecosystem that one way or another use parts of
|
||||
<a href=#127 id=127 data-nosnippet>127</a>//! the Pezkuwi SDK:
|
||||
<a href=#128 id=128 data-nosnippet>128</a>//!
|
||||
<a href=#129 id=129 data-nosnippet>129</a>//! * [Avail](https://github.com/availproject/avail)
|
||||
<a href=#130 id=130 data-nosnippet>130</a>//! * [Cardano Partner Chains](https://iohk.io/en/blog/posts/2023/11/03/partner-chains-are-coming-to-cardano/)
|
||||
<a href=#131 id=131 data-nosnippet>131</a>//! * [Starknet's Madara Sequencer](https://github.com/keep-starknet-strange/madara)
|
||||
<a href=#132 id=132 data-nosnippet>132</a>//! * [Polymesh](https://polymesh.network/)
|
||||
<a href=#133 id=133 data-nosnippet>133</a>//!
|
||||
<a href=#134 id=134 data-nosnippet>134</a>//! [`substrate`]: crate::pezkuwi_sdk::substrate
|
||||
<a href=#135 id=135 data-nosnippet>135</a>//! [`frame`]: crate::pezkuwi_sdk::frame_runtime
|
||||
<a href=#136 id=136 data-nosnippet>136</a>//! [`cumulus`]: crate::pezkuwi_sdk::cumulus
|
||||
<a href=#137 id=137 data-nosnippet>137</a>//! [`pezkuwi`]: crate::pezkuwi_sdk::pezkuwi
|
||||
<a href=#138 id=138 data-nosnippet>138</a>//! [`xcm`]: crate::pezkuwi_sdk::xcm
|
||||
<a href=#139 id=139 data-nosnippet>139</a>//! [`frame-omni-bencher`]: https://crates.io/crates/frame-omni-bencher
|
||||
<a href=#140 id=140 data-nosnippet>140</a>//! [`pezkuwi-teyrchain-bin`]: https://crates.io/crates/pezkuwi-teyrchain-bin
|
||||
<a href=#141 id=141 data-nosnippet>141</a>//! [`pezkuwi-omni-node`]: https://crates.io/crates/pezkuwi-omni-node
|
||||
<a href=#142 id=142 data-nosnippet>142</a>
|
||||
<a href=#143 id=143 data-nosnippet>143</a>/// Learn about Cumulus, the framework that transforms [`substrate`]-based chains into
|
||||
<a href=#144 id=144 data-nosnippet>144</a>/// [`pezkuwi`]-enabled teyrchains.
|
||||
<a href=#145 id=145 data-nosnippet>145</a></span><span class="kw">pub mod </span>cumulus;
|
||||
<a href=#146 id=146 data-nosnippet>146</a><span class="doccomment">/// Learn about FRAME, the framework used to build Substrate runtimes.
|
||||
<a href=#147 id=147 data-nosnippet>147</a></span><span class="kw">pub mod </span>frame_runtime;
|
||||
<a href=#148 id=148 data-nosnippet>148</a><span class="doccomment">/// Learn about Pezkuwi as a platform.
|
||||
<a href=#149 id=149 data-nosnippet>149</a></span><span class="kw">pub mod </span>pezkuwi;
|
||||
<a href=#150 id=150 data-nosnippet>150</a><span class="doccomment">/// Learn about different ways through which smart contracts can be utilized on top of Substrate,
|
||||
<a href=#151 id=151 data-nosnippet>151</a>/// and in the Pezkuwi ecosystem.
|
||||
<a href=#152 id=152 data-nosnippet>152</a></span><span class="kw">pub mod </span>smart_contracts;
|
||||
<a href=#153 id=153 data-nosnippet>153</a><span class="doccomment">/// Learn about Substrate, the main blockchain framework used in the Pezkuwi ecosystem.
|
||||
<a href=#154 id=154 data-nosnippet>154</a></span><span class="kw">pub mod </span>substrate;
|
||||
<a href=#155 id=155 data-nosnippet>155</a><span class="doccomment">/// Index of all the templates that can act as first scaffold for a new project.
|
||||
<a href=#156 id=156 data-nosnippet>156</a></span><span class="kw">pub mod </span>templates;
|
||||
<a href=#157 id=157 data-nosnippet>157</a><span class="doccomment">/// Learn about XCM, the de-facto communication language between different consensus systems.
|
||||
<a href=#158 id=158 data-nosnippet>158</a></span><span class="kw">pub mod </span>xcm;</code></pre></div></section></main></body></html>
|
||||
@@ -0,0 +1,96 @@
|
||||
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `docs/sdk/src/pezkuwi_sdk/pezkuwi.rs`."><title>pezkuwi.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2"href="../../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../../../static.files/rustdoc-e56847b5.css"><meta name="rustdoc-vars" data-root-path="../../../" data-static-root-path="../../../static.files/" data-current-crate="pezkuwi_sdk_docs" data-themes="" data-resource-suffix="" data-rustdoc-version="1.91.1 (ed61e7d7e 2025-11-07)" data-channel="1.91.1" data-search-js="search-e256b49e.js" data-stringdex-js="stringdex-c3e638e9.js" data-settings-js="settings-c38705f0.js" ><script src="../../../static.files/storage-e2aeef58.js"></script><script defer src="../../../static.files/src-script-813739b1.js"></script><script defer src="../../../src-files.js"></script><script defer src="../../../static.files/main-6dc2a7f3.js"></script><noscript><link rel="stylesheet" href="../../../static.files/noscript-263c88ec.css"></noscript><link rel="icon" href="https://pezkuwichain.io/favicon.ico"></head><body class="rustdoc src"><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer" title="Drag to resize sidebar"></div><main><section id="main-content" class="content"><div class="main-heading"><h1><div class="sub-heading">pezkuwi_sdk_docs/pezkuwi_sdk/</div>pezkuwi.rs</h1><rustdoc-toolbar></rustdoc-toolbar></div><div class="example-wrap digits-2"><pre class="rust"><code><a href=#1 id=1 data-nosnippet>1</a><span class="doccomment">//! # Pezkuwi
|
||||
<a href=#2 id=2 data-nosnippet>2</a>//!
|
||||
<a href=#3 id=3 data-nosnippet>3</a>//! Implementation of the Pezkuwi node/host in Rust.
|
||||
<a href=#4 id=4 data-nosnippet>4</a>//!
|
||||
<a href=#5 id=5 data-nosnippet>5</a>//! ## Learn More and Get Involved
|
||||
<a href=#6 id=6 data-nosnippet>6</a>//!
|
||||
<a href=#7 id=7 data-nosnippet>7</a>//! - [Pezkuwi Forum](https://forum.network.pezkuwichain.io/)
|
||||
<a href=#8 id=8 data-nosnippet>8</a>//! - [Pezkuwi Teyrchains](https://teyrchains.info/)
|
||||
<a href=#9 id=9 data-nosnippet>9</a>//! - [Pezkuwi (multi-chain) Explorer: Subscan](https://subscan.io/)
|
||||
<a href=#10 id=10 data-nosnippet>10</a>//! - Pezkuwi Fellowship
|
||||
<a href=#11 id=11 data-nosnippet>11</a>//! - [Manifesto](https://github.com/pezkuwichain/pezkuwi-fellows/tree/main/manifesto/blob/main/manifesto.pdf)
|
||||
<a href=#12 id=12 data-nosnippet>12</a>//! - [Runtimes](https://github.com/pezkuwichain/pezkuwi-fellows/tree/main/runtimes)
|
||||
<a href=#13 id=13 data-nosnippet>13</a>//! - [RFCs](https://github.com/pezkuwichain/pezkuwi-fellows/tree/main/rfcs)
|
||||
<a href=#14 id=14 data-nosnippet>14</a>//! - [Dashboard](https://pezkuwi-fellows.github.io/dashboard/)
|
||||
<a href=#15 id=15 data-nosnippet>15</a>//! - [Pezkuwi Specs](http://spec.pezkuwi.network)
|
||||
<a href=#16 id=16 data-nosnippet>16</a>//! - [The Pezkuwi Teyrchain Host Implementers' Guide](https://docs.pezkuwichain.io/sdk/book/)
|
||||
<a href=#17 id=17 data-nosnippet>17</a>//! - [Pezkuwi papers](https://pezkuwichain.io/papers/)
|
||||
<a href=#18 id=18 data-nosnippet>18</a>//! - [JAM Graypaper](https://graypaper.com)
|
||||
<a href=#19 id=19 data-nosnippet>19</a>//!
|
||||
<a href=#20 id=20 data-nosnippet>20</a>//! ## Alternative Node Implementations 🌈
|
||||
<a href=#21 id=21 data-nosnippet>21</a>//!
|
||||
<a href=#22 id=22 data-nosnippet>22</a>//! - [Smoldot](https://docs.rs/crate/smoldot-light/latest). Pezkuwi light node/client.
|
||||
<a href=#23 id=23 data-nosnippet>23</a>//! - [KAGOME](https://github.com/qdrvm/kagome). C++ implementation of the Pezkuwi host.
|
||||
<a href=#24 id=24 data-nosnippet>24</a>//! - [Gossamer](https://github.com/ChainSafe/gossamer). Golang implementation of the Pezkuwi host.
|
||||
<a href=#25 id=25 data-nosnippet>25</a>//!
|
||||
<a href=#26 id=26 data-nosnippet>26</a>//! ## Platform
|
||||
<a href=#27 id=27 data-nosnippet>27</a>//!
|
||||
<a href=#28 id=28 data-nosnippet>28</a>//! In this section, we examine what platform Pezkuwi exactly provides to developers.
|
||||
<a href=#29 id=29 data-nosnippet>29</a>//!
|
||||
<a href=#30 id=30 data-nosnippet>30</a>//! ### Pezkuwi White Paper
|
||||
<a href=#31 id=31 data-nosnippet>31</a>//!
|
||||
<a href=#32 id=32 data-nosnippet>32</a>//! The original vision of Pezkuwi (everything in the whitepaper, which was eventually called
|
||||
<a href=#33 id=33 data-nosnippet>33</a>//! **Pezkuwi 1.0**) revolves around the following arguments:
|
||||
<a href=#34 id=34 data-nosnippet>34</a>//!
|
||||
<a href=#35 id=35 data-nosnippet>35</a>//! * Future is multi-chain, because we need different chains with different specialization to
|
||||
<a href=#36 id=36 data-nosnippet>36</a>//! achieve widespread goals.
|
||||
<a href=#37 id=37 data-nosnippet>37</a>//! * In other words, no single chain is good enough to achieve all goals.
|
||||
<a href=#38 id=38 data-nosnippet>38</a>//! * A multi-chain future will inadvertently suffer from fragmentation of economic security.
|
||||
<a href=#39 id=39 data-nosnippet>39</a>//! * This stake fragmentation will make communication over consensus system with varying security
|
||||
<a href=#40 id=40 data-nosnippet>40</a>//! levels inherently unsafe.
|
||||
<a href=#41 id=41 data-nosnippet>41</a>//!
|
||||
<a href=#42 id=42 data-nosnippet>42</a>//! Pezkuwi's answer to the above is:
|
||||
<a href=#43 id=43 data-nosnippet>43</a>//!
|
||||
<a href=#44 id=44 data-nosnippet>44</a>//! > The chains of the future must have a way to share their economic security, whilst maintaining
|
||||
<a href=#45 id=45 data-nosnippet>45</a>//! > their execution and governance sovereignty. These chains are called "Teyrchains".
|
||||
<a href=#46 id=46 data-nosnippet>46</a>//!
|
||||
<a href=#47 id=47 data-nosnippet>47</a>//! * Shared Security: The idea of shared economic security sits at the core of Pezkuwi. Pezkuwi
|
||||
<a href=#48 id=48 data-nosnippet>48</a>//! enables different teyrchains to pool their economic security from Pezkuwi (i.e. "*Relay
|
||||
<a href=#49 id=49 data-nosnippet>49</a>//! Chain*").
|
||||
<a href=#50 id=50 data-nosnippet>50</a>//! * (heterogenous) Sharded Execution: Yet, each teyrchain is free to have its own execution logic
|
||||
<a href=#51 id=51 data-nosnippet>51</a>//! (runtime), which also encompasses governance and sovereignty. Moreover, Pezkuwi ensures the
|
||||
<a href=#52 id=52 data-nosnippet>52</a>//! correct execution of all teyrchains, without having all of its validators re-execute all
|
||||
<a href=#53 id=53 data-nosnippet>53</a>//! teyrchain blocks. When seen from this perspective, Pezkuwi achieves the ability to verify
|
||||
<a href=#54 id=54 data-nosnippet>54</a>//! the validity of the block execution of multiple teyrchains using the same set of validators as
|
||||
<a href=#55 id=55 data-nosnippet>55</a>//! the Relay Chain. In practice, this means that the shards (teyrchains) share the same economic
|
||||
<a href=#56 id=56 data-nosnippet>56</a>//! security as the Relay Chain.
|
||||
<a href=#57 id=57 data-nosnippet>57</a>//! Learn about this process called [Approval Checking](https://pezkuwichain.io/blog/pezkuwi-v1-0-sharding-and-economic-security#approval-checking-and-finality).
|
||||
<a href=#58 id=58 data-nosnippet>58</a>//! * A framework to build blockchains: In order to materialize the ecosystem of teyrchains, an easy
|
||||
<a href=#59 id=59 data-nosnippet>59</a>//! blockchain framework must exist. This is [Substrate](crate::pezkuwi_sdk::substrate),
|
||||
<a href=#60 id=60 data-nosnippet>60</a>//! [FRAME](crate::pezkuwi_sdk::frame_runtime) and [Cumulus](crate::pezkuwi_sdk::cumulus).
|
||||
<a href=#61 id=61 data-nosnippet>61</a>//! * A communication language between blockchains: In order for these blockchains to communicate,
|
||||
<a href=#62 id=62 data-nosnippet>62</a>//! they need a shared language. [XCM](crate::pezkuwi_sdk::xcm) is one such language, and the one
|
||||
<a href=#63 id=63 data-nosnippet>63</a>//! that is most endorsed in the Pezkuwi ecosystem.
|
||||
<a href=#64 id=64 data-nosnippet>64</a>//!
|
||||
<a href=#65 id=65 data-nosnippet>65</a>//! > Note that the interoperability promised by Pezkuwi is unparalleled in that any two teyrchains
|
||||
<a href=#66 id=66 data-nosnippet>66</a>//! > connected to Pezkuwi have the same security and can have much better guarantees about the
|
||||
<a href=#67 id=67 data-nosnippet>67</a>//! > security of the recipient of any message.
|
||||
<a href=#68 id=68 data-nosnippet>68</a>//! > Bridges enable transaction and information flow between different consensus systems, crucial
|
||||
<a href=#69 id=69 data-nosnippet>69</a>//! > for Pezkuwi's multi-chain architecture. However, they can become the network's most
|
||||
<a href=#70 id=70 data-nosnippet>70</a>//! > vulnerable points. If a bridge's security measures are weaker than those of the connected
|
||||
<a href=#71 id=71 data-nosnippet>71</a>//! > blockchains, it poses a significant risk. Attackers might exploit these weaknesses to launch
|
||||
<a href=#72 id=72 data-nosnippet>72</a>//! > attacks such as theft or disruption of services.
|
||||
<a href=#73 id=73 data-nosnippet>73</a>//!
|
||||
<a href=#74 id=74 data-nosnippet>74</a>//! Pezkuwi delivers the above vision, alongside a flexible means for teyrchains to schedule
|
||||
<a href=#75 id=75 data-nosnippet>75</a>//! themselves with the Relay Chain. To achieve this, Pezkuwi has been developed with an
|
||||
<a href=#76 id=76 data-nosnippet>76</a>//! architecture similar to that of a computer. Pezkuwi Relay Chain has a number of "cores". Each
|
||||
<a href=#77 id=77 data-nosnippet>77</a>//! core is (in simple terms) capable of progressing 1 teyrchain at a time. For example, a teyrchain
|
||||
<a href=#78 id=78 data-nosnippet>78</a>//! can schedule itself on a single core for 5 relay chain blocks.
|
||||
<a href=#79 id=79 data-nosnippet>79</a>//!
|
||||
<a href=#80 id=80 data-nosnippet>80</a>//! Within the scope of Pezkuwi 1.x, two main scheduling ways have been considered:
|
||||
<a href=#81 id=81 data-nosnippet>81</a>//!
|
||||
<a href=#82 id=82 data-nosnippet>82</a>//! * Long term Teyrchains, obtained through locking a sum of HEZ in an auction system.
|
||||
<a href=#83 id=83 data-nosnippet>83</a>//! * On-demand Teyrchains, purchased through paying HEZ to the relay-chain whenever needed.
|
||||
<a href=#84 id=84 data-nosnippet>84</a>//!
|
||||
<a href=#85 id=85 data-nosnippet>85</a>//! ### The Future
|
||||
<a href=#86 id=86 data-nosnippet>86</a>//!
|
||||
<a href=#87 id=87 data-nosnippet>87</a>//! After delivering Pezkuwi 1.x, the future of Pezkuwi as a protocol and platform is in the hands
|
||||
<a href=#88 id=88 data-nosnippet>88</a>//! of the community and the fellowship. This is happening most notable through the RFC process.
|
||||
<a href=#89 id=89 data-nosnippet>89</a>//! Some of the RFCs that do alter Pezkuwi as a platform and have already passed are as follows:
|
||||
<a href=#90 id=90 data-nosnippet>90</a>//!
|
||||
<a href=#91 id=91 data-nosnippet>91</a>//! - RFC#1: [Agile-coretime](https://github.com/pezkuwichain/pezkuwi-fellows/RFCs/blob/main/text/0001-agile-coretime.md):
|
||||
<a href=#92 id=92 data-nosnippet>92</a>//! Agile periodic-sale-based model for assigning Coretime on the Pezkuwi Ubiquitous Computer.
|
||||
<a href=#93 id=93 data-nosnippet>93</a>//! - RFC#5: [Coretime-interface](https://github.com/pezkuwichain/pezkuwi-fellows/RFCs/blob/main/text/0005-coretime-interface.md):
|
||||
<a href=#94 id=94 data-nosnippet>94</a>//! Interface for manipulating the usage of cores on the Pezkuwi Ubiquitous Computer.
|
||||
<a href=#95 id=95 data-nosnippet>95</a>//!
|
||||
<a href=#96 id=96 data-nosnippet>96</a>//! Learn more about [Pezkuwi as a Computational Resource](https://wiki.network.pezkuwichain.io/docs/pezkuwi-direction#pezkuwi-as-a-computational-resource).</span></code></pre></div></section></main></body></html>
|
||||
@@ -0,0 +1,9 @@
|
||||
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `docs/sdk/src/pezkuwi_sdk/smart_contracts.rs`."><title>smart_contracts.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2"href="../../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../../../static.files/rustdoc-e56847b5.css"><meta name="rustdoc-vars" data-root-path="../../../" data-static-root-path="../../../static.files/" data-current-crate="pezkuwi_sdk_docs" data-themes="" data-resource-suffix="" data-rustdoc-version="1.91.1 (ed61e7d7e 2025-11-07)" data-channel="1.91.1" data-search-js="search-e256b49e.js" data-stringdex-js="stringdex-c3e638e9.js" data-settings-js="settings-c38705f0.js" ><script src="../../../static.files/storage-e2aeef58.js"></script><script defer src="../../../static.files/src-script-813739b1.js"></script><script defer src="../../../src-files.js"></script><script defer src="../../../static.files/main-6dc2a7f3.js"></script><noscript><link rel="stylesheet" href="../../../static.files/noscript-263c88ec.css"></noscript><link rel="icon" href="https://pezkuwichain.io/favicon.ico"></head><body class="rustdoc src"><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer" title="Drag to resize sidebar"></div><main><section id="main-content" class="content"><div class="main-heading"><h1><div class="sub-heading">pezkuwi_sdk_docs/pezkuwi_sdk/</div>smart_contracts.rs</h1><rustdoc-toolbar></rustdoc-toolbar></div><div class="example-wrap digits-1"><pre class="rust"><code><a href=#1 id=1 data-nosnippet>1</a><span class="doccomment">//! # Smart Contracts
|
||||
<a href=#2 id=2 data-nosnippet>2</a>//!
|
||||
<a href=#3 id=3 data-nosnippet>3</a>//! TODO: @cmichi <https://github.com/pezkuwichain/pezkuwi-sdk/issues/161>
|
||||
<a href=#4 id=4 data-nosnippet>4</a>//!
|
||||
<a href=#5 id=5 data-nosnippet>5</a>//! - WASM and EVM based, pallet-contracts and pallet-evm.
|
||||
<a href=#6 id=6 data-nosnippet>6</a>//! - single-daap-chain, transition from ink! to FRAME.
|
||||
<a href=#7 id=7 data-nosnippet>7</a>//! - Link to `use.ink`
|
||||
<a href=#8 id=8 data-nosnippet>8</a>//! - Link to [`crate::reference_docs::runtime_vs_smart_contract`].
|
||||
<a href=#9 id=9 data-nosnippet>9</a>//! - <https://use.ink/migrate-ink-contracts-to-pezkuwi-frame-teyrchain/></span></code></pre></div></section></main></body></html>
|
||||
@@ -0,0 +1,137 @@
|
||||
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `docs/sdk/src/pezkuwi_sdk/substrate.rs`."><title>substrate.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2"href="../../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../../../static.files/rustdoc-e56847b5.css"><meta name="rustdoc-vars" data-root-path="../../../" data-static-root-path="../../../static.files/" data-current-crate="pezkuwi_sdk_docs" data-themes="" data-resource-suffix="" data-rustdoc-version="1.91.1 (ed61e7d7e 2025-11-07)" data-channel="1.91.1" data-search-js="search-e256b49e.js" data-stringdex-js="stringdex-c3e638e9.js" data-settings-js="settings-c38705f0.js" ><script src="../../../static.files/storage-e2aeef58.js"></script><script defer src="../../../static.files/src-script-813739b1.js"></script><script defer src="../../../src-files.js"></script><script defer src="../../../static.files/main-6dc2a7f3.js"></script><noscript><link rel="stylesheet" href="../../../static.files/noscript-263c88ec.css"></noscript><link rel="icon" href="https://pezkuwichain.io/favicon.ico"></head><body class="rustdoc src"><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer" title="Drag to resize sidebar"></div><main><section id="main-content" class="content"><div class="main-heading"><h1><div class="sub-heading">pezkuwi_sdk_docs/pezkuwi_sdk/</div>substrate.rs</h1><rustdoc-toolbar></rustdoc-toolbar></div><div class="example-wrap digits-3"><pre class="rust"><code><a href=#1 id=1 data-nosnippet>1</a><span class="doccomment">//! # Substrate
|
||||
<a href=#2 id=2 data-nosnippet>2</a>//!
|
||||
<a href=#3 id=3 data-nosnippet>3</a>//! Substrate is a Rust framework for building blockchains in a modular and extensible way. While in
|
||||
<a href=#4 id=4 data-nosnippet>4</a>//! itself un-opinionated, it is the main engine behind the Pezkuwi ecosystem.
|
||||
<a href=#5 id=5 data-nosnippet>5</a>//!
|
||||
<a href=#6 id=6 data-nosnippet>6</a>//! ## Overview, Philosophy
|
||||
<a href=#7 id=7 data-nosnippet>7</a>//!
|
||||
<a href=#8 id=8 data-nosnippet>8</a>//! Substrate approaches blockchain development with an acknowledgement of a few self-evident
|
||||
<a href=#9 id=9 data-nosnippet>9</a>//! truths:
|
||||
<a href=#10 id=10 data-nosnippet>10</a>//!
|
||||
<a href=#11 id=11 data-nosnippet>11</a>//! 1. Society and technology evolves.
|
||||
<a href=#12 id=12 data-nosnippet>12</a>//! 2. Humans are fallible.
|
||||
<a href=#13 id=13 data-nosnippet>13</a>//!
|
||||
<a href=#14 id=14 data-nosnippet>14</a>//! This makes the task of designing a correct, safe and long-lasting blockchain system hard.
|
||||
<a href=#15 id=15 data-nosnippet>15</a>//!
|
||||
<a href=#16 id=16 data-nosnippet>16</a>//! Nonetheless, in strive towards achieving this goal, Substrate embraces the following:
|
||||
<a href=#17 id=17 data-nosnippet>17</a>//!
|
||||
<a href=#18 id=18 data-nosnippet>18</a>//! 1. Use of **Rust** as a modern and safe programming language, which limits human error through
|
||||
<a href=#19 id=19 data-nosnippet>19</a>//! various means, most notably memory and type safety.
|
||||
<a href=#20 id=20 data-nosnippet>20</a>//! 2. Substrate is written from the ground-up with a *generic, modular and extensible* design. This
|
||||
<a href=#21 id=21 data-nosnippet>21</a>//! ensures that software components can be easily swapped and upgraded. Examples of this is
|
||||
<a href=#22 id=22 data-nosnippet>22</a>//! multiple consensus mechanisms provided by Substrate, as listed below.
|
||||
<a href=#23 id=23 data-nosnippet>23</a>//! 3. Lastly, the final blockchain system created with the above properties needs to be
|
||||
<a href=#24 id=24 data-nosnippet>24</a>//! upgradeable. In order to achieve this, Substrate is designed as a meta-protocol, whereby the
|
||||
<a href=#25 id=25 data-nosnippet>25</a>//! application logic of the blockchain (called "Runtime") is encoded as a WASM blob, and is
|
||||
<a href=#26 id=26 data-nosnippet>26</a>//! stored in the state. The rest of the system (called "node") acts as the executor of the WASM
|
||||
<a href=#27 id=27 data-nosnippet>27</a>//! blob.
|
||||
<a href=#28 id=28 data-nosnippet>28</a>//!
|
||||
<a href=#29 id=29 data-nosnippet>29</a>//! In essence, the meta-protocol of all Substrate based chains is the "Runtime as WASM blob"
|
||||
<a href=#30 id=30 data-nosnippet>30</a>//! accord. This enables the Runtime to become inherently upgradeable, crucially without [forks](https://en.wikipedia.org/wiki/Fork_(blockchain)). The
|
||||
<a href=#31 id=31 data-nosnippet>31</a>//! upgrade is merely a matter of the WASM blob being changed in the state, which is, in principle,
|
||||
<a href=#32 id=32 data-nosnippet>32</a>//! same as updating an account's balance. Learn more about this in detail in
|
||||
<a href=#33 id=33 data-nosnippet>33</a>//! [`crate::reference_docs::wasm_meta_protocol`].
|
||||
<a href=#34 id=34 data-nosnippet>34</a>//!
|
||||
<a href=#35 id=35 data-nosnippet>35</a>//! > A great analogy for substrate is the following: Substrate node is a gaming console, and a WASM
|
||||
<a href=#36 id=36 data-nosnippet>36</a>//! > runtime, possibly created with FRAME is the game being inserted into the console.
|
||||
<a href=#37 id=37 data-nosnippet>37</a>//!
|
||||
<a href=#38 id=38 data-nosnippet>38</a>//! [`frame`], Substrate's default runtime development library, takes the above safety practices
|
||||
<a href=#39 id=39 data-nosnippet>39</a>//! even further by embracing a declarative programming model whereby correctness is enhanced and
|
||||
<a href=#40 id=40 data-nosnippet>40</a>//! the system is highly configurable through parameterization. Learn more about this in
|
||||
<a href=#41 id=41 data-nosnippet>41</a>//! [`crate::reference_docs::trait_based_programming`].
|
||||
<a href=#42 id=42 data-nosnippet>42</a>//!
|
||||
<a href=#43 id=43 data-nosnippet>43</a>//! ## How to Get Started
|
||||
<a href=#44 id=44 data-nosnippet>44</a>//!
|
||||
<a href=#45 id=45 data-nosnippet>45</a>//! Substrate offers different options at the spectrum of technical freedom <-> development ease.
|
||||
<a href=#46 id=46 data-nosnippet>46</a>//!
|
||||
<a href=#47 id=47 data-nosnippet>47</a>//! * The easiest way to use Substrate is to use one of the templates (some of which listed at
|
||||
<a href=#48 id=48 data-nosnippet>48</a>//! [`crate::pezkuwi_sdk::templates`]) and only tweak the parameters of the runtime or node. This
|
||||
<a href=#49 id=49 data-nosnippet>49</a>//! allows you to launch a blockchain in minutes, but is limited in technical freedom.
|
||||
<a href=#50 id=50 data-nosnippet>50</a>//! * Next, most developers wish to develop their custom runtime modules, for which the de-facto way
|
||||
<a href=#51 id=51 data-nosnippet>51</a>//! is [`frame`](crate::pezkuwi_sdk::frame_runtime).
|
||||
<a href=#52 id=52 data-nosnippet>52</a>//! * Finally, Substrate is highly configurable at the node side as well, but this is the most
|
||||
<a href=#53 id=53 data-nosnippet>53</a>//! technically demanding.
|
||||
<a href=#54 id=54 data-nosnippet>54</a>//!
|
||||
<a href=#55 id=55 data-nosnippet>55</a>//! > A notable Substrate-based blockchain that has built both custom FRAME pallets and custom
|
||||
<a href=#56 id=56 data-nosnippet>56</a>//! > node-side components is <https://github.com/Cardinal-Cryptography/aleph-node>.
|
||||
<a href=#57 id=57 data-nosnippet>57</a></span><span class="attr">#![doc = <span class="macro">simple_mermaid::mermaid!</span>(<span class="string">"../../../mermaid/substrate_dev.mmd"</span>)]
|
||||
<a href=#58 id=58 data-nosnippet>58</a></span><span class="doccomment">//!
|
||||
<a href=#59 id=59 data-nosnippet>59</a>//! ## Structure
|
||||
<a href=#60 id=60 data-nosnippet>60</a>//!
|
||||
<a href=#61 id=61 data-nosnippet>61</a>//! Substrate contains a large number of crates, therefore it is useful to have an overview of what
|
||||
<a href=#62 id=62 data-nosnippet>62</a>//! they are, and how they are organized. In broad terms, these crates are divided into three
|
||||
<a href=#63 id=63 data-nosnippet>63</a>//! categories:
|
||||
<a href=#64 id=64 data-nosnippet>64</a>//!
|
||||
<a href=#65 id=65 data-nosnippet>65</a>//! * `sc-*` (short for *Substrate-client*) crates, located under `./client` folder. These are all
|
||||
<a href=#66 id=66 data-nosnippet>66</a>//! the crates that lead to the node software. Notable examples are [`sc_network`], various
|
||||
<a href=#67 id=67 data-nosnippet>67</a>//! consensus crates, RPC ([`sc_rpc_api`]) and database ([`sc_client_db`]), all of which are
|
||||
<a href=#68 id=68 data-nosnippet>68</a>//! expected to reside in the node side.
|
||||
<a href=#69 id=69 data-nosnippet>69</a>//! * `sp-*` (short for *substrate-primitives*) crates, located under `./primitives` folder. These
|
||||
<a href=#70 id=70 data-nosnippet>70</a>//! are crates that facilitate both the node and the runtime, but are not opinionated about what
|
||||
<a href=#71 id=71 data-nosnippet>71</a>//! framework is using for building the runtime. Notable examples are [`sp_api`] and [`sp_io`],
|
||||
<a href=#72 id=72 data-nosnippet>72</a>//! which form the communication bridge between the node and runtime.
|
||||
<a href=#73 id=73 data-nosnippet>73</a>//! * `pallet-*` and `frame-*` crates, located under `./frame` folder. These are the crates related
|
||||
<a href=#74 id=74 data-nosnippet>74</a>//! to FRAME. See [`frame`] for more information.
|
||||
<a href=#75 id=75 data-nosnippet>75</a>//!
|
||||
<a href=#76 id=76 data-nosnippet>76</a>//! ### WASM Build
|
||||
<a href=#77 id=77 data-nosnippet>77</a>//!
|
||||
<a href=#78 id=78 data-nosnippet>78</a>//! Many of the Substrate crates, such as entire `sp-*`, need to compile to both WASM (when a WASM
|
||||
<a href=#79 id=79 data-nosnippet>79</a>//! runtime is being generated) and native (for example, when testing). To achieve this, Substrate
|
||||
<a href=#80 id=80 data-nosnippet>80</a>//! follows the convention of the Rust community, and uses a `feature = "std"` to signify that a
|
||||
<a href=#81 id=81 data-nosnippet>81</a>//! crate is being built with the standard library, and is built for native. Otherwise, it is built
|
||||
<a href=#82 id=82 data-nosnippet>82</a>//! for `no_std`.
|
||||
<a href=#83 id=83 data-nosnippet>83</a>//!
|
||||
<a href=#84 id=84 data-nosnippet>84</a>//! This can be summarized in `#![cfg_attr(not(feature = "std"), no_std)]`, which you can often find
|
||||
<a href=#85 id=85 data-nosnippet>85</a>//! in any Substrate-based runtime.
|
||||
<a href=#86 id=86 data-nosnippet>86</a>//!
|
||||
<a href=#87 id=87 data-nosnippet>87</a>//! Substrate-based runtimes use [`substrate_wasm_builder`] in their `build.rs` to automatically
|
||||
<a href=#88 id=88 data-nosnippet>88</a>//! build their WASM files as a part of normal build command (e.g. `cargo build`). Once built, the
|
||||
<a href=#89 id=89 data-nosnippet>89</a>//! wasm file is placed in `./target/{debug|release}/wbuild/{runtime_name}/{runtime_name}.wasm`.
|
||||
<a href=#90 id=90 data-nosnippet>90</a>//!
|
||||
<a href=#91 id=91 data-nosnippet>91</a>//! In order to ensure that the WASM build is **deterministic**, the [Substrate Runtime Toolbox (srtool)](https://github.com/paritytech/srtool) can be used.
|
||||
<a href=#92 id=92 data-nosnippet>92</a>//!
|
||||
<a href=#93 id=93 data-nosnippet>93</a>//! ### Anatomy of a Binary Crate
|
||||
<a href=#94 id=94 data-nosnippet>94</a>//!
|
||||
<a href=#95 id=95 data-nosnippet>95</a>//! From the above, [`node_cli`]/[`kitchensink_runtime`] and `node-template` are essentially
|
||||
<a href=#96 id=96 data-nosnippet>96</a>//! blueprints of a Substrate-based project, as the name of the latter is implying. Each
|
||||
<a href=#97 id=97 data-nosnippet>97</a>//! Substrate-based project typically contains the following:
|
||||
<a href=#98 id=98 data-nosnippet>98</a>//!
|
||||
<a href=#99 id=99 data-nosnippet>99</a>//! * Under `./runtime`, a `./runtime/src/lib.rs` which is the top level runtime amalgamator file.
|
||||
<a href=#100 id=100 data-nosnippet>100</a>//! This file typically contains the [`frame::runtime::prelude::construct_runtime`] and
|
||||
<a href=#101 id=101 data-nosnippet>101</a>//! [`frame::runtime::prelude::impl_runtime_apis`] macro calls, which is the final definition of a
|
||||
<a href=#102 id=102 data-nosnippet>102</a>//! runtime.
|
||||
<a href=#103 id=103 data-nosnippet>103</a>//!
|
||||
<a href=#104 id=104 data-nosnippet>104</a>//! * Under `./node`, a `main.rs`, which is the starting point, and a `./service.rs`, which contains
|
||||
<a href=#105 id=105 data-nosnippet>105</a>//! all the node side components. Skimming this file yields an overview of the networking,
|
||||
<a href=#106 id=106 data-nosnippet>106</a>//! database, consensus and similar node side components.
|
||||
<a href=#107 id=107 data-nosnippet>107</a>//!
|
||||
<a href=#108 id=108 data-nosnippet>108</a>//! > The above two are conventions, not rules.
|
||||
<a href=#109 id=109 data-nosnippet>109</a>//!
|
||||
<a href=#110 id=110 data-nosnippet>110</a>//! > See <https://github.com/pezkuwichain/pezkuwi-sdk/issues/94> for an update on how the node side
|
||||
<a href=#111 id=111 data-nosnippet>111</a>//! > components are being amalgamated.
|
||||
<a href=#112 id=112 data-nosnippet>112</a>//!
|
||||
<a href=#113 id=113 data-nosnippet>113</a>//! ## Teyrchain?
|
||||
<a href=#114 id=114 data-nosnippet>114</a>//!
|
||||
<a href=#115 id=115 data-nosnippet>115</a>//! As noted above, Substrate is the main engine behind the Pezkuwi ecosystem. One of the ways
|
||||
<a href=#116 id=116 data-nosnippet>116</a>//! through which Pezkuwi can be utilized is by building "teyrchains", blockchains that are
|
||||
<a href=#117 id=117 data-nosnippet>117</a>//! connected to Pezkuwi's shared security.
|
||||
<a href=#118 id=118 data-nosnippet>118</a>//!
|
||||
<a href=#119 id=119 data-nosnippet>119</a>//! To build a teyrchain, one could use [Cumulus](crate::pezkuwi_sdk::cumulus), the library on
|
||||
<a href=#120 id=120 data-nosnippet>120</a>//! top of Substrate, empowering any substrate-based chain to be a Pezkuwi teyrchain.
|
||||
<a href=#121 id=121 data-nosnippet>121</a>//!
|
||||
<a href=#122 id=122 data-nosnippet>122</a>//! ## Where To Go Next?
|
||||
<a href=#123 id=123 data-nosnippet>123</a>//!
|
||||
<a href=#124 id=124 data-nosnippet>124</a>//! Additional noteworthy crates within substrate:
|
||||
<a href=#125 id=125 data-nosnippet>125</a>//!
|
||||
<a href=#126 id=126 data-nosnippet>126</a>//! - RPC APIs of a Substrate node: [`sc_rpc_api`]/[`sc_rpc`]
|
||||
<a href=#127 id=127 data-nosnippet>127</a>//! - CLI Options of a Substrate node: [`sc_cli`]
|
||||
<a href=#128 id=128 data-nosnippet>128</a>//! - All of the consensus related crates provided by Substrate:
|
||||
<a href=#129 id=129 data-nosnippet>129</a>//! - [`sc_consensus_aura`]
|
||||
<a href=#130 id=130 data-nosnippet>130</a>//! - [`sc_consensus_babe`]
|
||||
<a href=#131 id=131 data-nosnippet>131</a>//! - [`sc_consensus_grandpa`]
|
||||
<a href=#132 id=132 data-nosnippet>132</a>//! - [`sc_consensus_beefy`] (TODO: @adrian, add some high level docs <https://github.com/pezkuwichain/pezkuwi-sdk/issues/162>)
|
||||
<a href=#133 id=133 data-nosnippet>133</a>//! - [`sc_consensus_manual_seal`]
|
||||
<a href=#134 id=134 data-nosnippet>134</a>//! - [`sc_consensus_pow`]
|
||||
<a href=#135 id=135 data-nosnippet>135</a>
|
||||
<a href=#136 id=136 data-nosnippet>136</a></span><span class="attr">#[doc(hidden)]
|
||||
<a href=#137 id=137 data-nosnippet>137</a></span><span class="kw">pub use </span><span class="kw">crate</span>::pezkuwi_sdk;</code></pre></div></section></main></body></html>
|
||||
@@ -0,0 +1,44 @@
|
||||
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `docs/sdk/src/pezkuwi_sdk/templates.rs`."><title>templates.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2"href="../../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../../../static.files/rustdoc-e56847b5.css"><meta name="rustdoc-vars" data-root-path="../../../" data-static-root-path="../../../static.files/" data-current-crate="pezkuwi_sdk_docs" data-themes="" data-resource-suffix="" data-rustdoc-version="1.91.1 (ed61e7d7e 2025-11-07)" data-channel="1.91.1" data-search-js="search-e256b49e.js" data-stringdex-js="stringdex-c3e638e9.js" data-settings-js="settings-c38705f0.js" ><script src="../../../static.files/storage-e2aeef58.js"></script><script defer src="../../../static.files/src-script-813739b1.js"></script><script defer src="../../../src-files.js"></script><script defer src="../../../static.files/main-6dc2a7f3.js"></script><noscript><link rel="stylesheet" href="../../../static.files/noscript-263c88ec.css"></noscript><link rel="icon" href="https://pezkuwichain.io/favicon.ico"></head><body class="rustdoc src"><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer" title="Drag to resize sidebar"></div><main><section id="main-content" class="content"><div class="main-heading"><h1><div class="sub-heading">pezkuwi_sdk_docs/pezkuwi_sdk/</div>templates.rs</h1><rustdoc-toolbar></rustdoc-toolbar></div><div class="example-wrap digits-2"><pre class="rust"><code><a href=#1 id=1 data-nosnippet>1</a><span class="doccomment">//! # Templates
|
||||
<a href=#2 id=2 data-nosnippet>2</a>//!
|
||||
<a href=#3 id=3 data-nosnippet>3</a>//! This document enumerates a non-exhaustive list of templates that one can use to get started with
|
||||
<a href=#4 id=4 data-nosnippet>4</a>//! pezkuwi-sdk.
|
||||
<a href=#5 id=5 data-nosnippet>5</a>//!
|
||||
<a href=#6 id=6 data-nosnippet>6</a>//! > Know more tools/templates that are not listed here? please contribute them by opening a PR.
|
||||
<a href=#7 id=7 data-nosnippet>7</a>//!
|
||||
<a href=#8 id=8 data-nosnippet>8</a>//! ## Internal
|
||||
<a href=#9 id=9 data-nosnippet>9</a>//!
|
||||
<a href=#10 id=10 data-nosnippet>10</a>//! The following templates are maintained as a part of the `pezkuwi-sdk` repository:
|
||||
<a href=#11 id=11 data-nosnippet>11</a>//!
|
||||
<a href=#12 id=12 data-nosnippet>12</a>//! - [`minimal-template`](https://github.com/pezkuwichain/pezkuwi-sdk/issues/25): A minimal
|
||||
<a href=#13 id=13 data-nosnippet>13</a>//! template that contains the least amount of features to be a functioning blockchain. Suitable
|
||||
<a href=#14 id=14 data-nosnippet>14</a>//! for learning and testing.
|
||||
<a href=#15 id=15 data-nosnippet>15</a>//! - [`solochain-template`](https://github.com/pezkuwichain/pezkuwi-sdk/issues/25): Formerly known
|
||||
<a href=#16 id=16 data-nosnippet>16</a>//! as "substrate-node-template", is a white-labeled substrate-based blockchain (aka. solochain)
|
||||
<a href=#17 id=17 data-nosnippet>17</a>//! that contains moderate features, such as a basic consensus engine and some FRAME pallets. This
|
||||
<a href=#18 id=18 data-nosnippet>18</a>//! template can act as a good starting point for those who want to launch a solochain.
|
||||
<a href=#19 id=19 data-nosnippet>19</a>//! - [`teyrchain-template`](https://github.com/pezkuwichain/pezkuwi-sdk-teyrchain-template):
|
||||
<a href=#20 id=20 data-nosnippet>20</a>//! A teyrchain template ready to be connected to a relay-chain, such as [Paseo](https://github.com/paseo-network/.github)
|
||||
<a href=#21 id=21 data-nosnippet>21</a>//! , Kusama or Pezkuwi.
|
||||
<a href=#22 id=22 data-nosnippet>22</a>//!
|
||||
<a href=#23 id=23 data-nosnippet>23</a>//! Note that these templates are mirrored automatically from [this](https://github.com/pezkuwichain/pezkuwi-sdk/blob/master/templates)
|
||||
<a href=#24 id=24 data-nosnippet>24</a>//! directory of pezkuwi-sdk, therefore any changes to them should be made as a PR to this repo.
|
||||
<a href=#25 id=25 data-nosnippet>25</a>//!
|
||||
<a href=#26 id=26 data-nosnippet>26</a>//! ## OpenZeppelin
|
||||
<a href=#27 id=27 data-nosnippet>27</a>//!
|
||||
<a href=#28 id=28 data-nosnippet>28</a>//! In June 2023, OpenZeppelin was awarded a grant from the Pezkuwi
|
||||
<a href=#29 id=29 data-nosnippet>29</a>//! treasury for building a number of Pezkuwi-sdk
|
||||
<a href=#30 id=30 data-nosnippet>30</a>//! based templates. These templates are a great starting point for developers and newcomers.
|
||||
<a href=#31 id=31 data-nosnippet>31</a>//! So far OpenZeppelin has released two templates, which have been fully [audited](https://github.com/pezkuwichain/pezkuwi-runtime-templates/tree/main/audits):
|
||||
<a href=#32 id=32 data-nosnippet>32</a>//! - [`generic-runtime-template`](https://github.com/pezkuwichain/pezkuwi-runtime-templates?tab=readme-ov-file#generic-runtime-template):
|
||||
<a href=#33 id=33 data-nosnippet>33</a>//! A minimal template that has all the common pallets that teyrchains use with secure defaults.
|
||||
<a href=#34 id=34 data-nosnippet>34</a>//! - [`evm-runtime-template`](https://github.com/pezkuwichain/pezkuwi-runtime-templates/tree/main?tab=readme-ov-file#evm-template):
|
||||
<a href=#35 id=35 data-nosnippet>35</a>//! This template has EVM compatibility out of the box and allows migrating your solidity contracts
|
||||
<a href=#36 id=36 data-nosnippet>36</a>//! or EVM compatible dapps easily. It also uses 20 byte addresses like Ethereum and has some
|
||||
<a href=#37 id=37 data-nosnippet>37</a>//! Account Abstraction support.
|
||||
<a href=#38 id=38 data-nosnippet>38</a>//!
|
||||
<a href=#39 id=39 data-nosnippet>39</a>//! ## POP-CLI
|
||||
<a href=#40 id=40 data-nosnippet>40</a>//!
|
||||
<a href=#41 id=41 data-nosnippet>41</a>//! Is a CLI tool capable of scaffolding a new pezkuwi-sdk-based project, possibly removing the
|
||||
<a href=#42 id=42 data-nosnippet>42</a>//! need for templates.
|
||||
<a href=#43 id=43 data-nosnippet>43</a>//!
|
||||
<a href=#44 id=44 data-nosnippet>44</a>//! - <https://pop.r0gue.io/cli/></span></code></pre></div></section></main></body></html>
|
||||
@@ -0,0 +1,70 @@
|
||||
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `docs/sdk/src/pezkuwi_sdk/xcm.rs`."><title>xcm.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2"href="../../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../../../static.files/rustdoc-e56847b5.css"><meta name="rustdoc-vars" data-root-path="../../../" data-static-root-path="../../../static.files/" data-current-crate="pezkuwi_sdk_docs" data-themes="" data-resource-suffix="" data-rustdoc-version="1.91.1 (ed61e7d7e 2025-11-07)" data-channel="1.91.1" data-search-js="search-e256b49e.js" data-stringdex-js="stringdex-c3e638e9.js" data-settings-js="settings-c38705f0.js" ><script src="../../../static.files/storage-e2aeef58.js"></script><script defer src="../../../static.files/src-script-813739b1.js"></script><script defer src="../../../src-files.js"></script><script defer src="../../../static.files/main-6dc2a7f3.js"></script><noscript><link rel="stylesheet" href="../../../static.files/noscript-263c88ec.css"></noscript><link rel="icon" href="https://pezkuwichain.io/favicon.ico"></head><body class="rustdoc src"><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer" title="Drag to resize sidebar"></div><main><section id="main-content" class="content"><div class="main-heading"><h1><div class="sub-heading">pezkuwi_sdk_docs/pezkuwi_sdk/</div>xcm.rs</h1><rustdoc-toolbar></rustdoc-toolbar></div><div class="example-wrap digits-2"><pre class="rust"><code><a href=#1 id=1 data-nosnippet>1</a><span class="doccomment">//! # XCM
|
||||
<a href=#2 id=2 data-nosnippet>2</a>//!
|
||||
<a href=#3 id=3 data-nosnippet>3</a>//! XCM, or Cross-Consensus Messaging, is a **language** to communicate **intentions** between
|
||||
<a href=#4 id=4 data-nosnippet>4</a>//! **consensus systems**.
|
||||
<a href=#5 id=5 data-nosnippet>5</a>//!
|
||||
<a href=#6 id=6 data-nosnippet>6</a>//! ## Overview
|
||||
<a href=#7 id=7 data-nosnippet>7</a>//!
|
||||
<a href=#8 id=8 data-nosnippet>8</a>//! XCM is a standard, specification of which lives in the [xcm format repo](https://github.com/paritytech/xcm-format).
|
||||
<a href=#9 id=9 data-nosnippet>9</a>//! It's agnostic both in programming language and blockchain platform, which means it could be used
|
||||
<a href=#10 id=10 data-nosnippet>10</a>//! in Rust in Pezkuwi, or in Go or C++ in any other platform like Cosmos or Ethereum.
|
||||
<a href=#11 id=11 data-nosnippet>11</a>//!
|
||||
<a href=#12 id=12 data-nosnippet>12</a>//! It enables different consensus systems to communicate with each other in an expressive manner.
|
||||
<a href=#13 id=13 data-nosnippet>13</a>//! Consensus systems include blockchains, smart contracts, and any other state machine that
|
||||
<a href=#14 id=14 data-nosnippet>14</a>//! achieves consensus in some way.
|
||||
<a href=#15 id=15 data-nosnippet>15</a>//!
|
||||
<a href=#16 id=16 data-nosnippet>16</a>//! XCM is executed on a virtual machine called the XCVM.
|
||||
<a href=#17 id=17 data-nosnippet>17</a>//! Scripts can be written with the XCM language, which are often called XCMs, messages or XCM
|
||||
<a href=#18 id=18 data-nosnippet>18</a>//! programs. Each program is a series of instructions, which get executed one after the other by
|
||||
<a href=#19 id=19 data-nosnippet>19</a>//! the virtual machine. These instructions aim to encompass all major things users typically do in
|
||||
<a href=#20 id=20 data-nosnippet>20</a>//! consensus systems. There are instructions on asset transferring, teleporting, locking, among
|
||||
<a href=#21 id=21 data-nosnippet>21</a>//! others. New instructions are added and changes to the XCVM are made via the [RFC process](https://github.com/paritytech/xcm-format/blob/master/proposals/0032-process.md).
|
||||
<a href=#22 id=22 data-nosnippet>22</a>//!
|
||||
<a href=#23 id=23 data-nosnippet>23</a>//! ## In Pezkuwi SDK
|
||||
<a href=#24 id=24 data-nosnippet>24</a>//!
|
||||
<a href=#25 id=25 data-nosnippet>25</a>//! The Pezkuwi SDK allows for easily deploying sovereign blockchains from scratch, all very
|
||||
<a href=#26 id=26 data-nosnippet>26</a>//! customizable. Dealing with many heterogeneous blockchains can be cumbersome.
|
||||
<a href=#27 id=27 data-nosnippet>27</a>//! XCM allows all these blockchains to communicate with an agreed-upon language.
|
||||
<a href=#28 id=28 data-nosnippet>28</a>//! As long as an implementation of the XCVM is implemented, the same XCM program can be executed in
|
||||
<a href=#29 id=29 data-nosnippet>29</a>//! all blockchains and perform the same task.
|
||||
<a href=#30 id=30 data-nosnippet>30</a>//!
|
||||
<a href=#31 id=31 data-nosnippet>31</a>//! ## Implementation
|
||||
<a href=#32 id=32 data-nosnippet>32</a>//!
|
||||
<a href=#33 id=33 data-nosnippet>33</a>//! A ready-to-use Rust implementation lives in the [pezkuwi-sdk repo](https://github.com/pezkuwichain/pezkuwi-sdk/tree/master/pezkuwi/xcm),
|
||||
<a href=#34 id=34 data-nosnippet>34</a>//! but will be moved to its own repo in the future.
|
||||
<a href=#35 id=35 data-nosnippet>35</a>//!
|
||||
<a href=#36 id=36 data-nosnippet>36</a>//! Its main components are:
|
||||
<a href=#37 id=37 data-nosnippet>37</a>//! - [`xcm`](::xcm): The definition of the basic types and instructions.
|
||||
<a href=#38 id=38 data-nosnippet>38</a>//! - [`xcm_executor`]: An implementation of the virtual machine to execute instructions.
|
||||
<a href=#39 id=39 data-nosnippet>39</a>//! - [`pallet_xcm`]: A FRAME pallet for interacting with the executor.
|
||||
<a href=#40 id=40 data-nosnippet>40</a>//! - [`xcm_builder`]: A collection of types to configure the executor.
|
||||
<a href=#41 id=41 data-nosnippet>41</a>//! - [`xcm_simulator`]: A playground for trying out different XCM programs and executor
|
||||
<a href=#42 id=42 data-nosnippet>42</a>//! configurations.
|
||||
<a href=#43 id=43 data-nosnippet>43</a>//!
|
||||
<a href=#44 id=44 data-nosnippet>44</a>//! ## Example
|
||||
<a href=#45 id=45 data-nosnippet>45</a>//!
|
||||
<a href=#46 id=46 data-nosnippet>46</a>//! To perform the very usual operation of transferring assets, the following XCM program can be
|
||||
<a href=#47 id=47 data-nosnippet>47</a>//! used:
|
||||
<a href=#48 id=48 data-nosnippet>48</a></span><span class="attr">#![doc = <span class="macro">docify::embed!</span>(<span class="string">"src/pezkuwi_sdk/xcm.rs"</span>, example_transfer)]
|
||||
<a href=#49 id=49 data-nosnippet>49</a></span><span class="doccomment">//!
|
||||
<a href=#50 id=50 data-nosnippet>50</a>//! ## Get started
|
||||
<a href=#51 id=51 data-nosnippet>51</a>//!
|
||||
<a href=#52 id=52 data-nosnippet>52</a>//! To learn how it works and to get started, go to the [XCM docs](xcm_docs).
|
||||
<a href=#53 id=53 data-nosnippet>53</a>
|
||||
<a href=#54 id=54 data-nosnippet>54</a></span><span class="attr">#[cfg(test)]
|
||||
<a href=#55 id=55 data-nosnippet>55</a></span><span class="kw">mod </span>tests {
|
||||
<a href=#56 id=56 data-nosnippet>56</a> <span class="kw">use </span>xcm::latest::prelude::<span class="kw-2">*</span>;
|
||||
<a href=#57 id=57 data-nosnippet>57</a>
|
||||
<a href=#58 id=58 data-nosnippet>58</a> <span class="attr">#[docify::export]
|
||||
<a href=#59 id=59 data-nosnippet>59</a> #[test]
|
||||
<a href=#60 id=60 data-nosnippet>60</a> </span><span class="kw">fn </span>example_transfer() {
|
||||
<a href=#61 id=61 data-nosnippet>61</a> <span class="kw">let </span>_transfer_program = Xcm::<()>(<span class="macro">vec!</span>[
|
||||
<a href=#62 id=62 data-nosnippet>62</a> WithdrawAsset((Here, <span class="number">100u128</span>).into()),
|
||||
<a href=#63 id=63 data-nosnippet>63</a> BuyExecution { fees: (Here, <span class="number">100u128</span>).into(), weight_limit: Unlimited },
|
||||
<a href=#64 id=64 data-nosnippet>64</a> DepositAsset {
|
||||
<a href=#65 id=65 data-nosnippet>65</a> assets: All.into(),
|
||||
<a href=#66 id=66 data-nosnippet>66</a> beneficiary: AccountId32 { id: [<span class="number">0u8</span>; <span class="number">32</span>].into(), network: <span class="prelude-val">None </span>}.into(),
|
||||
<a href=#67 id=67 data-nosnippet>67</a> },
|
||||
<a href=#68 id=68 data-nosnippet>68</a> ]);
|
||||
<a href=#69 id=69 data-nosnippet>69</a> }
|
||||
<a href=#70 id=70 data-nosnippet>70</a>}</code></pre></div></section></main></body></html>
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `docs/sdk/src/reference_docs/blockchain_state_machines.rs`."><title>blockchain_state_machines.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2"href="../../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../../../static.files/rustdoc-e56847b5.css"><meta name="rustdoc-vars" data-root-path="../../../" data-static-root-path="../../../static.files/" data-current-crate="pezkuwi_sdk_docs" data-themes="" data-resource-suffix="" data-rustdoc-version="1.91.1 (ed61e7d7e 2025-11-07)" data-channel="1.91.1" data-search-js="search-e256b49e.js" data-stringdex-js="stringdex-c3e638e9.js" data-settings-js="settings-c38705f0.js" ><script src="../../../static.files/storage-e2aeef58.js"></script><script defer src="../../../static.files/src-script-813739b1.js"></script><script defer src="../../../src-files.js"></script><script defer src="../../../static.files/main-6dc2a7f3.js"></script><noscript><link rel="stylesheet" href="../../../static.files/noscript-263c88ec.css"></noscript><link rel="icon" href="https://pezkuwichain.io/favicon.ico"></head><body class="rustdoc src"><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer" title="Drag to resize sidebar"></div><main><section id="main-content" class="content"><div class="main-heading"><h1><div class="sub-heading">pezkuwi_sdk_docs/reference_docs/</div>blockchain_state_machines.rs</h1><rustdoc-toolbar></rustdoc-toolbar></div><div class="example-wrap digits-2"><pre class="rust"><code><a href=#1 id=1 data-nosnippet>1</a><span class="doccomment">//! # State Transition Function
|
||||
<a href=#2 id=2 data-nosnippet>2</a>//!
|
||||
<a href=#3 id=3 data-nosnippet>3</a>//! This document briefly explains how in the context of Substrate-based blockchains, we view the
|
||||
<a href=#4 id=4 data-nosnippet>4</a>//! blockchain as a **decentralized state transition function**.
|
||||
<a href=#5 id=5 data-nosnippet>5</a>//!
|
||||
<a href=#6 id=6 data-nosnippet>6</a>//! Recall that a blockchain's main purpose is to help a permissionless set of entities to agree on
|
||||
<a href=#7 id=7 data-nosnippet>7</a>//! a shared data-set, and how it evolves. This is called the **State**, also referred to as
|
||||
<a href=#8 id=8 data-nosnippet>8</a>//! "onchain" data, or *Storage* in the context of FRAME. The state is where the account balance of
|
||||
<a href=#9 id=9 data-nosnippet>9</a>//! each user is, for example, stored, and there is a canonical version of it that everyone agrees
|
||||
<a href=#10 id=10 data-nosnippet>10</a>//! upon.
|
||||
<a href=#11 id=11 data-nosnippet>11</a>//!
|
||||
<a href=#12 id=12 data-nosnippet>12</a>//! Then, recall that a typical blockchain system will alter its state through execution of blocks.
|
||||
<a href=#13 id=13 data-nosnippet>13</a>//! *The component that dictates how this state alteration can happen is called the state transition
|
||||
<a href=#14 id=14 data-nosnippet>14</a>//! function*.
|
||||
<a href=#15 id=15 data-nosnippet>15</a></span><span class="attr">#![doc = <span class="macro">simple_mermaid::mermaid!</span>(<span class="string">"../../../mermaid/stf_simple.mmd"</span>)]
|
||||
<a href=#16 id=16 data-nosnippet>16</a></span><span class="doccomment">//!
|
||||
<a href=#17 id=17 data-nosnippet>17</a>//! In Substrate-based blockchains, the state transition function is called the *Runtime*. This is
|
||||
<a href=#18 id=18 data-nosnippet>18</a>//! explained further in [`crate::reference_docs::wasm_meta_protocol`].
|
||||
<a href=#19 id=19 data-nosnippet>19</a>//!
|
||||
<a href=#20 id=20 data-nosnippet>20</a>//! With this in mind, we can paint a complete picture of a blockchain as a state machine:
|
||||
<a href=#21 id=21 data-nosnippet>21</a></span><span class="attr">#![doc = <span class="macro">simple_mermaid::mermaid!</span>(<span class="string">"../../../mermaid/stf.mmd"</span>)]
|
||||
<a href=#22 id=22 data-nosnippet>22</a></span><span class="doccomment">//!
|
||||
<a href=#23 id=23 data-nosnippet>23</a>//! In essence, the state of the blockchain at block N is the outcome of applying the state
|
||||
<a href=#24 id=24 data-nosnippet>24</a>//! transition function to the previous state, and the current block as input. This can be
|
||||
<a href=#25 id=25 data-nosnippet>25</a>//! mathematically represented as:
|
||||
<a href=#26 id=26 data-nosnippet>26</a>//!
|
||||
<a href=#27 id=27 data-nosnippet>27</a>//! ```math
|
||||
<a href=#28 id=28 data-nosnippet>28</a>//! STF = F(State_N, Block_N) -> State_{N+1}
|
||||
<a href=#29 id=29 data-nosnippet>29</a>//! ```</span></code></pre></div></section></main></body></html>
|
||||
@@ -0,0 +1,200 @@
|
||||
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `docs/sdk/src/reference_docs/chain_spec_genesis.rs`."><title>chain_spec_genesis.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2"href="../../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../../../static.files/rustdoc-e56847b5.css"><meta name="rustdoc-vars" data-root-path="../../../" data-static-root-path="../../../static.files/" data-current-crate="pezkuwi_sdk_docs" data-themes="" data-resource-suffix="" data-rustdoc-version="1.91.1 (ed61e7d7e 2025-11-07)" data-channel="1.91.1" data-search-js="search-e256b49e.js" data-stringdex-js="stringdex-c3e638e9.js" data-settings-js="settings-c38705f0.js" ><script src="../../../static.files/storage-e2aeef58.js"></script><script defer src="../../../static.files/src-script-813739b1.js"></script><script defer src="../../../src-files.js"></script><script defer src="../../../static.files/main-6dc2a7f3.js"></script><noscript><link rel="stylesheet" href="../../../static.files/noscript-263c88ec.css"></noscript><link rel="icon" href="https://pezkuwichain.io/favicon.ico"></head><body class="rustdoc src"><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer" title="Drag to resize sidebar"></div><main><section id="main-content" class="content"><div class="main-heading"><h1><div class="sub-heading">pezkuwi_sdk_docs/reference_docs/</div>chain_spec_genesis.rs</h1><rustdoc-toolbar></rustdoc-toolbar></div><div class="example-wrap digits-3"><pre class="rust"><code><a href=#1 id=1 data-nosnippet>1</a><span class="doccomment">//! # What is a chain specification
|
||||
<a href=#2 id=2 data-nosnippet>2</a>//!
|
||||
<a href=#3 id=3 data-nosnippet>3</a>//! A chain specification file defines the set of properties that are required to run the node as
|
||||
<a href=#4 id=4 data-nosnippet>4</a>//! part of the chain. The chain specification consists of two main parts:
|
||||
<a href=#5 id=5 data-nosnippet>5</a>//! - initial state of the runtime,
|
||||
<a href=#6 id=6 data-nosnippet>6</a>//! - network / logical properties of the chain, the most important property being the list of
|
||||
<a href=#7 id=7 data-nosnippet>7</a>//! bootnodes.
|
||||
<a href=#8 id=8 data-nosnippet>8</a>//!
|
||||
<a href=#9 id=9 data-nosnippet>9</a>//! This document describes how the initial state is handled in pallets and runtime, and how to
|
||||
<a href=#10 id=10 data-nosnippet>10</a>//! interact with the runtime in order to build the genesis state.
|
||||
<a href=#11 id=11 data-nosnippet>11</a>//!
|
||||
<a href=#12 id=12 data-nosnippet>12</a>//! For more information on chain specification and its properties, refer to
|
||||
<a href=#13 id=13 data-nosnippet>13</a>//! [`sc_chain_spec#from-initial-state-to-raw-genesis`].
|
||||
<a href=#14 id=14 data-nosnippet>14</a>//!
|
||||
<a href=#15 id=15 data-nosnippet>15</a>//! The initial genesis state can be provided in the following formats:
|
||||
<a href=#16 id=16 data-nosnippet>16</a>//! - full
|
||||
<a href=#17 id=17 data-nosnippet>17</a>//! - patch
|
||||
<a href=#18 id=18 data-nosnippet>18</a>//! - raw
|
||||
<a href=#19 id=19 data-nosnippet>19</a>//!
|
||||
<a href=#20 id=20 data-nosnippet>20</a>//! Each of the formats is explained in [_chain-spec-format_][`sc_chain_spec#chain-spec-formats`].
|
||||
<a href=#21 id=21 data-nosnippet>21</a>//!
|
||||
<a href=#22 id=22 data-nosnippet>22</a>//!
|
||||
<a href=#23 id=23 data-nosnippet>23</a>//! # `GenesisConfig` for `pallet`
|
||||
<a href=#24 id=24 data-nosnippet>24</a>//!
|
||||
<a href=#25 id=25 data-nosnippet>25</a>//! Every frame pallet may have its initial state which is defined by the `GenesisConfig` internal
|
||||
<a href=#26 id=26 data-nosnippet>26</a>//! struct. It is a regular Rust struct, annotated with the [`pallet::genesis_config`] attribute.
|
||||
<a href=#27 id=27 data-nosnippet>27</a></span><span class="attr">#![doc = <span class="macro">docify::embed!</span>(<span class="string">"./src/reference_docs/chain_spec_runtime/src/pallets.rs"</span>, pallet_bar_GenesisConfig)]
|
||||
<a href=#28 id=28 data-nosnippet>28</a></span><span class="doccomment">//!
|
||||
<a href=#29 id=29 data-nosnippet>29</a>//! The struct shall be defined within the pallet `mod`, as in the following code:
|
||||
<a href=#30 id=30 data-nosnippet>30</a></span><span class="attr">#![doc = <span class="macro">docify::embed!</span>(<span class="string">"./src/reference_docs/chain_spec_runtime/src/pallets.rs"</span>, pallet_bar)]
|
||||
<a href=#31 id=31 data-nosnippet>31</a></span><span class="doccomment">//!
|
||||
<a href=#32 id=32 data-nosnippet>32</a>//! The initial state conveyed in the `GenesisConfig` struct is transformed into state storage
|
||||
<a href=#33 id=33 data-nosnippet>33</a>//! items by means of the [`BuildGenesisConfig`] trait, which shall be implemented for the pallet's
|
||||
<a href=#34 id=34 data-nosnippet>34</a>//! `GenesisConfig` struct. The [`pallet::genesis_build`] attribute shall be attached to the `impl`
|
||||
<a href=#35 id=35 data-nosnippet>35</a>//! block:
|
||||
<a href=#36 id=36 data-nosnippet>36</a></span><span class="attr">#![doc = <span class="macro">docify::embed!</span>(<span class="string">"./src/reference_docs/chain_spec_runtime/src/pallets.rs"</span>, pallet_bar_build)]
|
||||
<a href=#37 id=37 data-nosnippet>37</a></span><span class="doccomment">//!
|
||||
<a href=#38 id=38 data-nosnippet>38</a>//! `GenesisConfig` may also contain more complicated types, including nested structs or enums, as
|
||||
<a href=#39 id=39 data-nosnippet>39</a>//! in the example for `pallet_foo`:
|
||||
<a href=#40 id=40 data-nosnippet>40</a></span><span class="attr">#![doc = <span class="macro">docify::embed!</span>(<span class="string">"./src/reference_docs/chain_spec_runtime/src/pallets.rs"</span>, pallet_foo_GenesisConfig)]
|
||||
<a href=#41 id=41 data-nosnippet>41</a></span><span class="doccomment">//!
|
||||
<a href=#42 id=42 data-nosnippet>42</a>//! Note that [`serde`] attributes can be used to control how the data
|
||||
<a href=#43 id=43 data-nosnippet>43</a>//! structures are stored into JSON. In the following example, the [`sp_core::bytes`] function is
|
||||
<a href=#44 id=44 data-nosnippet>44</a>//! used to serialize the `values` field.
|
||||
<a href=#45 id=45 data-nosnippet>45</a></span><span class="attr">#![doc = <span class="macro">docify::embed!</span>(<span class="string">"./src/reference_docs/chain_spec_runtime/src/pallets.rs"</span>, SomeFooData2)]
|
||||
<a href=#46 id=46 data-nosnippet>46</a></span><span class="doccomment">//!
|
||||
<a href=#47 id=47 data-nosnippet>47</a>//! Please note that fields of `GenesisConfig` may not be directly mapped to storage items. In the
|
||||
<a href=#48 id=48 data-nosnippet>48</a>//! following example, the initial struct fields are used to compute (sum) the value that will be
|
||||
<a href=#49 id=49 data-nosnippet>49</a>//! stored in the state as `ProcessedEnumValue`:
|
||||
<a href=#50 id=50 data-nosnippet>50</a></span><span class="attr">#![doc = <span class="macro">docify::embed!</span>(<span class="string">"./src/reference_docs/chain_spec_runtime/src/pallets.rs"</span>, pallet_foo_build)]
|
||||
<a href=#51 id=51 data-nosnippet>51</a></span><span class="doccomment">//!
|
||||
<a href=#52 id=52 data-nosnippet>52</a>//! # `GenesisConfig` for `runtimes`
|
||||
<a href=#53 id=53 data-nosnippet>53</a>//!
|
||||
<a href=#54 id=54 data-nosnippet>54</a>//! The runtime genesis config struct consists of configs for every pallet. For the [_demonstration
|
||||
<a href=#55 id=55 data-nosnippet>55</a>//! runtime_][`chain_spec_guide_runtime`] used in this guide, it consists of `SystemConfig`,
|
||||
<a href=#56 id=56 data-nosnippet>56</a>//! `BarConfig`, and `FooConfig`. This structure was automatically generated by a macro and it can
|
||||
<a href=#57 id=57 data-nosnippet>57</a>//! be sneak-peeked here: [`RuntimeGenesisConfig`]. For further reading on generated runtime
|
||||
<a href=#58 id=58 data-nosnippet>58</a>//! types, refer to [`frame_runtime_types`].
|
||||
<a href=#59 id=59 data-nosnippet>59</a>//!
|
||||
<a href=#60 id=60 data-nosnippet>60</a>//! The macro automatically adds an attribute that renames all the fields to [`camelCase`]. It is a
|
||||
<a href=#61 id=61 data-nosnippet>61</a>//! good practice to add it to nested structures too, to have the naming of the JSON keys consistent
|
||||
<a href=#62 id=62 data-nosnippet>62</a>//! across the chain-spec file.
|
||||
<a href=#63 id=63 data-nosnippet>63</a>//!
|
||||
<a href=#64 id=64 data-nosnippet>64</a>//! ## `Default` for `GenesisConfig`
|
||||
<a href=#65 id=65 data-nosnippet>65</a>//!
|
||||
<a href=#66 id=66 data-nosnippet>66</a>//! `GenesisConfig` of all pallets must implement the `Default` trait. These are aggregated into
|
||||
<a href=#67 id=67 data-nosnippet>67</a>//! the runtime's `RuntimeGenesisConfig`'s `Default`.
|
||||
<a href=#68 id=68 data-nosnippet>68</a>//!
|
||||
<a href=#69 id=69 data-nosnippet>69</a>//! The default value of `RuntimeGenesisConfig` can be queried by the [`GenesisBuilder::get_preset`]
|
||||
<a href=#70 id=70 data-nosnippet>70</a>//! function provided by the runtime with `id:None`.
|
||||
<a href=#71 id=71 data-nosnippet>71</a>//!
|
||||
<a href=#72 id=72 data-nosnippet>72</a>//! A default value for `RuntimeGenesisConfig` usually is not operational. This is because for some
|
||||
<a href=#73 id=73 data-nosnippet>73</a>//! pallets it is not possible to define good defaults (e.g. an initial set of authorities).
|
||||
<a href=#74 id=74 data-nosnippet>74</a>//!
|
||||
<a href=#75 id=75 data-nosnippet>75</a>//! A default value is a base upon which a patch for `GenesisConfig` is applied. A good description
|
||||
<a href=#76 id=76 data-nosnippet>76</a>//! of how it exactly works is provided in [`get_storage_for_patch`] (and also in
|
||||
<a href=#77 id=77 data-nosnippet>77</a>//! [`GenesisBuilder::get_preset`]). A patch can be provided as an external file (manually created)
|
||||
<a href=#78 id=78 data-nosnippet>78</a>//! or as a built-in runtime preset. More info on presets is in the material to follow.
|
||||
<a href=#79 id=79 data-nosnippet>79</a>//!
|
||||
<a href=#80 id=80 data-nosnippet>80</a>//! ## Implementing `GenesisBuilder` for runtime
|
||||
<a href=#81 id=81 data-nosnippet>81</a>//!
|
||||
<a href=#82 id=82 data-nosnippet>82</a>//! The runtime exposes a dedicated runtime API for interacting with its genesis config:
|
||||
<a href=#83 id=83 data-nosnippet>83</a>//! [`sp_genesis_builder::GenesisBuilder`]. The implementation shall be provided within
|
||||
<a href=#84 id=84 data-nosnippet>84</a>//! the [`sp_api::impl_runtime_apis`] macro, typically making use of some helpers provided:
|
||||
<a href=#85 id=85 data-nosnippet>85</a>//! [`build_state`], [`get_preset`].
|
||||
<a href=#86 id=86 data-nosnippet>86</a>//! A typical implementation of [`sp_genesis_builder::GenesisBuilder`] looks as follows:
|
||||
<a href=#87 id=87 data-nosnippet>87</a></span><span class="attr">#![doc = <span class="macro">docify::embed!</span>(<span class="string">"./src/reference_docs/chain_spec_runtime/src/runtime.rs"</span>, runtime_impl)]
|
||||
<a href=#88 id=88 data-nosnippet>88</a></span><span class="doccomment">//!
|
||||
<a href=#89 id=89 data-nosnippet>89</a>//! Please note that two functions are customized: `preset_names` and `get_preset`. The first one
|
||||
<a href=#90 id=90 data-nosnippet>90</a>//! just provides a `Vec` of the names of supported presets, while the latter delegates the call
|
||||
<a href=#91 id=91 data-nosnippet>91</a>//! to a function that maps the name to an actual preset:
|
||||
<a href=#92 id=92 data-nosnippet>92</a>//! [`chain_spec_guide_runtime::presets::get_builtin_preset`]
|
||||
<a href=#93 id=93 data-nosnippet>93</a></span><span class="attr">#![doc = <span class="macro">docify::embed!</span>(<span class="string">"./src/reference_docs/chain_spec_runtime/src/presets.rs"</span>, get_builtin_preset)]
|
||||
<a href=#94 id=94 data-nosnippet>94</a></span><span class="doccomment">//!
|
||||
<a href=#95 id=95 data-nosnippet>95</a>//! ## Genesis state presets for runtime
|
||||
<a href=#96 id=96 data-nosnippet>96</a>//!
|
||||
<a href=#97 id=97 data-nosnippet>97</a>//! The runtime may provide many flavors of initial genesis state. This may be useful for predefined
|
||||
<a href=#98 id=98 data-nosnippet>98</a>//! testing networks, local development, or CI integration tests. Predefined genesis state may
|
||||
<a href=#99 id=99 data-nosnippet>99</a>//! contain a list of pre-funded accounts, predefined authorities for consensus, sudo key, and many
|
||||
<a href=#100 id=100 data-nosnippet>100</a>//! others useful for testing.
|
||||
<a href=#101 id=101 data-nosnippet>101</a>//!
|
||||
<a href=#102 id=102 data-nosnippet>102</a>//! Internally, presets can be provided in a number of ways:
|
||||
<a href=#103 id=103 data-nosnippet>103</a>//! - using [`build_struct_json_patch`] macro (**recommended**):
|
||||
<a href=#104 id=104 data-nosnippet>104</a></span><span class="attr">#![doc = <span class="macro">docify::embed!</span>(<span class="string">"./src/reference_docs/chain_spec_runtime/src/presets.rs"</span>, preset_2)]
|
||||
<a href=#105 id=105 data-nosnippet>105</a></span><span class="doccomment">//! - JSON using runtime types to serialize values:
|
||||
<a href=#106 id=106 data-nosnippet>106</a></span><span class="attr">#![doc = <span class="macro">docify::embed!</span>(<span class="string">"./src/reference_docs/chain_spec_runtime/src/presets.rs"</span>, preset_3)]
|
||||
<a href=#107 id=107 data-nosnippet>107</a></span><span class="doccomment">//! - JSON in string form:
|
||||
<a href=#108 id=108 data-nosnippet>108</a></span><span class="attr">#![doc = <span class="macro">docify::embed!</span>(<span class="string">"./src/reference_docs/chain_spec_runtime/src/presets.rs"</span>, preset_1)]
|
||||
<a href=#109 id=109 data-nosnippet>109</a></span><span class="doccomment">//!
|
||||
<a href=#110 id=110 data-nosnippet>110</a>//! It is worth noting that a preset does not have to be the full `RuntimeGenesisConfig`, in that
|
||||
<a href=#111 id=111 data-nosnippet>111</a>//! sense that it does not have to contain all the keys of the struct. The preset is actually a JSON
|
||||
<a href=#112 id=112 data-nosnippet>112</a>//! patch that will be merged with the default value of `RuntimeGenesisConfig`. This approach should
|
||||
<a href=#113 id=113 data-nosnippet>113</a>//! simplify maintenance of built-in presets. The following example illustrates a runtime genesis
|
||||
<a href=#114 id=114 data-nosnippet>114</a>//! config patch with a single key built using [`build_struct_json_patch`] macro:
|
||||
<a href=#115 id=115 data-nosnippet>115</a></span><span class="attr">#![doc = <span class="macro">docify::embed!</span>(<span class="string">"./src/reference_docs/chain_spec_runtime/src/presets.rs"</span>, preset_4)]
|
||||
<a href=#116 id=116 data-nosnippet>116</a></span><span class="doccomment">//! This results in the following JSON blob:
|
||||
<a href=#117 id=117 data-nosnippet>117</a></span><span class="attr">#![doc = <span class="macro">docify::embed!</span>(<span class="string">"./src/reference_docs/chain_spec_runtime/tests/chain_spec_builder_tests.rs"</span>, preset_4_json)]
|
||||
<a href=#118 id=118 data-nosnippet>118</a></span><span class="doccomment">//!
|
||||
<a href=#119 id=119 data-nosnippet>119</a>//!
|
||||
<a href=#120 id=120 data-nosnippet>120</a>//! ## Note on the importance of testing presets
|
||||
<a href=#121 id=121 data-nosnippet>121</a>//!
|
||||
<a href=#122 id=122 data-nosnippet>122</a>//! It is recommended to always test presets by adding tests that convert the preset into the
|
||||
<a href=#123 id=123 data-nosnippet>123</a>//! raw storage. Converting to raw storage involves the deserialization of the provided JSON blob,
|
||||
<a href=#124 id=124 data-nosnippet>124</a>//! which enforces the verification of the preset. The following code shows one of the approaches
|
||||
<a href=#125 id=125 data-nosnippet>125</a>//! that can be taken for testing:
|
||||
<a href=#126 id=126 data-nosnippet>126</a></span><span class="attr">#![doc = <span class="macro">docify::embed!</span>(<span class="string">"./src/reference_docs/chain_spec_runtime/src/presets.rs"</span>, check_presets)]
|
||||
<a href=#127 id=127 data-nosnippet>127</a></span><span class="doccomment">//!
|
||||
<a href=#128 id=128 data-nosnippet>128</a>//! ## Note on the importance of using the `deny_unknown_fields` attribute
|
||||
<a href=#129 id=129 data-nosnippet>129</a>//!
|
||||
<a href=#130 id=130 data-nosnippet>130</a>//! It is worth noting that when manually building preset JSON blobs it is easy to make a
|
||||
<a href=#131 id=131 data-nosnippet>131</a>//! hard-to-spot mistake, as in the following example ([`FooStruct`] does not contain `fieldC`):
|
||||
<a href=#132 id=132 data-nosnippet>132</a></span><span class="attr">#![doc = <span class="macro">docify::embed!</span>(<span class="string">"./src/reference_docs/chain_spec_runtime/src/presets.rs"</span>, preset_invalid)]
|
||||
<a href=#133 id=133 data-nosnippet>133</a></span><span class="doccomment">//! Even though `preset_invalid` contains a key that does not exist, the deserialization of the JSON
|
||||
<a href=#134 id=134 data-nosnippet>134</a>//! blob does not fail. The misspelling is silently ignored due to the lack of the
|
||||
<a href=#135 id=135 data-nosnippet>135</a>//! [`deny_unknown_fields`] attribute on the [`FooStruct`] struct, which is internally used in
|
||||
<a href=#136 id=136 data-nosnippet>136</a>//! `GenesisConfig`.
|
||||
<a href=#137 id=137 data-nosnippet>137</a></span><span class="attr">#![doc = <span class="macro">docify::embed!</span>(<span class="string">"./src/reference_docs/chain_spec_runtime/src/presets.rs"</span>, invalid_preset_works)]
|
||||
<a href=#138 id=138 data-nosnippet>138</a></span><span class="doccomment">//!
|
||||
<a href=#139 id=139 data-nosnippet>139</a>//! To avoid this problem [`build_struct_json_patch`] macro shall be used whenever possible (it
|
||||
<a href=#140 id=140 data-nosnippet>140</a>//! internally instantiates the struct before serializang it JSON blob, so all unknown fields shall
|
||||
<a href=#141 id=141 data-nosnippet>141</a>//! be caught at compilation time).
|
||||
<a href=#142 id=142 data-nosnippet>142</a>//!
|
||||
<a href=#143 id=143 data-nosnippet>143</a>//! ## Runtime `GenesisConfig` raw format
|
||||
<a href=#144 id=144 data-nosnippet>144</a>//!
|
||||
<a href=#145 id=145 data-nosnippet>145</a>//! A raw format of genesis config contains just the state's keys and values as they are stored in
|
||||
<a href=#146 id=146 data-nosnippet>146</a>//! the storage. This format is used to directly initialize the genesis storage. This format is
|
||||
<a href=#147 id=147 data-nosnippet>147</a>//! useful for long-term running chains, where the `GenesisConfig` structure for pallets may be
|
||||
<a href=#148 id=148 data-nosnippet>148</a>//! evolving over time. The JSON representation created at some point in time may no longer be
|
||||
<a href=#149 id=149 data-nosnippet>149</a>//! deserializable in the future, making a chain specification useless. The raw format is
|
||||
<a href=#150 id=150 data-nosnippet>150</a>//! recommended for production chains.
|
||||
<a href=#151 id=151 data-nosnippet>151</a>//!
|
||||
<a href=#152 id=152 data-nosnippet>152</a>//! For a detailed description of how the raw format is built, please refer to
|
||||
<a href=#153 id=153 data-nosnippet>153</a>//! [_chain-spec-raw-genesis_][`sc_chain_spec#from-initial-state-to-raw-genesis`]. Plain and
|
||||
<a href=#154 id=154 data-nosnippet>154</a>//! corresponding raw examples of chain-spec are given in
|
||||
<a href=#155 id=155 data-nosnippet>155</a>//! [_chain-spec-examples_][`sc_chain_spec#json-chain-specification-example`].
|
||||
<a href=#156 id=156 data-nosnippet>156</a>//! The [`chain_spec_builder`] util supports building the raw storage.
|
||||
<a href=#157 id=157 data-nosnippet>157</a>//!
|
||||
<a href=#158 id=158 data-nosnippet>158</a>//! # Interacting with the tool
|
||||
<a href=#159 id=159 data-nosnippet>159</a>//!
|
||||
<a href=#160 id=160 data-nosnippet>160</a>//! The [`chain_spec_builder`] util allows interaction with the runtime in order to list or display
|
||||
<a href=#161 id=161 data-nosnippet>161</a>//! presets and build the chain specification file. It is possible to use the tool with the
|
||||
<a href=#162 id=162 data-nosnippet>162</a>//! [_demonstration runtime_][`chain_spec_guide_runtime`]. To build the required packages, just run
|
||||
<a href=#163 id=163 data-nosnippet>163</a>//! the following command:
|
||||
<a href=#164 id=164 data-nosnippet>164</a>//!
|
||||
<a href=#165 id=165 data-nosnippet>165</a>//! ```ignore
|
||||
<a href=#166 id=166 data-nosnippet>166</a>//! cargo build -p staging-chain-spec-builder -p chain-spec-guide-runtime --release
|
||||
<a href=#167 id=167 data-nosnippet>167</a>//! ```
|
||||
<a href=#168 id=168 data-nosnippet>168</a>//!
|
||||
<a href=#169 id=169 data-nosnippet>169</a>//! The `chain-spec-builder` util can also be installed with `cargo install`:
|
||||
<a href=#170 id=170 data-nosnippet>170</a>//!
|
||||
<a href=#171 id=171 data-nosnippet>171</a>//! ```ignore
|
||||
<a href=#172 id=172 data-nosnippet>172</a>//! cargo install staging-chain-spec-builder
|
||||
<a href=#173 id=173 data-nosnippet>173</a>//! cargo build -p chain-spec-guide-runtime --release
|
||||
<a href=#174 id=174 data-nosnippet>174</a>//! ```
|
||||
<a href=#175 id=175 data-nosnippet>175</a>//! Here are some examples in the form of rust tests:
|
||||
<a href=#176 id=176 data-nosnippet>176</a>//! ## Listing available preset names:
|
||||
<a href=#177 id=177 data-nosnippet>177</a></span><span class="attr">#![doc = <span class="macro">docify::embed!</span>(<span class="string">"./src/reference_docs/chain_spec_runtime/tests/chain_spec_builder_tests.rs"</span>, cmd_list_presets)]
|
||||
<a href=#178 id=178 data-nosnippet>178</a></span><span class="doccomment">//! ## Displaying preset with given name
|
||||
<a href=#179 id=179 data-nosnippet>179</a></span><span class="attr">#![doc = <span class="macro">docify::embed!</span>(<span class="string">"./src/reference_docs/chain_spec_runtime/tests/chain_spec_builder_tests.rs"</span>, cmd_get_preset)]
|
||||
<a href=#180 id=180 data-nosnippet>180</a></span><span class="doccomment">//! ## Building a solo chain-spec (the default) using given preset
|
||||
<a href=#181 id=181 data-nosnippet>181</a></span><span class="attr">#![doc = <span class="macro">docify::embed!</span>(<span class="string">"./src/reference_docs/chain_spec_runtime/tests/chain_spec_builder_tests.rs"</span>, cmd_generate_chain_spec)]
|
||||
<a href=#182 id=182 data-nosnippet>182</a></span><span class="doccomment">//! ## Building a teyrchain chain-spec using given preset
|
||||
<a href=#183 id=183 data-nosnippet>183</a></span><span class="attr">#![doc = <span class="macro">docify::embed!</span>(<span class="string">"./src/reference_docs/chain_spec_runtime/tests/chain_spec_builder_tests.rs"</span>, cmd_generate_para_chain_spec)]
|
||||
<a href=#184 id=184 data-nosnippet>184</a></span><span class="doccomment">//!
|
||||
<a href=#185 id=185 data-nosnippet>185</a>//! [`RuntimeGenesisConfig`]:
|
||||
<a href=#186 id=186 data-nosnippet>186</a>//! chain_spec_guide_runtime::runtime::RuntimeGenesisConfig
|
||||
<a href=#187 id=187 data-nosnippet>187</a>//! [`FooStruct`]:
|
||||
<a href=#188 id=188 data-nosnippet>188</a>//! chain_spec_guide_runtime::pallets::FooStruct
|
||||
<a href=#189 id=189 data-nosnippet>189</a>//! [`impl_runtime_apis`]: frame::runtime::prelude::impl_runtime_apis
|
||||
<a href=#190 id=190 data-nosnippet>190</a>//! [`build_state`]: frame_support::genesis_builder_helper::build_state
|
||||
<a href=#191 id=191 data-nosnippet>191</a>//! [`get_preset`]: frame_support::genesis_builder_helper::get_preset
|
||||
<a href=#192 id=192 data-nosnippet>192</a>//! [`pallet::genesis_build`]: frame_support::pallet_macros::genesis_build
|
||||
<a href=#193 id=193 data-nosnippet>193</a>//! [`pallet::genesis_config`]: frame_support::pallet_macros::genesis_config
|
||||
<a href=#194 id=194 data-nosnippet>194</a>//! [`build_struct_json_patch`]: frame_support::build_struct_json_patch
|
||||
<a href=#195 id=195 data-nosnippet>195</a>//! [`BuildGenesisConfig`]: frame_support::traits::BuildGenesisConfig
|
||||
<a href=#196 id=196 data-nosnippet>196</a>//! [`serde`]: https://serde.rs/field-attrs.html
|
||||
<a href=#197 id=197 data-nosnippet>197</a>//! [`get_storage_for_patch`]: sc_chain_spec::GenesisConfigBuilderRuntimeCaller::get_storage_for_patch
|
||||
<a href=#198 id=198 data-nosnippet>198</a>//! [`GenesisBuilder::get_preset`]: sp_genesis_builder::GenesisBuilder::get_preset
|
||||
<a href=#199 id=199 data-nosnippet>199</a>//! [`deny_unknown_fields`]: https://serde.rs/container-attrs.html#deny_unknown_fields
|
||||
<a href=#200 id=200 data-nosnippet>200</a>//! [`camelCase`]: https://serde.rs/container-attrs.html#rename_all</span></code></pre></div></section></main></body></html>
|
||||
@@ -0,0 +1,104 @@
|
||||
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `docs/sdk/src/reference_docs/cli.rs`."><title>cli.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2"href="../../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../../../static.files/rustdoc-e56847b5.css"><meta name="rustdoc-vars" data-root-path="../../../" data-static-root-path="../../../static.files/" data-current-crate="pezkuwi_sdk_docs" data-themes="" data-resource-suffix="" data-rustdoc-version="1.91.1 (ed61e7d7e 2025-11-07)" data-channel="1.91.1" data-search-js="search-e256b49e.js" data-stringdex-js="stringdex-c3e638e9.js" data-settings-js="settings-c38705f0.js" ><script src="../../../static.files/storage-e2aeef58.js"></script><script defer src="../../../static.files/src-script-813739b1.js"></script><script defer src="../../../src-files.js"></script><script defer src="../../../static.files/main-6dc2a7f3.js"></script><noscript><link rel="stylesheet" href="../../../static.files/noscript-263c88ec.css"></noscript><link rel="icon" href="https://pezkuwichain.io/favicon.ico"></head><body class="rustdoc src"><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer" title="Drag to resize sidebar"></div><main><section id="main-content" class="content"><div class="main-heading"><h1><div class="sub-heading">pezkuwi_sdk_docs/reference_docs/</div>cli.rs</h1><rustdoc-toolbar></rustdoc-toolbar></div><div class="example-wrap digits-3"><pre class="rust"><code><a href=#1 id=1 data-nosnippet>1</a><span class="doccomment">//! # Substrate CLI
|
||||
<a href=#2 id=2 data-nosnippet>2</a>//!
|
||||
<a href=#3 id=3 data-nosnippet>3</a>//! Let's see some examples of typical CLI arguments used when setting up and running a
|
||||
<a href=#4 id=4 data-nosnippet>4</a>//! Substrate-based blockchain. We use the [`solochain-template`](https://github.com/pezkuwichain/pezkuwi-sdk/issues/25)
|
||||
<a href=#5 id=5 data-nosnippet>5</a>//! on these examples.
|
||||
<a href=#6 id=6 data-nosnippet>6</a>//!
|
||||
<a href=#7 id=7 data-nosnippet>7</a>//! #### Checking the available CLI arguments
|
||||
<a href=#8 id=8 data-nosnippet>8</a>//! ```bash
|
||||
<a href=#9 id=9 data-nosnippet>9</a>//! ./target/debug/node-template --help
|
||||
<a href=#10 id=10 data-nosnippet>10</a>//! ```
|
||||
<a href=#11 id=11 data-nosnippet>11</a>//! - `--help`: Displays the available CLI arguments.
|
||||
<a href=#12 id=12 data-nosnippet>12</a>//!
|
||||
<a href=#13 id=13 data-nosnippet>13</a>//! #### Starting a Local Substrate Node in Development Mode
|
||||
<a href=#14 id=14 data-nosnippet>14</a>//! ```bash
|
||||
<a href=#15 id=15 data-nosnippet>15</a>//! ./target/release/node-template \
|
||||
<a href=#16 id=16 data-nosnippet>16</a>//! --dev
|
||||
<a href=#17 id=17 data-nosnippet>17</a>//! ```
|
||||
<a href=#18 id=18 data-nosnippet>18</a>//! - `--dev`: Runs the node in development mode, using a pre-defined development chain
|
||||
<a href=#19 id=19 data-nosnippet>19</a>//! specification.
|
||||
<a href=#20 id=20 data-nosnippet>20</a>//! This mode ensures a fresh state by deleting existing data on restart.
|
||||
<a href=#21 id=21 data-nosnippet>21</a>//!
|
||||
<a href=#22 id=22 data-nosnippet>22</a>//! #### Generating Custom Chain Specification
|
||||
<a href=#23 id=23 data-nosnippet>23</a>//! ```bash
|
||||
<a href=#24 id=24 data-nosnippet>24</a>//! ./target/debug/node-template \
|
||||
<a href=#25 id=25 data-nosnippet>25</a>//! build-spec \
|
||||
<a href=#26 id=26 data-nosnippet>26</a>//! --disable-default-bootnode \
|
||||
<a href=#27 id=27 data-nosnippet>27</a>//! --chain local \
|
||||
<a href=#28 id=28 data-nosnippet>28</a>//! > customSpec.json
|
||||
<a href=#29 id=29 data-nosnippet>29</a>//! ```
|
||||
<a href=#30 id=30 data-nosnippet>30</a>//!
|
||||
<a href=#31 id=31 data-nosnippet>31</a>//! - `build-spec`: A subcommand to generate a chain specification file.
|
||||
<a href=#32 id=32 data-nosnippet>32</a>//! - `--disable-default-bootnode`: Disables the default bootnodes in the node template.
|
||||
<a href=#33 id=33 data-nosnippet>33</a>//! - `--chain local`: Indicates the chain specification is for a local development chain.
|
||||
<a href=#34 id=34 data-nosnippet>34</a>//! - `> customSpec.json`: Redirects the output into a customSpec.json file.
|
||||
<a href=#35 id=35 data-nosnippet>35</a>//!
|
||||
<a href=#36 id=36 data-nosnippet>36</a>//! #### Converting Chain Specification to Raw Format
|
||||
<a href=#37 id=37 data-nosnippet>37</a>//! ```bash
|
||||
<a href=#38 id=38 data-nosnippet>38</a>//! ./target/debug/node-template build-spec \
|
||||
<a href=#39 id=39 data-nosnippet>39</a>//! --chain=customSpec.json \
|
||||
<a href=#40 id=40 data-nosnippet>40</a>//! --raw \
|
||||
<a href=#41 id=41 data-nosnippet>41</a>//! --disable-default-bootnode \
|
||||
<a href=#42 id=42 data-nosnippet>42</a>//! > customSpecRaw.json
|
||||
<a href=#43 id=43 data-nosnippet>43</a>//! ```
|
||||
<a href=#44 id=44 data-nosnippet>44</a>//!
|
||||
<a href=#45 id=45 data-nosnippet>45</a>//! - `--chain=customSpec.json`: Uses the custom chain specification as input.
|
||||
<a href=#46 id=46 data-nosnippet>46</a>//! - `--disable-default-bootnode`: Disables the default bootnodes in the node template.
|
||||
<a href=#47 id=47 data-nosnippet>47</a>//! - `--raw`: Converts the chain specification into a raw format with encoded storage keys.
|
||||
<a href=#48 id=48 data-nosnippet>48</a>//! - `> customSpecRaw.json`: Outputs to `customSpecRaw.json`.
|
||||
<a href=#49 id=49 data-nosnippet>49</a>//!
|
||||
<a href=#50 id=50 data-nosnippet>50</a>//! #### Starting the First Node in a Private Network
|
||||
<a href=#51 id=51 data-nosnippet>51</a>//! ```bash
|
||||
<a href=#52 id=52 data-nosnippet>52</a>//! ./target/debug/node-template \
|
||||
<a href=#53 id=53 data-nosnippet>53</a>//! --base-path /tmp/node01 \
|
||||
<a href=#54 id=54 data-nosnippet>54</a>//! --chain ./customSpecRaw.json \
|
||||
<a href=#55 id=55 data-nosnippet>55</a>//! --port 30333 \
|
||||
<a href=#56 id=56 data-nosnippet>56</a>//! --ws-port 9945 \
|
||||
<a href=#57 id=57 data-nosnippet>57</a>//! --rpc-port 9933 \
|
||||
<a href=#58 id=58 data-nosnippet>58</a>//! --telemetry-url "wss://telemetry.pezkuwichain.io/submit/ 0" \
|
||||
<a href=#59 id=59 data-nosnippet>59</a>//! --validator \
|
||||
<a href=#60 id=60 data-nosnippet>60</a>//! --rpc-methods Unsafe \
|
||||
<a href=#61 id=61 data-nosnippet>61</a>//! --name MyNode01
|
||||
<a href=#62 id=62 data-nosnippet>62</a>//! ```
|
||||
<a href=#63 id=63 data-nosnippet>63</a>//!
|
||||
<a href=#64 id=64 data-nosnippet>64</a>//! - `--base-path`: Sets the directory for node data.
|
||||
<a href=#65 id=65 data-nosnippet>65</a>//! - `--chain`: Specifies the chain specification file.
|
||||
<a href=#66 id=66 data-nosnippet>66</a>//! - `--port`: TCP port for peer-to-peer communication.
|
||||
<a href=#67 id=67 data-nosnippet>67</a>//! - `--ws-port`: WebSocket port for RPC.
|
||||
<a href=#68 id=68 data-nosnippet>68</a>//! - `--rpc-port`: HTTP port for JSON-RPC.
|
||||
<a href=#69 id=69 data-nosnippet>69</a>//! - `--telemetry-url`: Endpoint for sending telemetry data.
|
||||
<a href=#70 id=70 data-nosnippet>70</a>//! - `--validator`: Indicates the node’s participation in block production.
|
||||
<a href=#71 id=71 data-nosnippet>71</a>//! - `--rpc-methods Unsafe`: Allows potentially unsafe RPC methods.
|
||||
<a href=#72 id=72 data-nosnippet>72</a>//! - `--name`: Sets a human-readable name for the node.
|
||||
<a href=#73 id=73 data-nosnippet>73</a>//!
|
||||
<a href=#74 id=74 data-nosnippet>74</a>//! #### Adding a Second Node to the Network
|
||||
<a href=#75 id=75 data-nosnippet>75</a>//! ```bash
|
||||
<a href=#76 id=76 data-nosnippet>76</a>//! ./target/release/node-template \
|
||||
<a href=#77 id=77 data-nosnippet>77</a>//! --base-path /tmp/bob \
|
||||
<a href=#78 id=78 data-nosnippet>78</a>//! --chain local \
|
||||
<a href=#79 id=79 data-nosnippet>79</a>//! --bob \
|
||||
<a href=#80 id=80 data-nosnippet>80</a>//! --port 30334 \
|
||||
<a href=#81 id=81 data-nosnippet>81</a>//! --rpc-port 9946 \
|
||||
<a href=#82 id=82 data-nosnippet>82</a>//! --telemetry-url "wss://telemetry.pezkuwichain.io/submit/ 0" \
|
||||
<a href=#83 id=83 data-nosnippet>83</a>//! --validator \
|
||||
<a href=#84 id=84 data-nosnippet>84</a>//! --bootnodes /ip4/127.0.0.1/tcp/30333/p2p/12D3KooWEyoppNCUx8Yx66oV9fJnriXwCcXwDDUA2kj6vnc6iDEp
|
||||
<a href=#85 id=85 data-nosnippet>85</a>//! ```
|
||||
<a href=#86 id=86 data-nosnippet>86</a>//!
|
||||
<a href=#87 id=87 data-nosnippet>87</a>//! - `--base-path`: Sets the directory for node data.
|
||||
<a href=#88 id=88 data-nosnippet>88</a>//! - `--chain`: Specifies the chain specification file.
|
||||
<a href=#89 id=89 data-nosnippet>89</a>//! - `--bob`: Initializes the node with the session keys of the "Bob" account.
|
||||
<a href=#90 id=90 data-nosnippet>90</a>//! - `--port`: TCP port for peer-to-peer communication.
|
||||
<a href=#91 id=91 data-nosnippet>91</a>//! - `--rpc-port`: HTTP port for JSON-RPC.
|
||||
<a href=#92 id=92 data-nosnippet>92</a>//! - `--telemetry-url`: Endpoint for sending telemetry data.
|
||||
<a href=#93 id=93 data-nosnippet>93</a>//! - `--validator`: Indicates the node’s participation in block production.
|
||||
<a href=#94 id=94 data-nosnippet>94</a>//! - `--bootnodes`: Specifies the address of the first node for peer discovery. Nodes should find
|
||||
<a href=#95 id=95 data-nosnippet>95</a>//! each other using mDNS. This command needs to be used if they don't find each other.
|
||||
<a href=#96 id=96 data-nosnippet>96</a>//!
|
||||
<a href=#97 id=97 data-nosnippet>97</a>//! ---
|
||||
<a href=#98 id=98 data-nosnippet>98</a>//!
|
||||
<a href=#99 id=99 data-nosnippet>99</a>//! > If you are interested in learning how to extend the CLI with your custom arguments, you can
|
||||
<a href=#100 id=100 data-nosnippet>100</a>//! > check out the [Customize your Substrate chain CLI](https://www.youtube.com/watch?v=IVifko1fqjw)
|
||||
<a href=#101 id=101 data-nosnippet>101</a>//! > seminar.
|
||||
<a href=#102 id=102 data-nosnippet>102</a>//! > Please note that the seminar is based on an older version of Substrate, and [Clap](https://docs.rs/clap/latest/clap/)
|
||||
<a href=#103 id=103 data-nosnippet>103</a>//! > is now used instead of [StructOpt](https://docs.rs/structopt/latest/structopt/) for parsing
|
||||
<a href=#104 id=104 data-nosnippet>104</a>//! > CLI arguments.</span></code></pre></div></section></main></body></html>
|
||||
@@ -0,0 +1,27 @@
|
||||
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `docs/sdk/src/reference_docs/custom_host_functions.rs`."><title>custom_host_functions.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2"href="../../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../../../static.files/rustdoc-e56847b5.css"><meta name="rustdoc-vars" data-root-path="../../../" data-static-root-path="../../../static.files/" data-current-crate="pezkuwi_sdk_docs" data-themes="" data-resource-suffix="" data-rustdoc-version="1.91.1 (ed61e7d7e 2025-11-07)" data-channel="1.91.1" data-search-js="search-e256b49e.js" data-stringdex-js="stringdex-c3e638e9.js" data-settings-js="settings-c38705f0.js" ><script src="../../../static.files/storage-e2aeef58.js"></script><script defer src="../../../static.files/src-script-813739b1.js"></script><script defer src="../../../src-files.js"></script><script defer src="../../../static.files/main-6dc2a7f3.js"></script><noscript><link rel="stylesheet" href="../../../static.files/noscript-263c88ec.css"></noscript><link rel="icon" href="https://pezkuwichain.io/favicon.ico"></head><body class="rustdoc src"><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer" title="Drag to resize sidebar"></div><main><section id="main-content" class="content"><div class="main-heading"><h1><div class="sub-heading">pezkuwi_sdk_docs/reference_docs/</div>custom_host_functions.rs</h1><rustdoc-toolbar></rustdoc-toolbar></div><div class="example-wrap digits-2"><pre class="rust"><code><a href=#1 id=1 data-nosnippet>1</a><span class="doccomment">//! # Custom Host Functions
|
||||
<a href=#2 id=2 data-nosnippet>2</a>//!
|
||||
<a href=#3 id=3 data-nosnippet>3</a>//! Host functions are functions that the wasm instance can use to communicate with the node. Learn
|
||||
<a href=#4 id=4 data-nosnippet>4</a>//! more about this in [`crate::reference_docs::wasm_meta_protocol`].
|
||||
<a href=#5 id=5 data-nosnippet>5</a>//!
|
||||
<a href=#6 id=6 data-nosnippet>6</a>//! ## Finding Host Functions
|
||||
<a href=#7 id=7 data-nosnippet>7</a>//!
|
||||
<a href=#8 id=8 data-nosnippet>8</a>//! To declare a set of functions as host functions, you need to use the `#[runtime_interface]`
|
||||
<a href=#9 id=9 data-nosnippet>9</a>//! ([`sp_runtime_interface`]) attribute macro. The most notable set of host functions are those
|
||||
<a href=#10 id=10 data-nosnippet>10</a>//! that allow the runtime to access the chain state, namely [`sp_io::storage`]. Some other notable
|
||||
<a href=#11 id=11 data-nosnippet>11</a>//! host functions are also defined in [`sp_io`].
|
||||
<a href=#12 id=12 data-nosnippet>12</a>//!
|
||||
<a href=#13 id=13 data-nosnippet>13</a>//! ## Adding New Host Functions
|
||||
<a href=#14 id=14 data-nosnippet>14</a>//!
|
||||
<a href=#15 id=15 data-nosnippet>15</a>//! > Adding a new host function is a big commitment and should be done with care. Namely, the nodes
|
||||
<a href=#16 id=16 data-nosnippet>16</a>//! > in the network need to support all host functions forever in order to be able to sync
|
||||
<a href=#17 id=17 data-nosnippet>17</a>//! > historical blocks.
|
||||
<a href=#18 id=18 data-nosnippet>18</a>//!
|
||||
<a href=#19 id=19 data-nosnippet>19</a>//! Adding host functions is only possible when you are using a node-template, so that you have
|
||||
<a href=#20 id=20 data-nosnippet>20</a>//! access to the boilerplate of building your node.
|
||||
<a href=#21 id=21 data-nosnippet>21</a>//!
|
||||
<a href=#22 id=22 data-nosnippet>22</a>//! A group of host functions can always be grouped to gether as a tuple:
|
||||
<a href=#23 id=23 data-nosnippet>23</a></span><span class="attr">#![doc = <span class="macro">docify::embed!</span>(<span class="string">"../../substrate/primitives/io/src/lib.rs"</span>, SubstrateHostFunctions)]
|
||||
<a href=#24 id=24 data-nosnippet>24</a></span><span class="doccomment">//!
|
||||
<a href=#25 id=25 data-nosnippet>25</a>//! The host functions are attached to the node side's [`sc_executor::WasmExecutor`]. For example in
|
||||
<a href=#26 id=26 data-nosnippet>26</a>//! the minimal template, the setup looks as follows:
|
||||
<a href=#27 id=27 data-nosnippet>27</a></span><span class="attr">#![doc = <span class="macro">docify::embed!</span>(<span class="string">"../../templates/minimal/node/src/service.rs"</span>, FullClient)]</span></code></pre></div></section></main></body></html>
|
||||
+77
@@ -0,0 +1,77 @@
|
||||
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `docs/sdk/src/reference_docs/custom_runtime_api_rpc.rs`."><title>custom_runtime_api_rpc.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2"href="../../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../../../static.files/rustdoc-e56847b5.css"><meta name="rustdoc-vars" data-root-path="../../../" data-static-root-path="../../../static.files/" data-current-crate="pezkuwi_sdk_docs" data-themes="" data-resource-suffix="" data-rustdoc-version="1.91.1 (ed61e7d7e 2025-11-07)" data-channel="1.91.1" data-search-js="search-e256b49e.js" data-stringdex-js="stringdex-c3e638e9.js" data-settings-js="settings-c38705f0.js" ><script src="../../../static.files/storage-e2aeef58.js"></script><script defer src="../../../static.files/src-script-813739b1.js"></script><script defer src="../../../src-files.js"></script><script defer src="../../../static.files/main-6dc2a7f3.js"></script><noscript><link rel="stylesheet" href="../../../static.files/noscript-263c88ec.css"></noscript><link rel="icon" href="https://pezkuwichain.io/favicon.ico"></head><body class="rustdoc src"><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer" title="Drag to resize sidebar"></div><main><section id="main-content" class="content"><div class="main-heading"><h1><div class="sub-heading">pezkuwi_sdk_docs/reference_docs/</div>custom_runtime_api_rpc.rs</h1><rustdoc-toolbar></rustdoc-toolbar></div><div class="example-wrap digits-2"><pre class="rust"><code><a href=#1 id=1 data-nosnippet>1</a><span class="doccomment">//! # Custom RPC do's and don'ts
|
||||
<a href=#2 id=2 data-nosnippet>2</a>//!
|
||||
<a href=#3 id=3 data-nosnippet>3</a>//! **TLDR:** Don't create new custom RPCs. Instead, rely on custom Runtime APIs, combined with
|
||||
<a href=#4 id=4 data-nosnippet>4</a>//! `state_call`.
|
||||
<a href=#5 id=5 data-nosnippet>5</a>//!
|
||||
<a href=#6 id=6 data-nosnippet>6</a>//! ## Background
|
||||
<a href=#7 id=7 data-nosnippet>7</a>//!
|
||||
<a href=#8 id=8 data-nosnippet>8</a>//! Pezkuwi-SDK offers the ability to query and subscribe storages directly. However what it does
|
||||
<a href=#9 id=9 data-nosnippet>9</a>//! not have is [view functions](https://github.com/pezkuwichain/pezkuwi-sdk/issues/101). This is an
|
||||
<a href=#10 id=10 data-nosnippet>10</a>//! essential feature to avoid duplicated logic between runtime and the client SDK. Custom RPC was
|
||||
<a href=#11 id=11 data-nosnippet>11</a>//! used as a solution. It allow the RPC node to expose new RPCs that clients can be used to query
|
||||
<a href=#12 id=12 data-nosnippet>12</a>//! computed properties.
|
||||
<a href=#13 id=13 data-nosnippet>13</a>//!
|
||||
<a href=#14 id=14 data-nosnippet>14</a>//! ## Problems with Custom RPC
|
||||
<a href=#15 id=15 data-nosnippet>15</a>//!
|
||||
<a href=#16 id=16 data-nosnippet>16</a>//! Unfortunately, custom RPC comes with many problems. To list a few:
|
||||
<a href=#17 id=17 data-nosnippet>17</a>//!
|
||||
<a href=#18 id=18 data-nosnippet>18</a>//! - It is offchain logic executed by the RPC node and therefore the client has to trust the RPC
|
||||
<a href=#19 id=19 data-nosnippet>19</a>//! node.
|
||||
<a href=#20 id=20 data-nosnippet>20</a>//! - To upgrade or add a new RPC logic, the RPC node has to be upgraded. This can cause significant
|
||||
<a href=#21 id=21 data-nosnippet>21</a>//! trouble when the RPC infrastructure is decentralized as we will need to coordinate multiple
|
||||
<a href=#22 id=22 data-nosnippet>22</a>//! parties to upgrade the RPC nodes.
|
||||
<a href=#23 id=23 data-nosnippet>23</a>//! - A lot of boilerplate code is required to add custom RPC.
|
||||
<a href=#24 id=24 data-nosnippet>24</a>//! - It prevents dApps from using a light client or an alternative client.
|
||||
<a href=#25 id=25 data-nosnippet>25</a>//! - It makes ecosystem tooling integration much more complicated. For example, dApps will not
|
||||
<a href=#26 id=26 data-nosnippet>26</a>//! be able to use [Chopsticks](https://github.com/AcalaNetwork/chopsticks) for testing as
|
||||
<a href=#27 id=27 data-nosnippet>27</a>//! Chopsticks will not have the custom RPC implementation.
|
||||
<a href=#28 id=28 data-nosnippet>28</a>//! - Poorly implemented custom RPC can be a DoS vector.
|
||||
<a href=#29 id=29 data-nosnippet>29</a>//!
|
||||
<a href=#30 id=30 data-nosnippet>30</a>//! Hence, we should avoid custom RPC.
|
||||
<a href=#31 id=31 data-nosnippet>31</a>//!
|
||||
<a href=#32 id=32 data-nosnippet>32</a>//! ## Alternatives
|
||||
<a href=#33 id=33 data-nosnippet>33</a>//!
|
||||
<a href=#34 id=34 data-nosnippet>34</a>//! Generally, [`sc_rpc::state::StateBackend::call`] aka. `state_call` should be used instead of
|
||||
<a href=#35 id=35 data-nosnippet>35</a>//! custom RPC.
|
||||
<a href=#36 id=36 data-nosnippet>36</a>//!
|
||||
<a href=#37 id=37 data-nosnippet>37</a>//! Usually, each custom RPC comes with a corresponding runtime API which implements the business
|
||||
<a href=#38 id=38 data-nosnippet>38</a>//! logic. So instead of invoke the custom RPC, we can use `state_call` to invoke the runtime API
|
||||
<a href=#39 id=39 data-nosnippet>39</a>//! directly. This is a trivial change on the dApp and no change on the runtime side. We may remove
|
||||
<a href=#40 id=40 data-nosnippet>40</a>//! the custom RPC from the node side if wanted.
|
||||
<a href=#41 id=41 data-nosnippet>41</a>//!
|
||||
<a href=#42 id=42 data-nosnippet>42</a>//! There are some other cases that a simple runtime API is not enough. For example, implementation
|
||||
<a href=#43 id=43 data-nosnippet>43</a>//! of Ethereum RPC requires an additional offchain database to index transactions. In this
|
||||
<a href=#44 id=44 data-nosnippet>44</a>//! particular case, we can have the RPC implemented on another client.
|
||||
<a href=#45 id=45 data-nosnippet>45</a>//!
|
||||
<a href=#46 id=46 data-nosnippet>46</a>//! For example, the Acala EVM+ RPC are implemented by
|
||||
<a href=#47 id=47 data-nosnippet>47</a>//! [eth-rpc-adapter](https://github.com/AcalaNetwork/bodhi.js/tree/master/packages/eth-rpc-adapter).
|
||||
<a href=#48 id=48 data-nosnippet>48</a>//! Alternatively, the [Frontier](https://github.com/pezkuwi-evm/frontier) project also provided
|
||||
<a href=#49 id=49 data-nosnippet>49</a>//! Ethereum RPC compatibility directly in the node-side software.
|
||||
<a href=#50 id=50 data-nosnippet>50</a>//!
|
||||
<a href=#51 id=51 data-nosnippet>51</a>//! ## Create a new Runtime API
|
||||
<a href=#52 id=52 data-nosnippet>52</a>//!
|
||||
<a href=#53 id=53 data-nosnippet>53</a>//! For example, let's take a look at the process through which the account nonce can be queried
|
||||
<a href=#54 id=54 data-nosnippet>54</a>//! through an RPC. First, a new runtime-api needs to be declared:
|
||||
<a href=#55 id=55 data-nosnippet>55</a></span><span class="attr">#![doc = <span class="macro">docify::embed!</span>(<span class="string">"../../substrate/frame/system/rpc/runtime-api/src/lib.rs"</span>, AccountNonceApi)]
|
||||
<a href=#56 id=56 data-nosnippet>56</a></span><span class="doccomment">//!
|
||||
<a href=#57 id=57 data-nosnippet>57</a>//! This API is implemented at the runtime level, always inside [`sp_api::impl_runtime_apis!`].
|
||||
<a href=#58 id=58 data-nosnippet>58</a>//!
|
||||
<a href=#59 id=59 data-nosnippet>59</a>//! As noted, this is already enough to make this API usable via `state_call`.
|
||||
<a href=#60 id=60 data-nosnippet>60</a>//!
|
||||
<a href=#61 id=61 data-nosnippet>61</a>//! ## Create a new custom RPC (Legacy)
|
||||
<a href=#62 id=62 data-nosnippet>62</a>//!
|
||||
<a href=#63 id=63 data-nosnippet>63</a>//! Should you wish to implement the legacy approach of exposing this runtime-api as a custom
|
||||
<a href=#64 id=64 data-nosnippet>64</a>//! RPC-api, then a custom RPC server has to be defined.
|
||||
<a href=#65 id=65 data-nosnippet>65</a></span><span class="attr">#![doc = <span class="macro">docify::embed!</span>(<span class="string">"../../substrate/utils/frame/rpc/system/src/lib.rs"</span>, SystemApi)]
|
||||
<a href=#66 id=66 data-nosnippet>66</a></span><span class="doccomment">//!
|
||||
<a href=#67 id=67 data-nosnippet>67</a>//! ## Add a new RPC to the node (Legacy)
|
||||
<a href=#68 id=68 data-nosnippet>68</a>//!
|
||||
<a href=#69 id=69 data-nosnippet>69</a>//! Finally, this custom RPC needs to be integrated into the node side. This is usually done in a
|
||||
<a href=#70 id=70 data-nosnippet>70</a>//! `rpc.rs` in a typical template, as follows:
|
||||
<a href=#71 id=71 data-nosnippet>71</a></span><span class="attr">#![doc = <span class="macro">docify::embed!</span>(<span class="string">"../../templates/minimal/node/src/rpc.rs"</span>, create_full)]
|
||||
<a href=#72 id=72 data-nosnippet>72</a></span><span class="doccomment">//!
|
||||
<a href=#73 id=73 data-nosnippet>73</a>//! ## Future
|
||||
<a href=#74 id=74 data-nosnippet>74</a>//!
|
||||
<a href=#75 id=75 data-nosnippet>75</a>//! - [XCQ](https://forum.network.pezkuwichain.io/t/cross-consensus-query-language-xcq/7583) will be a good
|
||||
<a href=#76 id=76 data-nosnippet>76</a>//! solution for most of the query needs.
|
||||
<a href=#77 id=77 data-nosnippet>77</a>//! - [New JSON-RPC Specification](https://github.com/paritytech/json-rpc-interface-spec)</span></code></pre></div></section></main></body></html>
|
||||
+395
@@ -0,0 +1,395 @@
|
||||
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `docs/sdk/src/reference_docs/defensive_programming.rs`."><title>defensive_programming.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2"href="../../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../../../static.files/rustdoc-e56847b5.css"><meta name="rustdoc-vars" data-root-path="../../../" data-static-root-path="../../../static.files/" data-current-crate="pezkuwi_sdk_docs" data-themes="" data-resource-suffix="" data-rustdoc-version="1.91.1 (ed61e7d7e 2025-11-07)" data-channel="1.91.1" data-search-js="search-e256b49e.js" data-stringdex-js="stringdex-c3e638e9.js" data-settings-js="settings-c38705f0.js" ><script src="../../../static.files/storage-e2aeef58.js"></script><script defer src="../../../static.files/src-script-813739b1.js"></script><script defer src="../../../src-files.js"></script><script defer src="../../../static.files/main-6dc2a7f3.js"></script><noscript><link rel="stylesheet" href="../../../static.files/noscript-263c88ec.css"></noscript><link rel="icon" href="https://pezkuwichain.io/favicon.ico"></head><body class="rustdoc src"><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer" title="Drag to resize sidebar"></div><main><section id="main-content" class="content"><div class="main-heading"><h1><div class="sub-heading">pezkuwi_sdk_docs/reference_docs/</div>defensive_programming.rs</h1><rustdoc-toolbar></rustdoc-toolbar></div><div class="example-wrap digits-3"><pre class="rust"><code><a href=#1 id=1 data-nosnippet>1</a><span class="comment">// Copyright (C) Parity Technologies (UK) Ltd.
|
||||
<a href=#2 id=2 data-nosnippet>2</a>// SPDX-License-Identifier: Apache-2.0
|
||||
<a href=#3 id=3 data-nosnippet>3</a>
|
||||
<a href=#4 id=4 data-nosnippet>4</a>// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
<a href=#5 id=5 data-nosnippet>5</a>// you may not use this file except in compliance with the License.
|
||||
<a href=#6 id=6 data-nosnippet>6</a>// You may obtain a copy of the License at
|
||||
<a href=#7 id=7 data-nosnippet>7</a>//
|
||||
<a href=#8 id=8 data-nosnippet>8</a>// http://www.apache.org/licenses/LICENSE-2.0
|
||||
<a href=#9 id=9 data-nosnippet>9</a>//
|
||||
<a href=#10 id=10 data-nosnippet>10</a>// Unless required by applicable law or agreed to in writing, software
|
||||
<a href=#11 id=11 data-nosnippet>11</a>// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
<a href=#12 id=12 data-nosnippet>12</a>// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
<a href=#13 id=13 data-nosnippet>13</a>// See the License for the specific language governing permissions and
|
||||
<a href=#14 id=14 data-nosnippet>14</a>// limitations under the License.
|
||||
<a href=#15 id=15 data-nosnippet>15</a>
|
||||
<a href=#16 id=16 data-nosnippet>16</a></span><span class="doccomment">//! [Defensive programming](https://en.wikipedia.org/wiki/Defensive_programming) is a design paradigm that enables a program to continue
|
||||
<a href=#17 id=17 data-nosnippet>17</a>//! running despite unexpected behavior, input, or events that may arise in runtime.
|
||||
<a href=#18 id=18 data-nosnippet>18</a>//! Usually, unforeseen circumstances may cause the program to stop or, in the Rust context,
|
||||
<a href=#19 id=19 data-nosnippet>19</a>//! `panic!`. Defensive practices allow for these circumstances to be accounted for ahead of time
|
||||
<a href=#20 id=20 data-nosnippet>20</a>//! and for them to be handled gracefully, which is in line with the intended fault-tolerant and
|
||||
<a href=#21 id=21 data-nosnippet>21</a>//! deterministic nature of blockchains.
|
||||
<a href=#22 id=22 data-nosnippet>22</a>//!
|
||||
<a href=#23 id=23 data-nosnippet>23</a>//! The Pezkuwi SDK is built to reflect these principles and to facilitate their usage accordingly.
|
||||
<a href=#24 id=24 data-nosnippet>24</a>//!
|
||||
<a href=#25 id=25 data-nosnippet>25</a>//! ## General Overview
|
||||
<a href=#26 id=26 data-nosnippet>26</a>//!
|
||||
<a href=#27 id=27 data-nosnippet>27</a>//! When developing within the context of the Substrate runtime, there is one golden rule:
|
||||
<a href=#28 id=28 data-nosnippet>28</a>//!
|
||||
<a href=#29 id=29 data-nosnippet>29</a>//! ***DO NOT PANIC***. There are some exceptions, but generally, this is the default precedent.
|
||||
<a href=#30 id=30 data-nosnippet>30</a>//!
|
||||
<a href=#31 id=31 data-nosnippet>31</a>//! > It’s important to differentiate between the runtime and node. The runtime refers to the core
|
||||
<a href=#32 id=32 data-nosnippet>32</a>//! > business logic of a Substrate-based chain, whereas the node refers to the outer client, which
|
||||
<a href=#33 id=33 data-nosnippet>33</a>//! > deals with telemetry and gossip from other nodes. For more information, read about
|
||||
<a href=#34 id=34 data-nosnippet>34</a>//! > [Substrate's node
|
||||
<a href=#35 id=35 data-nosnippet>35</a>//! > architecture](crate::reference_docs::wasm_meta_protocol#node-vs-runtime). It’s also important
|
||||
<a href=#36 id=36 data-nosnippet>36</a>//! > to note that the criticality of the node is slightly lesser
|
||||
<a href=#37 id=37 data-nosnippet>37</a>//! > than that of the runtime, which is why you may see `unwrap()` or other “non-defensive”
|
||||
<a href=#38 id=38 data-nosnippet>38</a>//! > approaches
|
||||
<a href=#39 id=39 data-nosnippet>39</a>//! in a few places of the node's code repository.
|
||||
<a href=#40 id=40 data-nosnippet>40</a>//!
|
||||
<a href=#41 id=41 data-nosnippet>41</a>//! Most of these practices fall within Rust's
|
||||
<a href=#42 id=42 data-nosnippet>42</a>//! colloquial usage of proper error propagation, handling, and arithmetic-based edge cases.
|
||||
<a href=#43 id=43 data-nosnippet>43</a>//!
|
||||
<a href=#44 id=44 data-nosnippet>44</a>//! General guidelines:
|
||||
<a href=#45 id=45 data-nosnippet>45</a>//!
|
||||
<a href=#46 id=46 data-nosnippet>46</a>//! - **Avoid writing functions that could explicitly panic,** such as directly using `unwrap()` on
|
||||
<a href=#47 id=47 data-nosnippet>47</a>//! a [`Result`], or accessing an out-of-bounds index on a collection. Safer methods to access
|
||||
<a href=#48 id=48 data-nosnippet>48</a>//! collection types, i.e., `get()` which allow defensive handling of the resulting [`Option`] are
|
||||
<a href=#49 id=49 data-nosnippet>49</a>//! recommended to be used.
|
||||
<a href=#50 id=50 data-nosnippet>50</a>//! - **It may be acceptable to use `except()`,** but only if one is completely certain (and has
|
||||
<a href=#51 id=51 data-nosnippet>51</a>//! performed a check beforehand) that a value won't panic upon unwrapping. *Even this is
|
||||
<a href=#52 id=52 data-nosnippet>52</a>//! discouraged*, however, as future changes to that function could then cause that statement to
|
||||
<a href=#53 id=53 data-nosnippet>53</a>//! panic. It is important to ensure all possible errors are propagated and handled effectively.
|
||||
<a href=#54 id=54 data-nosnippet>54</a>//! - **If a function *can* panic,** it usually is prefaced with `unchecked_` to indicate its
|
||||
<a href=#55 id=55 data-nosnippet>55</a>//! unsafety.
|
||||
<a href=#56 id=56 data-nosnippet>56</a>//! - **If you are writing a function that could panic,** [document it!](https://doc.rust-lang.org/rustdoc/how-to-write-documentation.html#documenting-components)
|
||||
<a href=#57 id=57 data-nosnippet>57</a>//! - **Carefully handle mathematical operations.** Many seemingly, simplistic operations, such as
|
||||
<a href=#58 id=58 data-nosnippet>58</a>//! **arithmetic** in the runtime, could present a number of issues [(see more later in this
|
||||
<a href=#59 id=59 data-nosnippet>59</a>//! document)](#integer-overflow). Use checked arithmetic wherever possible.
|
||||
<a href=#60 id=60 data-nosnippet>60</a>//!
|
||||
<a href=#61 id=61 data-nosnippet>61</a>//! These guidelines could be summarized in the following example, where `bad_pop` is prone to
|
||||
<a href=#62 id=62 data-nosnippet>62</a>//! panicking, and `good_pop` allows for proper error handling to take place:
|
||||
<a href=#63 id=63 data-nosnippet>63</a>//!
|
||||
<a href=#64 id=64 data-nosnippet>64</a>//!```ignore
|
||||
<a href=#65 id=65 data-nosnippet>65</a>//! // Bad pop always requires that we return something, even if vector/array is empty.
|
||||
<a href=#66 id=66 data-nosnippet>66</a>//! fn bad_pop<T>(v: Vec<T>) -> T {}
|
||||
<a href=#67 id=67 data-nosnippet>67</a>//! // Good pop allows us to return None from the Option if need be.
|
||||
<a href=#68 id=68 data-nosnippet>68</a>//! fn good_pop<T>(v: Vec<T>) -> Option<T> {}
|
||||
<a href=#69 id=69 data-nosnippet>69</a>//! ```
|
||||
<a href=#70 id=70 data-nosnippet>70</a>//!
|
||||
<a href=#71 id=71 data-nosnippet>71</a>//! ### Defensive Traits
|
||||
<a href=#72 id=72 data-nosnippet>72</a>//!
|
||||
<a href=#73 id=73 data-nosnippet>73</a>//! The [`Defensive`](frame::traits::Defensive) trait provides a number of functions, all of which
|
||||
<a href=#74 id=74 data-nosnippet>74</a>//! provide an alternative to 'vanilla' Rust functions, e.g.:
|
||||
<a href=#75 id=75 data-nosnippet>75</a>//!
|
||||
<a href=#76 id=76 data-nosnippet>76</a>//! - [`defensive_unwrap_or()`](frame::traits::Defensive::defensive_unwrap_or) instead of
|
||||
<a href=#77 id=77 data-nosnippet>77</a>//! `unwrap_or()`
|
||||
<a href=#78 id=78 data-nosnippet>78</a>//! - [`defensive_ok_or()`](frame::traits::DefensiveOption::defensive_ok_or) instead of `ok_or()`
|
||||
<a href=#79 id=79 data-nosnippet>79</a>//!
|
||||
<a href=#80 id=80 data-nosnippet>80</a>//! Defensive methods use [`debug_assertions`](https://doc.rust-lang.org/reference/conditional-compilation.html#debug_assertions), which panic in development, but in
|
||||
<a href=#81 id=81 data-nosnippet>81</a>//! production/release, they will merely log an error (i.e., `log::error`).
|
||||
<a href=#82 id=82 data-nosnippet>82</a>//!
|
||||
<a href=#83 id=83 data-nosnippet>83</a>//! The [`Defensive`](frame::traits::Defensive) trait and its various implementations can be found
|
||||
<a href=#84 id=84 data-nosnippet>84</a>//! [here](frame::traits::Defensive).
|
||||
<a href=#85 id=85 data-nosnippet>85</a>//!
|
||||
<a href=#86 id=86 data-nosnippet>86</a>//! ## Integer Overflow
|
||||
<a href=#87 id=87 data-nosnippet>87</a>//!
|
||||
<a href=#88 id=88 data-nosnippet>88</a>//! The Rust compiler prevents static overflow from happening at compile time.
|
||||
<a href=#89 id=89 data-nosnippet>89</a>//! The compiler panics in **debug** mode in the event of an integer overflow. In
|
||||
<a href=#90 id=90 data-nosnippet>90</a>//! **release** mode, it resorts to silently _wrapping_ the overflowed amount in a modular fashion
|
||||
<a href=#91 id=91 data-nosnippet>91</a>//! (from the `MAX` back to zero).
|
||||
<a href=#92 id=92 data-nosnippet>92</a>//!
|
||||
<a href=#93 id=93 data-nosnippet>93</a>//! In runtime development, we don't always have control over what is being supplied
|
||||
<a href=#94 id=94 data-nosnippet>94</a>//! as a parameter. For example, even this simple add function could present one of two outcomes
|
||||
<a href=#95 id=95 data-nosnippet>95</a>//! depending on whether it is in **release** or **debug** mode:
|
||||
<a href=#96 id=96 data-nosnippet>96</a>//!
|
||||
<a href=#97 id=97 data-nosnippet>97</a>//! ```ignore
|
||||
<a href=#98 id=98 data-nosnippet>98</a>//! fn naive_add(x: u8, y: u8) -> u8 {
|
||||
<a href=#99 id=99 data-nosnippet>99</a>//! x + y
|
||||
<a href=#100 id=100 data-nosnippet>100</a>//! }
|
||||
<a href=#101 id=101 data-nosnippet>101</a>//! ```
|
||||
<a href=#102 id=102 data-nosnippet>102</a>//! If we passed overflow-able values at runtime, this could panic (or wrap if in release).
|
||||
<a href=#103 id=103 data-nosnippet>103</a>//!
|
||||
<a href=#104 id=104 data-nosnippet>104</a>//! ```ignore
|
||||
<a href=#105 id=105 data-nosnippet>105</a>//! naive_add(250u8, 10u8); // In debug mode, this would panic. In release, this would return 4.
|
||||
<a href=#106 id=106 data-nosnippet>106</a>//! ```
|
||||
<a href=#107 id=107 data-nosnippet>107</a>//!
|
||||
<a href=#108 id=108 data-nosnippet>108</a>//! It is the silent portion of this behavior that presents a real issue. Such behavior should be
|
||||
<a href=#109 id=109 data-nosnippet>109</a>//! made obvious, especially in blockchain development, where unsafe arithmetic could produce
|
||||
<a href=#110 id=110 data-nosnippet>110</a>//! unexpected consequences like a user balance over or underflowing.
|
||||
<a href=#111 id=111 data-nosnippet>111</a>//!
|
||||
<a href=#112 id=112 data-nosnippet>112</a>//! Fortunately, there are ways to both represent and handle these scenarios depending on our
|
||||
<a href=#113 id=113 data-nosnippet>113</a>//! specific use case natively built into Rust and libraries like [`sp_arithmetic`].
|
||||
<a href=#114 id=114 data-nosnippet>114</a>//!
|
||||
<a href=#115 id=115 data-nosnippet>115</a>//! ## Infallible Arithmetic
|
||||
<a href=#116 id=116 data-nosnippet>116</a>//!
|
||||
<a href=#117 id=117 data-nosnippet>117</a>//! Both Rust and Substrate provide safe ways to deal with numbers and alternatives to floating
|
||||
<a href=#118 id=118 data-nosnippet>118</a>//! point arithmetic.
|
||||
<a href=#119 id=119 data-nosnippet>119</a>//!
|
||||
<a href=#120 id=120 data-nosnippet>120</a>//! Known scenarios that could be fallible should be avoided: i.e., avoiding the possibility of
|
||||
<a href=#121 id=121 data-nosnippet>121</a>//! dividing/modulo by zero at any point should be mitigated. One should be opting for a
|
||||
<a href=#122 id=122 data-nosnippet>122</a>//! `checked_*` method to introduce safe arithmetic in their code in most cases.
|
||||
<a href=#123 id=123 data-nosnippet>123</a>//!
|
||||
<a href=#124 id=124 data-nosnippet>124</a>//! A developer should use fixed-point instead of floating-point arithmetic to mitigate the
|
||||
<a href=#125 id=125 data-nosnippet>125</a>//! potential for inaccuracy, rounding errors, or other unexpected behavior.
|
||||
<a href=#126 id=126 data-nosnippet>126</a>//!
|
||||
<a href=#127 id=127 data-nosnippet>127</a>//! - [Fixed point types](sp_arithmetic::fixed_point) and their associated usage can be found here.
|
||||
<a href=#128 id=128 data-nosnippet>128</a>//! - [PerThing](sp_arithmetic::per_things) and its associated types can be found here.
|
||||
<a href=#129 id=129 data-nosnippet>129</a>//!
|
||||
<a href=#130 id=130 data-nosnippet>130</a>//! Using floating point number types (i.e. f32, f64) in the runtime should be avoided, as a single non-deterministic result could cause chaos for blockchain consensus along with the issues above. For more on the specifics of the peculiarities of floating point calculations, [watch this video by the Computerphile](https://www.youtube.com/watch?v=PZRI1IfStY0).
|
||||
<a href=#131 id=131 data-nosnippet>131</a>//!
|
||||
<a href=#132 id=132 data-nosnippet>132</a>//! The following methods demonstrate different ways to handle numbers natively in Rust safely,
|
||||
<a href=#133 id=133 data-nosnippet>133</a>//! without fear of panic or unexpected behavior from wrapping.
|
||||
<a href=#134 id=134 data-nosnippet>134</a>//!
|
||||
<a href=#135 id=135 data-nosnippet>135</a>//! ### Checked Arithmetic
|
||||
<a href=#136 id=136 data-nosnippet>136</a>//!
|
||||
<a href=#137 id=137 data-nosnippet>137</a>//! **Checked operations** utilize an `Option<T>` as a return type. This allows for
|
||||
<a href=#138 id=138 data-nosnippet>138</a>//! catching any unexpected behavior in the event of an overflow through simple pattern matching.
|
||||
<a href=#139 id=139 data-nosnippet>139</a>//!
|
||||
<a href=#140 id=140 data-nosnippet>140</a>//! This is an example of a valid operation:
|
||||
<a href=#141 id=141 data-nosnippet>141</a></span><span class="attr">#![doc = <span class="macro">docify::embed!</span>(<span class="string">"./src/reference_docs/defensive_programming.rs"</span>, checked_add_example)]
|
||||
<a href=#142 id=142 data-nosnippet>142</a></span><span class="doccomment">//!
|
||||
<a href=#143 id=143 data-nosnippet>143</a>//! This is an example of an invalid operation. In this case, a simulated integer overflow, which
|
||||
<a href=#144 id=144 data-nosnippet>144</a>//! would simply result in `None`:
|
||||
<a href=#145 id=145 data-nosnippet>145</a></span><span class="attr">#![doc = <span class="macro">docify::embed!</span>(
|
||||
<a href=#146 id=146 data-nosnippet>146</a> <span class="string">"./src/reference_docs/defensive_programming.rs"</span>,
|
||||
<a href=#147 id=147 data-nosnippet>147</a> checked_add_handle_error_example
|
||||
<a href=#148 id=148 data-nosnippet>148</a>)]
|
||||
<a href=#149 id=149 data-nosnippet>149</a></span><span class="doccomment">//!
|
||||
<a href=#150 id=150 data-nosnippet>150</a>//! Suppose you aren’t sure which operation to use for runtime math. In that case, checked
|
||||
<a href=#151 id=151 data-nosnippet>151</a>//! operations are the safest bet, presenting two predictable (and erroring) outcomes that can be
|
||||
<a href=#152 id=152 data-nosnippet>152</a>//! handled accordingly (Some and None).
|
||||
<a href=#153 id=153 data-nosnippet>153</a>//!
|
||||
<a href=#154 id=154 data-nosnippet>154</a>//! The following conventions can be seen within the Pezkuwi SDK, where it is
|
||||
<a href=#155 id=155 data-nosnippet>155</a>//! handled in two ways:
|
||||
<a href=#156 id=156 data-nosnippet>156</a>//!
|
||||
<a href=#157 id=157 data-nosnippet>157</a>//! - As an [`Option`], using the `if let` / `if` or `match`
|
||||
<a href=#158 id=158 data-nosnippet>158</a>//! - As a [`Result`], via `ok_or` (or similar conversion to [`Result`] from [`Option`])
|
||||
<a href=#159 id=159 data-nosnippet>159</a>//!
|
||||
<a href=#160 id=160 data-nosnippet>160</a>//! #### Handling via Option - More Verbose
|
||||
<a href=#161 id=161 data-nosnippet>161</a>//!
|
||||
<a href=#162 id=162 data-nosnippet>162</a>//! Because wrapped operations return `Option<T>`, you can use a more verbose/explicit form of error
|
||||
<a href=#163 id=163 data-nosnippet>163</a>//! handling via `if` or `if let`:
|
||||
<a href=#164 id=164 data-nosnippet>164</a></span><span class="attr">#![doc = <span class="macro">docify::embed!</span>(<span class="string">"./src/reference_docs/defensive_programming.rs"</span>, increase_balance)]
|
||||
<a href=#165 id=165 data-nosnippet>165</a></span><span class="doccomment">//!
|
||||
<a href=#166 id=166 data-nosnippet>166</a>//! Optionally, match may also be directly used in a more concise manner:
|
||||
<a href=#167 id=167 data-nosnippet>167</a></span><span class="attr">#![doc = <span class="macro">docify::embed!</span>(<span class="string">"./src/reference_docs/defensive_programming.rs"</span>, increase_balance_match)]
|
||||
<a href=#168 id=168 data-nosnippet>168</a></span><span class="doccomment">//!
|
||||
<a href=#169 id=169 data-nosnippet>169</a>//! This is generally a useful convention for handling checked types and most types that return
|
||||
<a href=#170 id=170 data-nosnippet>170</a>//! `Option<T>`.
|
||||
<a href=#171 id=171 data-nosnippet>171</a>//!
|
||||
<a href=#172 id=172 data-nosnippet>172</a>//! #### Handling via Result - Less Verbose
|
||||
<a href=#173 id=173 data-nosnippet>173</a>//!
|
||||
<a href=#174 id=174 data-nosnippet>174</a>//! In the Pezkuwi SDK codebase, checked operations are handled as a `Result` via `ok_or`. This is
|
||||
<a href=#175 id=175 data-nosnippet>175</a>//! a less verbose way of expressing the above. This usage often boils down to the developer’s
|
||||
<a href=#176 id=176 data-nosnippet>176</a>//! preference:
|
||||
<a href=#177 id=177 data-nosnippet>177</a></span><span class="attr">#![doc = <span class="macro">docify::embed!</span>(<span class="string">"./src/reference_docs/defensive_programming.rs"</span>, increase_balance_result)]
|
||||
<a href=#178 id=178 data-nosnippet>178</a></span><span class="doccomment">//!
|
||||
<a href=#179 id=179 data-nosnippet>179</a>//! ### Saturating Operations
|
||||
<a href=#180 id=180 data-nosnippet>180</a>//!
|
||||
<a href=#181 id=181 data-nosnippet>181</a>//! Saturating a number limits it to the type’s upper or lower bound, even if the integer type
|
||||
<a href=#182 id=182 data-nosnippet>182</a>//! overflowed in runtime. For example, adding to `u32::MAX` would simply limit itself to
|
||||
<a href=#183 id=183 data-nosnippet>183</a>//! `u32::MAX`:
|
||||
<a href=#184 id=184 data-nosnippet>184</a></span><span class="attr">#![doc = <span class="macro">docify::embed!</span>(<span class="string">"./src/reference_docs/defensive_programming.rs"</span>, saturated_add_example)]
|
||||
<a href=#185 id=185 data-nosnippet>185</a></span><span class="doccomment">//!
|
||||
<a href=#186 id=186 data-nosnippet>186</a>//! Saturating calculations can be used if one is very sure that something won't overflow, but wants
|
||||
<a href=#187 id=187 data-nosnippet>187</a>//! to avoid introducing the notion of any potential-panic or wrapping behavior.
|
||||
<a href=#188 id=188 data-nosnippet>188</a>//!
|
||||
<a href=#189 id=189 data-nosnippet>189</a>//! There is also a series of defensive alternatives via
|
||||
<a href=#190 id=190 data-nosnippet>190</a>//! [`DefensiveSaturating`](frame::traits::DefensiveSaturating), which introduces the same behavior
|
||||
<a href=#191 id=191 data-nosnippet>191</a>//! of the [`Defensive`](frame::traits::Defensive) trait, only with saturating, mathematical
|
||||
<a href=#192 id=192 data-nosnippet>192</a>//! operations:
|
||||
<a href=#193 id=193 data-nosnippet>193</a></span><span class="attr">#![doc = <span class="macro">docify::embed!</span>(
|
||||
<a href=#194 id=194 data-nosnippet>194</a> <span class="string">"./src/reference_docs/defensive_programming.rs"</span>,
|
||||
<a href=#195 id=195 data-nosnippet>195</a> saturated_defensive_example
|
||||
<a href=#196 id=196 data-nosnippet>196</a>)]
|
||||
<a href=#197 id=197 data-nosnippet>197</a></span><span class="doccomment">//!
|
||||
<a href=#198 id=198 data-nosnippet>198</a>//! ### Mathematical Operations in Substrate Development - Further Context
|
||||
<a href=#199 id=199 data-nosnippet>199</a>//!
|
||||
<a href=#200 id=200 data-nosnippet>200</a>//! As a recap, we covered the following concepts:
|
||||
<a href=#201 id=201 data-nosnippet>201</a>//!
|
||||
<a href=#202 id=202 data-nosnippet>202</a>//! 1. **Checked** operations - using [`Option`] or [`Result`]
|
||||
<a href=#203 id=203 data-nosnippet>203</a>//! 2. **Saturating** operations - limited to the lower and upper bounds of a number type
|
||||
<a href=#204 id=204 data-nosnippet>204</a>//! 3. **Wrapped** operations (the default) - wrap around to above or below the bounds of a type
|
||||
<a href=#205 id=205 data-nosnippet>205</a>//!
|
||||
<a href=#206 id=206 data-nosnippet>206</a>//! #### The problem with 'default' wrapped operations
|
||||
<a href=#207 id=207 data-nosnippet>207</a>//!
|
||||
<a href=#208 id=208 data-nosnippet>208</a>//! **Wrapped operations** cause the overflow to wrap around to either the maximum or minimum of
|
||||
<a href=#209 id=209 data-nosnippet>209</a>//! that type. Imagine this in the context of a blockchain, where there are account balances, voting
|
||||
<a href=#210 id=210 data-nosnippet>210</a>//! counters, nonces for transactions, and other aspects of a blockchain.
|
||||
<a href=#211 id=211 data-nosnippet>211</a>//!
|
||||
<a href=#212 id=212 data-nosnippet>212</a>//! While it may seem trivial, choosing how to handle numbers is quite important. As a thought
|
||||
<a href=#213 id=213 data-nosnippet>213</a>//! exercise, here are some scenarios of which will shed more light on when to use which.
|
||||
<a href=#214 id=214 data-nosnippet>214</a>//!
|
||||
<a href=#215 id=215 data-nosnippet>215</a>//! #### Bob's Overflowed Balance
|
||||
<a href=#216 id=216 data-nosnippet>216</a>//!
|
||||
<a href=#217 id=217 data-nosnippet>217</a>//! **Bob's** balance exceeds the `Balance` type on the `EduChain`. Because the pallet developer did
|
||||
<a href=#218 id=218 data-nosnippet>218</a>//! not handle the calculation to add to Bob's balance with any regard to this overflow, **Bob's**
|
||||
<a href=#219 id=219 data-nosnippet>219</a>//! balance is now essentially `0`, the operation **wrapped**.
|
||||
<a href=#220 id=220 data-nosnippet>220</a>//!
|
||||
<a href=#221 id=221 data-nosnippet>221</a>//! <details>
|
||||
<a href=#222 id=222 data-nosnippet>222</a>//! <summary><b>Solution: Saturating or Checked</b></summary>
|
||||
<a href=#223 id=223 data-nosnippet>223</a>//! For Bob's balance problems, using a `saturating_add` or `checked_add` could've mitigated
|
||||
<a href=#224 id=224 data-nosnippet>224</a>//! this issue. They simply would've reached the upper, or lower bounds, of the particular type for
|
||||
<a href=#225 id=225 data-nosnippet>225</a>//! an on-chain balance. In other words: Bob's balance would've stayed at the maximum of the
|
||||
<a href=#226 id=226 data-nosnippet>226</a>//! Balance type. </details>
|
||||
<a href=#227 id=227 data-nosnippet>227</a>//!
|
||||
<a href=#228 id=228 data-nosnippet>228</a>//! #### Alice's 'Underflowed' Balance
|
||||
<a href=#229 id=229 data-nosnippet>229</a>//!
|
||||
<a href=#230 id=230 data-nosnippet>230</a>//! Alice’s balance has reached `0` after a transfer to Bob. Suddenly, she has been slashed on
|
||||
<a href=#231 id=231 data-nosnippet>231</a>//! EduChain, causing her balance to reach near the limit of `u32::MAX` - a very large amount - as
|
||||
<a href=#232 id=232 data-nosnippet>232</a>//! wrapped operations can go both ways. Alice can now successfully vote using her new, overpowered
|
||||
<a href=#233 id=233 data-nosnippet>233</a>//! token balance, destroying the chain's integrity.
|
||||
<a href=#234 id=234 data-nosnippet>234</a>//!
|
||||
<a href=#235 id=235 data-nosnippet>235</a>//! <details>
|
||||
<a href=#236 id=236 data-nosnippet>236</a>//! <summary><b>Solution: Saturating</b></summary>
|
||||
<a href=#237 id=237 data-nosnippet>237</a>//! For Alice's balance problem, using `saturated_sub` could've mitigated this issue. A saturating
|
||||
<a href=#238 id=238 data-nosnippet>238</a>//! calculation would've simply limited her balance to the lower bound of u32, as having a negative
|
||||
<a href=#239 id=239 data-nosnippet>239</a>//! balance is not a concept within blockchains. In other words: Alice's balance would've stayed
|
||||
<a href=#240 id=240 data-nosnippet>240</a>//! at "0", even after being slashed.
|
||||
<a href=#241 id=241 data-nosnippet>241</a>//!
|
||||
<a href=#242 id=242 data-nosnippet>242</a>//! This is also an example that while one system may work in isolation, shared interfaces, such
|
||||
<a href=#243 id=243 data-nosnippet>243</a>//! as the notion of balances, are often shared across multiple pallets - meaning these small
|
||||
<a href=#244 id=244 data-nosnippet>244</a>//! changes can make a big difference depending on the scenario. </details>
|
||||
<a href=#245 id=245 data-nosnippet>245</a>//!
|
||||
<a href=#246 id=246 data-nosnippet>246</a>//! #### Proposal ID Overwrite
|
||||
<a href=#247 id=247 data-nosnippet>247</a>//!
|
||||
<a href=#248 id=248 data-nosnippet>248</a>//! A `u8` parameter, called `proposals_count`, represents the type for counting the number of
|
||||
<a href=#249 id=249 data-nosnippet>249</a>//! proposals on-chain. Every time a new proposal is added to the system, this number increases.
|
||||
<a href=#250 id=250 data-nosnippet>250</a>//! With the proposal pallet's high usage, it has reached `u8::MAX`’s limit of 255, causing
|
||||
<a href=#251 id=251 data-nosnippet>251</a>//! `proposals_count` to go to 0. Unfortunately, this results in new proposals overwriting old ones,
|
||||
<a href=#252 id=252 data-nosnippet>252</a>//! effectively erasing any notion of past proposals!
|
||||
<a href=#253 id=253 data-nosnippet>253</a>//!
|
||||
<a href=#254 id=254 data-nosnippet>254</a>//! <details>
|
||||
<a href=#255 id=255 data-nosnippet>255</a>//! <summary><b>Solution: Checked</b></summary>
|
||||
<a href=#256 id=256 data-nosnippet>256</a>//! For the proposal IDs, proper handling via `checked` math would've been suitable,
|
||||
<a href=#257 id=257 data-nosnippet>257</a>//! Saturating could've been used - but it also would've 'failed' silently. Using `checked_add` to
|
||||
<a href=#258 id=258 data-nosnippet>258</a>//! ensure that the next proposal ID would've been valid would've been a viable way to let the user
|
||||
<a href=#259 id=259 data-nosnippet>259</a>//! know the state of their proposal:
|
||||
<a href=#260 id=260 data-nosnippet>260</a>//!
|
||||
<a href=#261 id=261 data-nosnippet>261</a>//! ```ignore
|
||||
<a href=#262 id=262 data-nosnippet>262</a>//! let next_proposal_id = current_count.checked_add(1).ok_or_else(|| Error::TooManyProposals)?;
|
||||
<a href=#263 id=263 data-nosnippet>263</a>//! ```
|
||||
<a href=#264 id=264 data-nosnippet>264</a>//!
|
||||
<a href=#265 id=265 data-nosnippet>265</a>//! </details>
|
||||
<a href=#266 id=266 data-nosnippet>266</a>//!
|
||||
<a href=#267 id=267 data-nosnippet>267</a>//! From the above, we can clearly see the problematic nature of seemingly simple operations in the
|
||||
<a href=#268 id=268 data-nosnippet>268</a>//! runtime, and care should be given to ensure a defensive approach is taken.
|
||||
<a href=#269 id=269 data-nosnippet>269</a>//!
|
||||
<a href=#270 id=270 data-nosnippet>270</a>//! ### Edge cases of `panic!`-able instances in Substrate
|
||||
<a href=#271 id=271 data-nosnippet>271</a>//!
|
||||
<a href=#272 id=272 data-nosnippet>272</a>//! As you traverse through the codebase (particularly in `substrate/frame`, where the majority of
|
||||
<a href=#273 id=273 data-nosnippet>273</a>//! runtime code lives), you may notice that there (only a few!) occurrences where `panic!` is used
|
||||
<a href=#274 id=274 data-nosnippet>274</a>//! explicitly. This is used when the runtime should stall, rather than keep running, as that is
|
||||
<a href=#275 id=275 data-nosnippet>275</a>//! considered safer. Particularly when it comes to mission-critical components, such as block
|
||||
<a href=#276 id=276 data-nosnippet>276</a>//! authoring, consensus, or other protocol-level dependencies, going through with an action may
|
||||
<a href=#277 id=277 data-nosnippet>277</a>//! actually cause harm to the network, and thus stalling would be the better option.
|
||||
<a href=#278 id=278 data-nosnippet>278</a>//!
|
||||
<a href=#279 id=279 data-nosnippet>279</a>//! Take the example of the BABE pallet ([`pallet_babe`]), which doesn't allow for a validator to
|
||||
<a href=#280 id=280 data-nosnippet>280</a>//! participate if it is disabled (see: [`frame::traits::DisabledValidators`]):
|
||||
<a href=#281 id=281 data-nosnippet>281</a>//!
|
||||
<a href=#282 id=282 data-nosnippet>282</a>//! ```ignore
|
||||
<a href=#283 id=283 data-nosnippet>283</a>//! if T::DisabledValidators::is_disabled(authority_index) {
|
||||
<a href=#284 id=284 data-nosnippet>284</a>//! panic!(
|
||||
<a href=#285 id=285 data-nosnippet>285</a>//! "Validator with index {:?} is disabled and should not be attempting to author blocks.",
|
||||
<a href=#286 id=286 data-nosnippet>286</a>//! authority_index,
|
||||
<a href=#287 id=287 data-nosnippet>287</a>//! );
|
||||
<a href=#288 id=288 data-nosnippet>288</a>//! }
|
||||
<a href=#289 id=289 data-nosnippet>289</a>//! ```
|
||||
<a href=#290 id=290 data-nosnippet>290</a>//!
|
||||
<a href=#291 id=291 data-nosnippet>291</a>//! There are other examples in various pallets, mostly those crucial to the blockchain’s
|
||||
<a href=#292 id=292 data-nosnippet>292</a>//! functionality. Most of the time, you will not be writing pallets which operate at this level,
|
||||
<a href=#293 id=293 data-nosnippet>293</a>//! but these exceptions should be noted regardless.
|
||||
<a href=#294 id=294 data-nosnippet>294</a>//!
|
||||
<a href=#295 id=295 data-nosnippet>295</a>//! ## Other Resources
|
||||
<a href=#296 id=296 data-nosnippet>296</a>//!
|
||||
<a href=#297 id=297 data-nosnippet>297</a>//! - [PBA Lectures on YouTube](https://www.youtube.com/playlist?list=PL-w_i5kwVqbni1Ch2j_RwTIXiB-bwnYqq)
|
||||
<a href=#298 id=298 data-nosnippet>298</a></span><span class="attr">#![allow(dead_code)]
|
||||
<a href=#299 id=299 data-nosnippet>299</a>#[allow(unused_variables)]
|
||||
<a href=#300 id=300 data-nosnippet>300</a></span><span class="kw">mod </span>fake_runtime_types {
|
||||
<a href=#301 id=301 data-nosnippet>301</a> <span class="comment">// Note: The following types are purely for the purpose of example, and do not contain any
|
||||
<a href=#302 id=302 data-nosnippet>302</a> // *real* use case other than demonstrating various concepts.
|
||||
<a href=#303 id=303 data-nosnippet>303</a> </span><span class="kw">pub enum </span>RuntimeError {
|
||||
<a href=#304 id=304 data-nosnippet>304</a> Overflow,
|
||||
<a href=#305 id=305 data-nosnippet>305</a> UserDoesntExist,
|
||||
<a href=#306 id=306 data-nosnippet>306</a> }
|
||||
<a href=#307 id=307 data-nosnippet>307</a>
|
||||
<a href=#308 id=308 data-nosnippet>308</a> <span class="kw">pub type </span>Address = ();
|
||||
<a href=#309 id=309 data-nosnippet>309</a>
|
||||
<a href=#310 id=310 data-nosnippet>310</a> <span class="kw">pub struct </span>Runtime;
|
||||
<a href=#311 id=311 data-nosnippet>311</a>
|
||||
<a href=#312 id=312 data-nosnippet>312</a> <span class="kw">impl </span>Runtime {
|
||||
<a href=#313 id=313 data-nosnippet>313</a> <span class="kw">fn </span>get_balance(account: Address) -> <span class="prelude-ty">Result</span><u64, RuntimeError> {
|
||||
<a href=#314 id=314 data-nosnippet>314</a> <span class="prelude-val">Ok</span>(<span class="number">0u64</span>)
|
||||
<a href=#315 id=315 data-nosnippet>315</a> }
|
||||
<a href=#316 id=316 data-nosnippet>316</a>
|
||||
<a href=#317 id=317 data-nosnippet>317</a> <span class="kw">fn </span>set_balance(account: Address, new_balance: u64) {}
|
||||
<a href=#318 id=318 data-nosnippet>318</a> }
|
||||
<a href=#319 id=319 data-nosnippet>319</a>
|
||||
<a href=#320 id=320 data-nosnippet>320</a> <span class="attr">#[docify::export]
|
||||
<a href=#321 id=321 data-nosnippet>321</a> </span><span class="kw">fn </span>increase_balance(account: Address, amount: u64) -> <span class="prelude-ty">Result</span><(), RuntimeError> {
|
||||
<a href=#322 id=322 data-nosnippet>322</a> <span class="comment">// Get a user's current balance
|
||||
<a href=#323 id=323 data-nosnippet>323</a> </span><span class="kw">let </span>balance = Runtime::get_balance(account)<span class="question-mark">?</span>;
|
||||
<a href=#324 id=324 data-nosnippet>324</a> <span class="comment">// SAFELY increase the balance by some amount
|
||||
<a href=#325 id=325 data-nosnippet>325</a> </span><span class="kw">if let </span><span class="prelude-val">Some</span>(new_balance) = balance.checked_add(amount) {
|
||||
<a href=#326 id=326 data-nosnippet>326</a> Runtime::set_balance(account, new_balance);
|
||||
<a href=#327 id=327 data-nosnippet>327</a> <span class="prelude-val">Ok</span>(())
|
||||
<a href=#328 id=328 data-nosnippet>328</a> } <span class="kw">else </span>{
|
||||
<a href=#329 id=329 data-nosnippet>329</a> <span class="prelude-val">Err</span>(RuntimeError::Overflow)
|
||||
<a href=#330 id=330 data-nosnippet>330</a> }
|
||||
<a href=#331 id=331 data-nosnippet>331</a> }
|
||||
<a href=#332 id=332 data-nosnippet>332</a>
|
||||
<a href=#333 id=333 data-nosnippet>333</a> <span class="attr">#[docify::export]
|
||||
<a href=#334 id=334 data-nosnippet>334</a> </span><span class="kw">fn </span>increase_balance_match(account: Address, amount: u64) -> <span class="prelude-ty">Result</span><(), RuntimeError> {
|
||||
<a href=#335 id=335 data-nosnippet>335</a> <span class="comment">// Get a user's current balance
|
||||
<a href=#336 id=336 data-nosnippet>336</a> </span><span class="kw">let </span>balance = Runtime::get_balance(account)<span class="question-mark">?</span>;
|
||||
<a href=#337 id=337 data-nosnippet>337</a> <span class="comment">// SAFELY increase the balance by some amount
|
||||
<a href=#338 id=338 data-nosnippet>338</a> </span><span class="kw">let </span>new_balance = <span class="kw">match </span>balance.checked_add(amount) {
|
||||
<a href=#339 id=339 data-nosnippet>339</a> <span class="prelude-val">Some</span>(balance) => balance,
|
||||
<a href=#340 id=340 data-nosnippet>340</a> <span class="prelude-val">None </span>=> {
|
||||
<a href=#341 id=341 data-nosnippet>341</a> <span class="kw">return </span><span class="prelude-val">Err</span>(RuntimeError::Overflow);
|
||||
<a href=#342 id=342 data-nosnippet>342</a> },
|
||||
<a href=#343 id=343 data-nosnippet>343</a> };
|
||||
<a href=#344 id=344 data-nosnippet>344</a> Runtime::set_balance(account, new_balance);
|
||||
<a href=#345 id=345 data-nosnippet>345</a> <span class="prelude-val">Ok</span>(())
|
||||
<a href=#346 id=346 data-nosnippet>346</a> }
|
||||
<a href=#347 id=347 data-nosnippet>347</a>
|
||||
<a href=#348 id=348 data-nosnippet>348</a> <span class="attr">#[docify::export]
|
||||
<a href=#349 id=349 data-nosnippet>349</a> </span><span class="kw">fn </span>increase_balance_result(account: Address, amount: u64) -> <span class="prelude-ty">Result</span><(), RuntimeError> {
|
||||
<a href=#350 id=350 data-nosnippet>350</a> <span class="comment">// Get a user's current balance
|
||||
<a href=#351 id=351 data-nosnippet>351</a> </span><span class="kw">let </span>balance = Runtime::get_balance(account)<span class="question-mark">?</span>;
|
||||
<a href=#352 id=352 data-nosnippet>352</a> <span class="comment">// SAFELY increase the balance by some amount - this time, by using `ok_or`
|
||||
<a href=#353 id=353 data-nosnippet>353</a> </span><span class="kw">let </span>new_balance = balance.checked_add(amount).ok_or(RuntimeError::Overflow)<span class="question-mark">?</span>;
|
||||
<a href=#354 id=354 data-nosnippet>354</a> Runtime::set_balance(account, new_balance);
|
||||
<a href=#355 id=355 data-nosnippet>355</a> <span class="prelude-val">Ok</span>(())
|
||||
<a href=#356 id=356 data-nosnippet>356</a> }
|
||||
<a href=#357 id=357 data-nosnippet>357</a>}
|
||||
<a href=#358 id=358 data-nosnippet>358</a>
|
||||
<a href=#359 id=359 data-nosnippet>359</a><span class="attr">#[cfg(test)]
|
||||
<a href=#360 id=360 data-nosnippet>360</a></span><span class="kw">mod </span>tests {
|
||||
<a href=#361 id=361 data-nosnippet>361</a> <span class="kw">use </span>frame::traits::DefensiveSaturating;
|
||||
<a href=#362 id=362 data-nosnippet>362</a> <span class="attr">#[docify::export]
|
||||
<a href=#363 id=363 data-nosnippet>363</a> #[test]
|
||||
<a href=#364 id=364 data-nosnippet>364</a> </span><span class="kw">fn </span>checked_add_example() {
|
||||
<a href=#365 id=365 data-nosnippet>365</a> <span class="comment">// This is valid, as 20 is perfectly within the bounds of u32.
|
||||
<a href=#366 id=366 data-nosnippet>366</a> </span><span class="kw">let </span>add = (<span class="number">10u32</span>).checked_add(<span class="number">10</span>);
|
||||
<a href=#367 id=367 data-nosnippet>367</a> <span class="macro">assert_eq!</span>(add, <span class="prelude-val">Some</span>(<span class="number">20</span>))
|
||||
<a href=#368 id=368 data-nosnippet>368</a> }
|
||||
<a href=#369 id=369 data-nosnippet>369</a>
|
||||
<a href=#370 id=370 data-nosnippet>370</a> <span class="attr">#[docify::export]
|
||||
<a href=#371 id=371 data-nosnippet>371</a> #[test]
|
||||
<a href=#372 id=372 data-nosnippet>372</a> </span><span class="kw">fn </span>checked_add_handle_error_example() {
|
||||
<a href=#373 id=373 data-nosnippet>373</a> <span class="comment">// This is invalid - we are adding something to the max of u32::MAX, which would overflow.
|
||||
<a href=#374 id=374 data-nosnippet>374</a> // Luckily, checked_add just marks this as None!
|
||||
<a href=#375 id=375 data-nosnippet>375</a> </span><span class="kw">let </span>add = u32::MAX.checked_add(<span class="number">10</span>);
|
||||
<a href=#376 id=376 data-nosnippet>376</a> <span class="macro">assert_eq!</span>(add, <span class="prelude-val">None</span>)
|
||||
<a href=#377 id=377 data-nosnippet>377</a> }
|
||||
<a href=#378 id=378 data-nosnippet>378</a>
|
||||
<a href=#379 id=379 data-nosnippet>379</a> <span class="attr">#[docify::export]
|
||||
<a href=#380 id=380 data-nosnippet>380</a> #[test]
|
||||
<a href=#381 id=381 data-nosnippet>381</a> </span><span class="kw">fn </span>saturated_add_example() {
|
||||
<a href=#382 id=382 data-nosnippet>382</a> <span class="comment">// Saturating add simply saturates
|
||||
<a href=#383 id=383 data-nosnippet>383</a> // to the numeric bound of that type if it overflows.
|
||||
<a href=#384 id=384 data-nosnippet>384</a> </span><span class="kw">let </span>add = u32::MAX.saturating_add(<span class="number">10</span>);
|
||||
<a href=#385 id=385 data-nosnippet>385</a> <span class="macro">assert_eq!</span>(add, u32::MAX)
|
||||
<a href=#386 id=386 data-nosnippet>386</a> }
|
||||
<a href=#387 id=387 data-nosnippet>387</a>
|
||||
<a href=#388 id=388 data-nosnippet>388</a> <span class="attr">#[docify::export]
|
||||
<a href=#389 id=389 data-nosnippet>389</a> #[test]
|
||||
<a href=#390 id=390 data-nosnippet>390</a> #[cfg_attr(debug_assertions, should_panic(expected = <span class="string">"Defensive failure has been triggered!"</span>))]
|
||||
<a href=#391 id=391 data-nosnippet>391</a> </span><span class="kw">fn </span>saturated_defensive_example() {
|
||||
<a href=#392 id=392 data-nosnippet>392</a> <span class="kw">let </span>saturated_defensive = u32::MAX.defensive_saturating_add(<span class="number">10</span>);
|
||||
<a href=#393 id=393 data-nosnippet>393</a> <span class="macro">assert_eq!</span>(saturated_defensive, u32::MAX);
|
||||
<a href=#394 id=394 data-nosnippet>394</a> }
|
||||
<a href=#395 id=395 data-nosnippet>395</a>}</code></pre></div></section></main></body></html>
|
||||
+223
@@ -0,0 +1,223 @@
|
||||
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `docs/sdk/src/reference_docs/development_environment_advice.rs`."><title>development_environment_advice.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2"href="../../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../../../static.files/rustdoc-e56847b5.css"><meta name="rustdoc-vars" data-root-path="../../../" data-static-root-path="../../../static.files/" data-current-crate="pezkuwi_sdk_docs" data-themes="" data-resource-suffix="" data-rustdoc-version="1.91.1 (ed61e7d7e 2025-11-07)" data-channel="1.91.1" data-search-js="search-e256b49e.js" data-stringdex-js="stringdex-c3e638e9.js" data-settings-js="settings-c38705f0.js" ><script src="../../../static.files/storage-e2aeef58.js"></script><script defer src="../../../static.files/src-script-813739b1.js"></script><script defer src="../../../src-files.js"></script><script defer src="../../../static.files/main-6dc2a7f3.js"></script><noscript><link rel="stylesheet" href="../../../static.files/noscript-263c88ec.css"></noscript><link rel="icon" href="https://pezkuwichain.io/favicon.ico"></head><body class="rustdoc src"><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer" title="Drag to resize sidebar"></div><main><section id="main-content" class="content"><div class="main-heading"><h1><div class="sub-heading">pezkuwi_sdk_docs/reference_docs/</div>development_environment_advice.rs</h1><rustdoc-toolbar></rustdoc-toolbar></div><div class="example-wrap digits-3"><pre class="rust"><code><a href=#1 id=1 data-nosnippet>1</a><span class="doccomment">//! # Development Environment Advice
|
||||
<a href=#2 id=2 data-nosnippet>2</a>//!
|
||||
<a href=#3 id=3 data-nosnippet>3</a>//! Large Rust projects are known for sometimes long compile times and sluggish dev tooling, and
|
||||
<a href=#4 id=4 data-nosnippet>4</a>//! pezkuwi-sdk is no exception.
|
||||
<a href=#5 id=5 data-nosnippet>5</a>//!
|
||||
<a href=#6 id=6 data-nosnippet>6</a>//! This page contains some advice to improve your workflow when using common tooling.
|
||||
<a href=#7 id=7 data-nosnippet>7</a>//!
|
||||
<a href=#8 id=8 data-nosnippet>8</a>//! ## Rust Analyzer Configuration
|
||||
<a href=#9 id=9 data-nosnippet>9</a>//!
|
||||
<a href=#10 id=10 data-nosnippet>10</a>//! [Rust Analyzer](https://rust-analyzer.github.io/) is the defacto [LSP](https://langserver.org/) for Rust. Its default
|
||||
<a href=#11 id=11 data-nosnippet>11</a>//! settings are fine for smaller projects, but not well optimised for pezkuwi-sdk.
|
||||
<a href=#12 id=12 data-nosnippet>12</a>//!
|
||||
<a href=#13 id=13 data-nosnippet>13</a>//! Below is a suggested configuration for VSCode or any VSCode-based editor like Cursor:
|
||||
<a href=#14 id=14 data-nosnippet>14</a>//!
|
||||
<a href=#15 id=15 data-nosnippet>15</a>//! ```json
|
||||
<a href=#16 id=16 data-nosnippet>16</a>//! {
|
||||
<a href=#17 id=17 data-nosnippet>17</a>//! // Use a separate target dir for Rust Analyzer. Helpful if you want to use Rust
|
||||
<a href=#18 id=18 data-nosnippet>18</a>//! // Analyzer and cargo on the command line at the same time,
|
||||
<a href=#19 id=19 data-nosnippet>19</a>//! // at the expense of duplicating build artifacts.
|
||||
<a href=#20 id=20 data-nosnippet>20</a>//! "rust-analyzer.cargo.targetDir": "target/vscode-rust-analyzer",
|
||||
<a href=#21 id=21 data-nosnippet>21</a>//! // Improve stability
|
||||
<a href=#22 id=22 data-nosnippet>22</a>//! "rust-analyzer.server.extraEnv": {
|
||||
<a href=#23 id=23 data-nosnippet>23</a>//! "CHALK_OVERFLOW_DEPTH": "100000000",
|
||||
<a href=#24 id=24 data-nosnippet>24</a>//! "CHALK_SOLVER_MAX_SIZE": "10000000"
|
||||
<a href=#25 id=25 data-nosnippet>25</a>//! },
|
||||
<a href=#26 id=26 data-nosnippet>26</a>//! // Check feature-gated code
|
||||
<a href=#27 id=27 data-nosnippet>27</a>//! "rust-analyzer.cargo.features": "all",
|
||||
<a href=#28 id=28 data-nosnippet>28</a>//! "rust-analyzer.cargo.extraEnv": {
|
||||
<a href=#29 id=29 data-nosnippet>29</a>//! // Skip building WASM, there is never need for it here
|
||||
<a href=#30 id=30 data-nosnippet>30</a>//! "SKIP_WASM_BUILD": "1"
|
||||
<a href=#31 id=31 data-nosnippet>31</a>//! },
|
||||
<a href=#32 id=32 data-nosnippet>32</a>//! // Don't expand some problematic proc_macros
|
||||
<a href=#33 id=33 data-nosnippet>33</a>//! "rust-analyzer.procMacro.ignored": {
|
||||
<a href=#34 id=34 data-nosnippet>34</a>//! "async-trait": ["async_trait"],
|
||||
<a href=#35 id=35 data-nosnippet>35</a>//! "napi-derive": ["napi"],
|
||||
<a href=#36 id=36 data-nosnippet>36</a>//! "async-recursion": ["async_recursion"],
|
||||
<a href=#37 id=37 data-nosnippet>37</a>//! "async-std": ["async_std"]
|
||||
<a href=#38 id=38 data-nosnippet>38</a>//! },
|
||||
<a href=#39 id=39 data-nosnippet>39</a>//! // Use nightly formatting.
|
||||
<a href=#40 id=40 data-nosnippet>40</a>//! // See the pezkuwi-sdk CI job that checks formatting for the current version used in
|
||||
<a href=#41 id=41 data-nosnippet>41</a>//! // pezkuwi-sdk.
|
||||
<a href=#42 id=42 data-nosnippet>42</a>//! "rust-analyzer.rustfmt.extraArgs": ["+nightly-2024-04-10"],
|
||||
<a href=#43 id=43 data-nosnippet>43</a>//! }
|
||||
<a href=#44 id=44 data-nosnippet>44</a>//! ```
|
||||
<a href=#45 id=45 data-nosnippet>45</a>//!
|
||||
<a href=#46 id=46 data-nosnippet>46</a>//! and the same in Lua for `neovim/nvim-lspconfig`:
|
||||
<a href=#47 id=47 data-nosnippet>47</a>//!
|
||||
<a href=#48 id=48 data-nosnippet>48</a>//! ```lua
|
||||
<a href=#49 id=49 data-nosnippet>49</a>//! ["rust-analyzer"] = {
|
||||
<a href=#50 id=50 data-nosnippet>50</a>//! rust = {
|
||||
<a href=#51 id=51 data-nosnippet>51</a>//! # Use a separate target dir for Rust Analyzer. Helpful if you want to use Rust
|
||||
<a href=#52 id=52 data-nosnippet>52</a>//! # Analyzer and cargo on the command line at the same time.
|
||||
<a href=#53 id=53 data-nosnippet>53</a>//! analyzerTargetDir = "target/nvim-rust-analyzer",
|
||||
<a href=#54 id=54 data-nosnippet>54</a>//! },
|
||||
<a href=#55 id=55 data-nosnippet>55</a>//! server = {
|
||||
<a href=#56 id=56 data-nosnippet>56</a>//! # Improve stability
|
||||
<a href=#57 id=57 data-nosnippet>57</a>//! extraEnv = {
|
||||
<a href=#58 id=58 data-nosnippet>58</a>//! ["CHALK_OVERFLOW_DEPTH"] = "100000000",
|
||||
<a href=#59 id=59 data-nosnippet>59</a>//! ["CHALK_SOLVER_MAX_SIZE"] = "100000000",
|
||||
<a href=#60 id=60 data-nosnippet>60</a>//! },
|
||||
<a href=#61 id=61 data-nosnippet>61</a>//! },
|
||||
<a href=#62 id=62 data-nosnippet>62</a>//! cargo = {
|
||||
<a href=#63 id=63 data-nosnippet>63</a>//! # Check feature-gated code
|
||||
<a href=#64 id=64 data-nosnippet>64</a>//! features = "all",
|
||||
<a href=#65 id=65 data-nosnippet>65</a>//! extraEnv = {
|
||||
<a href=#66 id=66 data-nosnippet>66</a>//! # Skip building WASM, there is never need for it here
|
||||
<a href=#67 id=67 data-nosnippet>67</a>//! ["SKIP_WASM_BUILD"] = "1",
|
||||
<a href=#68 id=68 data-nosnippet>68</a>//! },
|
||||
<a href=#69 id=69 data-nosnippet>69</a>//! },
|
||||
<a href=#70 id=70 data-nosnippet>70</a>//! procMacro = {
|
||||
<a href=#71 id=71 data-nosnippet>71</a>//! # Don't expand some problematic proc_macros
|
||||
<a href=#72 id=72 data-nosnippet>72</a>//! ignored = {
|
||||
<a href=#73 id=73 data-nosnippet>73</a>//! ["async-trait"] = { "async_trait" },
|
||||
<a href=#74 id=74 data-nosnippet>74</a>//! ["napi-derive"] = { "napi" },
|
||||
<a href=#75 id=75 data-nosnippet>75</a>//! ["async-recursion"] = { "async_recursion" },
|
||||
<a href=#76 id=76 data-nosnippet>76</a>//! ["async-std"] = { "async_std" },
|
||||
<a href=#77 id=77 data-nosnippet>77</a>//! },
|
||||
<a href=#78 id=78 data-nosnippet>78</a>//! },
|
||||
<a href=#79 id=79 data-nosnippet>79</a>//! rustfmt = {
|
||||
<a href=#80 id=80 data-nosnippet>80</a>//! # Use nightly formatting.
|
||||
<a href=#81 id=81 data-nosnippet>81</a>//! # See the pezkuwi-sdk CI job that checks formatting for the current version used in
|
||||
<a href=#82 id=82 data-nosnippet>82</a>//! # pezkuwi-sdk.
|
||||
<a href=#83 id=83 data-nosnippet>83</a>//! extraArgs = { "+nightly-2024-04-10" },
|
||||
<a href=#84 id=84 data-nosnippet>84</a>//! },
|
||||
<a href=#85 id=85 data-nosnippet>85</a>//! },
|
||||
<a href=#86 id=86 data-nosnippet>86</a>//! ```
|
||||
<a href=#87 id=87 data-nosnippet>87</a>//!
|
||||
<a href=#88 id=88 data-nosnippet>88</a>//! Alternatively for neovim, if you are using [Rustaceanvim](https://github.com/mrcjkb/rustaceanvim),
|
||||
<a href=#89 id=89 data-nosnippet>89</a>//! you can achieve the same configuring `rust-analyzer` via `rustaceanvim` as follows:
|
||||
<a href=#90 id=90 data-nosnippet>90</a>//! ```lua
|
||||
<a href=#91 id=91 data-nosnippet>91</a>//! return {
|
||||
<a href=#92 id=92 data-nosnippet>92</a>//! {
|
||||
<a href=#93 id=93 data-nosnippet>93</a>//! "mrcjkb/rustaceanvim",
|
||||
<a href=#94 id=94 data-nosnippet>94</a>//! opts = {
|
||||
<a href=#95 id=95 data-nosnippet>95</a>//! server = {
|
||||
<a href=#96 id=96 data-nosnippet>96</a>//! default_settings = {
|
||||
<a href=#97 id=97 data-nosnippet>97</a>//! ["rust-analyzer"] = {
|
||||
<a href=#98 id=98 data-nosnippet>98</a>//! // put the same config as for nvim-lspconfig here
|
||||
<a href=#99 id=99 data-nosnippet>99</a>//! },
|
||||
<a href=#100 id=100 data-nosnippet>100</a>//! },
|
||||
<a href=#101 id=101 data-nosnippet>101</a>//! },
|
||||
<a href=#102 id=102 data-nosnippet>102</a>//! },
|
||||
<a href=#103 id=103 data-nosnippet>103</a>//! },
|
||||
<a href=#104 id=104 data-nosnippet>104</a>//! }
|
||||
<a href=#105 id=105 data-nosnippet>105</a>//! ```
|
||||
<a href=#106 id=106 data-nosnippet>106</a>//!
|
||||
<a href=#107 id=107 data-nosnippet>107</a>//! Similarly for Zed, you can replicate the same VSCode configuration in
|
||||
<a href=#108 id=108 data-nosnippet>108</a>//! `~/.config/zed/settings.json` as follows:
|
||||
<a href=#109 id=109 data-nosnippet>109</a>//! ```json
|
||||
<a href=#110 id=110 data-nosnippet>110</a>//! "lsp": {
|
||||
<a href=#111 id=111 data-nosnippet>111</a>//! "rust-analyzer": {
|
||||
<a href=#112 id=112 data-nosnippet>112</a>//! "initialization_options": {
|
||||
<a href=#113 id=113 data-nosnippet>113</a>//! // same config as for VSCode for rust, cargo, procMacros, ...
|
||||
<a href=#114 id=114 data-nosnippet>114</a>//! }
|
||||
<a href=#115 id=115 data-nosnippet>115</a>//! }
|
||||
<a href=#116 id=116 data-nosnippet>116</a>//! },
|
||||
<a href=#117 id=117 data-nosnippet>117</a>//! ```
|
||||
<a href=#118 id=118 data-nosnippet>118</a>//!
|
||||
<a href=#119 id=119 data-nosnippet>119</a>//! In general, refer to your favorite editor / IDE's documentation to properly configure
|
||||
<a href=#120 id=120 data-nosnippet>120</a>//! `rust-analyzer` as language server.
|
||||
<a href=#121 id=121 data-nosnippet>121</a>//! For the full set of configuration options see <https://rust-analyzer.github.io/manual.html#configuration>.
|
||||
<a href=#122 id=122 data-nosnippet>122</a>//!
|
||||
<a href=#123 id=123 data-nosnippet>123</a>//! ## Cargo Usage
|
||||
<a href=#124 id=124 data-nosnippet>124</a>//!
|
||||
<a href=#125 id=125 data-nosnippet>125</a>//! ### Using `--package` (a.k.a. `-p`)
|
||||
<a href=#126 id=126 data-nosnippet>126</a>//!
|
||||
<a href=#127 id=127 data-nosnippet>127</a>//! pezkuwi-sdk is a monorepo containing many crates. When you run a cargo command without
|
||||
<a href=#128 id=128 data-nosnippet>128</a>//! `-p`, you will almost certainly compile crates outside of the scope you are working.
|
||||
<a href=#129 id=129 data-nosnippet>129</a>//!
|
||||
<a href=#130 id=130 data-nosnippet>130</a>//! Instead, you should identify the name of the crate you are working on by checking the `name`
|
||||
<a href=#131 id=131 data-nosnippet>131</a>//! field in the closest `Cargo.toml` file. Then, use `-p` with your cargo commands to only compile
|
||||
<a href=#132 id=132 data-nosnippet>132</a>//! that crate.
|
||||
<a href=#133 id=133 data-nosnippet>133</a>//!
|
||||
<a href=#134 id=134 data-nosnippet>134</a>//! ### `SKIP_WASM_BUILD=1` environment variable
|
||||
<a href=#135 id=135 data-nosnippet>135</a>//!
|
||||
<a href=#136 id=136 data-nosnippet>136</a>//! When cargo touches a runtime crate, by default it will also compile the WASM binary,
|
||||
<a href=#137 id=137 data-nosnippet>137</a>//! approximately doubling the compilation time.
|
||||
<a href=#138 id=138 data-nosnippet>138</a>//!
|
||||
<a href=#139 id=139 data-nosnippet>139</a>//! The WASM binary is usually not needed, especially when running `check` or `test`. To skip the
|
||||
<a href=#140 id=140 data-nosnippet>140</a>//! WASM build, set the `SKIP_WASM_BUILD` environment variable to `1`. For example:
|
||||
<a href=#141 id=141 data-nosnippet>141</a>//! `SKIP_WASM_BUILD=1 cargo check -p frame-support`.
|
||||
<a href=#142 id=142 data-nosnippet>142</a>//!
|
||||
<a href=#143 id=143 data-nosnippet>143</a>//! ### Cargo Remote
|
||||
<a href=#144 id=144 data-nosnippet>144</a>//!
|
||||
<a href=#145 id=145 data-nosnippet>145</a>//! Warning: cargo remote by default doesn't transfer hidden files to the remote machine. But hidden
|
||||
<a href=#146 id=146 data-nosnippet>146</a>//! files can be useful, e.g. for sqlx usage. On the other hand using `--transfer-hidden` flag will
|
||||
<a href=#147 id=147 data-nosnippet>147</a>//! transfer `.git` which is big.
|
||||
<a href=#148 id=148 data-nosnippet>148</a>//!
|
||||
<a href=#149 id=149 data-nosnippet>149</a>//! If you have a powerful remote server available, you may consider using
|
||||
<a href=#150 id=150 data-nosnippet>150</a>//! [cargo-remote](https://github.com/sgeisler/cargo-remote) to execute cargo commands on it,
|
||||
<a href=#151 id=151 data-nosnippet>151</a>//! freeing up local resources for other tasks like `rust-analyzer`.
|
||||
<a href=#152 id=152 data-nosnippet>152</a>//!
|
||||
<a href=#153 id=153 data-nosnippet>153</a>//! When using `cargo-remote`, you can configure your editor to perform the the typical
|
||||
<a href=#154 id=154 data-nosnippet>154</a>//! "check-on-save" remotely as well. The configuration for VSCode (or any VSCode-based editor like
|
||||
<a href=#155 id=155 data-nosnippet>155</a>//! Cursor) is as follows:
|
||||
<a href=#156 id=156 data-nosnippet>156</a>//!
|
||||
<a href=#157 id=157 data-nosnippet>157</a>//! ```json
|
||||
<a href=#158 id=158 data-nosnippet>158</a>//! {
|
||||
<a href=#159 id=159 data-nosnippet>159</a>//! "rust-analyzer.cargo.buildScripts.overrideCommand": [
|
||||
<a href=#160 id=160 data-nosnippet>160</a>//! "cargo",
|
||||
<a href=#161 id=161 data-nosnippet>161</a>//! "remote",
|
||||
<a href=#162 id=162 data-nosnippet>162</a>//! "--build-env",
|
||||
<a href=#163 id=163 data-nosnippet>163</a>//! "SKIP_WASM_BUILD=1",
|
||||
<a href=#164 id=164 data-nosnippet>164</a>//! "--",
|
||||
<a href=#165 id=165 data-nosnippet>165</a>//! "check",
|
||||
<a href=#166 id=166 data-nosnippet>166</a>//! "--message-format=json",
|
||||
<a href=#167 id=167 data-nosnippet>167</a>//! "--all-targets",
|
||||
<a href=#168 id=168 data-nosnippet>168</a>//! "--all-features",
|
||||
<a href=#169 id=169 data-nosnippet>169</a>//! "--target-dir=target/rust-analyzer"
|
||||
<a href=#170 id=170 data-nosnippet>170</a>//! ],
|
||||
<a href=#171 id=171 data-nosnippet>171</a>//! "rust-analyzer.check.overrideCommand": [
|
||||
<a href=#172 id=172 data-nosnippet>172</a>//! "cargo",
|
||||
<a href=#173 id=173 data-nosnippet>173</a>//! "remote",
|
||||
<a href=#174 id=174 data-nosnippet>174</a>//! "--build-env",
|
||||
<a href=#175 id=175 data-nosnippet>175</a>//! "SKIP_WASM_BUILD=1",
|
||||
<a href=#176 id=176 data-nosnippet>176</a>//! "--",
|
||||
<a href=#177 id=177 data-nosnippet>177</a>//! "check",
|
||||
<a href=#178 id=178 data-nosnippet>178</a>//! "--workspace",
|
||||
<a href=#179 id=179 data-nosnippet>179</a>//! "--message-format=json",
|
||||
<a href=#180 id=180 data-nosnippet>180</a>//! "--all-targets",
|
||||
<a href=#181 id=181 data-nosnippet>181</a>//! "--all-features",
|
||||
<a href=#182 id=182 data-nosnippet>182</a>//! "--target-dir=target/rust-analyzer"
|
||||
<a href=#183 id=183 data-nosnippet>183</a>//! ],
|
||||
<a href=#184 id=184 data-nosnippet>184</a>//! }
|
||||
<a href=#185 id=185 data-nosnippet>185</a>//! ```
|
||||
<a href=#186 id=186 data-nosnippet>186</a>//!
|
||||
<a href=#187 id=187 data-nosnippet>187</a>//! and the same in Lua for `neovim/nvim-lspconfig`:
|
||||
<a href=#188 id=188 data-nosnippet>188</a>//!
|
||||
<a href=#189 id=189 data-nosnippet>189</a>//! ```lua
|
||||
<a href=#190 id=190 data-nosnippet>190</a>//! ["rust-analyzer"] = {
|
||||
<a href=#191 id=191 data-nosnippet>191</a>//! cargo = {
|
||||
<a href=#192 id=192 data-nosnippet>192</a>//! buildScripts = {
|
||||
<a href=#193 id=193 data-nosnippet>193</a>//! overrideCommand = {
|
||||
<a href=#194 id=194 data-nosnippet>194</a>//! "cargo",
|
||||
<a href=#195 id=195 data-nosnippet>195</a>//! "remote",
|
||||
<a href=#196 id=196 data-nosnippet>196</a>//! "--build-env",
|
||||
<a href=#197 id=197 data-nosnippet>197</a>//! "SKIP_WASM_BUILD=1",
|
||||
<a href=#198 id=198 data-nosnippet>198</a>//! "--",
|
||||
<a href=#199 id=199 data-nosnippet>199</a>//! "check",
|
||||
<a href=#200 id=200 data-nosnippet>200</a>//! "--message-format=json",
|
||||
<a href=#201 id=201 data-nosnippet>201</a>//! "--all-targets",
|
||||
<a href=#202 id=202 data-nosnippet>202</a>//! "--all-features",
|
||||
<a href=#203 id=203 data-nosnippet>203</a>//! "--target-dir=target/rust-analyzer"
|
||||
<a href=#204 id=204 data-nosnippet>204</a>//! },
|
||||
<a href=#205 id=205 data-nosnippet>205</a>//! },
|
||||
<a href=#206 id=206 data-nosnippet>206</a>//! },
|
||||
<a href=#207 id=207 data-nosnippet>207</a>//! check = {
|
||||
<a href=#208 id=208 data-nosnippet>208</a>//! overrideCommand = {
|
||||
<a href=#209 id=209 data-nosnippet>209</a>//! "cargo",
|
||||
<a href=#210 id=210 data-nosnippet>210</a>//! "remote",
|
||||
<a href=#211 id=211 data-nosnippet>211</a>//! "--build-env",
|
||||
<a href=#212 id=212 data-nosnippet>212</a>//! "SKIP_WASM_BUILD=1",
|
||||
<a href=#213 id=213 data-nosnippet>213</a>//! "--",
|
||||
<a href=#214 id=214 data-nosnippet>214</a>//! "check",
|
||||
<a href=#215 id=215 data-nosnippet>215</a>//! "--workspace",
|
||||
<a href=#216 id=216 data-nosnippet>216</a>//! "--message-format=json",
|
||||
<a href=#217 id=217 data-nosnippet>217</a>//! "--all-targets",
|
||||
<a href=#218 id=218 data-nosnippet>218</a>//! "--all-features",
|
||||
<a href=#219 id=219 data-nosnippet>219</a>//! "--target-dir=target/rust-analyzer"
|
||||
<a href=#220 id=220 data-nosnippet>220</a>//! },
|
||||
<a href=#221 id=221 data-nosnippet>221</a>//! },
|
||||
<a href=#222 id=222 data-nosnippet>222</a>//! },
|
||||
<a href=#223 id=223 data-nosnippet>223</a>//! ```</span></code></pre></div></section></main></body></html>
|
||||
@@ -0,0 +1,333 @@
|
||||
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `docs/sdk/src/reference_docs/extrinsic_encoding.rs`."><title>extrinsic_encoding.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2"href="../../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../../../static.files/rustdoc-e56847b5.css"><meta name="rustdoc-vars" data-root-path="../../../" data-static-root-path="../../../static.files/" data-current-crate="pezkuwi_sdk_docs" data-themes="" data-resource-suffix="" data-rustdoc-version="1.91.1 (ed61e7d7e 2025-11-07)" data-channel="1.91.1" data-search-js="search-e256b49e.js" data-stringdex-js="stringdex-c3e638e9.js" data-settings-js="settings-c38705f0.js" ><script src="../../../static.files/storage-e2aeef58.js"></script><script defer src="../../../static.files/src-script-813739b1.js"></script><script defer src="../../../src-files.js"></script><script defer src="../../../static.files/main-6dc2a7f3.js"></script><noscript><link rel="stylesheet" href="../../../static.files/noscript-263c88ec.css"></noscript><link rel="icon" href="https://pezkuwichain.io/favicon.ico"></head><body class="rustdoc src"><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer" title="Drag to resize sidebar"></div><main><section id="main-content" class="content"><div class="main-heading"><h1><div class="sub-heading">pezkuwi_sdk_docs/reference_docs/</div>extrinsic_encoding.rs</h1><rustdoc-toolbar></rustdoc-toolbar></div><div class="example-wrap digits-3"><pre class="rust"><code><a href=#1 id=1 data-nosnippet>1</a><span class="doccomment">//! # Constructing and Signing Extrinsics
|
||||
<a href=#2 id=2 data-nosnippet>2</a>//!
|
||||
<a href=#3 id=3 data-nosnippet>3</a>//! Extrinsics are payloads that are stored in blocks which are responsible for altering the state
|
||||
<a href=#4 id=4 data-nosnippet>4</a>//! of a blockchain via the [_state transition
|
||||
<a href=#5 id=5 data-nosnippet>5</a>//! function_][crate::reference_docs::blockchain_state_machines].
|
||||
<a href=#6 id=6 data-nosnippet>6</a>//!
|
||||
<a href=#7 id=7 data-nosnippet>7</a>//! Substrate is configurable enough that extrinsics can take any format. In practice, runtimes
|
||||
<a href=#8 id=8 data-nosnippet>8</a>//! tend to use our [`sp_runtime::generic::UncheckedExtrinsic`] type to represent extrinsics,
|
||||
<a href=#9 id=9 data-nosnippet>9</a>//! because it's generic enough to cater for most (if not all) use cases. In Pezkuwi, this is
|
||||
<a href=#10 id=10 data-nosnippet>10</a>//! configured [here](https://github.com/pezkuwichain/pezkuwi-fellows/tree/main/runtimes/blob/94b2798b69ba6779764e20a50f056e48db78ebef/relay/pezkuwi/src/lib.rs#L1478)
|
||||
<a href=#11 id=11 data-nosnippet>11</a>//! at the time of writing.
|
||||
<a href=#12 id=12 data-nosnippet>12</a>//!
|
||||
<a href=#13 id=13 data-nosnippet>13</a>//! What follows is a description of how extrinsics based on this
|
||||
<a href=#14 id=14 data-nosnippet>14</a>//! [`sp_runtime::generic::UncheckedExtrinsic`] type are encoded into bytes. Specifically, we are
|
||||
<a href=#15 id=15 data-nosnippet>15</a>//! looking at how extrinsics with a format version of 5 are encoded. This version is itself a part
|
||||
<a href=#16 id=16 data-nosnippet>16</a>//! of the payload, and if it changes, it indicates that something about the encoding may have
|
||||
<a href=#17 id=17 data-nosnippet>17</a>//! changed.
|
||||
<a href=#18 id=18 data-nosnippet>18</a>//!
|
||||
<a href=#19 id=19 data-nosnippet>19</a>//! # Encoding an Extrinsic
|
||||
<a href=#20 id=20 data-nosnippet>20</a>//!
|
||||
<a href=#21 id=21 data-nosnippet>21</a>//! At a high level, all extrinsics compatible with [`sp_runtime::generic::UncheckedExtrinsic`]
|
||||
<a href=#22 id=22 data-nosnippet>22</a>//! are formed from concatenating some details together, as in the following pseudo-code:
|
||||
<a href=#23 id=23 data-nosnippet>23</a>//!
|
||||
<a href=#24 id=24 data-nosnippet>24</a>//! ```text
|
||||
<a href=#25 id=25 data-nosnippet>25</a>//! extrinsic_bytes = concat(
|
||||
<a href=#26 id=26 data-nosnippet>26</a>//! compact_encoded_length,
|
||||
<a href=#27 id=27 data-nosnippet>27</a>//! version_and_extrinsic_type,
|
||||
<a href=#28 id=28 data-nosnippet>28</a>//! maybe_extension_data,
|
||||
<a href=#29 id=29 data-nosnippet>29</a>//! call_data
|
||||
<a href=#30 id=30 data-nosnippet>30</a>//! )
|
||||
<a href=#31 id=31 data-nosnippet>31</a>//! ```
|
||||
<a href=#32 id=32 data-nosnippet>32</a>//!
|
||||
<a href=#33 id=33 data-nosnippet>33</a>//! For clarity, the actual implementation in Substrate looks like this:
|
||||
<a href=#34 id=34 data-nosnippet>34</a></span><span class="attr">#![doc = <span class="macro">docify::embed!</span>(<span class="string">"../../substrate/primitives/runtime/src/generic/unchecked_extrinsic.rs"</span>, unchecked_extrinsic_encode_impl)]
|
||||
<a href=#35 id=35 data-nosnippet>35</a></span><span class="doccomment">//!
|
||||
<a href=#36 id=36 data-nosnippet>36</a>//! Let's look at how each of these details is constructed:
|
||||
<a href=#37 id=37 data-nosnippet>37</a>//!
|
||||
<a href=#38 id=38 data-nosnippet>38</a>//! ## compact_encoded_length
|
||||
<a href=#39 id=39 data-nosnippet>39</a>//!
|
||||
<a href=#40 id=40 data-nosnippet>40</a>//! This is a [SCALE compact encoded][frame::deps::codec::Compact] integer which is equal to the
|
||||
<a href=#41 id=41 data-nosnippet>41</a>//! length, in bytes, of the rest of the extrinsic details.
|
||||
<a href=#42 id=42 data-nosnippet>42</a>//!
|
||||
<a href=#43 id=43 data-nosnippet>43</a>//! To obtain this value, we must encode and concatenate together the rest of the extrinsic details
|
||||
<a href=#44 id=44 data-nosnippet>44</a>//! first, and then obtain the byte length of these. We can then compact encode that length, and
|
||||
<a href=#45 id=45 data-nosnippet>45</a>//! prepend it to the rest of the details.
|
||||
<a href=#46 id=46 data-nosnippet>46</a>//!
|
||||
<a href=#47 id=47 data-nosnippet>47</a>//! ## version_and_maybe_signature
|
||||
<a href=#48 id=48 data-nosnippet>48</a>//!
|
||||
<a href=#49 id=49 data-nosnippet>49</a>//! If the extrinsic is _unsigned_, then `version_and_maybe_signature` will be just one byte
|
||||
<a href=#50 id=50 data-nosnippet>50</a>//! denoting the _transaction protocol version_, which is 4 (or `0b0000_0100`).
|
||||
<a href=#51 id=51 data-nosnippet>51</a>//!
|
||||
<a href=#52 id=52 data-nosnippet>52</a>//! If the extrinsic is _signed_ (all extrinsics submitted from users must be signed), then
|
||||
<a href=#53 id=53 data-nosnippet>53</a>//! `version_and_maybe_signature` is obtained by concatenating some details together, ie:
|
||||
<a href=#54 id=54 data-nosnippet>54</a>//!
|
||||
<a href=#55 id=55 data-nosnippet>55</a>//! ```text
|
||||
<a href=#56 id=56 data-nosnippet>56</a>//! version_and_maybe_signature = concat(
|
||||
<a href=#57 id=57 data-nosnippet>57</a>//! version_and_signed,
|
||||
<a href=#58 id=58 data-nosnippet>58</a>//! from_address,
|
||||
<a href=#59 id=59 data-nosnippet>59</a>//! signature,
|
||||
<a href=#60 id=60 data-nosnippet>60</a>//! transaction_extensions_extra,
|
||||
<a href=#61 id=61 data-nosnippet>61</a>//! )
|
||||
<a href=#62 id=62 data-nosnippet>62</a>//! ```
|
||||
<a href=#63 id=63 data-nosnippet>63</a>//!
|
||||
<a href=#64 id=64 data-nosnippet>64</a>//! Each of the details to be concatenated together is explained below:
|
||||
<a href=#65 id=65 data-nosnippet>65</a>//!
|
||||
<a href=#66 id=66 data-nosnippet>66</a>//! ## version_and_extrinsic_type
|
||||
<a href=#67 id=67 data-nosnippet>67</a>//!
|
||||
<a href=#68 id=68 data-nosnippet>68</a>//! This byte has 2 components:
|
||||
<a href=#69 id=69 data-nosnippet>69</a>//! - the 2 most significant bits represent the extrinsic type:
|
||||
<a href=#70 id=70 data-nosnippet>70</a>//! - bare - `0b00`
|
||||
<a href=#71 id=71 data-nosnippet>71</a>//! - signed - `0b10`
|
||||
<a href=#72 id=72 data-nosnippet>72</a>//! - general - `0b01`
|
||||
<a href=#73 id=73 data-nosnippet>73</a>//! - the 6 least significant bits represent the extrinsic format version (currently 5)
|
||||
<a href=#74 id=74 data-nosnippet>74</a>//!
|
||||
<a href=#75 id=75 data-nosnippet>75</a>//! ### Bare extrinsics
|
||||
<a href=#76 id=76 data-nosnippet>76</a>//!
|
||||
<a href=#77 id=77 data-nosnippet>77</a>//! If the extrinsic is _bare_, then `version_and_extrinsic_type` will be just the _transaction
|
||||
<a href=#78 id=78 data-nosnippet>78</a>//! protocol version_, which is 5 (or `0b0000_0101`). Bare extrinsics do not carry any other
|
||||
<a href=#79 id=79 data-nosnippet>79</a>//! extension data, so `maybe_extension_data` would not be included in the payload and the
|
||||
<a href=#80 id=80 data-nosnippet>80</a>//! `version_and_extrinsic_type` would always be followed by the encoded call bytes.
|
||||
<a href=#81 id=81 data-nosnippet>81</a>//!
|
||||
<a href=#82 id=82 data-nosnippet>82</a>//! ### Signed extrinsics
|
||||
<a href=#83 id=83 data-nosnippet>83</a>//!
|
||||
<a href=#84 id=84 data-nosnippet>84</a>//! If the extrinsic is _signed_ (all extrinsics submitted from users used to be signed up until
|
||||
<a href=#85 id=85 data-nosnippet>85</a>//! version 4), then `version_and_extrinsic_type` is obtained by having a MSB of `1` on the
|
||||
<a href=#86 id=86 data-nosnippet>86</a>//! _transaction protocol version_ byte (which translates to `0b1000_0101`).
|
||||
<a href=#87 id=87 data-nosnippet>87</a>//!
|
||||
<a href=#88 id=88 data-nosnippet>88</a>//! Additionally, _signed_ extrinsics also carry with them address and signature information encoded
|
||||
<a href=#89 id=89 data-nosnippet>89</a>//! as follows:
|
||||
<a href=#90 id=90 data-nosnippet>90</a>//!
|
||||
<a href=#91 id=91 data-nosnippet>91</a>//! #### from_address
|
||||
<a href=#92 id=92 data-nosnippet>92</a>//!
|
||||
<a href=#93 id=93 data-nosnippet>93</a>//! This is the [SCALE encoded][frame::deps::codec] address of the sender of the extrinsic. The
|
||||
<a href=#94 id=94 data-nosnippet>94</a>//! address is the first generic parameter of [`sp_runtime::generic::UncheckedExtrinsic`], and so
|
||||
<a href=#95 id=95 data-nosnippet>95</a>//! can vary from chain to chain.
|
||||
<a href=#96 id=96 data-nosnippet>96</a>//!
|
||||
<a href=#97 id=97 data-nosnippet>97</a>//! The address type used on the Pezkuwi relay chain is [`sp_runtime::MultiAddress<AccountId32>`],
|
||||
<a href=#98 id=98 data-nosnippet>98</a>//! where `AccountId32` is defined [here][`sp_core::crypto::AccountId32`]. When constructing a
|
||||
<a href=#99 id=99 data-nosnippet>99</a>//! signed extrinsic to be submitted to a Pezkuwi node, you'll always use the
|
||||
<a href=#100 id=100 data-nosnippet>100</a>//! [`sp_runtime::MultiAddress::Id`] variant to wrap your `AccountId32`.
|
||||
<a href=#101 id=101 data-nosnippet>101</a>//!
|
||||
<a href=#102 id=102 data-nosnippet>102</a>//! #### signature
|
||||
<a href=#103 id=103 data-nosnippet>103</a>//!
|
||||
<a href=#104 id=104 data-nosnippet>104</a>//! This is the [SCALE encoded][frame::deps::codec] signature. The signature type is configured via
|
||||
<a href=#105 id=105 data-nosnippet>105</a>//! the third generic parameter of [`sp_runtime::generic::UncheckedExtrinsic`], which determines the
|
||||
<a href=#106 id=106 data-nosnippet>106</a>//! shape of the signature and signing algorithm that should be used.
|
||||
<a href=#107 id=107 data-nosnippet>107</a>//!
|
||||
<a href=#108 id=108 data-nosnippet>108</a>//! The signature is obtained by signing the _signed payload_ bytes (see below on how this is
|
||||
<a href=#109 id=109 data-nosnippet>109</a>//! constructed) using the private key associated with the address and correct algorithm.
|
||||
<a href=#110 id=110 data-nosnippet>110</a>//!
|
||||
<a href=#111 id=111 data-nosnippet>111</a>//! The signature type used on the Pezkuwi relay chain is [`sp_runtime::MultiSignature`]; the
|
||||
<a href=#112 id=112 data-nosnippet>112</a>//! variants there are the types of signature that can be provided.
|
||||
<a href=#113 id=113 data-nosnippet>113</a>//!
|
||||
<a href=#114 id=114 data-nosnippet>114</a>//! ### General extrinsics
|
||||
<a href=#115 id=115 data-nosnippet>115</a>//!
|
||||
<a href=#116 id=116 data-nosnippet>116</a>//! If the extrinsic is _general_ (it doesn't carry a signature in the payload, only extension
|
||||
<a href=#117 id=117 data-nosnippet>117</a>//! data), then `version_and_extrinsic_type` is obtained by logical OR between the general
|
||||
<a href=#118 id=118 data-nosnippet>118</a>//! transaction type bits and the _transaction protocol version_ byte (which translates to
|
||||
<a href=#119 id=119 data-nosnippet>119</a>//! `0b0100_0101`).
|
||||
<a href=#120 id=120 data-nosnippet>120</a>//!
|
||||
<a href=#121 id=121 data-nosnippet>121</a>//! ### transaction_extensions_extra
|
||||
<a href=#122 id=122 data-nosnippet>122</a>//!
|
||||
<a href=#123 id=123 data-nosnippet>123</a>//! This is the concatenation of the [SCALE encoded][frame::deps::codec] bytes representing first a
|
||||
<a href=#124 id=124 data-nosnippet>124</a>//! single byte describing the extension version (this is bumped whenever a change occurs in the
|
||||
<a href=#125 id=125 data-nosnippet>125</a>//! transaction extension pipeline) followed by the bytes of each of the [_transaction
|
||||
<a href=#126 id=126 data-nosnippet>126</a>//! extensions_][sp_runtime::traits::TransactionExtension], and are configured by the fourth generic
|
||||
<a href=#127 id=127 data-nosnippet>127</a>//! parameter of [`sp_runtime::generic::UncheckedExtrinsic`]. Learn more about transaction
|
||||
<a href=#128 id=128 data-nosnippet>128</a>//! extensions [here][crate::reference_docs::transaction_extensions].
|
||||
<a href=#129 id=129 data-nosnippet>129</a>//!
|
||||
<a href=#130 id=130 data-nosnippet>130</a>//! When it comes to constructing an extrinsic, each transaction extension has two things that we
|
||||
<a href=#131 id=131 data-nosnippet>131</a>//! are interested in here:
|
||||
<a href=#132 id=132 data-nosnippet>132</a>//!
|
||||
<a href=#133 id=133 data-nosnippet>133</a>//! - The actual SCALE encoding of the transaction extension type itself; this is what will form our
|
||||
<a href=#134 id=134 data-nosnippet>134</a>//! `transaction_extensions_extra` bytes.
|
||||
<a href=#135 id=135 data-nosnippet>135</a>//! - An `Implicit` type. This is SCALE encoded into the `transaction_extensions_implicit` data (see
|
||||
<a href=#136 id=136 data-nosnippet>136</a>//! below).
|
||||
<a href=#137 id=137 data-nosnippet>137</a>//!
|
||||
<a href=#138 id=138 data-nosnippet>138</a>//! Either (or both) of these can encode to zero bytes.
|
||||
<a href=#139 id=139 data-nosnippet>139</a>//!
|
||||
<a href=#140 id=140 data-nosnippet>140</a>//! Each chain configures the set of transaction extensions that it uses in its runtime
|
||||
<a href=#141 id=141 data-nosnippet>141</a>//! configuration. At the time of writing, Pezkuwi configures them
|
||||
<a href=#142 id=142 data-nosnippet>142</a>//! [here](https://github.com/pezkuwichain/pezkuwi-fellows/tree/main/runtimes/blob/1dc04eb954eadf8aadb5d83990b89662dbb5a074/relay/pezkuwi/src/lib.rs#L1432C25-L1432C25).
|
||||
<a href=#143 id=143 data-nosnippet>143</a>//! Some of the common transaction extensions are defined
|
||||
<a href=#144 id=144 data-nosnippet>144</a>//! [here][frame::deps::frame_system#transaction-extensions].
|
||||
<a href=#145 id=145 data-nosnippet>145</a>//!
|
||||
<a href=#146 id=146 data-nosnippet>146</a>//! Information about exactly which transaction extensions are present on a chain and in what order
|
||||
<a href=#147 id=147 data-nosnippet>147</a>//! is also a part of the metadata for the chain. For V15 metadata, it can be [found
|
||||
<a href=#148 id=148 data-nosnippet>148</a>//! here][frame::deps::frame_support::__private::metadata::v15::ExtrinsicMetadata].
|
||||
<a href=#149 id=149 data-nosnippet>149</a>//!
|
||||
<a href=#150 id=150 data-nosnippet>150</a>//! ## call_data
|
||||
<a href=#151 id=151 data-nosnippet>151</a>//!
|
||||
<a href=#152 id=152 data-nosnippet>152</a>//! This is the main payload of the extrinsic, which is used to determine how the chain's state is
|
||||
<a href=#153 id=153 data-nosnippet>153</a>//! altered. This is defined by the second generic parameter of
|
||||
<a href=#154 id=154 data-nosnippet>154</a>//! [`sp_runtime::generic::UncheckedExtrinsic`].
|
||||
<a href=#155 id=155 data-nosnippet>155</a>//!
|
||||
<a href=#156 id=156 data-nosnippet>156</a>//! A call can be anything that implements [`Encode`][frame::deps::codec::Encode]. In FRAME-based
|
||||
<a href=#157 id=157 data-nosnippet>157</a>//! runtimes, a call is represented as an enum of enums, where the outer enum represents the FRAME
|
||||
<a href=#158 id=158 data-nosnippet>158</a>//! pallet being called, and the inner enum represents the call being made within that pallet, and
|
||||
<a href=#159 id=159 data-nosnippet>159</a>//! any arguments to it. Read more about the call enum
|
||||
<a href=#160 id=160 data-nosnippet>160</a>//! [here][crate::reference_docs::frame_runtime_types].
|
||||
<a href=#161 id=161 data-nosnippet>161</a>//!
|
||||
<a href=#162 id=162 data-nosnippet>162</a>//! FRAME `Call` enums are automatically generated, and end up looking something like this:
|
||||
<a href=#163 id=163 data-nosnippet>163</a></span><span class="attr">#![doc = <span class="macro">docify::embed!</span>(<span class="string">"./src/reference_docs/extrinsic_encoding.rs"</span>, call_data)]
|
||||
<a href=#164 id=164 data-nosnippet>164</a></span><span class="doccomment">//!
|
||||
<a href=#165 id=165 data-nosnippet>165</a>//! In pseudo-code, this `Call` enum encodes equivalently to:
|
||||
<a href=#166 id=166 data-nosnippet>166</a>//!
|
||||
<a href=#167 id=167 data-nosnippet>167</a>//! ```text
|
||||
<a href=#168 id=168 data-nosnippet>168</a>//! call_data = concat(
|
||||
<a href=#169 id=169 data-nosnippet>169</a>//! pallet_index,
|
||||
<a href=#170 id=170 data-nosnippet>170</a>//! call_index,
|
||||
<a href=#171 id=171 data-nosnippet>171</a>//! call_args
|
||||
<a href=#172 id=172 data-nosnippet>172</a>//! )
|
||||
<a href=#173 id=173 data-nosnippet>173</a>//! ```
|
||||
<a href=#174 id=174 data-nosnippet>174</a>//!
|
||||
<a href=#175 id=175 data-nosnippet>175</a>//! - `pallet_index` is a single byte denoting the index of the pallet that we are calling into, and
|
||||
<a href=#176 id=176 data-nosnippet>176</a>//! is what the tag of the outermost enum will encode to.
|
||||
<a href=#177 id=177 data-nosnippet>177</a>//! - `call_index` is a single byte denoting the index of the call that we are making the pallet,
|
||||
<a href=#178 id=178 data-nosnippet>178</a>//! and is what the tag of the inner enum will encode to.
|
||||
<a href=#179 id=179 data-nosnippet>179</a>//! - `call_args` are the SCALE encoded bytes for each of the arguments that the call expects, and
|
||||
<a href=#180 id=180 data-nosnippet>180</a>//! are typically provided as values to the inner enum.
|
||||
<a href=#181 id=181 data-nosnippet>181</a>//!
|
||||
<a href=#182 id=182 data-nosnippet>182</a>//! Information about the pallets that exist for a chain (including their indexes), the calls
|
||||
<a href=#183 id=183 data-nosnippet>183</a>//! available in each pallet (including their indexes), and the arguments required for each call can
|
||||
<a href=#184 id=184 data-nosnippet>184</a>//! be found in the metadata for the chain. For V15 metadata, this information [is
|
||||
<a href=#185 id=185 data-nosnippet>185</a>//! here][frame::deps::frame_support::__private::metadata::v15::PalletMetadata].
|
||||
<a href=#186 id=186 data-nosnippet>186</a>//!
|
||||
<a href=#187 id=187 data-nosnippet>187</a>//! # The Signed Payload Format
|
||||
<a href=#188 id=188 data-nosnippet>188</a>//!
|
||||
<a href=#189 id=189 data-nosnippet>189</a>//! All _signed_ extrinsics submitted to a node from the outside world (also known as
|
||||
<a href=#190 id=190 data-nosnippet>190</a>//! _transactions_) need to be _signed_. The data that needs to be signed for some extrinsic is
|
||||
<a href=#191 id=191 data-nosnippet>191</a>//! called the _signed payload_, and its shape is described by the following pseudo-code:
|
||||
<a href=#192 id=192 data-nosnippet>192</a>//!
|
||||
<a href=#193 id=193 data-nosnippet>193</a>//! ```text
|
||||
<a href=#194 id=194 data-nosnippet>194</a>//! signed_payload = blake2_256(
|
||||
<a href=#195 id=195 data-nosnippet>195</a>//! concat(
|
||||
<a href=#196 id=196 data-nosnippet>196</a>//! call_data,
|
||||
<a href=#197 id=197 data-nosnippet>197</a>//! transaction_extensions_extra,
|
||||
<a href=#198 id=198 data-nosnippet>198</a>//! transaction_extensions_implicit,
|
||||
<a href=#199 id=199 data-nosnippet>199</a>//! )
|
||||
<a href=#200 id=200 data-nosnippet>200</a>//! )
|
||||
<a href=#201 id=201 data-nosnippet>201</a>//! ```
|
||||
<a href=#202 id=202 data-nosnippet>202</a>//!
|
||||
<a href=#203 id=203 data-nosnippet>203</a>//! The bytes representing `call_data` and `transaction_extensions_extra` can be obtained as
|
||||
<a href=#204 id=204 data-nosnippet>204</a>//! descibed above. `transaction_extensions_implicit` is constructed by SCALE encoding the
|
||||
<a href=#205 id=205 data-nosnippet>205</a>//! ["implicit" data][sp_runtime::traits::TransactionExtension::Implicit] for each transaction
|
||||
<a href=#206 id=206 data-nosnippet>206</a>//! extension that the chain is using, in order.
|
||||
<a href=#207 id=207 data-nosnippet>207</a>//!
|
||||
<a href=#208 id=208 data-nosnippet>208</a>//! Once we've concatenated those together, we hash the result using a Blake2 256bit hasher.
|
||||
<a href=#209 id=209 data-nosnippet>209</a>//!
|
||||
<a href=#210 id=210 data-nosnippet>210</a>//! The [`sp_runtime::generic::SignedPayload`] type takes care of assembling the correct payload for
|
||||
<a href=#211 id=211 data-nosnippet>211</a>//! us, given `call_data` and a tuple of transaction extensions.
|
||||
<a href=#212 id=212 data-nosnippet>212</a>//!
|
||||
<a href=#213 id=213 data-nosnippet>213</a>//! # The General Transaction Format
|
||||
<a href=#214 id=214 data-nosnippet>214</a>//!
|
||||
<a href=#215 id=215 data-nosnippet>215</a>//! A General transaction does not have a signature method hardcoded in the check logic of the
|
||||
<a href=#216 id=216 data-nosnippet>216</a>//! extrinsic, such as a traditionally signed transaction. Instead, general transactions should have
|
||||
<a href=#217 id=217 data-nosnippet>217</a>//! one or more extensions in the transaction extension pipeline that auhtorize origins in some way,
|
||||
<a href=#218 id=218 data-nosnippet>218</a>//! one of which could be the traditional signature check that happens for all signed transactions
|
||||
<a href=#219 id=219 data-nosnippet>219</a>//! in the [Checkable](sp_runtime::traits::Checkable) implementation of
|
||||
<a href=#220 id=220 data-nosnippet>220</a>//! [UncheckedExtrinsic](sp_runtime::generic::UncheckedExtrinsic). Therefore, it is up to each
|
||||
<a href=#221 id=221 data-nosnippet>221</a>//! extension to define the format of the payload it will try to check and authorize the right
|
||||
<a href=#222 id=222 data-nosnippet>222</a>//! origin type. For an example, look into the [authorization example pallet
|
||||
<a href=#223 id=223 data-nosnippet>223</a>//! extensions](pallet_example_authorization_tx_extension::extensions)
|
||||
<a href=#224 id=224 data-nosnippet>224</a>//!
|
||||
<a href=#225 id=225 data-nosnippet>225</a>//! # Example Encoding
|
||||
<a href=#226 id=226 data-nosnippet>226</a>//!
|
||||
<a href=#227 id=227 data-nosnippet>227</a>//! Using [`sp_runtime::generic::UncheckedExtrinsic`], we can construct and encode an extrinsic as
|
||||
<a href=#228 id=228 data-nosnippet>228</a>//! follows:
|
||||
<a href=#229 id=229 data-nosnippet>229</a></span><span class="attr">#![doc = <span class="macro">docify::embed!</span>(<span class="string">"./src/reference_docs/extrinsic_encoding.rs"</span>, encoding_example)]
|
||||
<a href=#230 id=230 data-nosnippet>230</a>
|
||||
<a href=#231 id=231 data-nosnippet>231</a>#[docify::export]
|
||||
<a href=#232 id=232 data-nosnippet>232</a></span><span class="kw">pub mod </span>call_data {
|
||||
<a href=#233 id=233 data-nosnippet>233</a> <span class="kw">use </span>codec::{Decode, Encode};
|
||||
<a href=#234 id=234 data-nosnippet>234</a> <span class="kw">use </span>sp_runtime::{traits::Dispatchable, DispatchResultWithInfo};
|
||||
<a href=#235 id=235 data-nosnippet>235</a>
|
||||
<a href=#236 id=236 data-nosnippet>236</a> <span class="comment">// The outer enum composes calls within
|
||||
<a href=#237 id=237 data-nosnippet>237</a> // different pallets together. We have two
|
||||
<a href=#238 id=238 data-nosnippet>238</a> // pallets, "PalletA" and "PalletB".
|
||||
<a href=#239 id=239 data-nosnippet>239</a> </span><span class="attr">#[derive(Encode, Decode, Clone)]
|
||||
<a href=#240 id=240 data-nosnippet>240</a> </span><span class="kw">pub enum </span>Call {
|
||||
<a href=#241 id=241 data-nosnippet>241</a> <span class="attr">#[codec(index = <span class="number">0</span>)]
|
||||
<a href=#242 id=242 data-nosnippet>242</a> </span>PalletA(PalletACall),
|
||||
<a href=#243 id=243 data-nosnippet>243</a> <span class="attr">#[codec(index = <span class="number">7</span>)]
|
||||
<a href=#244 id=244 data-nosnippet>244</a> </span>PalletB(PalletBCall),
|
||||
<a href=#245 id=245 data-nosnippet>245</a> }
|
||||
<a href=#246 id=246 data-nosnippet>246</a>
|
||||
<a href=#247 id=247 data-nosnippet>247</a> <span class="comment">// An inner enum represents the calls within
|
||||
<a href=#248 id=248 data-nosnippet>248</a> // a specific pallet. "PalletA" has one call,
|
||||
<a href=#249 id=249 data-nosnippet>249</a> // "Foo".
|
||||
<a href=#250 id=250 data-nosnippet>250</a> </span><span class="attr">#[derive(Encode, Decode, Clone)]
|
||||
<a href=#251 id=251 data-nosnippet>251</a> </span><span class="kw">pub enum </span>PalletACall {
|
||||
<a href=#252 id=252 data-nosnippet>252</a> <span class="attr">#[codec(index = <span class="number">0</span>)]
|
||||
<a href=#253 id=253 data-nosnippet>253</a> </span>Foo(String),
|
||||
<a href=#254 id=254 data-nosnippet>254</a> }
|
||||
<a href=#255 id=255 data-nosnippet>255</a>
|
||||
<a href=#256 id=256 data-nosnippet>256</a> <span class="attr">#[derive(Encode, Decode, Clone)]
|
||||
<a href=#257 id=257 data-nosnippet>257</a> </span><span class="kw">pub enum </span>PalletBCall {
|
||||
<a href=#258 id=258 data-nosnippet>258</a> <span class="attr">#[codec(index = <span class="number">0</span>)]
|
||||
<a href=#259 id=259 data-nosnippet>259</a> </span>Bar(String),
|
||||
<a href=#260 id=260 data-nosnippet>260</a> }
|
||||
<a href=#261 id=261 data-nosnippet>261</a>
|
||||
<a href=#262 id=262 data-nosnippet>262</a> <span class="kw">impl </span>Dispatchable <span class="kw">for </span>Call {
|
||||
<a href=#263 id=263 data-nosnippet>263</a> <span class="kw">type </span>RuntimeOrigin = ();
|
||||
<a href=#264 id=264 data-nosnippet>264</a> <span class="kw">type </span>Config = ();
|
||||
<a href=#265 id=265 data-nosnippet>265</a> <span class="kw">type </span>Info = ();
|
||||
<a href=#266 id=266 data-nosnippet>266</a> <span class="kw">type </span>PostInfo = ();
|
||||
<a href=#267 id=267 data-nosnippet>267</a> <span class="kw">fn </span>dispatch(<span class="self">self</span>, _origin: <span class="self">Self</span>::RuntimeOrigin) -> DispatchResultWithInfo<<span class="self">Self</span>::PostInfo> {
|
||||
<a href=#268 id=268 data-nosnippet>268</a> <span class="prelude-val">Ok</span>(())
|
||||
<a href=#269 id=269 data-nosnippet>269</a> }
|
||||
<a href=#270 id=270 data-nosnippet>270</a> }
|
||||
<a href=#271 id=271 data-nosnippet>271</a>}
|
||||
<a href=#272 id=272 data-nosnippet>272</a>
|
||||
<a href=#273 id=273 data-nosnippet>273</a><span class="attr">#[docify::export]
|
||||
<a href=#274 id=274 data-nosnippet>274</a></span><span class="kw">pub mod </span>encoding_example {
|
||||
<a href=#275 id=275 data-nosnippet>275</a> <span class="kw">use </span><span class="kw">super</span>::call_data::{Call, PalletACall};
|
||||
<a href=#276 id=276 data-nosnippet>276</a> <span class="kw">use </span><span class="kw">crate</span>::reference_docs::transaction_extensions::transaction_extensions_example;
|
||||
<a href=#277 id=277 data-nosnippet>277</a> <span class="kw">use </span>codec::Encode;
|
||||
<a href=#278 id=278 data-nosnippet>278</a> <span class="kw">use </span>sp_core::crypto::AccountId32;
|
||||
<a href=#279 id=279 data-nosnippet>279</a> <span class="kw">use </span>sp_keyring::sr25519::Keyring;
|
||||
<a href=#280 id=280 data-nosnippet>280</a> <span class="kw">use </span>sp_runtime::{
|
||||
<a href=#281 id=281 data-nosnippet>281</a> generic::{SignedPayload, UncheckedExtrinsic},
|
||||
<a href=#282 id=282 data-nosnippet>282</a> MultiAddress, MultiSignature,
|
||||
<a href=#283 id=283 data-nosnippet>283</a> };
|
||||
<a href=#284 id=284 data-nosnippet>284</a>
|
||||
<a href=#285 id=285 data-nosnippet>285</a> <span class="comment">// Define some transaction extensions to use. We'll use a couple of examples
|
||||
<a href=#286 id=286 data-nosnippet>286</a> // from the transaction extensions reference doc.
|
||||
<a href=#287 id=287 data-nosnippet>287</a> </span><span class="kw">type </span>TransactionExtensions = (
|
||||
<a href=#288 id=288 data-nosnippet>288</a> transaction_extensions_example::AddToPayload,
|
||||
<a href=#289 id=289 data-nosnippet>289</a> transaction_extensions_example::AddToSignaturePayload,
|
||||
<a href=#290 id=290 data-nosnippet>290</a> );
|
||||
<a href=#291 id=291 data-nosnippet>291</a>
|
||||
<a href=#292 id=292 data-nosnippet>292</a> <span class="comment">// We'll use `UncheckedExtrinsic` to encode our extrinsic for us. We set
|
||||
<a href=#293 id=293 data-nosnippet>293</a> // the address and signature type to those used on Pezkuwi, use our custom
|
||||
<a href=#294 id=294 data-nosnippet>294</a> // `Call` type, and use our custom set of `TransactionExtensions`.
|
||||
<a href=#295 id=295 data-nosnippet>295</a> </span><span class="kw">type </span>Extrinsic = UncheckedExtrinsic<
|
||||
<a href=#296 id=296 data-nosnippet>296</a> MultiAddress<AccountId32, ()>,
|
||||
<a href=#297 id=297 data-nosnippet>297</a> Call,
|
||||
<a href=#298 id=298 data-nosnippet>298</a> MultiSignature,
|
||||
<a href=#299 id=299 data-nosnippet>299</a> TransactionExtensions,
|
||||
<a href=#300 id=300 data-nosnippet>300</a> >;
|
||||
<a href=#301 id=301 data-nosnippet>301</a>
|
||||
<a href=#302 id=302 data-nosnippet>302</a> <span class="kw">pub fn </span>encode_demo_extrinsic() -> Vec<u8> {
|
||||
<a href=#303 id=303 data-nosnippet>303</a> <span class="comment">// The "from" address will be our Alice dev account.
|
||||
<a href=#304 id=304 data-nosnippet>304</a> </span><span class="kw">let </span>from_address = MultiAddress::<AccountId32, ()>::Id(Keyring::Alice.to_account_id());
|
||||
<a href=#305 id=305 data-nosnippet>305</a>
|
||||
<a href=#306 id=306 data-nosnippet>306</a> <span class="comment">// We provide some values for our expected transaction extensions.
|
||||
<a href=#307 id=307 data-nosnippet>307</a> </span><span class="kw">let </span>transaction_extensions = (
|
||||
<a href=#308 id=308 data-nosnippet>308</a> transaction_extensions_example::AddToPayload(<span class="number">1</span>),
|
||||
<a href=#309 id=309 data-nosnippet>309</a> transaction_extensions_example::AddToSignaturePayload,
|
||||
<a href=#310 id=310 data-nosnippet>310</a> );
|
||||
<a href=#311 id=311 data-nosnippet>311</a>
|
||||
<a href=#312 id=312 data-nosnippet>312</a> <span class="comment">// Construct our call data:
|
||||
<a href=#313 id=313 data-nosnippet>313</a> </span><span class="kw">let </span>call_data = Call::PalletA(PalletACall::Foo(<span class="string">"Hello"</span>.to_string()));
|
||||
<a href=#314 id=314 data-nosnippet>314</a>
|
||||
<a href=#315 id=315 data-nosnippet>315</a> <span class="comment">// The signed payload. This takes care of encoding the call_data,
|
||||
<a href=#316 id=316 data-nosnippet>316</a> // transaction_extensions_extra and transaction_extensions_implicit, and hashing
|
||||
<a href=#317 id=317 data-nosnippet>317</a> // the result if it's > 256 bytes:
|
||||
<a href=#318 id=318 data-nosnippet>318</a> </span><span class="kw">let </span>signed_payload = SignedPayload::new(call_data.clone(), transaction_extensions.clone());
|
||||
<a href=#319 id=319 data-nosnippet>319</a>
|
||||
<a href=#320 id=320 data-nosnippet>320</a> <span class="comment">// Sign the signed payload with our Alice dev account's private key,
|
||||
<a href=#321 id=321 data-nosnippet>321</a> // and wrap the signature into the expected type:
|
||||
<a href=#322 id=322 data-nosnippet>322</a> </span><span class="kw">let </span>signature = {
|
||||
<a href=#323 id=323 data-nosnippet>323</a> <span class="kw">let </span>sig = Keyring::Alice.sign(<span class="kw-2">&</span>signed_payload.encode());
|
||||
<a href=#324 id=324 data-nosnippet>324</a> MultiSignature::Sr25519(sig)
|
||||
<a href=#325 id=325 data-nosnippet>325</a> };
|
||||
<a href=#326 id=326 data-nosnippet>326</a>
|
||||
<a href=#327 id=327 data-nosnippet>327</a> <span class="comment">// Now, we can build and encode our extrinsic:
|
||||
<a href=#328 id=328 data-nosnippet>328</a> </span><span class="kw">let </span>ext = Extrinsic::new_signed(call_data, from_address, signature, transaction_extensions);
|
||||
<a href=#329 id=329 data-nosnippet>329</a>
|
||||
<a href=#330 id=330 data-nosnippet>330</a> <span class="kw">let </span>encoded_ext = ext.encode();
|
||||
<a href=#331 id=331 data-nosnippet>331</a> encoded_ext
|
||||
<a href=#332 id=332 data-nosnippet>332</a> }
|
||||
<a href=#333 id=333 data-nosnippet>333</a>}</code></pre></div></section></main></body></html>
|
||||
@@ -0,0 +1,13 @@
|
||||
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `docs/sdk/src/reference_docs/fee_less_runtime.rs`."><title>fee_less_runtime.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2"href="../../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../../../static.files/rustdoc-e56847b5.css"><meta name="rustdoc-vars" data-root-path="../../../" data-static-root-path="../../../static.files/" data-current-crate="pezkuwi_sdk_docs" data-themes="" data-resource-suffix="" data-rustdoc-version="1.91.1 (ed61e7d7e 2025-11-07)" data-channel="1.91.1" data-search-js="search-e256b49e.js" data-stringdex-js="stringdex-c3e638e9.js" data-settings-js="settings-c38705f0.js" ><script src="../../../static.files/storage-e2aeef58.js"></script><script defer src="../../../static.files/src-script-813739b1.js"></script><script defer src="../../../src-files.js"></script><script defer src="../../../static.files/main-6dc2a7f3.js"></script><noscript><link rel="stylesheet" href="../../../static.files/noscript-263c88ec.css"></noscript><link rel="icon" href="https://pezkuwichain.io/favicon.ico"></head><body class="rustdoc src"><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer" title="Drag to resize sidebar"></div><main><section id="main-content" class="content"><div class="main-heading"><h1><div class="sub-heading">pezkuwi_sdk_docs/reference_docs/</div>fee_less_runtime.rs</h1><rustdoc-toolbar></rustdoc-toolbar></div><div class="example-wrap digits-2"><pre class="rust"><code><a href=#1 id=1 data-nosnippet>1</a><span class="doccomment">//! # Fee-Less Runtime
|
||||
<a href=#2 id=2 data-nosnippet>2</a>//!
|
||||
<a href=#3 id=3 data-nosnippet>3</a>//! 🚧 Work In Progress 🚧
|
||||
<a href=#4 id=4 data-nosnippet>4</a>//!
|
||||
<a href=#5 id=5 data-nosnippet>5</a>//! Notes:
|
||||
<a href=#6 id=6 data-nosnippet>6</a>//!
|
||||
<a href=#7 id=7 data-nosnippet>7</a>//! - An extension of [`runtime_vs_smart_contract`], showcasing the tools needed to build a safe
|
||||
<a href=#8 id=8 data-nosnippet>8</a>//! runtime that is fee-less.
|
||||
<a href=#9 id=9 data-nosnippet>9</a>//! - Would need to use unsigned origins, custom validate_unsigned, check the existence of some NFT
|
||||
<a href=#10 id=10 data-nosnippet>10</a>//! and some kind of rate limiting (eg. any account gets 5 free tx per day).
|
||||
<a href=#11 id=11 data-nosnippet>11</a>//! - The rule of thumb is that as long as the unsigned validate does one storage read, similar to
|
||||
<a href=#12 id=12 data-nosnippet>12</a>//! nonce, it is fine.
|
||||
<a href=#13 id=13 data-nosnippet>13</a>//! - This could possibly be a good guide/template, rather than a reference doc.</span></code></pre></div></section></main></body></html>
|
||||
+212
@@ -0,0 +1,212 @@
|
||||
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `docs/sdk/src/reference_docs/frame_benchmarking_weight.rs`."><title>frame_benchmarking_weight.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2"href="../../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../../../static.files/rustdoc-e56847b5.css"><meta name="rustdoc-vars" data-root-path="../../../" data-static-root-path="../../../static.files/" data-current-crate="pezkuwi_sdk_docs" data-themes="" data-resource-suffix="" data-rustdoc-version="1.91.1 (ed61e7d7e 2025-11-07)" data-channel="1.91.1" data-search-js="search-e256b49e.js" data-stringdex-js="stringdex-c3e638e9.js" data-settings-js="settings-c38705f0.js" ><script src="../../../static.files/storage-e2aeef58.js"></script><script defer src="../../../static.files/src-script-813739b1.js"></script><script defer src="../../../src-files.js"></script><script defer src="../../../static.files/main-6dc2a7f3.js"></script><noscript><link rel="stylesheet" href="../../../static.files/noscript-263c88ec.css"></noscript><link rel="icon" href="https://pezkuwichain.io/favicon.ico"></head><body class="rustdoc src"><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer" title="Drag to resize sidebar"></div><main><section id="main-content" class="content"><div class="main-heading"><h1><div class="sub-heading">pezkuwi_sdk_docs/reference_docs/</div>frame_benchmarking_weight.rs</h1><rustdoc-toolbar></rustdoc-toolbar></div><div class="example-wrap digits-3"><pre class="rust"><code><a href=#1 id=1 data-nosnippet>1</a><span class="doccomment">//! # FRAME Benchmarking and Weights.
|
||||
<a href=#2 id=2 data-nosnippet>2</a>//!
|
||||
<a href=#3 id=3 data-nosnippet>3</a>//! This reference doc explores the concept of weights within Pezkuwi-SDK runtimes, and more
|
||||
<a href=#4 id=4 data-nosnippet>4</a>//! specifically how FRAME-based runtimes handle it.
|
||||
<a href=#5 id=5 data-nosnippet>5</a>//!
|
||||
<a href=#6 id=6 data-nosnippet>6</a>//! ## Metering
|
||||
<a href=#7 id=7 data-nosnippet>7</a>//!
|
||||
<a href=#8 id=8 data-nosnippet>8</a>//! The existence of "weight" as a concept in Pezkuwi-SDK is a direct consequence of the usage of
|
||||
<a href=#9 id=9 data-nosnippet>9</a>//! WASM as a virtual machine. Unlike a metered virtual machine like EVM, where every instruction
|
||||
<a href=#10 id=10 data-nosnippet>10</a>//! can have a (fairly) deterministic "cost" (also known as "gas price") associated with it, WASM is
|
||||
<a href=#11 id=11 data-nosnippet>11</a>//! a stack machine with more complex instruction set, and more unpredictable execution times. This
|
||||
<a href=#12 id=12 data-nosnippet>12</a>//! means that unlike EVM, it is not possible to implement a "metering" system in WASM. A metering
|
||||
<a href=#13 id=13 data-nosnippet>13</a>//! system is one in which instructions are executed one by one, and the cost/gas is stored in an
|
||||
<a href=#14 id=14 data-nosnippet>14</a>//! accumulator. The execution may then halt once a gas limit is reached.
|
||||
<a href=#15 id=15 data-nosnippet>15</a>//!
|
||||
<a href=#16 id=16 data-nosnippet>16</a>//! In Pezkuwi-SDK, the WASM runtime is not assumed to be metered.
|
||||
<a href=#17 id=17 data-nosnippet>17</a>//!
|
||||
<a href=#18 id=18 data-nosnippet>18</a>//! ## Trusted Code
|
||||
<a href=#19 id=19 data-nosnippet>19</a>//!
|
||||
<a href=#20 id=20 data-nosnippet>20</a>//! Another important difference is that EVM is mostly used to express smart contracts, which are
|
||||
<a href=#21 id=21 data-nosnippet>21</a>//! foreign and untrusted codes from the perspective of the blockchain executing them. In such
|
||||
<a href=#22 id=22 data-nosnippet>22</a>//! cases, metering is crucial, in order to ensure a malicious code cannot consume more gas than
|
||||
<a href=#23 id=23 data-nosnippet>23</a>//! expected.
|
||||
<a href=#24 id=24 data-nosnippet>24</a>//!
|
||||
<a href=#25 id=25 data-nosnippet>25</a>//! This assumption does not hold about the runtime of Pezkuwi-SDK-based blockchains. The runtime
|
||||
<a href=#26 id=26 data-nosnippet>26</a>//! is trusted code, and it is assumed to be written by the same team/developers who are running the
|
||||
<a href=#27 id=27 data-nosnippet>27</a>//! blockchain itself. Therefore, this assumption of "untrusted foreign code" does not hold.
|
||||
<a href=#28 id=28 data-nosnippet>28</a>//!
|
||||
<a href=#29 id=29 data-nosnippet>29</a>//! This is why the runtime can opt for a more performant, more flexible virtual machine like WASM,
|
||||
<a href=#30 id=30 data-nosnippet>30</a>//! and get away without having metering.
|
||||
<a href=#31 id=31 data-nosnippet>31</a>//!
|
||||
<a href=#32 id=32 data-nosnippet>32</a>//! ## Benchmarking
|
||||
<a href=#33 id=33 data-nosnippet>33</a>//!
|
||||
<a href=#34 id=34 data-nosnippet>34</a>//! With the matter of untrusted code execution out of the way, the need for strict metering goes
|
||||
<a href=#35 id=35 data-nosnippet>35</a>//! out of the way. Yet, it would still be very beneficial for block producers to be able to know an
|
||||
<a href=#36 id=36 data-nosnippet>36</a>//! upper bound on how much resources a operation is going to consume before actually executing that
|
||||
<a href=#37 id=37 data-nosnippet>37</a>//! operation. This is why FRAME has a toolkit for benchmarking pallets: So that this upper bound
|
||||
<a href=#38 id=38 data-nosnippet>38</a>//! can be empirically determined.
|
||||
<a href=#39 id=39 data-nosnippet>39</a>//!
|
||||
<a href=#40 id=40 data-nosnippet>40</a>//! > Note: Benchmarking is a static analysis: It is all about knowing the upper bound of how much
|
||||
<a href=#41 id=41 data-nosnippet>41</a>//! > resources an operation takes statically, without actually executing it. In the context of
|
||||
<a href=#42 id=42 data-nosnippet>42</a>//! > FRAME extrinsics, this static-ness is expressed by the keyword "pre-dispatch".
|
||||
<a href=#43 id=43 data-nosnippet>43</a>//!
|
||||
<a href=#44 id=44 data-nosnippet>44</a>//! To understand why this upper bound is needed, consider the following: A block producer knows
|
||||
<a href=#45 id=45 data-nosnippet>45</a>//! they have 20ms left to finish producing their block, and wishes to include more transactions in
|
||||
<a href=#46 id=46 data-nosnippet>46</a>//! the block. Yet, in a metered environment, it would not know which transaction is likely to fit
|
||||
<a href=#47 id=47 data-nosnippet>47</a>//! the 20ms. In a benchmarked environment, it can examine the transactions for their upper bound,
|
||||
<a href=#48 id=48 data-nosnippet>48</a>//! and include the ones that are known to fit based on the worst case.
|
||||
<a href=#49 id=49 data-nosnippet>49</a>//!
|
||||
<a href=#50 id=50 data-nosnippet>50</a>//! The benchmarking code can be written as a part of FRAME pallet, using the macros provided in
|
||||
<a href=#51 id=51 data-nosnippet>51</a>//! [`frame_benchmarking`]. See any of the existing pallets in `pezkuwi-sdk`, or the pallets in our
|
||||
<a href=#52 id=52 data-nosnippet>52</a>//! [`crate::pezkuwi_sdk::templates`] for examples.
|
||||
<a href=#53 id=53 data-nosnippet>53</a>//!
|
||||
<a href=#54 id=54 data-nosnippet>54</a>//! ## Weight
|
||||
<a href=#55 id=55 data-nosnippet>55</a>//!
|
||||
<a href=#56 id=56 data-nosnippet>56</a>//! Finally, [`sp_weights::Weight`] is the output of the benchmarking process. It is a
|
||||
<a href=#57 id=57 data-nosnippet>57</a>//! two-dimensional data structure that demonstrates the resources consumed by a given block of
|
||||
<a href=#58 id=58 data-nosnippet>58</a>//! code (for example, a transaction). The two dimensions are:
|
||||
<a href=#59 id=59 data-nosnippet>59</a>//!
|
||||
<a href=#60 id=60 data-nosnippet>60</a>//! * reference time: The time consumed in pico-seconds, on a reference hardware.
|
||||
<a href=#61 id=61 data-nosnippet>61</a>//! * proof size: The amount of storage proof necessary to re-execute the block of code. This is
|
||||
<a href=#62 id=62 data-nosnippet>62</a>//! mainly needed for teyrchain <> relay-chain verification.
|
||||
<a href=#63 id=63 data-nosnippet>63</a>//!
|
||||
<a href=#64 id=64 data-nosnippet>64</a>//! ## How To Write Benchmarks: Worst Case
|
||||
<a href=#65 id=65 data-nosnippet>65</a>//!
|
||||
<a href=#66 id=66 data-nosnippet>66</a>//! The most important detail about writing benchmarking code is that it must be written such that
|
||||
<a href=#67 id=67 data-nosnippet>67</a>//! it captures the worst case execution of any block of code.
|
||||
<a href=#68 id=68 data-nosnippet>68</a>//!
|
||||
<a href=#69 id=69 data-nosnippet>69</a>//! Consider:
|
||||
<a href=#70 id=70 data-nosnippet>70</a></span><span class="attr">#![doc = <span class="macro">docify::embed!</span>(<span class="string">"./src/reference_docs/frame_benchmarking_weight.rs"</span>, simple_transfer)]
|
||||
<a href=#71 id=71 data-nosnippet>71</a></span><span class="doccomment">//!
|
||||
<a href=#72 id=72 data-nosnippet>72</a>//! If this block of code is to be benchmarked, then the benchmarking code must be written such that
|
||||
<a href=#73 id=73 data-nosnippet>73</a>//! it captures the worst case.
|
||||
<a href=#74 id=74 data-nosnippet>74</a>//!
|
||||
<a href=#75 id=75 data-nosnippet>75</a>//! ## Gluing Pallet Benchmarking with Runtime
|
||||
<a href=#76 id=76 data-nosnippet>76</a>//!
|
||||
<a href=#77 id=77 data-nosnippet>77</a>//! FRAME pallets are mandated to provide their own benchmarking code. Runtimes contain the
|
||||
<a href=#78 id=78 data-nosnippet>78</a>//! boilerplate needed to run these benchmarking (see [Running Benchmarks
|
||||
<a href=#79 id=79 data-nosnippet>79</a>//! below](#running-benchmarks)). The outcome of running these benchmarks are meant to be fed back
|
||||
<a href=#80 id=80 data-nosnippet>80</a>//! into the pallet via a conventional `trait WeightInfo` on `Config`:
|
||||
<a href=#81 id=81 data-nosnippet>81</a></span><span class="attr">#![doc = <span class="macro">docify::embed!</span>(<span class="string">"src/reference_docs/frame_benchmarking_weight.rs"</span>, WeightInfo)]
|
||||
<a href=#82 id=82 data-nosnippet>82</a></span><span class="doccomment">//!
|
||||
<a href=#83 id=83 data-nosnippet>83</a>//! Then, individual functions of this trait are the final values that we assigned to the
|
||||
<a href=#84 id=84 data-nosnippet>84</a>//! [`frame::pallet_macros::weight`] attribute:
|
||||
<a href=#85 id=85 data-nosnippet>85</a></span><span class="attr">#![doc = <span class="macro">docify::embed!</span>(<span class="string">"./src/reference_docs/frame_benchmarking_weight.rs"</span>, simple_transfer_2)]
|
||||
<a href=#86 id=86 data-nosnippet>86</a></span><span class="doccomment">//!
|
||||
<a href=#87 id=87 data-nosnippet>87</a>//! ## Manual Refund
|
||||
<a href=#88 id=88 data-nosnippet>88</a>//!
|
||||
<a href=#89 id=89 data-nosnippet>89</a>//! Back to the assumption of writing benchmarks for worst case: Sometimes, the pre-dispatch weight
|
||||
<a href=#90 id=90 data-nosnippet>90</a>//! significantly differ from the post-dispatch actual weight consumed. This can be expressed with
|
||||
<a href=#91 id=91 data-nosnippet>91</a>//! the following FRAME syntax:
|
||||
<a href=#92 id=92 data-nosnippet>92</a></span><span class="attr">#![doc = <span class="macro">docify::embed!</span>(<span class="string">"./src/reference_docs/frame_benchmarking_weight.rs"</span>, simple_transfer_3)]
|
||||
<a href=#93 id=93 data-nosnippet>93</a></span><span class="doccomment">//!
|
||||
<a href=#94 id=94 data-nosnippet>94</a>//! ## Running Benchmarks
|
||||
<a href=#95 id=95 data-nosnippet>95</a>//!
|
||||
<a href=#96 id=96 data-nosnippet>96</a>//! Two ways exist to run the benchmarks of a runtime.
|
||||
<a href=#97 id=97 data-nosnippet>97</a>//!
|
||||
<a href=#98 id=98 data-nosnippet>98</a>//! 1. The old school way: Most Pezkuwi-SDK based nodes (such as the ones integrated in
|
||||
<a href=#99 id=99 data-nosnippet>99</a>//! [`templates`]) have a `benchmark` subcommand integrated into themselves.
|
||||
<a href=#100 id=100 data-nosnippet>100</a>//! 2. The more [`crate::reference_docs::omni_node`] compatible way of running the benchmarks would
|
||||
<a href=#101 id=101 data-nosnippet>101</a>//! be using [`frame-omni-bencher`] CLI, which only relies on a runtime.
|
||||
<a href=#102 id=102 data-nosnippet>102</a>//!
|
||||
<a href=#103 id=103 data-nosnippet>103</a>//! Note that by convention, the runtime and pallets always have their benchmarking code feature
|
||||
<a href=#104 id=104 data-nosnippet>104</a>//! gated as behind `runtime-benchmarks`. So, the runtime should be compiled with `--features
|
||||
<a href=#105 id=105 data-nosnippet>105</a>//! runtime-benchmarks`.
|
||||
<a href=#106 id=106 data-nosnippet>106</a>//!
|
||||
<a href=#107 id=107 data-nosnippet>107</a>//! ## Automatic Refund of `proof_size`.
|
||||
<a href=#108 id=108 data-nosnippet>108</a>//!
|
||||
<a href=#109 id=109 data-nosnippet>109</a>//! A new feature in FRAME allows the runtime to be configured for "automatic refund" of the proof
|
||||
<a href=#110 id=110 data-nosnippet>110</a>//! size weight. This is very useful for maximizing the throughput of teyrchains. Please see:
|
||||
<a href=#111 id=111 data-nosnippet>111</a>//! [`crate::guides::enable_pov_reclaim`].
|
||||
<a href=#112 id=112 data-nosnippet>112</a>//!
|
||||
<a href=#113 id=113 data-nosnippet>113</a>//! ## Summary
|
||||
<a href=#114 id=114 data-nosnippet>114</a>//!
|
||||
<a href=#115 id=115 data-nosnippet>115</a>//! Pezkuwi-SDK runtimes use a more performant VM, namely WASM, which does not have metering. In
|
||||
<a href=#116 id=116 data-nosnippet>116</a>//! return they have to be benchmarked to provide an upper bound on the resources they consume. This
|
||||
<a href=#117 id=117 data-nosnippet>117</a>//! upper bound is represented as [`sp_weights::Weight`].
|
||||
<a href=#118 id=118 data-nosnippet>118</a>//!
|
||||
<a href=#119 id=119 data-nosnippet>119</a>//! ## Future: PolkaVM
|
||||
<a href=#120 id=120 data-nosnippet>120</a>//!
|
||||
<a href=#121 id=121 data-nosnippet>121</a>//! With the transition of Pezkuwi relay chain to [JAM], a set of new features are being
|
||||
<a href=#122 id=122 data-nosnippet>122</a>//! introduced, one of which being a new virtual machine named [PolkaVM] that is as flexible as
|
||||
<a href=#123 id=123 data-nosnippet>123</a>//! WASM, but also capable of metering. This might alter the future of benchmarking in FRAME and
|
||||
<a href=#124 id=124 data-nosnippet>124</a>//! Pezkuwi-SDK, rendering them not needed anymore once PolkaVM is fully integrated into
|
||||
<a href=#125 id=125 data-nosnippet>125</a>//! Pezkuwi-sdk. For a basic explanation of JAM and PolkaVM, see [here](https://blog.kianenigma.com/posts/tech/demystifying-jam/#pvm).
|
||||
<a href=#126 id=126 data-nosnippet>126</a>//!
|
||||
<a href=#127 id=127 data-nosnippet>127</a>//!
|
||||
<a href=#128 id=128 data-nosnippet>128</a>//! [`frame-omni-bencher`]: https://crates.io/crates/frame-omni-bencher
|
||||
<a href=#129 id=129 data-nosnippet>129</a>//! [`templates`]: crate::pezkuwi_sdk::templates
|
||||
<a href=#130 id=130 data-nosnippet>130</a>//! [PolkaVM]: https://github.com/koute/polkavm
|
||||
<a href=#131 id=131 data-nosnippet>131</a>//! [JAM]: https://graypaper.com
|
||||
<a href=#132 id=132 data-nosnippet>132</a>
|
||||
<a href=#133 id=133 data-nosnippet>133</a></span><span class="attr">#[frame::pallet(dev_mode)]
|
||||
<a href=#134 id=134 data-nosnippet>134</a>#[allow(unused_variables, unreachable_code, unused, clippy::diverging_sub_expression)]
|
||||
<a href=#135 id=135 data-nosnippet>135</a></span><span class="kw">pub mod </span>pallet {
|
||||
<a href=#136 id=136 data-nosnippet>136</a> <span class="kw">use </span>frame::prelude::<span class="kw-2">*</span>;
|
||||
<a href=#137 id=137 data-nosnippet>137</a>
|
||||
<a href=#138 id=138 data-nosnippet>138</a> <span class="attr">#[docify::export]
|
||||
<a href=#139 id=139 data-nosnippet>139</a> </span><span class="kw">pub trait </span>WeightInfo {
|
||||
<a href=#140 id=140 data-nosnippet>140</a> <span class="kw">fn </span>simple_transfer() -> Weight;
|
||||
<a href=#141 id=141 data-nosnippet>141</a> }
|
||||
<a href=#142 id=142 data-nosnippet>142</a>
|
||||
<a href=#143 id=143 data-nosnippet>143</a> <span class="attr">#[pallet::config]
|
||||
<a href=#144 id=144 data-nosnippet>144</a> </span><span class="kw">pub trait </span>Config: frame_system::Config {
|
||||
<a href=#145 id=145 data-nosnippet>145</a> <span class="kw">type </span>WeightInfo: WeightInfo;
|
||||
<a href=#146 id=146 data-nosnippet>146</a> }
|
||||
<a href=#147 id=147 data-nosnippet>147</a>
|
||||
<a href=#148 id=148 data-nosnippet>148</a> <span class="attr">#[pallet::pallet]
|
||||
<a href=#149 id=149 data-nosnippet>149</a> </span><span class="kw">pub struct </span>Pallet<T>(<span class="kw">_</span>);
|
||||
<a href=#150 id=150 data-nosnippet>150</a>
|
||||
<a href=#151 id=151 data-nosnippet>151</a> <span class="attr">#[pallet::call]
|
||||
<a href=#152 id=152 data-nosnippet>152</a> </span><span class="kw">impl</span><T: Config> Pallet<T> {
|
||||
<a href=#153 id=153 data-nosnippet>153</a> <span class="attr">#[docify::export]
|
||||
<a href=#154 id=154 data-nosnippet>154</a> #[pallet::weight(<span class="number">10_000</span>)]
|
||||
<a href=#155 id=155 data-nosnippet>155</a> </span><span class="kw">pub fn </span>simple_transfer(
|
||||
<a href=#156 id=156 data-nosnippet>156</a> origin: OriginFor<T>,
|
||||
<a href=#157 id=157 data-nosnippet>157</a> destination: T::AccountId,
|
||||
<a href=#158 id=158 data-nosnippet>158</a> amount: u32,
|
||||
<a href=#159 id=159 data-nosnippet>159</a> ) -> DispatchResult {
|
||||
<a href=#160 id=160 data-nosnippet>160</a> <span class="kw">let </span>destination_exists = <span class="macro">todo!</span>();
|
||||
<a href=#161 id=161 data-nosnippet>161</a> <span class="kw">if </span>destination_exists {
|
||||
<a href=#162 id=162 data-nosnippet>162</a> <span class="comment">// simpler code path
|
||||
<a href=#163 id=163 data-nosnippet>163</a> </span>} <span class="kw">else </span>{
|
||||
<a href=#164 id=164 data-nosnippet>164</a> <span class="comment">// more complex code path
|
||||
<a href=#165 id=165 data-nosnippet>165</a> </span>}
|
||||
<a href=#166 id=166 data-nosnippet>166</a> <span class="prelude-val">Ok</span>(())
|
||||
<a href=#167 id=167 data-nosnippet>167</a> }
|
||||
<a href=#168 id=168 data-nosnippet>168</a>
|
||||
<a href=#169 id=169 data-nosnippet>169</a> <span class="attr">#[docify::export]
|
||||
<a href=#170 id=170 data-nosnippet>170</a> #[pallet::weight(T::WeightInfo::simple_transfer())]
|
||||
<a href=#171 id=171 data-nosnippet>171</a> </span><span class="kw">pub fn </span>simple_transfer_2(
|
||||
<a href=#172 id=172 data-nosnippet>172</a> origin: OriginFor<T>,
|
||||
<a href=#173 id=173 data-nosnippet>173</a> destination: T::AccountId,
|
||||
<a href=#174 id=174 data-nosnippet>174</a> amount: u32,
|
||||
<a href=#175 id=175 data-nosnippet>175</a> ) -> DispatchResult {
|
||||
<a href=#176 id=176 data-nosnippet>176</a> <span class="kw">let </span>destination_exists = <span class="macro">todo!</span>();
|
||||
<a href=#177 id=177 data-nosnippet>177</a> <span class="kw">if </span>destination_exists {
|
||||
<a href=#178 id=178 data-nosnippet>178</a> <span class="comment">// simpler code path
|
||||
<a href=#179 id=179 data-nosnippet>179</a> </span>} <span class="kw">else </span>{
|
||||
<a href=#180 id=180 data-nosnippet>180</a> <span class="comment">// more complex code path
|
||||
<a href=#181 id=181 data-nosnippet>181</a> </span>}
|
||||
<a href=#182 id=182 data-nosnippet>182</a> <span class="prelude-val">Ok</span>(())
|
||||
<a href=#183 id=183 data-nosnippet>183</a> }
|
||||
<a href=#184 id=184 data-nosnippet>184</a>
|
||||
<a href=#185 id=185 data-nosnippet>185</a> <span class="attr">#[docify::export]
|
||||
<a href=#186 id=186 data-nosnippet>186</a> </span><span class="comment">// This is the worst-case, pre-dispatch weight.
|
||||
<a href=#187 id=187 data-nosnippet>187</a> </span><span class="attr">#[pallet::weight(T::WeightInfo::simple_transfer())]
|
||||
<a href=#188 id=188 data-nosnippet>188</a> </span><span class="kw">pub fn </span>simple_transfer_3(
|
||||
<a href=#189 id=189 data-nosnippet>189</a> origin: OriginFor<T>,
|
||||
<a href=#190 id=190 data-nosnippet>190</a> destination: T::AccountId,
|
||||
<a href=#191 id=191 data-nosnippet>191</a> amount: u32,
|
||||
<a href=#192 id=192 data-nosnippet>192</a> ) -> DispatchResultWithPostInfo {
|
||||
<a href=#193 id=193 data-nosnippet>193</a> <span class="comment">// ^^ Notice the new return type
|
||||
<a href=#194 id=194 data-nosnippet>194</a> </span><span class="kw">let </span>destination_exists = <span class="macro">todo!</span>();
|
||||
<a href=#195 id=195 data-nosnippet>195</a> <span class="kw">if </span>destination_exists {
|
||||
<a href=#196 id=196 data-nosnippet>196</a> <span class="comment">// simpler code path
|
||||
<a href=#197 id=197 data-nosnippet>197</a> // Note that need for .into(), to convert `()` to `PostDispatchInfo`
|
||||
<a href=#198 id=198 data-nosnippet>198</a> // See: https://docs.pezkuwichain.io/sdk/master/frame_support/dispatch/struct.PostDispatchInfo.html#impl-From%3C()%3E-for-PostDispatchInfo
|
||||
<a href=#199 id=199 data-nosnippet>199</a> </span><span class="prelude-val">Ok</span>(().into())
|
||||
<a href=#200 id=200 data-nosnippet>200</a> } <span class="kw">else </span>{
|
||||
<a href=#201 id=201 data-nosnippet>201</a> <span class="comment">// more complex code path
|
||||
<a href=#202 id=202 data-nosnippet>202</a> </span><span class="kw">let </span>actual_weight =
|
||||
<a href=#203 id=203 data-nosnippet>203</a> <span class="macro">todo!</span>(<span class="string">"this can likely come from another benchmark that is NOT the worst case"</span>);
|
||||
<a href=#204 id=204 data-nosnippet>204</a> <span class="kw">let </span>pays_fee = <span class="macro">todo!</span>(<span class="string">"You can set this to `Pays::Yes` or `Pays::No` to change if this transaction should pay fees"</span>);
|
||||
<a href=#205 id=205 data-nosnippet>205</a> <span class="prelude-val">Ok</span>(frame::deps::frame_support::dispatch::PostDispatchInfo {
|
||||
<a href=#206 id=206 data-nosnippet>206</a> actual_weight: <span class="prelude-val">Some</span>(actual_weight),
|
||||
<a href=#207 id=207 data-nosnippet>207</a> pays_fee,
|
||||
<a href=#208 id=208 data-nosnippet>208</a> })
|
||||
<a href=#209 id=209 data-nosnippet>209</a> }
|
||||
<a href=#210 id=210 data-nosnippet>210</a> }
|
||||
<a href=#211 id=211 data-nosnippet>211</a> }
|
||||
<a href=#212 id=212 data-nosnippet>212</a>}</code></pre></div></section></main></body></html>
|
||||
@@ -0,0 +1,155 @@
|
||||
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `docs/sdk/src/reference_docs/frame_logging.rs`."><title>frame_logging.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2"href="../../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../../../static.files/rustdoc-e56847b5.css"><meta name="rustdoc-vars" data-root-path="../../../" data-static-root-path="../../../static.files/" data-current-crate="pezkuwi_sdk_docs" data-themes="" data-resource-suffix="" data-rustdoc-version="1.91.1 (ed61e7d7e 2025-11-07)" data-channel="1.91.1" data-search-js="search-e256b49e.js" data-stringdex-js="stringdex-c3e638e9.js" data-settings-js="settings-c38705f0.js" ><script src="../../../static.files/storage-e2aeef58.js"></script><script defer src="../../../static.files/src-script-813739b1.js"></script><script defer src="../../../src-files.js"></script><script defer src="../../../static.files/main-6dc2a7f3.js"></script><noscript><link rel="stylesheet" href="../../../static.files/noscript-263c88ec.css"></noscript><link rel="icon" href="https://pezkuwichain.io/favicon.ico"></head><body class="rustdoc src"><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer" title="Drag to resize sidebar"></div><main><section id="main-content" class="content"><div class="main-heading"><h1><div class="sub-heading">pezkuwi_sdk_docs/reference_docs/</div>frame_logging.rs</h1><rustdoc-toolbar></rustdoc-toolbar></div><div class="example-wrap digits-3"><pre class="rust"><code><a href=#1 id=1 data-nosnippet>1</a><span class="doccomment">//! # FRAME Logging
|
||||
<a href=#2 id=2 data-nosnippet>2</a>//!
|
||||
<a href=#3 id=3 data-nosnippet>3</a>//! This reference docs briefly explores how to do logging and printing runtimes, mainly
|
||||
<a href=#4 id=4 data-nosnippet>4</a>//! FRAME-based.
|
||||
<a href=#5 id=5 data-nosnippet>5</a>//!
|
||||
<a href=#6 id=6 data-nosnippet>6</a>//! > Please make sure to read [the section below](#using-logging-in-production) on using logging in
|
||||
<a href=#7 id=7 data-nosnippet>7</a>//! > production.
|
||||
<a href=#8 id=8 data-nosnippet>8</a>//!
|
||||
<a href=#9 id=9 data-nosnippet>9</a>//! ## Using `println!`
|
||||
<a href=#10 id=10 data-nosnippet>10</a>//!
|
||||
<a href=#11 id=11 data-nosnippet>11</a>//! To recap, as with standard Rust, you can use `println!` _in your tests_, but it will only print
|
||||
<a href=#12 id=12 data-nosnippet>12</a>//! out if executed with `--nocapture`, or if the test panics.
|
||||
<a href=#13 id=13 data-nosnippet>13</a>//!
|
||||
<a href=#14 id=14 data-nosnippet>14</a>//! ```
|
||||
<a href=#15 id=15 data-nosnippet>15</a>//! fn it_print() {
|
||||
<a href=#16 id=16 data-nosnippet>16</a>//! println!("Hello, world!");
|
||||
<a href=#17 id=17 data-nosnippet>17</a>//! }
|
||||
<a href=#18 id=18 data-nosnippet>18</a>//! ```
|
||||
<a href=#19 id=19 data-nosnippet>19</a>//!
|
||||
<a href=#20 id=20 data-nosnippet>20</a>//! within the pallet, if you want to use the standard `println!`, it needs to be wrapped in
|
||||
<a href=#21 id=21 data-nosnippet>21</a>//! [`sp_std::if_std`]. Of course, this means that this print code is only available to you in the
|
||||
<a href=#22 id=22 data-nosnippet>22</a>//! `std` compiler flag, and never present in a wasm build.
|
||||
<a href=#23 id=23 data-nosnippet>23</a>//!
|
||||
<a href=#24 id=24 data-nosnippet>24</a>//! ```
|
||||
<a href=#25 id=25 data-nosnippet>25</a>//! // somewhere in your pallet. This is not a real pallet code.
|
||||
<a href=#26 id=26 data-nosnippet>26</a>//! mod pallet {
|
||||
<a href=#27 id=27 data-nosnippet>27</a>//! struct Pallet;
|
||||
<a href=#28 id=28 data-nosnippet>28</a>//! impl Pallet {
|
||||
<a href=#29 id=29 data-nosnippet>29</a>//! fn print() {
|
||||
<a href=#30 id=30 data-nosnippet>30</a>//! sp_std::if_std! {
|
||||
<a href=#31 id=31 data-nosnippet>31</a>//! println!("Hello, world!");
|
||||
<a href=#32 id=32 data-nosnippet>32</a>//! }
|
||||
<a href=#33 id=33 data-nosnippet>33</a>//! }
|
||||
<a href=#34 id=34 data-nosnippet>34</a>//! }
|
||||
<a href=#35 id=35 data-nosnippet>35</a>//! }
|
||||
<a href=#36 id=36 data-nosnippet>36</a>//! ```
|
||||
<a href=#37 id=37 data-nosnippet>37</a>//!
|
||||
<a href=#38 id=38 data-nosnippet>38</a>//! ## Using `log`
|
||||
<a href=#39 id=39 data-nosnippet>39</a>//!
|
||||
<a href=#40 id=40 data-nosnippet>40</a>//! First, ensure you are familiar with the [`log`] crate. In short, each log statement has:
|
||||
<a href=#41 id=41 data-nosnippet>41</a>//!
|
||||
<a href=#42 id=42 data-nosnippet>42</a>//! 1. `log-level`, signifying how important it is.
|
||||
<a href=#43 id=43 data-nosnippet>43</a>//! 2. `log-target`, signifying to which component it belongs.
|
||||
<a href=#44 id=44 data-nosnippet>44</a>//!
|
||||
<a href=#45 id=45 data-nosnippet>45</a>//! Add log statements to your pallet as such:
|
||||
<a href=#46 id=46 data-nosnippet>46</a>//!
|
||||
<a href=#47 id=47 data-nosnippet>47</a>//! You can add the log crate to the `Cargo.toml` of the pallet.
|
||||
<a href=#48 id=48 data-nosnippet>48</a>//!
|
||||
<a href=#49 id=49 data-nosnippet>49</a>//! ```text
|
||||
<a href=#50 id=50 data-nosnippet>50</a>//! #[dependencies]
|
||||
<a href=#51 id=51 data-nosnippet>51</a>//! log = { version = "x.y.z", default-features = false }
|
||||
<a href=#52 id=52 data-nosnippet>52</a>//!
|
||||
<a href=#53 id=53 data-nosnippet>53</a>//! #[features]
|
||||
<a href=#54 id=54 data-nosnippet>54</a>//! std = [
|
||||
<a href=#55 id=55 data-nosnippet>55</a>//! // snip -- other pallets
|
||||
<a href=#56 id=56 data-nosnippet>56</a>//! "log/std"
|
||||
<a href=#57 id=57 data-nosnippet>57</a>//! ]
|
||||
<a href=#58 id=58 data-nosnippet>58</a>//! ```
|
||||
<a href=#59 id=59 data-nosnippet>59</a>//!
|
||||
<a href=#60 id=60 data-nosnippet>60</a>//! More conveniently, the `frame` umbrella crate re-exports the log crate as [`frame::log`].
|
||||
<a href=#61 id=61 data-nosnippet>61</a>//!
|
||||
<a href=#62 id=62 data-nosnippet>62</a>//! Then, the pallet can use this crate to emit log statements. In this statement, we use the info
|
||||
<a href=#63 id=63 data-nosnippet>63</a>//! level, and the target is `pallet-example`.
|
||||
<a href=#64 id=64 data-nosnippet>64</a>//!
|
||||
<a href=#65 id=65 data-nosnippet>65</a>//! ```
|
||||
<a href=#66 id=66 data-nosnippet>66</a>//! mod pallet {
|
||||
<a href=#67 id=67 data-nosnippet>67</a>//! struct Pallet;
|
||||
<a href=#68 id=68 data-nosnippet>68</a>//!
|
||||
<a href=#69 id=69 data-nosnippet>69</a>//! impl Pallet {
|
||||
<a href=#70 id=70 data-nosnippet>70</a>//! fn logs() {
|
||||
<a href=#71 id=71 data-nosnippet>71</a>//! frame::log::info!(target: "pallet-example", "Hello, world!");
|
||||
<a href=#72 id=72 data-nosnippet>72</a>//! }
|
||||
<a href=#73 id=73 data-nosnippet>73</a>//! }
|
||||
<a href=#74 id=74 data-nosnippet>74</a>//! }
|
||||
<a href=#75 id=75 data-nosnippet>75</a>//! ```
|
||||
<a href=#76 id=76 data-nosnippet>76</a>//!
|
||||
<a href=#77 id=77 data-nosnippet>77</a>//! This will in itself just emit the log messages, **but unless if captured by a logger, they will
|
||||
<a href=#78 id=78 data-nosnippet>78</a>//! not go anywhere**. [`sp_api`] provides a handy function to enable the runtime logging:
|
||||
<a href=#79 id=79 data-nosnippet>79</a>//!
|
||||
<a href=#80 id=80 data-nosnippet>80</a>//! ```
|
||||
<a href=#81 id=81 data-nosnippet>81</a>//! // in your test
|
||||
<a href=#82 id=82 data-nosnippet>82</a>//! fn it_also_prints() {
|
||||
<a href=#83 id=83 data-nosnippet>83</a>//! sp_api::init_runtime_logger();
|
||||
<a href=#84 id=84 data-nosnippet>84</a>//! // call into your pallet, and now it will print `log` statements.
|
||||
<a href=#85 id=85 data-nosnippet>85</a>//! }
|
||||
<a href=#86 id=86 data-nosnippet>86</a>//! ```
|
||||
<a href=#87 id=87 data-nosnippet>87</a>//!
|
||||
<a href=#88 id=88 data-nosnippet>88</a>//! Alternatively, you can use [`sp_tracing::try_init_simple`].
|
||||
<a href=#89 id=89 data-nosnippet>89</a>//!
|
||||
<a href=#90 id=90 data-nosnippet>90</a>//! `info`, `error` and `warn` logs are printed by default, but if you want lower level logs to also
|
||||
<a href=#91 id=91 data-nosnippet>91</a>//! be printed, you must to add the following compiler flag:
|
||||
<a href=#92 id=92 data-nosnippet>92</a>//!
|
||||
<a href=#93 id=93 data-nosnippet>93</a>//! ```text
|
||||
<a href=#94 id=94 data-nosnippet>94</a>//! RUST_LOG=pallet-example=trace cargo test
|
||||
<a href=#95 id=95 data-nosnippet>95</a>//! ```
|
||||
<a href=#96 id=96 data-nosnippet>96</a>//!
|
||||
<a href=#97 id=97 data-nosnippet>97</a>//! ## Enabling Logs in Production
|
||||
<a href=#98 id=98 data-nosnippet>98</a>//!
|
||||
<a href=#99 id=99 data-nosnippet>99</a>//! All logs from the runtime are emitted by default, but there is a feature flag in [`sp_api`],
|
||||
<a href=#100 id=100 data-nosnippet>100</a>//! called `disable-logging`, that can be used to disable all logs in the runtime. This is useful
|
||||
<a href=#101 id=101 data-nosnippet>101</a>//! for production chains to reduce the size and overhead of the wasm runtime.
|
||||
<a href=#102 id=102 data-nosnippet>102</a></span><span class="attr">#![doc = <span class="macro">docify::embed!</span>(<span class="string">"../../substrate/primitives/api/src/lib.rs"</span>, init_runtime_logger)]
|
||||
<a href=#103 id=103 data-nosnippet>103</a></span><span class="doccomment">//!
|
||||
<a href=#104 id=104 data-nosnippet>104</a>//! Similar to the above, the proper `RUST_LOG` must also be passed to your compiler flag when
|
||||
<a href=#105 id=105 data-nosnippet>105</a>//! compiling the runtime.
|
||||
<a href=#106 id=106 data-nosnippet>106</a>//!
|
||||
<a href=#107 id=107 data-nosnippet>107</a>//! ## Log Target Prefixing
|
||||
<a href=#108 id=108 data-nosnippet>108</a>//!
|
||||
<a href=#109 id=109 data-nosnippet>109</a>//! Many [`crate::pezkuwi_sdk::frame_runtime`] pallets emit logs with log target `runtime::<name of
|
||||
<a href=#110 id=110 data-nosnippet>110</a>//! pallet>`, for example `runtime::system`. This then allows one to run a node with a wasm blob
|
||||
<a href=#111 id=111 data-nosnippet>111</a>//! compiled with `LOG_TARGET=runtime=debug`, which enables the log target of all pallets who's log
|
||||
<a href=#112 id=112 data-nosnippet>112</a>//! target starts with `runtime`.
|
||||
<a href=#113 id=113 data-nosnippet>113</a>//!
|
||||
<a href=#114 id=114 data-nosnippet>114</a>//! ## Low Level Primitives
|
||||
<a href=#115 id=115 data-nosnippet>115</a>//!
|
||||
<a href=#116 id=116 data-nosnippet>116</a>//! Under the hood, logging is another instance of host functions under the hood (as defined in
|
||||
<a href=#117 id=117 data-nosnippet>117</a>//! [`crate::reference_docs::wasm_meta_protocol`]). The runtime uses a set of host functions under
|
||||
<a href=#118 id=118 data-nosnippet>118</a>//! [`sp_io::logging`] and [`sp_io::misc`] to emit all logs and prints. You typically do not need to
|
||||
<a href=#119 id=119 data-nosnippet>119</a>//! use these APIs directly.
|
||||
<a href=#120 id=120 data-nosnippet>120</a>//!
|
||||
<a href=#121 id=121 data-nosnippet>121</a>//! ## Using Logging in Production
|
||||
<a href=#122 id=122 data-nosnippet>122</a>//!
|
||||
<a href=#123 id=123 data-nosnippet>123</a>//! Note that within FRAME, reading storage values __only for the purpose of logging__ is dangerous,
|
||||
<a href=#124 id=124 data-nosnippet>124</a>//! and can lead to consensus issues. This is because with the introduction of
|
||||
<a href=#125 id=125 data-nosnippet>125</a>//! [`crate::guides::enable_pov_reclaim`], the node side code will track the storage changes, and
|
||||
<a href=#126 id=126 data-nosnippet>126</a>//! tries to update the onchain record of the `proof_size` weight used (stored in
|
||||
<a href=#127 id=127 data-nosnippet>127</a>//! [`frame_system::BlockWeight`]) after the block is executed.
|
||||
<a href=#128 id=128 data-nosnippet>128</a>//!
|
||||
<a href=#129 id=129 data-nosnippet>129</a>//! If one node has a different log level enabled than the rest of the network, and the extra logs
|
||||
<a href=#130 id=130 data-nosnippet>130</a>//! impose additional storage reads, then the amount of `proof_size` weight reclaimed into
|
||||
<a href=#131 id=131 data-nosnippet>131</a>//! [`frame_system::BlockWeight`] will be different, causing a state root mismatch, which is
|
||||
<a href=#132 id=132 data-nosnippet>132</a>//! typically a fatal error emitted from [`frame_executive`].
|
||||
<a href=#133 id=133 data-nosnippet>133</a>//!
|
||||
<a href=#134 id=134 data-nosnippet>134</a>//! This also can also happen in a teyrchain context, and cause discrepancies between the relay
|
||||
<a href=#135 id=135 data-nosnippet>135</a>//! chain and the teyrchain, when execution the Teyrchain Validation Function (PVF) on the relay
|
||||
<a href=#136 id=136 data-nosnippet>136</a>//! chain.
|
||||
<a href=#137 id=137 data-nosnippet>137</a>//!
|
||||
<a href=#138 id=138 data-nosnippet>138</a>//! **In summary, you should only used storage values in logging (especially for levels lower than
|
||||
<a href=#139 id=139 data-nosnippet>139</a>//! `info` which is typically enabled by all parties) that are already read from storage, and will
|
||||
<a href=#140 id=140 data-nosnippet>140</a>//! be part of the storage proof of execution in any case**.
|
||||
<a href=#141 id=141 data-nosnippet>141</a>//!
|
||||
<a href=#142 id=142 data-nosnippet>142</a>//! A typical faulty code would look like this:
|
||||
<a href=#143 id=143 data-nosnippet>143</a>//!
|
||||
<a href=#144 id=144 data-nosnippet>144</a>//! ```ignore
|
||||
<a href=#145 id=145 data-nosnippet>145</a>//! /// This function will have a different storage footprint depending on the log level
|
||||
<a href=#146 id=146 data-nosnippet>146</a>//! fn faulty_logging() {
|
||||
<a href=#147 id=147 data-nosnippet>147</a>//! log::debug!(
|
||||
<a href=#148 id=148 data-nosnippet>148</a>//! "what I am about to print is only read when `RUST_LOG=debug` {:?}",
|
||||
<a href=#149 id=149 data-nosnippet>149</a>//! StorageValue::<T>::get()
|
||||
<a href=#150 id=150 data-nosnippet>150</a>//! );
|
||||
<a href=#151 id=151 data-nosnippet>151</a>//! }
|
||||
<a href=#152 id=152 data-nosnippet>152</a>//! ```
|
||||
<a href=#153 id=153 data-nosnippet>153</a>//!
|
||||
<a href=#154 id=154 data-nosnippet>154</a>//! Please read [this issue](https://github.com/pezkuwichain/pezkuwi-sdk/issues/155) for one
|
||||
<a href=#155 id=155 data-nosnippet>155</a>//! instance of the consensus issues caused by this mistake.</span></code></pre></div></section></main></body></html>
|
||||
+114
@@ -0,0 +1,114 @@
|
||||
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `docs/sdk/src/reference_docs/frame_offchain_workers.rs`."><title>frame_offchain_workers.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2"href="../../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../../../static.files/rustdoc-e56847b5.css"><meta name="rustdoc-vars" data-root-path="../../../" data-static-root-path="../../../static.files/" data-current-crate="pezkuwi_sdk_docs" data-themes="" data-resource-suffix="" data-rustdoc-version="1.91.1 (ed61e7d7e 2025-11-07)" data-channel="1.91.1" data-search-js="search-e256b49e.js" data-stringdex-js="stringdex-c3e638e9.js" data-settings-js="settings-c38705f0.js" ><script src="../../../static.files/storage-e2aeef58.js"></script><script defer src="../../../static.files/src-script-813739b1.js"></script><script defer src="../../../src-files.js"></script><script defer src="../../../static.files/main-6dc2a7f3.js"></script><noscript><link rel="stylesheet" href="../../../static.files/noscript-263c88ec.css"></noscript><link rel="icon" href="https://pezkuwichain.io/favicon.ico"></head><body class="rustdoc src"><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer" title="Drag to resize sidebar"></div><main><section id="main-content" class="content"><div class="main-heading"><h1><div class="sub-heading">pezkuwi_sdk_docs/reference_docs/</div>frame_offchain_workers.rs</h1><rustdoc-toolbar></rustdoc-toolbar></div><div class="example-wrap digits-3"><pre class="rust"><code><a href=#1 id=1 data-nosnippet>1</a><span class="doccomment">//! # Offchain Workers
|
||||
<a href=#2 id=2 data-nosnippet>2</a>//!
|
||||
<a href=#3 id=3 data-nosnippet>3</a>//! This reference document explains how offchain workers work in Substrate and FRAME. The main
|
||||
<a href=#4 id=4 data-nosnippet>4</a>//! focus is upon FRAME's implementation of this functionality. Nonetheless, offchain workers are a
|
||||
<a href=#5 id=5 data-nosnippet>5</a>//! Substrate-provided feature and can be used with possible alternatives to [`frame`] as well.
|
||||
<a href=#6 id=6 data-nosnippet>6</a>//!
|
||||
<a href=#7 id=7 data-nosnippet>7</a>//! Offchain workers are a commonly misunderstood topic, therefore we explain them bottom-up,
|
||||
<a href=#8 id=8 data-nosnippet>8</a>//! starting at the fundamentals and then describing the developer interface.
|
||||
<a href=#9 id=9 data-nosnippet>9</a>//!
|
||||
<a href=#10 id=10 data-nosnippet>10</a>//! ## Context
|
||||
<a href=#11 id=11 data-nosnippet>11</a>//!
|
||||
<a href=#12 id=12 data-nosnippet>12</a>//! Recall from [`crate::reference_docs::wasm_meta_protocol`] that the node and the runtime
|
||||
<a href=#13 id=13 data-nosnippet>13</a>//! communicate with one another via host functions and runtime APIs. Many of these interactions
|
||||
<a href=#14 id=14 data-nosnippet>14</a>//! contribute to the actual state transition of the blockchain. For example [`sp_api::Core`] is the
|
||||
<a href=#15 id=15 data-nosnippet>15</a>//! main runtime API that is called to execute new blocks.
|
||||
<a href=#16 id=16 data-nosnippet>16</a>//!
|
||||
<a href=#17 id=17 data-nosnippet>17</a>//! Offchain workers are in principle not different in any way: It is a runtime API exposed by the
|
||||
<a href=#18 id=18 data-nosnippet>18</a>//! wasm blob ([`sp_offchain::OffchainWorkerApi`]), and the node software calls into it when it
|
||||
<a href=#19 id=19 data-nosnippet>19</a>//! deems fit. But, crucially, this API call is different in that:
|
||||
<a href=#20 id=20 data-nosnippet>20</a>//!
|
||||
<a href=#21 id=21 data-nosnippet>21</a>//! 1. It can have no impact on the state ie. it is _OFF (the) CHAIN_. If any state is altered
|
||||
<a href=#22 id=22 data-nosnippet>22</a>//! during the execution of this API call, it is discarded.
|
||||
<a href=#23 id=23 data-nosnippet>23</a>//! 2. It has access to an extended set of host functions that allow the wasm blob to do more. For
|
||||
<a href=#24 id=24 data-nosnippet>24</a>//! example, call into HTTP requests.
|
||||
<a href=#25 id=25 data-nosnippet>25</a>//!
|
||||
<a href=#26 id=26 data-nosnippet>26</a>//! > The main way through which an offchain worker can interact with the state is by submitting an
|
||||
<a href=#27 id=27 data-nosnippet>27</a>//! > extrinsic to the chain. This is the ONLY way to alter the state from an offchain worker.
|
||||
<a href=#28 id=28 data-nosnippet>28</a>//! > [`pallet_example_offchain_worker`] provides an example of this.
|
||||
<a href=#29 id=29 data-nosnippet>29</a>//!
|
||||
<a href=#30 id=30 data-nosnippet>30</a>//!
|
||||
<a href=#31 id=31 data-nosnippet>31</a>//! Given the "Off Chain" nature of this API, it is important to remember that calling this API is
|
||||
<a href=#32 id=32 data-nosnippet>32</a>//! entirely optional. Some nodes might call into it, some might not, and it would have no impact on
|
||||
<a href=#33 id=33 data-nosnippet>33</a>//! the execution of your blockchain because no state is altered no matter the execution of the
|
||||
<a href=#34 id=34 data-nosnippet>34</a>//! offchain worker API.
|
||||
<a href=#35 id=35 data-nosnippet>35</a>//!
|
||||
<a href=#36 id=36 data-nosnippet>36</a>//! Substrate's CLI allows some degree of configuration about this, allowing node operators to
|
||||
<a href=#37 id=37 data-nosnippet>37</a>//! specify when they want to run the offchain worker API. See
|
||||
<a href=#38 id=38 data-nosnippet>38</a>//! [`sc_cli::RunCmd::offchain_worker_params`].
|
||||
<a href=#39 id=39 data-nosnippet>39</a>//!
|
||||
<a href=#40 id=40 data-nosnippet>40</a>//! ## Nondeterministic Execution
|
||||
<a href=#41 id=41 data-nosnippet>41</a>//!
|
||||
<a href=#42 id=42 data-nosnippet>42</a>//! Needless to say, given the above description, the code in your offchain worker API can be
|
||||
<a href=#43 id=43 data-nosnippet>43</a>//! nondeterministic, as it is not part of the blockchain's STF, so it can be executed at unknown
|
||||
<a href=#44 id=44 data-nosnippet>44</a>//! times, by unknown nodes, and has no impact on the state. This is why an HTTP
|
||||
<a href=#45 id=45 data-nosnippet>45</a>//! ([`sp_runtime::offchain::http`]) API is readily provided to the offchain worker APIs. Because
|
||||
<a href=#46 id=46 data-nosnippet>46</a>//! there is no need for determinism in this context.
|
||||
<a href=#47 id=47 data-nosnippet>47</a>//!
|
||||
<a href=#48 id=48 data-nosnippet>48</a>//! > A common mistake here is for novice developers to see this HTTP API, and imagine that
|
||||
<a href=#49 id=49 data-nosnippet>49</a>//! > `pezkuwi-sdk` somehow magically solved the determinism in blockchains, and now a blockchain
|
||||
<a href=#50 id=50 data-nosnippet>50</a>//! > can make HTTP calls and it will all work. This is absolutely NOT the case. An HTTP call made
|
||||
<a href=#51 id=51 data-nosnippet>51</a>//! > by the offchain worker is non-deterministic by design. Blockchains can't and always won't be
|
||||
<a href=#52 id=52 data-nosnippet>52</a>//! > able to perform non-deterministic operations such as making HTTP calls to a foreign server.
|
||||
<a href=#53 id=53 data-nosnippet>53</a>//!
|
||||
<a href=#54 id=54 data-nosnippet>54</a>//! ## FRAME's API
|
||||
<a href=#55 id=55 data-nosnippet>55</a>//!
|
||||
<a href=#56 id=56 data-nosnippet>56</a>//! [`frame`] provides a simple API through which pallets can define offchain worker functions. This
|
||||
<a href=#57 id=57 data-nosnippet>57</a>//! is part of [`frame::traits::Hooks`], which is implemented as a part of
|
||||
<a href=#58 id=58 data-nosnippet>58</a>//! [`frame::pallet_macros::hooks`].
|
||||
<a href=#59 id=59 data-nosnippet>59</a>//!
|
||||
<a href=#60 id=60 data-nosnippet>60</a>//! ```
|
||||
<a href=#61 id=61 data-nosnippet>61</a>//! #[frame::pallet]
|
||||
<a href=#62 id=62 data-nosnippet>62</a>//! pub mod pallet {
|
||||
<a href=#63 id=63 data-nosnippet>63</a>//! use frame::prelude::*;
|
||||
<a href=#64 id=64 data-nosnippet>64</a>//!
|
||||
<a href=#65 id=65 data-nosnippet>65</a>//! #[pallet::config]
|
||||
<a href=#66 id=66 data-nosnippet>66</a>//! pub trait Config: frame_system::Config {}
|
||||
<a href=#67 id=67 data-nosnippet>67</a>//!
|
||||
<a href=#68 id=68 data-nosnippet>68</a>//! #[pallet::pallet]
|
||||
<a href=#69 id=69 data-nosnippet>69</a>//! pub struct Pallet<T>(_);
|
||||
<a href=#70 id=70 data-nosnippet>70</a>//!
|
||||
<a href=#71 id=71 data-nosnippet>71</a>//! #[pallet::hooks]
|
||||
<a href=#72 id=72 data-nosnippet>72</a>//! impl<T: Config> Hooks<BlockNumberFor<T>> for Pallet<T> {
|
||||
<a href=#73 id=73 data-nosnippet>73</a>//! fn offchain_worker(block_number: BlockNumberFor<T>) {
|
||||
<a href=#74 id=74 data-nosnippet>74</a>//! // ...
|
||||
<a href=#75 id=75 data-nosnippet>75</a>//! }
|
||||
<a href=#76 id=76 data-nosnippet>76</a>//! }
|
||||
<a href=#77 id=77 data-nosnippet>77</a>//! }
|
||||
<a href=#78 id=78 data-nosnippet>78</a>//! ```
|
||||
<a href=#79 id=79 data-nosnippet>79</a>//!
|
||||
<a href=#80 id=80 data-nosnippet>80</a>//! Additionally, [`sp_runtime::offchain`] provides a set of utilities that can be used to moderate
|
||||
<a href=#81 id=81 data-nosnippet>81</a>//! the execution of offchain workers.
|
||||
<a href=#82 id=82 data-nosnippet>82</a>//!
|
||||
<a href=#83 id=83 data-nosnippet>83</a>//! ## Think Twice: Why Use Substrate's Offchain Workers?
|
||||
<a href=#84 id=84 data-nosnippet>84</a>//!
|
||||
<a href=#85 id=85 data-nosnippet>85</a>//! Consider the fact that in principle, an offchain worker code written using the above API is no
|
||||
<a href=#86 id=86 data-nosnippet>86</a>//! different than an equivalent written with an _actual offchain interaction library_, such as
|
||||
<a href=#87 id=87 data-nosnippet>87</a>//! [Pezkuwi-JS](https://pezkuwi.js.org/docs/), or any of the other ones listed [here](https://github.com/substrate-developer-hub/awesome-substrate?tab=readme-ov-file#client-libraries).
|
||||
<a href=#88 id=88 data-nosnippet>88</a>//!
|
||||
<a href=#89 id=89 data-nosnippet>89</a>//! They can both read from the state, and have no means of updating the state, other than the route
|
||||
<a href=#90 id=90 data-nosnippet>90</a>//! of submitting an extrinsic to the chain. Therefore, it is worth thinking twice before embedding
|
||||
<a href=#91 id=91 data-nosnippet>91</a>//! a logic as a part of Substrate's offchain worker API. Does it have to be there? Can it not be a
|
||||
<a href=#92 id=92 data-nosnippet>92</a>//! simple, actual offchain application that lives outside of the chain's WASM blob?
|
||||
<a href=#93 id=93 data-nosnippet>93</a>//!
|
||||
<a href=#94 id=94 data-nosnippet>94</a>//! Some of the reasons why you might want to do the opposite, and actually embed an offchain worker
|
||||
<a href=#95 id=95 data-nosnippet>95</a>//! API into the WASM blob are:
|
||||
<a href=#96 id=96 data-nosnippet>96</a>//!
|
||||
<a href=#97 id=97 data-nosnippet>97</a>//! * Accessing the state is easier within the `offchain_worker` function, as it is already a part
|
||||
<a href=#98 id=98 data-nosnippet>98</a>//! of the runtime, and [`frame::pallet_macros::storage`] provides all the tools needed to read
|
||||
<a href=#99 id=99 data-nosnippet>99</a>//! the state. Other client libraries might provide varying degrees of capability here.
|
||||
<a href=#100 id=100 data-nosnippet>100</a>//! * It will be updated in synchrony with the runtime. A Substrate's offchain application is part
|
||||
<a href=#101 id=101 data-nosnippet>101</a>//! of the same WASM blob, and is therefore guaranteed to be up to date.
|
||||
<a href=#102 id=102 data-nosnippet>102</a>//!
|
||||
<a href=#103 id=103 data-nosnippet>103</a>//! For example, imagine you have modified a storage item to have a new type. This will possibly
|
||||
<a href=#104 id=104 data-nosnippet>104</a>//! require a [`crate::reference_docs::frame_runtime_upgrades_and_migrations`], and any offchain
|
||||
<a href=#105 id=105 data-nosnippet>105</a>//! code, such as a Pezkuwi-JS application, will have to be updated to reflect this change. Whereas
|
||||
<a href=#106 id=106 data-nosnippet>106</a>//! the WASM offchain worker code is guaranteed to already be updated, or else the runtime code will
|
||||
<a href=#107 id=107 data-nosnippet>107</a>//! not even compile.
|
||||
<a href=#108 id=108 data-nosnippet>108</a>//!
|
||||
<a href=#109 id=109 data-nosnippet>109</a>//!
|
||||
<a href=#110 id=110 data-nosnippet>110</a>//! ## Further References
|
||||
<a href=#111 id=111 data-nosnippet>111</a>//!
|
||||
<a href=#112 id=112 data-nosnippet>112</a>//! - <https://forum.network.pezkuwichain.io/t/offchain-workers-design-assumptions-vulnerabilities/2548>
|
||||
<a href=#113 id=113 data-nosnippet>113</a>//! - <https://exchange.pezkuwichain.app/questions/11058/how-can-i-create-ocw-that-wont-activates-every-block-but-will-activates-only-w/11060#11060>
|
||||
<a href=#114 id=114 data-nosnippet>114</a>//! - [Offchain worker example](https://github.com/pezkuwichain/pezkuwi-sdk/tree/master/substrate/frame/examples/offchain-worker)</span></code></pre></div></section></main></body></html>
|
||||
@@ -0,0 +1,270 @@
|
||||
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `docs/sdk/src/reference_docs/frame_origin.rs`."><title>frame_origin.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2"href="../../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../../../static.files/rustdoc-e56847b5.css"><meta name="rustdoc-vars" data-root-path="../../../" data-static-root-path="../../../static.files/" data-current-crate="pezkuwi_sdk_docs" data-themes="" data-resource-suffix="" data-rustdoc-version="1.91.1 (ed61e7d7e 2025-11-07)" data-channel="1.91.1" data-search-js="search-e256b49e.js" data-stringdex-js="stringdex-c3e638e9.js" data-settings-js="settings-c38705f0.js" ><script src="../../../static.files/storage-e2aeef58.js"></script><script defer src="../../../static.files/src-script-813739b1.js"></script><script defer src="../../../src-files.js"></script><script defer src="../../../static.files/main-6dc2a7f3.js"></script><noscript><link rel="stylesheet" href="../../../static.files/noscript-263c88ec.css"></noscript><link rel="icon" href="https://pezkuwichain.io/favicon.ico"></head><body class="rustdoc src"><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer" title="Drag to resize sidebar"></div><main><section id="main-content" class="content"><div class="main-heading"><h1><div class="sub-heading">pezkuwi_sdk_docs/reference_docs/</div>frame_origin.rs</h1><rustdoc-toolbar></rustdoc-toolbar></div><div class="example-wrap digits-3"><pre class="rust"><code><a href=#1 id=1 data-nosnippet>1</a><span class="doccomment">//! # FRAME Origin
|
||||
<a href=#2 id=2 data-nosnippet>2</a>//!
|
||||
<a href=#3 id=3 data-nosnippet>3</a>//! Let's start by clarifying a common wrong assumption about Origin:
|
||||
<a href=#4 id=4 data-nosnippet>4</a>//!
|
||||
<a href=#5 id=5 data-nosnippet>5</a>//! **ORIGIN IS NOT AN ACCOUNT ID**.
|
||||
<a href=#6 id=6 data-nosnippet>6</a>//!
|
||||
<a href=#7 id=7 data-nosnippet>7</a>//! FRAME's origin abstractions allow you to convey meanings far beyond just an account-id being the
|
||||
<a href=#8 id=8 data-nosnippet>8</a>//! caller of an extrinsic. Nonetheless, an account-id having signed an extrinsic is one of the
|
||||
<a href=#9 id=9 data-nosnippet>9</a>//! meanings that an origin can convey. This is the commonly used [`frame_system::ensure_signed`],
|
||||
<a href=#10 id=10 data-nosnippet>10</a>//! where the return value happens to be an account-id.
|
||||
<a href=#11 id=11 data-nosnippet>11</a>//!
|
||||
<a href=#12 id=12 data-nosnippet>12</a>//! Instead, let's establish the following as the correct definition of an origin:
|
||||
<a href=#13 id=13 data-nosnippet>13</a>//!
|
||||
<a href=#14 id=14 data-nosnippet>14</a>//! > The origin type represents the privilege level of the caller of an extrinsic.
|
||||
<a href=#15 id=15 data-nosnippet>15</a>//!
|
||||
<a href=#16 id=16 data-nosnippet>16</a>//! That is, an extrinsic, through checking the origin, can *express what privilege level it wishes
|
||||
<a href=#17 id=17 data-nosnippet>17</a>//! to impose on the caller of the extrinsic*. One of those checks can be as simple as "*any account
|
||||
<a href=#18 id=18 data-nosnippet>18</a>//! that has signed a statement can pass*".
|
||||
<a href=#19 id=19 data-nosnippet>19</a>//!
|
||||
<a href=#20 id=20 data-nosnippet>20</a>//! But the origin system can also express more abstract and complicated privilege levels. For
|
||||
<a href=#21 id=21 data-nosnippet>21</a>//! example:
|
||||
<a href=#22 id=22 data-nosnippet>22</a>//!
|
||||
<a href=#23 id=23 data-nosnippet>23</a>//! * If the majority of token holders agreed upon this. This is more or less what the
|
||||
<a href=#24 id=24 data-nosnippet>24</a>//! [`pallet_democracy`] does under the hood ([reference](https://github.com/pezkuwichain/pezkuwi-sdk/blob/edd95b3749754d2ed0c5738588e872c87be91624/substrate/frame/democracy/src/lib.rs#L1603-L1633)).
|
||||
<a href=#25 id=25 data-nosnippet>25</a>//! * If a specific ratio of an instance of [`pallet_collective`]/DAO agrees upon this.
|
||||
<a href=#26 id=26 data-nosnippet>26</a>//! * If another consensus system, for example a bridged network or a teyrchain, agrees upon this.
|
||||
<a href=#27 id=27 data-nosnippet>27</a>//! * If the majority of validator/authority set agrees upon this[^1].
|
||||
<a href=#28 id=28 data-nosnippet>28</a>//! * If caller holds a particular NFT.
|
||||
<a href=#29 id=29 data-nosnippet>29</a>//!
|
||||
<a href=#30 id=30 data-nosnippet>30</a>//! and many more.
|
||||
<a href=#31 id=31 data-nosnippet>31</a>//!
|
||||
<a href=#32 id=32 data-nosnippet>32</a>//! ## Context
|
||||
<a href=#33 id=33 data-nosnippet>33</a>//!
|
||||
<a href=#34 id=34 data-nosnippet>34</a>//! First, let's look at where the `origin` type is encountered in a typical pallet. The `origin:
|
||||
<a href=#35 id=35 data-nosnippet>35</a>//! OriginFor<T>` has to be the first argument of any given callable extrinsic in FRAME:
|
||||
<a href=#36 id=36 data-nosnippet>36</a></span><span class="attr">#![doc = <span class="macro">docify::embed!</span>(<span class="string">"./src/reference_docs/frame_origin.rs"</span>, call_simple)]
|
||||
<a href=#37 id=37 data-nosnippet>37</a></span><span class="doccomment">//!
|
||||
<a href=#38 id=38 data-nosnippet>38</a>//! Typically, the code of an extrinsic starts with an origin check, such as
|
||||
<a href=#39 id=39 data-nosnippet>39</a>//! [`frame_system::ensure_signed`].
|
||||
<a href=#40 id=40 data-nosnippet>40</a>//!
|
||||
<a href=#41 id=41 data-nosnippet>41</a>//! Note that [`OriginFor`](frame_system::pallet_prelude::OriginFor) is merely a shorthand for
|
||||
<a href=#42 id=42 data-nosnippet>42</a>//! [`frame_system::Config::RuntimeOrigin`]. Given the name prefix `Runtime`, we can learn that
|
||||
<a href=#43 id=43 data-nosnippet>43</a>//! `RuntimeOrigin` is similar to `RuntimeCall` and others, a runtime composite enum that is
|
||||
<a href=#44 id=44 data-nosnippet>44</a>//! amalgamated at the runtime level. Read [`crate::reference_docs::frame_runtime_types`] to
|
||||
<a href=#45 id=45 data-nosnippet>45</a>//! familiarize yourself with these types.
|
||||
<a href=#46 id=46 data-nosnippet>46</a>//!
|
||||
<a href=#47 id=47 data-nosnippet>47</a>//! To understand this better, we will next create a pallet with a custom origin, which will add a
|
||||
<a href=#48 id=48 data-nosnippet>48</a>//! new variant to `RuntimeOrigin`.
|
||||
<a href=#49 id=49 data-nosnippet>49</a>//!
|
||||
<a href=#50 id=50 data-nosnippet>50</a>//! ## Adding Custom Pallet Origin to the Runtime
|
||||
<a href=#51 id=51 data-nosnippet>51</a>//!
|
||||
<a href=#52 id=52 data-nosnippet>52</a>//! For example, given a pallet that defines the following custom origin:
|
||||
<a href=#53 id=53 data-nosnippet>53</a></span><span class="attr">#![doc = <span class="macro">docify::embed!</span>(<span class="string">"./src/reference_docs/frame_origin.rs"</span>, custom_origin)]
|
||||
<a href=#54 id=54 data-nosnippet>54</a></span><span class="doccomment">//!
|
||||
<a href=#55 id=55 data-nosnippet>55</a>//! And a runtime with the following pallets:
|
||||
<a href=#56 id=56 data-nosnippet>56</a></span><span class="attr">#![doc = <span class="macro">docify::embed!</span>(<span class="string">"./src/reference_docs/frame_origin.rs"</span>, runtime_exp)]
|
||||
<a href=#57 id=57 data-nosnippet>57</a></span><span class="doccomment">//!
|
||||
<a href=#58 id=58 data-nosnippet>58</a>//! The type [`crate::reference_docs::frame_origin::runtime_for_origin::RuntimeOrigin`] is expanded.
|
||||
<a href=#59 id=59 data-nosnippet>59</a>//! This `RuntimeOrigin` contains a variant for the [`frame_system::RawOrigin`] and the custom
|
||||
<a href=#60 id=60 data-nosnippet>60</a>//! origin of the pallet.
|
||||
<a href=#61 id=61 data-nosnippet>61</a>//!
|
||||
<a href=#62 id=62 data-nosnippet>62</a>//! > Notice how the [`frame_system::ensure_signed`] is nothing more than a `match` statement. If
|
||||
<a href=#63 id=63 data-nosnippet>63</a>//! > you want to know where the actual origin of an extrinsic is set (and the signature
|
||||
<a href=#64 id=64 data-nosnippet>64</a>//! > verification happens, if any), see
|
||||
<a href=#65 id=65 data-nosnippet>65</a>//! > [`sp_runtime::generic::CheckedExtrinsic#trait-implementations`], specifically
|
||||
<a href=#66 id=66 data-nosnippet>66</a>//! > [`sp_runtime::traits::Applyable`]'s implementation.
|
||||
<a href=#67 id=67 data-nosnippet>67</a>//!
|
||||
<a href=#68 id=68 data-nosnippet>68</a>//! ## Asserting on a Custom Internal Origin
|
||||
<a href=#69 id=69 data-nosnippet>69</a>//!
|
||||
<a href=#70 id=70 data-nosnippet>70</a>//! In order to assert on a custom origin that is defined within your pallet, we need a way to first
|
||||
<a href=#71 id=71 data-nosnippet>71</a>//! convert the `<T as frame_system::Config>::RuntimeOrigin` into the local `enum Origin` of the
|
||||
<a href=#72 id=72 data-nosnippet>72</a>//! current pallet. This is a common process that is explained in
|
||||
<a href=#73 id=73 data-nosnippet>73</a>//! [`crate::reference_docs::frame_runtime_types#
|
||||
<a href=#74 id=74 data-nosnippet>74</a>//! adding-further-constraints-to-runtime-composite-enums`].
|
||||
<a href=#75 id=75 data-nosnippet>75</a>//!
|
||||
<a href=#76 id=76 data-nosnippet>76</a>//! We use the same process here to express that `RuntimeOrigin` has a number of additional bounds,
|
||||
<a href=#77 id=77 data-nosnippet>77</a>//! as follows.
|
||||
<a href=#78 id=78 data-nosnippet>78</a>//!
|
||||
<a href=#79 id=79 data-nosnippet>79</a>//! 1. Defining a custom `RuntimeOrigin` with further bounds in the pallet.
|
||||
<a href=#80 id=80 data-nosnippet>80</a></span><span class="attr">#![doc = <span class="macro">docify::embed!</span>(<span class="string">"./src/reference_docs/frame_origin.rs"</span>, custom_origin_bound)]
|
||||
<a href=#81 id=81 data-nosnippet>81</a></span><span class="doccomment">//!
|
||||
<a href=#82 id=82 data-nosnippet>82</a>//! 2. Using it in the pallet.
|
||||
<a href=#83 id=83 data-nosnippet>83</a></span><span class="attr">#![doc = <span class="macro">docify::embed!</span>(<span class="string">"./src/reference_docs/frame_origin.rs"</span>, custom_origin_usage)]
|
||||
<a href=#84 id=84 data-nosnippet>84</a></span><span class="doccomment">//!
|
||||
<a href=#85 id=85 data-nosnippet>85</a>//! ## Asserting on a Custom External Origin
|
||||
<a href=#86 id=86 data-nosnippet>86</a>//!
|
||||
<a href=#87 id=87 data-nosnippet>87</a>//! Very often, a pallet wants to have a parameterized origin that is **NOT** defined within the
|
||||
<a href=#88 id=88 data-nosnippet>88</a>//! pallet. In other words, a pallet wants to delegate an origin check to something that is
|
||||
<a href=#89 id=89 data-nosnippet>89</a>//! specified later at the runtime level. Like many other parameterizations in FRAME, this implies
|
||||
<a href=#90 id=90 data-nosnippet>90</a>//! adding a new associated type to `trait Config`.
|
||||
<a href=#91 id=91 data-nosnippet>91</a></span><span class="attr">#![doc = <span class="macro">docify::embed!</span>(<span class="string">"./src/reference_docs/frame_origin.rs"</span>, external_origin_def)]
|
||||
<a href=#92 id=92 data-nosnippet>92</a></span><span class="doccomment">//!
|
||||
<a href=#93 id=93 data-nosnippet>93</a>//! Then, within the pallet, we can simply use this "unknown" origin check type:
|
||||
<a href=#94 id=94 data-nosnippet>94</a></span><span class="attr">#![doc = <span class="macro">docify::embed!</span>(<span class="string">"./src/reference_docs/frame_origin.rs"</span>, external_origin_usage)]
|
||||
<a href=#95 id=95 data-nosnippet>95</a></span><span class="doccomment">//!
|
||||
<a href=#96 id=96 data-nosnippet>96</a>//! Finally, at the runtime, any implementation of [`frame::traits::EnsureOrigin`] can be passed.
|
||||
<a href=#97 id=97 data-nosnippet>97</a></span><span class="attr">#![doc = <span class="macro">docify::embed!</span>(<span class="string">"./src/reference_docs/frame_origin.rs"</span>, external_origin_provide)]
|
||||
<a href=#98 id=98 data-nosnippet>98</a></span><span class="doccomment">//!
|
||||
<a href=#99 id=99 data-nosnippet>99</a>//! Indeed, some of these implementations of [`frame::traits::EnsureOrigin`] are similar to the ones
|
||||
<a href=#100 id=100 data-nosnippet>100</a>//! that we know about: [`frame::runtime::prelude::EnsureSigned`],
|
||||
<a href=#101 id=101 data-nosnippet>101</a>//! [`frame::runtime::prelude::EnsureSignedBy`], [`frame::runtime::prelude::EnsureRoot`],
|
||||
<a href=#102 id=102 data-nosnippet>102</a>//! [`frame::runtime::prelude::EnsureNone`], etc. But, there are also many more that are not known
|
||||
<a href=#103 id=103 data-nosnippet>103</a>//! to us, and are defined in other pallets.
|
||||
<a href=#104 id=104 data-nosnippet>104</a>//!
|
||||
<a href=#105 id=105 data-nosnippet>105</a>//! For example, [`pallet_collective`] defines [`pallet_collective::EnsureMember`] and
|
||||
<a href=#106 id=106 data-nosnippet>106</a>//! [`pallet_collective::EnsureProportionMoreThan`] and many more, which is exactly what we alluded
|
||||
<a href=#107 id=107 data-nosnippet>107</a>//! to earlier in this document.
|
||||
<a href=#108 id=108 data-nosnippet>108</a>//!
|
||||
<a href=#109 id=109 data-nosnippet>109</a>//! Make sure to check the full list of [implementors of
|
||||
<a href=#110 id=110 data-nosnippet>110</a>//! `EnsureOrigin`](frame::traits::EnsureOrigin#implementors) for more inspiration.
|
||||
<a href=#111 id=111 data-nosnippet>111</a>//!
|
||||
<a href=#112 id=112 data-nosnippet>112</a>//! ## Obtaining Abstract Origins
|
||||
<a href=#113 id=113 data-nosnippet>113</a>//!
|
||||
<a href=#114 id=114 data-nosnippet>114</a>//! So far we have learned that FRAME pallets can assert on custom and abstract origin types,
|
||||
<a href=#115 id=115 data-nosnippet>115</a>//! whether they are defined within the pallet or not. But how can we obtain these abstract origins?
|
||||
<a href=#116 id=116 data-nosnippet>116</a>//!
|
||||
<a href=#117 id=117 data-nosnippet>117</a>//! > All extrinsics that come from the outer world can generally only be obtained as either
|
||||
<a href=#118 id=118 data-nosnippet>118</a>//! > `signed` or `none` origin.
|
||||
<a href=#119 id=119 data-nosnippet>119</a>//!
|
||||
<a href=#120 id=120 data-nosnippet>120</a>//! Generally, these abstract origins are only obtained within the runtime, when a call is
|
||||
<a href=#121 id=121 data-nosnippet>121</a>//! dispatched within the runtime.
|
||||
<a href=#122 id=122 data-nosnippet>122</a>//!
|
||||
<a href=#123 id=123 data-nosnippet>123</a>//! ## Further References
|
||||
<a href=#124 id=124 data-nosnippet>124</a>//!
|
||||
<a href=#125 id=125 data-nosnippet>125</a>//! - [Gavin Wood's speech about FRAME features at Protocol Berg 2023.](https://youtu.be/j7b8Upipmeg?si=83_XUgYuJxMwWX4g&t=195)
|
||||
<a href=#126 id=126 data-nosnippet>126</a>//! - [A related StackExchange question.](https://exchange.pezkuwichain.app/questions/10992/how-do-you-find-the-public-key-for-the-medium-spender-track-origin)
|
||||
<a href=#127 id=127 data-nosnippet>127</a>//!
|
||||
<a href=#128 id=128 data-nosnippet>128</a>//! [^1]: Inherents are essentially unsigned extrinsics that need an [`frame_system::ensure_none`]
|
||||
<a href=#129 id=129 data-nosnippet>129</a>//! origin check, and through the virtue of being an inherent, are agreed upon by all validators.
|
||||
<a href=#130 id=130 data-nosnippet>130</a>
|
||||
<a href=#131 id=131 data-nosnippet>131</a></span><span class="kw">use </span>frame::prelude::<span class="kw-2">*</span>;
|
||||
<a href=#132 id=132 data-nosnippet>132</a>
|
||||
<a href=#133 id=133 data-nosnippet>133</a><span class="attr">#[frame::pallet(dev_mode)]
|
||||
<a href=#134 id=134 data-nosnippet>134</a></span><span class="kw">pub mod </span>pallet_for_origin {
|
||||
<a href=#135 id=135 data-nosnippet>135</a> <span class="kw">use super</span>::<span class="kw-2">*</span>;
|
||||
<a href=#136 id=136 data-nosnippet>136</a>
|
||||
<a href=#137 id=137 data-nosnippet>137</a> <span class="attr">#[pallet::config]
|
||||
<a href=#138 id=138 data-nosnippet>138</a> </span><span class="kw">pub trait </span>Config: frame_system::Config {}
|
||||
<a href=#139 id=139 data-nosnippet>139</a>
|
||||
<a href=#140 id=140 data-nosnippet>140</a> <span class="attr">#[pallet::pallet]
|
||||
<a href=#141 id=141 data-nosnippet>141</a> </span><span class="kw">pub struct </span>Pallet<T>(<span class="kw">_</span>);
|
||||
<a href=#142 id=142 data-nosnippet>142</a>
|
||||
<a href=#143 id=143 data-nosnippet>143</a> <span class="attr">#[docify::export(call_simple)]
|
||||
<a href=#144 id=144 data-nosnippet>144</a> #[pallet::call]
|
||||
<a href=#145 id=145 data-nosnippet>145</a> </span><span class="kw">impl</span><T: Config> Pallet<T> {
|
||||
<a href=#146 id=146 data-nosnippet>146</a> <span class="kw">pub fn </span>do_something(_origin: OriginFor<T>) -> DispatchResult {
|
||||
<a href=#147 id=147 data-nosnippet>147</a> <span class="comment">// ^^^^^^^^^^^^^^^^^^^^^
|
||||
<a href=#148 id=148 data-nosnippet>148</a> </span><span class="macro">todo!</span>();
|
||||
<a href=#149 id=149 data-nosnippet>149</a> }
|
||||
<a href=#150 id=150 data-nosnippet>150</a> }
|
||||
<a href=#151 id=151 data-nosnippet>151</a>}
|
||||
<a href=#152 id=152 data-nosnippet>152</a>
|
||||
<a href=#153 id=153 data-nosnippet>153</a><span class="attr">#[frame::pallet(dev_mode)]
|
||||
<a href=#154 id=154 data-nosnippet>154</a></span><span class="kw">pub mod </span>pallet_with_custom_origin {
|
||||
<a href=#155 id=155 data-nosnippet>155</a> <span class="kw">use super</span>::<span class="kw-2">*</span>;
|
||||
<a href=#156 id=156 data-nosnippet>156</a>
|
||||
<a href=#157 id=157 data-nosnippet>157</a> <span class="attr">#[docify::export(custom_origin_bound)]
|
||||
<a href=#158 id=158 data-nosnippet>158</a> #[pallet::config]
|
||||
<a href=#159 id=159 data-nosnippet>159</a> </span><span class="kw">pub trait </span>Config: frame_system::Config {
|
||||
<a href=#160 id=160 data-nosnippet>160</a> <span class="kw">type </span>RuntimeOrigin: From<<<span class="self">Self </span><span class="kw">as </span>frame_system::Config>::RuntimeOrigin>
|
||||
<a href=#161 id=161 data-nosnippet>161</a> + Into<<span class="prelude-ty">Result</span><Origin, <<span class="self">Self </span><span class="kw">as </span>Config>::RuntimeOrigin>>;
|
||||
<a href=#162 id=162 data-nosnippet>162</a> }
|
||||
<a href=#163 id=163 data-nosnippet>163</a>
|
||||
<a href=#164 id=164 data-nosnippet>164</a> <span class="attr">#[pallet::pallet]
|
||||
<a href=#165 id=165 data-nosnippet>165</a> </span><span class="kw">pub struct </span>Pallet<T>(<span class="kw">_</span>);
|
||||
<a href=#166 id=166 data-nosnippet>166</a>
|
||||
<a href=#167 id=167 data-nosnippet>167</a> <span class="attr">#[docify::export(custom_origin)]
|
||||
<a href=#168 id=168 data-nosnippet>168</a> </span><span class="doccomment">/// A dummy custom origin.
|
||||
<a href=#169 id=169 data-nosnippet>169</a> </span><span class="attr">#[pallet::origin]
|
||||
<a href=#170 id=170 data-nosnippet>170</a> #[derive(
|
||||
<a href=#171 id=171 data-nosnippet>171</a> PartialEq,
|
||||
<a href=#172 id=172 data-nosnippet>172</a> Eq,
|
||||
<a href=#173 id=173 data-nosnippet>173</a> Clone,
|
||||
<a href=#174 id=174 data-nosnippet>174</a> RuntimeDebug,
|
||||
<a href=#175 id=175 data-nosnippet>175</a> Encode,
|
||||
<a href=#176 id=176 data-nosnippet>176</a> Decode,
|
||||
<a href=#177 id=177 data-nosnippet>177</a> DecodeWithMemTracking,
|
||||
<a href=#178 id=178 data-nosnippet>178</a> TypeInfo,
|
||||
<a href=#179 id=179 data-nosnippet>179</a> MaxEncodedLen,
|
||||
<a href=#180 id=180 data-nosnippet>180</a> )]
|
||||
<a href=#181 id=181 data-nosnippet>181</a> </span><span class="kw">pub enum </span>Origin {
|
||||
<a href=#182 id=182 data-nosnippet>182</a> <span class="doccomment">/// If all holders of a particular NFT have agreed upon this.
|
||||
<a href=#183 id=183 data-nosnippet>183</a> </span>AllNftHolders,
|
||||
<a href=#184 id=184 data-nosnippet>184</a> <span class="doccomment">/// If all validators have agreed upon this.
|
||||
<a href=#185 id=185 data-nosnippet>185</a> </span>ValidatorSet,
|
||||
<a href=#186 id=186 data-nosnippet>186</a> }
|
||||
<a href=#187 id=187 data-nosnippet>187</a>
|
||||
<a href=#188 id=188 data-nosnippet>188</a> <span class="attr">#[docify::export(custom_origin_usage)]
|
||||
<a href=#189 id=189 data-nosnippet>189</a> #[pallet::call]
|
||||
<a href=#190 id=190 data-nosnippet>190</a> </span><span class="kw">impl</span><T: Config> Pallet<T> {
|
||||
<a href=#191 id=191 data-nosnippet>191</a> <span class="kw">pub fn </span>only_validators(origin: OriginFor<T>) -> DispatchResult {
|
||||
<a href=#192 id=192 data-nosnippet>192</a> <span class="comment">// first, we convert from `<T as frame_system::Config>::RuntimeOrigin` to `<T as
|
||||
<a href=#193 id=193 data-nosnippet>193</a> // Config>::RuntimeOrigin`
|
||||
<a href=#194 id=194 data-nosnippet>194</a> </span><span class="kw">let </span>local_runtime_origin = <<T <span class="kw">as </span>Config>::RuntimeOrigin <span class="kw">as </span>From<
|
||||
<a href=#195 id=195 data-nosnippet>195</a> <T <span class="kw">as </span>frame_system::Config>::RuntimeOrigin,
|
||||
<a href=#196 id=196 data-nosnippet>196</a> >>::from(origin);
|
||||
<a href=#197 id=197 data-nosnippet>197</a> <span class="comment">// then we convert to `origin`, if possible
|
||||
<a href=#198 id=198 data-nosnippet>198</a> </span><span class="kw">let </span>local_origin =
|
||||
<a href=#199 id=199 data-nosnippet>199</a> local_runtime_origin.into().map_err(|<span class="kw">_</span>| <span class="string">"invalid origin type provided"</span>)<span class="question-mark">?</span>;
|
||||
<a href=#200 id=200 data-nosnippet>200</a> <span class="macro">ensure!</span>(<span class="macro">matches!</span>(local_origin, Origin::ValidatorSet), <span class="string">"Not authorized"</span>);
|
||||
<a href=#201 id=201 data-nosnippet>201</a> <span class="macro">todo!</span>();
|
||||
<a href=#202 id=202 data-nosnippet>202</a> }
|
||||
<a href=#203 id=203 data-nosnippet>203</a> }
|
||||
<a href=#204 id=204 data-nosnippet>204</a>}
|
||||
<a href=#205 id=205 data-nosnippet>205</a>
|
||||
<a href=#206 id=206 data-nosnippet>206</a><span class="kw">pub mod </span>runtime_for_origin {
|
||||
<a href=#207 id=207 data-nosnippet>207</a> <span class="kw">use </span><span class="kw">super</span>::pallet_with_custom_origin;
|
||||
<a href=#208 id=208 data-nosnippet>208</a> <span class="kw">use </span>frame::{runtime::prelude::<span class="kw-2">*</span>, testing_prelude::<span class="kw-2">*</span>};
|
||||
<a href=#209 id=209 data-nosnippet>209</a>
|
||||
<a href=#210 id=210 data-nosnippet>210</a> <span class="attr">#[docify::export(runtime_exp)]
|
||||
<a href=#211 id=211 data-nosnippet>211</a> </span><span class="macro">construct_runtime!</span>(
|
||||
<a href=#212 id=212 data-nosnippet>212</a> <span class="kw">pub struct </span>Runtime {
|
||||
<a href=#213 id=213 data-nosnippet>213</a> System: frame_system,
|
||||
<a href=#214 id=214 data-nosnippet>214</a> PalletWithCustomOrigin: pallet_with_custom_origin,
|
||||
<a href=#215 id=215 data-nosnippet>215</a> }
|
||||
<a href=#216 id=216 data-nosnippet>216</a> );
|
||||
<a href=#217 id=217 data-nosnippet>217</a>
|
||||
<a href=#218 id=218 data-nosnippet>218</a> <span class="attr">#[derive_impl(frame_system::config_preludes::TestDefaultConfig)]
|
||||
<a href=#219 id=219 data-nosnippet>219</a> </span><span class="kw">impl </span>frame_system::Config <span class="kw">for </span>Runtime {
|
||||
<a href=#220 id=220 data-nosnippet>220</a> <span class="kw">type </span>Block = MockBlock<<span class="self">Self</span>>;
|
||||
<a href=#221 id=221 data-nosnippet>221</a> }
|
||||
<a href=#222 id=222 data-nosnippet>222</a>
|
||||
<a href=#223 id=223 data-nosnippet>223</a> <span class="kw">impl </span>pallet_with_custom_origin::Config <span class="kw">for </span>Runtime {
|
||||
<a href=#224 id=224 data-nosnippet>224</a> <span class="kw">type </span>RuntimeOrigin = RuntimeOrigin;
|
||||
<a href=#225 id=225 data-nosnippet>225</a> }
|
||||
<a href=#226 id=226 data-nosnippet>226</a>}
|
||||
<a href=#227 id=227 data-nosnippet>227</a>
|
||||
<a href=#228 id=228 data-nosnippet>228</a><span class="attr">#[frame::pallet(dev_mode)]
|
||||
<a href=#229 id=229 data-nosnippet>229</a></span><span class="kw">pub mod </span>pallet_with_external_origin {
|
||||
<a href=#230 id=230 data-nosnippet>230</a> <span class="kw">use super</span>::<span class="kw-2">*</span>;
|
||||
<a href=#231 id=231 data-nosnippet>231</a> <span class="attr">#[docify::export(external_origin_def)]
|
||||
<a href=#232 id=232 data-nosnippet>232</a> #[pallet::config]
|
||||
<a href=#233 id=233 data-nosnippet>233</a> </span><span class="kw">pub trait </span>Config: frame_system::Config {
|
||||
<a href=#234 id=234 data-nosnippet>234</a> <span class="kw">type </span>ExternalOrigin: EnsureOrigin<<span class="self">Self</span>::RuntimeOrigin>;
|
||||
<a href=#235 id=235 data-nosnippet>235</a> }
|
||||
<a href=#236 id=236 data-nosnippet>236</a>
|
||||
<a href=#237 id=237 data-nosnippet>237</a> <span class="attr">#[pallet::pallet]
|
||||
<a href=#238 id=238 data-nosnippet>238</a> </span><span class="kw">pub struct </span>Pallet<T>(<span class="kw">_</span>);
|
||||
<a href=#239 id=239 data-nosnippet>239</a>
|
||||
<a href=#240 id=240 data-nosnippet>240</a> <span class="attr">#[docify::export(external_origin_usage)]
|
||||
<a href=#241 id=241 data-nosnippet>241</a> #[pallet::call]
|
||||
<a href=#242 id=242 data-nosnippet>242</a> </span><span class="kw">impl</span><T: Config> Pallet<T> {
|
||||
<a href=#243 id=243 data-nosnippet>243</a> <span class="kw">pub fn </span>externally_checked_ext(origin: OriginFor<T>) -> DispatchResult {
|
||||
<a href=#244 id=244 data-nosnippet>244</a> T::ExternalOrigin::ensure_origin(origin)<span class="question-mark">?</span>;
|
||||
<a href=#245 id=245 data-nosnippet>245</a> <span class="macro">todo!</span>();
|
||||
<a href=#246 id=246 data-nosnippet>246</a> }
|
||||
<a href=#247 id=247 data-nosnippet>247</a> }
|
||||
<a href=#248 id=248 data-nosnippet>248</a>}
|
||||
<a href=#249 id=249 data-nosnippet>249</a>
|
||||
<a href=#250 id=250 data-nosnippet>250</a><span class="kw">pub mod </span>runtime_for_external_origin {
|
||||
<a href=#251 id=251 data-nosnippet>251</a> <span class="kw">use super</span>::<span class="kw-2">*</span>;
|
||||
<a href=#252 id=252 data-nosnippet>252</a> <span class="kw">use </span>frame::{runtime::prelude::<span class="kw-2">*</span>, testing_prelude::<span class="kw-2">*</span>};
|
||||
<a href=#253 id=253 data-nosnippet>253</a>
|
||||
<a href=#254 id=254 data-nosnippet>254</a> <span class="macro">construct_runtime!</span>(
|
||||
<a href=#255 id=255 data-nosnippet>255</a> <span class="kw">pub struct </span>Runtime {
|
||||
<a href=#256 id=256 data-nosnippet>256</a> System: frame_system,
|
||||
<a href=#257 id=257 data-nosnippet>257</a> PalletWithExternalOrigin: pallet_with_external_origin,
|
||||
<a href=#258 id=258 data-nosnippet>258</a> }
|
||||
<a href=#259 id=259 data-nosnippet>259</a> );
|
||||
<a href=#260 id=260 data-nosnippet>260</a>
|
||||
<a href=#261 id=261 data-nosnippet>261</a> <span class="attr">#[derive_impl(frame_system::config_preludes::TestDefaultConfig)]
|
||||
<a href=#262 id=262 data-nosnippet>262</a> </span><span class="kw">impl </span>frame_system::Config <span class="kw">for </span>Runtime {
|
||||
<a href=#263 id=263 data-nosnippet>263</a> <span class="kw">type </span>Block = MockBlock<<span class="self">Self</span>>;
|
||||
<a href=#264 id=264 data-nosnippet>264</a> }
|
||||
<a href=#265 id=265 data-nosnippet>265</a>
|
||||
<a href=#266 id=266 data-nosnippet>266</a> <span class="attr">#[docify::export(external_origin_provide)]
|
||||
<a href=#267 id=267 data-nosnippet>267</a> </span><span class="kw">impl </span>pallet_with_external_origin::Config <span class="kw">for </span>Runtime {
|
||||
<a href=#268 id=268 data-nosnippet>268</a> <span class="kw">type </span>ExternalOrigin = EnsureSigned<<<span class="self">Self </span><span class="kw">as </span>frame_system::Config>::AccountId>;
|
||||
<a href=#269 id=269 data-nosnippet>269</a> }
|
||||
<a href=#270 id=270 data-nosnippet>270</a>}</code></pre></div></section></main></body></html>
|
||||
+296
@@ -0,0 +1,296 @@
|
||||
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `docs/sdk/src/reference_docs/frame_pallet_coupling.rs`."><title>frame_pallet_coupling.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2"href="../../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../../../static.files/rustdoc-e56847b5.css"><meta name="rustdoc-vars" data-root-path="../../../" data-static-root-path="../../../static.files/" data-current-crate="pezkuwi_sdk_docs" data-themes="" data-resource-suffix="" data-rustdoc-version="1.91.1 (ed61e7d7e 2025-11-07)" data-channel="1.91.1" data-search-js="search-e256b49e.js" data-stringdex-js="stringdex-c3e638e9.js" data-settings-js="settings-c38705f0.js" ><script src="../../../static.files/storage-e2aeef58.js"></script><script defer src="../../../static.files/src-script-813739b1.js"></script><script defer src="../../../src-files.js"></script><script defer src="../../../static.files/main-6dc2a7f3.js"></script><noscript><link rel="stylesheet" href="../../../static.files/noscript-263c88ec.css"></noscript><link rel="icon" href="https://pezkuwichain.io/favicon.ico"></head><body class="rustdoc src"><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer" title="Drag to resize sidebar"></div><main><section id="main-content" class="content"><div class="main-heading"><h1><div class="sub-heading">pezkuwi_sdk_docs/reference_docs/</div>frame_pallet_coupling.rs</h1><rustdoc-toolbar></rustdoc-toolbar></div><div class="example-wrap digits-3"><pre class="rust"><code><a href=#1 id=1 data-nosnippet>1</a><span class="doccomment">//! # FRAME Pallet Coupling
|
||||
<a href=#2 id=2 data-nosnippet>2</a>//!
|
||||
<a href=#3 id=3 data-nosnippet>3</a>//! This reference document explains how FRAME pallets can be combined to interact together.
|
||||
<a href=#4 id=4 data-nosnippet>4</a>//!
|
||||
<a href=#5 id=5 data-nosnippet>5</a>//! It is suggested to re-read [`crate::pezkuwi_sdk::frame_runtime`], notably the information
|
||||
<a href=#6 id=6 data-nosnippet>6</a>//! around [`frame::pallet_macros::config`]. Recall that:
|
||||
<a href=#7 id=7 data-nosnippet>7</a>//!
|
||||
<a href=#8 id=8 data-nosnippet>8</a>//! > Configuration trait of a pallet: It allows a pallet to receive types at a later
|
||||
<a href=#9 id=9 data-nosnippet>9</a>//! > point from the runtime that wishes to contain it. It allows the pallet to be parameterized
|
||||
<a href=#10 id=10 data-nosnippet>10</a>//! > over both types and values.
|
||||
<a href=#11 id=11 data-nosnippet>11</a>//!
|
||||
<a href=#12 id=12 data-nosnippet>12</a>//! ## Context, Background
|
||||
<a href=#13 id=13 data-nosnippet>13</a>//!
|
||||
<a href=#14 id=14 data-nosnippet>14</a>//! FRAME pallets, as per described in [`crate::pezkuwi_sdk::frame_runtime`] are:
|
||||
<a href=#15 id=15 data-nosnippet>15</a>//!
|
||||
<a href=#16 id=16 data-nosnippet>16</a>//! > A pallet is a unit of encapsulated logic. It has a clearly defined responsibility and can be
|
||||
<a href=#17 id=17 data-nosnippet>17</a>//! linked to other pallets.
|
||||
<a href=#18 id=18 data-nosnippet>18</a>//!
|
||||
<a href=#19 id=19 data-nosnippet>19</a>//! That is to say:
|
||||
<a href=#20 id=20 data-nosnippet>20</a>//!
|
||||
<a href=#21 id=21 data-nosnippet>21</a>//! * *encapsulated*: Ideally, a FRAME pallet contains encapsulated logic which has clear
|
||||
<a href=#22 id=22 data-nosnippet>22</a>//! boundaries. It is generally a bad idea to build a single monolithic pallet that does multiple
|
||||
<a href=#23 id=23 data-nosnippet>23</a>//! things, such as handling currencies, identities and staking all at the same time.
|
||||
<a href=#24 id=24 data-nosnippet>24</a>//! * *linked to other pallets*: But, adhering extensively to the above also hinders the ability to
|
||||
<a href=#25 id=25 data-nosnippet>25</a>//! write useful applications. Pallets often need to work with each other, communicate and use
|
||||
<a href=#26 id=26 data-nosnippet>26</a>//! each other's functionalities.
|
||||
<a href=#27 id=27 data-nosnippet>27</a>//!
|
||||
<a href=#28 id=28 data-nosnippet>28</a>//! The broad principle that allows pallets to be linked together is the same way through which a
|
||||
<a href=#29 id=29 data-nosnippet>29</a>//! pallet uses its `Config` trait to receive types and values from the runtime that contains it.
|
||||
<a href=#30 id=30 data-nosnippet>30</a>//!
|
||||
<a href=#31 id=31 data-nosnippet>31</a>//! There are generally two ways to achieve this:
|
||||
<a href=#32 id=32 data-nosnippet>32</a>//!
|
||||
<a href=#33 id=33 data-nosnippet>33</a>//! 1. Tight coupling pallets.
|
||||
<a href=#34 id=34 data-nosnippet>34</a>//! 2. Loose coupling pallets.
|
||||
<a href=#35 id=35 data-nosnippet>35</a>//!
|
||||
<a href=#36 id=36 data-nosnippet>36</a>//! To explain the difference between the two, consider two pallets, `A` and `B`. In both cases, `A`
|
||||
<a href=#37 id=37 data-nosnippet>37</a>//! wants to use some functionality exposed by `B`.
|
||||
<a href=#38 id=38 data-nosnippet>38</a>//!
|
||||
<a href=#39 id=39 data-nosnippet>39</a>//! When tightly coupling pallets, `A` can only exist in a runtime if `B` is also present in the
|
||||
<a href=#40 id=40 data-nosnippet>40</a>//! same runtime. That is, `A` is expressing that can only work if `B` is present.
|
||||
<a href=#41 id=41 data-nosnippet>41</a>//!
|
||||
<a href=#42 id=42 data-nosnippet>42</a>//! This translates to the following Rust code:
|
||||
<a href=#43 id=43 data-nosnippet>43</a>//!
|
||||
<a href=#44 id=44 data-nosnippet>44</a>//! ```
|
||||
<a href=#45 id=45 data-nosnippet>45</a>//! trait Pallet_B_Config {}
|
||||
<a href=#46 id=46 data-nosnippet>46</a>//! trait Pallet_A_Config: Pallet_B_Config {}
|
||||
<a href=#47 id=47 data-nosnippet>47</a>//! ```
|
||||
<a href=#48 id=48 data-nosnippet>48</a>//!
|
||||
<a href=#49 id=49 data-nosnippet>49</a>//! Contrary, when pallets are loosely coupled, `A` expresses that some functionality, expressed via
|
||||
<a href=#50 id=50 data-nosnippet>50</a>//! a trait `F`, needs to be fulfilled. This trait is then implemented by `B`, and the two pallets
|
||||
<a href=#51 id=51 data-nosnippet>51</a>//! are linked together at the runtime level. This means that `A` only relies on the implementation
|
||||
<a href=#52 id=52 data-nosnippet>52</a>//! of `F`, which may be `B`, or another implementation of `F`.
|
||||
<a href=#53 id=53 data-nosnippet>53</a>//!
|
||||
<a href=#54 id=54 data-nosnippet>54</a>//! This translates to the following Rust code:
|
||||
<a href=#55 id=55 data-nosnippet>55</a>//!
|
||||
<a href=#56 id=56 data-nosnippet>56</a>//! ```
|
||||
<a href=#57 id=57 data-nosnippet>57</a>//! trait F {}
|
||||
<a href=#58 id=58 data-nosnippet>58</a>//! trait Pallet_A_Config {
|
||||
<a href=#59 id=59 data-nosnippet>59</a>//! type F: F;
|
||||
<a href=#60 id=60 data-nosnippet>60</a>//! }
|
||||
<a href=#61 id=61 data-nosnippet>61</a>//! // Pallet_B will implement and fulfill `F`.
|
||||
<a href=#62 id=62 data-nosnippet>62</a>//! ```
|
||||
<a href=#63 id=63 data-nosnippet>63</a>//!
|
||||
<a href=#64 id=64 data-nosnippet>64</a>//! ## Example
|
||||
<a href=#65 id=65 data-nosnippet>65</a>//!
|
||||
<a href=#66 id=66 data-nosnippet>66</a>//! Consider the following example, in which `pallet-foo` needs another pallet to provide the block
|
||||
<a href=#67 id=67 data-nosnippet>67</a>//! author to it, and `pallet-author` which has access to this information.
|
||||
<a href=#68 id=68 data-nosnippet>68</a></span><span class="attr">#![doc = <span class="macro">docify::embed!</span>(<span class="string">"./src/reference_docs/frame_pallet_coupling.rs"</span>, pallet_foo)]
|
||||
<a href=#69 id=69 data-nosnippet>69</a>#![doc = <span class="macro">docify::embed!</span>(<span class="string">"./src/reference_docs/frame_pallet_coupling.rs"</span>, pallet_author)]
|
||||
<a href=#70 id=70 data-nosnippet>70</a></span><span class="doccomment">//!
|
||||
<a href=#71 id=71 data-nosnippet>71</a>//! ### Tight Coupling Pallets
|
||||
<a href=#72 id=72 data-nosnippet>72</a>//!
|
||||
<a href=#73 id=73 data-nosnippet>73</a>//! To tightly couple `pallet-foo` and `pallet-author`, we use Rust's supertrait system. When a
|
||||
<a href=#74 id=74 data-nosnippet>74</a>//! pallet makes its own `trait Config` be bounded by another pallet's `trait Config`, it is
|
||||
<a href=#75 id=75 data-nosnippet>75</a>//! expressing two things:
|
||||
<a href=#76 id=76 data-nosnippet>76</a>//!
|
||||
<a href=#77 id=77 data-nosnippet>77</a>//! 1. That it can only exist in a runtime if the other pallet is also present.
|
||||
<a href=#78 id=78 data-nosnippet>78</a>//! 2. That it can use the other pallet's functionality.
|
||||
<a href=#79 id=79 data-nosnippet>79</a>//!
|
||||
<a href=#80 id=80 data-nosnippet>80</a>//! `pallet-foo`'s `Config` would then look like:
|
||||
<a href=#81 id=81 data-nosnippet>81</a></span><span class="attr">#![doc = <span class="macro">docify::embed!</span>(<span class="string">"./src/reference_docs/frame_pallet_coupling.rs"</span>, tight_config)]
|
||||
<a href=#82 id=82 data-nosnippet>82</a></span><span class="doccomment">//!
|
||||
<a href=#83 id=83 data-nosnippet>83</a>//! And `pallet-foo` can use the method exposed by `pallet_author::Pallet` directly:
|
||||
<a href=#84 id=84 data-nosnippet>84</a></span><span class="attr">#![doc = <span class="macro">docify::embed!</span>(<span class="string">"./src/reference_docs/frame_pallet_coupling.rs"</span>, tight_usage)]
|
||||
<a href=#85 id=85 data-nosnippet>85</a></span><span class="doccomment">//!
|
||||
<a href=#86 id=86 data-nosnippet>86</a>//!
|
||||
<a href=#87 id=87 data-nosnippet>87</a>//! ### Loosely Coupling Pallets
|
||||
<a href=#88 id=88 data-nosnippet>88</a>//!
|
||||
<a href=#89 id=89 data-nosnippet>89</a>//! If `pallet-foo` wants to *not* rely on `pallet-author` directly, it can leverage its
|
||||
<a href=#90 id=90 data-nosnippet>90</a>//! `Config`'s associated types. First, we need a trait to express the functionality that
|
||||
<a href=#91 id=91 data-nosnippet>91</a>//! `pallet-foo` wants to obtain:
|
||||
<a href=#92 id=92 data-nosnippet>92</a></span><span class="attr">#![doc = <span class="macro">docify::embed!</span>(<span class="string">"./src/reference_docs/frame_pallet_coupling.rs"</span>, AuthorProvider)]
|
||||
<a href=#93 id=93 data-nosnippet>93</a></span><span class="doccomment">//!
|
||||
<a href=#94 id=94 data-nosnippet>94</a>//! > We sometimes refer to such traits that help two pallets interact as "glue traits".
|
||||
<a href=#95 id=95 data-nosnippet>95</a>//!
|
||||
<a href=#96 id=96 data-nosnippet>96</a>//! Next, `pallet-foo` states that it needs this trait to be provided to it, at the runtime level,
|
||||
<a href=#97 id=97 data-nosnippet>97</a>//! via an associated type:
|
||||
<a href=#98 id=98 data-nosnippet>98</a></span><span class="attr">#![doc = <span class="macro">docify::embed!</span>(<span class="string">"./src/reference_docs/frame_pallet_coupling.rs"</span>, loose_config)]
|
||||
<a href=#99 id=99 data-nosnippet>99</a></span><span class="doccomment">//!
|
||||
<a href=#100 id=100 data-nosnippet>100</a>//! Then, `pallet-foo` can use this trait to obtain the block author, without knowing where it comes
|
||||
<a href=#101 id=101 data-nosnippet>101</a>//! from:
|
||||
<a href=#102 id=102 data-nosnippet>102</a></span><span class="attr">#![doc = <span class="macro">docify::embed!</span>(<span class="string">"./src/reference_docs/frame_pallet_coupling.rs"</span>, loose_usage)]
|
||||
<a href=#103 id=103 data-nosnippet>103</a></span><span class="doccomment">//!
|
||||
<a href=#104 id=104 data-nosnippet>104</a>//! Then, if `pallet-author` implements this glue-trait:
|
||||
<a href=#105 id=105 data-nosnippet>105</a></span><span class="attr">#![doc = <span class="macro">docify::embed!</span>(<span class="string">"./src/reference_docs/frame_pallet_coupling.rs"</span>, pallet_author_provider)]
|
||||
<a href=#106 id=106 data-nosnippet>106</a></span><span class="doccomment">//!
|
||||
<a href=#107 id=107 data-nosnippet>107</a>//! And upon the creation of the runtime, the two pallets are linked together as such:
|
||||
<a href=#108 id=108 data-nosnippet>108</a></span><span class="attr">#![doc = <span class="macro">docify::embed!</span>(<span class="string">"./src/reference_docs/frame_pallet_coupling.rs"</span>, runtime_author_provider)]
|
||||
<a href=#109 id=109 data-nosnippet>109</a></span><span class="doccomment">//!
|
||||
<a href=#110 id=110 data-nosnippet>110</a>//! Crucially, when using loose coupling, we gain the flexibility of providing different
|
||||
<a href=#111 id=111 data-nosnippet>111</a>//! implementations of `AuthorProvider`, such that different users of a `pallet-foo` can use
|
||||
<a href=#112 id=112 data-nosnippet>112</a>//! different ones, without any code change being needed. For example, in the code snippets of this
|
||||
<a href=#113 id=113 data-nosnippet>113</a>//! module, you can find [`OtherAuthorProvider`], which is an alternative implementation of
|
||||
<a href=#114 id=114 data-nosnippet>114</a>//! [`AuthorProvider`].
|
||||
<a href=#115 id=115 data-nosnippet>115</a></span><span class="attr">#![doc = <span class="macro">docify::embed!</span>(<span class="string">"./src/reference_docs/frame_pallet_coupling.rs"</span>, other_author_provider)]
|
||||
<a href=#116 id=116 data-nosnippet>116</a></span><span class="doccomment">//!
|
||||
<a href=#117 id=117 data-nosnippet>117</a>//! A common pattern in pezkuwi-sdk is to provide an implementation of such glu traits for the unit
|
||||
<a href=#118 id=118 data-nosnippet>118</a>//! type as a "default/test behavior".
|
||||
<a href=#119 id=119 data-nosnippet>119</a></span><span class="attr">#![doc = <span class="macro">docify::embed!</span>(<span class="string">"./src/reference_docs/frame_pallet_coupling.rs"</span>, unit_author_provider)]
|
||||
<a href=#120 id=120 data-nosnippet>120</a></span><span class="doccomment">//!
|
||||
<a href=#121 id=121 data-nosnippet>121</a>//! ## Frame System
|
||||
<a href=#122 id=122 data-nosnippet>122</a>//!
|
||||
<a href=#123 id=123 data-nosnippet>123</a>//! With the above information in context, we can conclude that **`frame_system` is a special pallet
|
||||
<a href=#124 id=124 data-nosnippet>124</a>//! that is tightly coupled with every other pallet**. This is because it provides the fundamental
|
||||
<a href=#125 id=125 data-nosnippet>125</a>//! system functionality that every pallet needs, such as some types like
|
||||
<a href=#126 id=126 data-nosnippet>126</a>//! [`frame::prelude::frame_system::Config::AccountId`],
|
||||
<a href=#127 id=127 data-nosnippet>127</a>//! [`frame::prelude::frame_system::Config::Hash`], and some functionality such as block number,
|
||||
<a href=#128 id=128 data-nosnippet>128</a>//! etc.
|
||||
<a href=#129 id=129 data-nosnippet>129</a>//!
|
||||
<a href=#130 id=130 data-nosnippet>130</a>//! ## Recap
|
||||
<a href=#131 id=131 data-nosnippet>131</a>//!
|
||||
<a href=#132 id=132 data-nosnippet>132</a>//! To recap, consider the following rules of thumb:
|
||||
<a href=#133 id=133 data-nosnippet>133</a>//!
|
||||
<a href=#134 id=134 data-nosnippet>134</a>//! * In all cases, try and break down big pallets apart with clear boundaries of responsibility. In
|
||||
<a href=#135 id=135 data-nosnippet>135</a>//! general, it is easier to argue about multiple pallet if they only communicate together via a
|
||||
<a href=#136 id=136 data-nosnippet>136</a>//! known trait, rather than having access to all of each others public items, such as storage and
|
||||
<a href=#137 id=137 data-nosnippet>137</a>//! dispatchables.
|
||||
<a href=#138 id=138 data-nosnippet>138</a>//! * If a group of pallets is meant to work together, but is not foreseen to be generalized, or
|
||||
<a href=#139 id=139 data-nosnippet>139</a>//! used by others, consider tightly coupling pallets, *if it simplifies the development*.
|
||||
<a href=#140 id=140 data-nosnippet>140</a>//! * If a pallet needs a functionality provided by another pallet, but multiple implementations can
|
||||
<a href=#141 id=141 data-nosnippet>141</a>//! be foreseen, consider loosely coupling pallets.
|
||||
<a href=#142 id=142 data-nosnippet>142</a>//!
|
||||
<a href=#143 id=143 data-nosnippet>143</a>//! For example, all pallets in `pezkuwi-sdk` that needed to work with currencies could have been
|
||||
<a href=#144 id=144 data-nosnippet>144</a>//! tightly coupled with [`pallet_balances`]. But, `pezkuwi-sdk` also provides [`pallet_assets`]
|
||||
<a href=#145 id=145 data-nosnippet>145</a>//! (and more implementations by the community), therefore all pallets use traits to loosely couple
|
||||
<a href=#146 id=146 data-nosnippet>146</a>//! with balances or assets pallet. More on this in [`crate::reference_docs::frame_tokens`].
|
||||
<a href=#147 id=147 data-nosnippet>147</a>//!
|
||||
<a href=#148 id=148 data-nosnippet>148</a>//! ## Further References
|
||||
<a href=#149 id=149 data-nosnippet>149</a>//!
|
||||
<a href=#150 id=150 data-nosnippet>150</a>//! - <https://www.youtube.com/watch?v=0eNGZpNkJk4>
|
||||
<a href=#151 id=151 data-nosnippet>151</a>//! - <https://exchange.pezkuwichain.app/questions/922/pallet-loose-couplingtight-coupling-and-missing-traits>
|
||||
<a href=#152 id=152 data-nosnippet>152</a>//!
|
||||
<a href=#153 id=153 data-nosnippet>153</a>//! [`AuthorProvider`]: crate::reference_docs::frame_pallet_coupling::AuthorProvider
|
||||
<a href=#154 id=154 data-nosnippet>154</a>//! [`OtherAuthorProvider`]: crate::reference_docs::frame_pallet_coupling::OtherAuthorProvider
|
||||
<a href=#155 id=155 data-nosnippet>155</a>
|
||||
<a href=#156 id=156 data-nosnippet>156</a></span><span class="attr">#![allow(unused)]
|
||||
<a href=#157 id=157 data-nosnippet>157</a>
|
||||
<a href=#158 id=158 data-nosnippet>158</a></span><span class="kw">use </span>frame::prelude::<span class="kw-2">*</span>;
|
||||
<a href=#159 id=159 data-nosnippet>159</a>
|
||||
<a href=#160 id=160 data-nosnippet>160</a><span class="attr">#[docify::export]
|
||||
<a href=#161 id=161 data-nosnippet>161</a>#[frame::pallet]
|
||||
<a href=#162 id=162 data-nosnippet>162</a></span><span class="kw">pub mod </span>pallet_foo {
|
||||
<a href=#163 id=163 data-nosnippet>163</a> <span class="kw">use super</span>::<span class="kw-2">*</span>;
|
||||
<a href=#164 id=164 data-nosnippet>164</a>
|
||||
<a href=#165 id=165 data-nosnippet>165</a> <span class="attr">#[pallet::config]
|
||||
<a href=#166 id=166 data-nosnippet>166</a> </span><span class="kw">pub trait </span>Config: frame_system::Config {}
|
||||
<a href=#167 id=167 data-nosnippet>167</a>
|
||||
<a href=#168 id=168 data-nosnippet>168</a> <span class="attr">#[pallet::pallet]
|
||||
<a href=#169 id=169 data-nosnippet>169</a> </span><span class="kw">pub struct </span>Pallet<T>(<span class="kw">_</span>);
|
||||
<a href=#170 id=170 data-nosnippet>170</a>
|
||||
<a href=#171 id=171 data-nosnippet>171</a> <span class="kw">impl</span><T: Config> Pallet<T> {
|
||||
<a href=#172 id=172 data-nosnippet>172</a> <span class="kw">fn </span>do_stuff_with_author() {
|
||||
<a href=#173 id=173 data-nosnippet>173</a> <span class="comment">// needs block author here
|
||||
<a href=#174 id=174 data-nosnippet>174</a> </span>}
|
||||
<a href=#175 id=175 data-nosnippet>175</a> }
|
||||
<a href=#176 id=176 data-nosnippet>176</a>}
|
||||
<a href=#177 id=177 data-nosnippet>177</a>
|
||||
<a href=#178 id=178 data-nosnippet>178</a><span class="attr">#[docify::export]
|
||||
<a href=#179 id=179 data-nosnippet>179</a>#[frame::pallet]
|
||||
<a href=#180 id=180 data-nosnippet>180</a></span><span class="kw">pub mod </span>pallet_author {
|
||||
<a href=#181 id=181 data-nosnippet>181</a> <span class="kw">use super</span>::<span class="kw-2">*</span>;
|
||||
<a href=#182 id=182 data-nosnippet>182</a>
|
||||
<a href=#183 id=183 data-nosnippet>183</a> <span class="attr">#[pallet::config]
|
||||
<a href=#184 id=184 data-nosnippet>184</a> </span><span class="kw">pub trait </span>Config: frame_system::Config {}
|
||||
<a href=#185 id=185 data-nosnippet>185</a>
|
||||
<a href=#186 id=186 data-nosnippet>186</a> <span class="attr">#[pallet::pallet]
|
||||
<a href=#187 id=187 data-nosnippet>187</a> </span><span class="kw">pub struct </span>Pallet<T>(<span class="kw">_</span>);
|
||||
<a href=#188 id=188 data-nosnippet>188</a>
|
||||
<a href=#189 id=189 data-nosnippet>189</a> <span class="kw">impl</span><T: Config> Pallet<T> {
|
||||
<a href=#190 id=190 data-nosnippet>190</a> <span class="kw">pub fn </span>author() -> T::AccountId {
|
||||
<a href=#191 id=191 data-nosnippet>191</a> <span class="macro">todo!</span>(<span class="string">"somehow has access to the block author and can return it here"</span>)
|
||||
<a href=#192 id=192 data-nosnippet>192</a> }
|
||||
<a href=#193 id=193 data-nosnippet>193</a> }
|
||||
<a href=#194 id=194 data-nosnippet>194</a>}
|
||||
<a href=#195 id=195 data-nosnippet>195</a>
|
||||
<a href=#196 id=196 data-nosnippet>196</a><span class="attr">#[frame::pallet]
|
||||
<a href=#197 id=197 data-nosnippet>197</a></span><span class="kw">pub mod </span>pallet_foo_tight {
|
||||
<a href=#198 id=198 data-nosnippet>198</a> <span class="kw">use super</span>::<span class="kw-2">*</span>;
|
||||
<a href=#199 id=199 data-nosnippet>199</a>
|
||||
<a href=#200 id=200 data-nosnippet>200</a> <span class="attr">#[pallet::pallet]
|
||||
<a href=#201 id=201 data-nosnippet>201</a> </span><span class="kw">pub struct </span>Pallet<T>(<span class="kw">_</span>);
|
||||
<a href=#202 id=202 data-nosnippet>202</a>
|
||||
<a href=#203 id=203 data-nosnippet>203</a> <span class="attr">#[docify::export(tight_config)]
|
||||
<a href=#204 id=204 data-nosnippet>204</a> </span><span class="doccomment">/// This pallet can only live in a runtime that has both `frame_system` and `pallet_author`.
|
||||
<a href=#205 id=205 data-nosnippet>205</a> </span><span class="attr">#[pallet::config]
|
||||
<a href=#206 id=206 data-nosnippet>206</a> </span><span class="kw">pub trait </span>Config: frame_system::Config + pallet_author::Config {}
|
||||
<a href=#207 id=207 data-nosnippet>207</a>
|
||||
<a href=#208 id=208 data-nosnippet>208</a> <span class="attr">#[docify::export(tight_usage)]
|
||||
<a href=#209 id=209 data-nosnippet>209</a> </span><span class="kw">impl</span><T: Config> Pallet<T> {
|
||||
<a href=#210 id=210 data-nosnippet>210</a> <span class="comment">// anywhere in `pallet-foo`, we can call into `pallet-author` directly, namely because
|
||||
<a href=#211 id=211 data-nosnippet>211</a> // `T: pallet_author::Config`
|
||||
<a href=#212 id=212 data-nosnippet>212</a> </span><span class="kw">fn </span>do_stuff_with_author() {
|
||||
<a href=#213 id=213 data-nosnippet>213</a> <span class="kw">let _ </span>= pallet_author::Pallet::<T>::author();
|
||||
<a href=#214 id=214 data-nosnippet>214</a> }
|
||||
<a href=#215 id=215 data-nosnippet>215</a> }
|
||||
<a href=#216 id=216 data-nosnippet>216</a>}
|
||||
<a href=#217 id=217 data-nosnippet>217</a>
|
||||
<a href=#218 id=218 data-nosnippet>218</a><span class="attr">#[docify::export]
|
||||
<a href=#219 id=219 data-nosnippet>219</a></span><span class="doccomment">/// Abstraction over "something that can provide the block author".
|
||||
<a href=#220 id=220 data-nosnippet>220</a></span><span class="kw">pub trait </span>AuthorProvider<AccountId> {
|
||||
<a href=#221 id=221 data-nosnippet>221</a> <span class="kw">fn </span>author() -> AccountId;
|
||||
<a href=#222 id=222 data-nosnippet>222</a>}
|
||||
<a href=#223 id=223 data-nosnippet>223</a>
|
||||
<a href=#224 id=224 data-nosnippet>224</a><span class="attr">#[frame::pallet]
|
||||
<a href=#225 id=225 data-nosnippet>225</a></span><span class="kw">pub mod </span>pallet_foo_loose {
|
||||
<a href=#226 id=226 data-nosnippet>226</a> <span class="kw">use super</span>::<span class="kw-2">*</span>;
|
||||
<a href=#227 id=227 data-nosnippet>227</a>
|
||||
<a href=#228 id=228 data-nosnippet>228</a> <span class="attr">#[pallet::pallet]
|
||||
<a href=#229 id=229 data-nosnippet>229</a> </span><span class="kw">pub struct </span>Pallet<T>(<span class="kw">_</span>);
|
||||
<a href=#230 id=230 data-nosnippet>230</a>
|
||||
<a href=#231 id=231 data-nosnippet>231</a> <span class="attr">#[docify::export(loose_config)]
|
||||
<a href=#232 id=232 data-nosnippet>232</a> #[pallet::config]
|
||||
<a href=#233 id=233 data-nosnippet>233</a> </span><span class="kw">pub trait </span>Config: frame_system::Config {
|
||||
<a href=#234 id=234 data-nosnippet>234</a> <span class="doccomment">/// This pallet relies on the existence of something that implements [`AuthorProvider`],
|
||||
<a href=#235 id=235 data-nosnippet>235</a> /// which may or may not be `pallet-author`.
|
||||
<a href=#236 id=236 data-nosnippet>236</a> </span><span class="kw">type </span>AuthorProvider: AuthorProvider<<span class="self">Self</span>::AccountId>;
|
||||
<a href=#237 id=237 data-nosnippet>237</a> }
|
||||
<a href=#238 id=238 data-nosnippet>238</a>
|
||||
<a href=#239 id=239 data-nosnippet>239</a> <span class="attr">#[docify::export(loose_usage)]
|
||||
<a href=#240 id=240 data-nosnippet>240</a> </span><span class="kw">impl</span><T: Config> Pallet<T> {
|
||||
<a href=#241 id=241 data-nosnippet>241</a> <span class="kw">fn </span>do_stuff_with_author() {
|
||||
<a href=#242 id=242 data-nosnippet>242</a> <span class="kw">let _ </span>= T::AuthorProvider::author();
|
||||
<a href=#243 id=243 data-nosnippet>243</a> }
|
||||
<a href=#244 id=244 data-nosnippet>244</a> }
|
||||
<a href=#245 id=245 data-nosnippet>245</a>}
|
||||
<a href=#246 id=246 data-nosnippet>246</a>
|
||||
<a href=#247 id=247 data-nosnippet>247</a><span class="attr">#[docify::export(pallet_author_provider)]
|
||||
<a href=#248 id=248 data-nosnippet>248</a></span><span class="kw">impl</span><T: pallet_author::Config> AuthorProvider<T::AccountId> <span class="kw">for </span>pallet_author::Pallet<T> {
|
||||
<a href=#249 id=249 data-nosnippet>249</a> <span class="kw">fn </span>author() -> T::AccountId {
|
||||
<a href=#250 id=250 data-nosnippet>250</a> pallet_author::Pallet::<T>::author()
|
||||
<a href=#251 id=251 data-nosnippet>251</a> }
|
||||
<a href=#252 id=252 data-nosnippet>252</a>}
|
||||
<a href=#253 id=253 data-nosnippet>253</a>
|
||||
<a href=#254 id=254 data-nosnippet>254</a><span class="kw">pub struct </span>OtherAuthorProvider;
|
||||
<a href=#255 id=255 data-nosnippet>255</a>
|
||||
<a href=#256 id=256 data-nosnippet>256</a><span class="attr">#[docify::export(other_author_provider)]
|
||||
<a href=#257 id=257 data-nosnippet>257</a></span><span class="kw">impl</span><AccountId> AuthorProvider<AccountId> <span class="kw">for </span>OtherAuthorProvider {
|
||||
<a href=#258 id=258 data-nosnippet>258</a> <span class="kw">fn </span>author() -> AccountId {
|
||||
<a href=#259 id=259 data-nosnippet>259</a> <span class="macro">todo!</span>(<span class="string">"somehow get the block author here"</span>)
|
||||
<a href=#260 id=260 data-nosnippet>260</a> }
|
||||
<a href=#261 id=261 data-nosnippet>261</a>}
|
||||
<a href=#262 id=262 data-nosnippet>262</a>
|
||||
<a href=#263 id=263 data-nosnippet>263</a><span class="attr">#[docify::export(unit_author_provider)]
|
||||
<a href=#264 id=264 data-nosnippet>264</a></span><span class="kw">impl</span><AccountId> AuthorProvider<AccountId> <span class="kw">for </span>() {
|
||||
<a href=#265 id=265 data-nosnippet>265</a> <span class="kw">fn </span>author() -> AccountId {
|
||||
<a href=#266 id=266 data-nosnippet>266</a> <span class="macro">todo!</span>(<span class="string">"somehow get the block author here"</span>)
|
||||
<a href=#267 id=267 data-nosnippet>267</a> }
|
||||
<a href=#268 id=268 data-nosnippet>268</a>}
|
||||
<a href=#269 id=269 data-nosnippet>269</a>
|
||||
<a href=#270 id=270 data-nosnippet>270</a><span class="kw">pub mod </span>runtime {
|
||||
<a href=#271 id=271 data-nosnippet>271</a> <span class="kw">use super</span>::<span class="kw-2">*</span>;
|
||||
<a href=#272 id=272 data-nosnippet>272</a> <span class="kw">use </span>cumulus_pallet_aura_ext::pallet;
|
||||
<a href=#273 id=273 data-nosnippet>273</a> <span class="kw">use </span>frame::{runtime::prelude::<span class="kw-2">*</span>, testing_prelude::<span class="kw-2">*</span>};
|
||||
<a href=#274 id=274 data-nosnippet>274</a>
|
||||
<a href=#275 id=275 data-nosnippet>275</a> <span class="macro">construct_runtime!</span>(
|
||||
<a href=#276 id=276 data-nosnippet>276</a> <span class="kw">pub struct </span>Runtime {
|
||||
<a href=#277 id=277 data-nosnippet>277</a> System: frame_system,
|
||||
<a href=#278 id=278 data-nosnippet>278</a> PalletFoo: pallet_foo_loose,
|
||||
<a href=#279 id=279 data-nosnippet>279</a> PalletAuthor: pallet_author,
|
||||
<a href=#280 id=280 data-nosnippet>280</a> }
|
||||
<a href=#281 id=281 data-nosnippet>281</a> );
|
||||
<a href=#282 id=282 data-nosnippet>282</a>
|
||||
<a href=#283 id=283 data-nosnippet>283</a> <span class="attr">#[derive_impl(frame_system::config_preludes::TestDefaultConfig)]
|
||||
<a href=#284 id=284 data-nosnippet>284</a> </span><span class="kw">impl </span>frame_system::Config <span class="kw">for </span>Runtime {
|
||||
<a href=#285 id=285 data-nosnippet>285</a> <span class="kw">type </span>Block = MockBlock<<span class="self">Self</span>>;
|
||||
<a href=#286 id=286 data-nosnippet>286</a> }
|
||||
<a href=#287 id=287 data-nosnippet>287</a>
|
||||
<a href=#288 id=288 data-nosnippet>288</a> <span class="kw">impl </span>pallet_author::Config <span class="kw">for </span>Runtime {}
|
||||
<a href=#289 id=289 data-nosnippet>289</a>
|
||||
<a href=#290 id=290 data-nosnippet>290</a> <span class="attr">#[docify::export(runtime_author_provider)]
|
||||
<a href=#291 id=291 data-nosnippet>291</a> </span><span class="kw">impl </span>pallet_foo_loose::Config <span class="kw">for </span>Runtime {
|
||||
<a href=#292 id=292 data-nosnippet>292</a> <span class="kw">type </span>AuthorProvider = pallet_author::Pallet<Runtime>;
|
||||
<a href=#293 id=293 data-nosnippet>293</a> <span class="comment">// which is also equivalent to
|
||||
<a href=#294 id=294 data-nosnippet>294</a> // type AuthorProvider = PalletAuthor;
|
||||
<a href=#295 id=295 data-nosnippet>295</a> </span>}
|
||||
<a href=#296 id=296 data-nosnippet>296</a>}</code></pre></div></section></main></body></html>
|
||||
@@ -0,0 +1,320 @@
|
||||
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `docs/sdk/src/reference_docs/frame_runtime_types.rs`."><title>frame_runtime_types.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2"href="../../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../../../static.files/rustdoc-e56847b5.css"><meta name="rustdoc-vars" data-root-path="../../../" data-static-root-path="../../../static.files/" data-current-crate="pezkuwi_sdk_docs" data-themes="" data-resource-suffix="" data-rustdoc-version="1.91.1 (ed61e7d7e 2025-11-07)" data-channel="1.91.1" data-search-js="search-e256b49e.js" data-stringdex-js="stringdex-c3e638e9.js" data-settings-js="settings-c38705f0.js" ><script src="../../../static.files/storage-e2aeef58.js"></script><script defer src="../../../static.files/src-script-813739b1.js"></script><script defer src="../../../src-files.js"></script><script defer src="../../../static.files/main-6dc2a7f3.js"></script><noscript><link rel="stylesheet" href="../../../static.files/noscript-263c88ec.css"></noscript><link rel="icon" href="https://pezkuwichain.io/favicon.ico"></head><body class="rustdoc src"><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer" title="Drag to resize sidebar"></div><main><section id="main-content" class="content"><div class="main-heading"><h1><div class="sub-heading">pezkuwi_sdk_docs/reference_docs/</div>frame_runtime_types.rs</h1><rustdoc-toolbar></rustdoc-toolbar></div><div class="example-wrap digits-3"><pre class="rust"><code><a href=#1 id=1 data-nosnippet>1</a><span class="doccomment">//! # FRAME Runtime Types
|
||||
<a href=#2 id=2 data-nosnippet>2</a>//!
|
||||
<a href=#3 id=3 data-nosnippet>3</a>//! This reference document briefly explores the idea around types generated at the runtime level by
|
||||
<a href=#4 id=4 data-nosnippet>4</a>//! the FRAME macros.
|
||||
<a href=#5 id=5 data-nosnippet>5</a>//!
|
||||
<a href=#6 id=6 data-nosnippet>6</a>//! > As of now, many of these important types are generated within the internals of
|
||||
<a href=#7 id=7 data-nosnippet>7</a>//! > [`construct_runtime`], and there is no easy way for you to visually know they exist.
|
||||
<a href=#8 id=8 data-nosnippet>8</a>//! > [#pezkuwi-sdk#1378](https://github.com/pezkuwichain/pezkuwi-sdk/pull/1378) is meant to
|
||||
<a href=#9 id=9 data-nosnippet>9</a>//! > significantly improve this. Exploring the rust-docs of a runtime, such as [`runtime`] which is
|
||||
<a href=#10 id=10 data-nosnippet>10</a>//! > defined in this module is as of now the best way to learn about these types.
|
||||
<a href=#11 id=11 data-nosnippet>11</a>//!
|
||||
<a href=#12 id=12 data-nosnippet>12</a>//! ## Composite Enums
|
||||
<a href=#13 id=13 data-nosnippet>13</a>//!
|
||||
<a href=#14 id=14 data-nosnippet>14</a>//! Many types within a FRAME runtime follow the following structure:
|
||||
<a href=#15 id=15 data-nosnippet>15</a>//!
|
||||
<a href=#16 id=16 data-nosnippet>16</a>//! * Each individual pallet defines a type, for example `Foo`.
|
||||
<a href=#17 id=17 data-nosnippet>17</a>//! * At the runtime level, these types are amalgamated into a single type, for example
|
||||
<a href=#18 id=18 data-nosnippet>18</a>//! `RuntimeFoo`.
|
||||
<a href=#19 id=19 data-nosnippet>19</a>//!
|
||||
<a href=#20 id=20 data-nosnippet>20</a>//! As the names suggest, all composite enums in a FRAME runtime start their name with `Runtime`.
|
||||
<a href=#21 id=21 data-nosnippet>21</a>//! For example, `RuntimeCall` is a representation of the most high level `Call`-able type in the
|
||||
<a href=#22 id=22 data-nosnippet>22</a>//! runtime.
|
||||
<a href=#23 id=23 data-nosnippet>23</a>//!
|
||||
<a href=#24 id=24 data-nosnippet>24</a>//! Composite enums are generally convertible to their individual parts as such:
|
||||
<a href=#25 id=25 data-nosnippet>25</a></span><span class="attr">#![doc = <span class="macro">simple_mermaid::mermaid!</span>(<span class="string">"../../../mermaid/outer_runtime_types.mmd"</span>)]
|
||||
<a href=#26 id=26 data-nosnippet>26</a></span><span class="doccomment">//!
|
||||
<a href=#27 id=27 data-nosnippet>27</a>//! In that one can always convert from the inner type into the outer type, but not vice versa. This
|
||||
<a href=#28 id=28 data-nosnippet>28</a>//! is usually expressed by implementing `From`, `TryFrom`, `From<Result<_>>` and similar traits.
|
||||
<a href=#29 id=29 data-nosnippet>29</a>//!
|
||||
<a href=#30 id=30 data-nosnippet>30</a>//! ### Example
|
||||
<a href=#31 id=31 data-nosnippet>31</a>//!
|
||||
<a href=#32 id=32 data-nosnippet>32</a>//! We provide the following two pallets: [`pallet_foo`] and [`pallet_bar`]. Each define a
|
||||
<a href=#33 id=33 data-nosnippet>33</a>//! dispatchable, and `Foo` also defines a custom origin. Lastly, `Bar` defines an additional
|
||||
<a href=#34 id=34 data-nosnippet>34</a>//! `GenesisConfig`.
|
||||
<a href=#35 id=35 data-nosnippet>35</a></span><span class="attr">#![doc = <span class="macro">docify::embed!</span>(<span class="string">"./src/reference_docs/frame_runtime_types.rs"</span>, pallet_foo)]
|
||||
<a href=#36 id=36 data-nosnippet>36</a>#![doc = <span class="macro">docify::embed!</span>(<span class="string">"./src/reference_docs/frame_runtime_types.rs"</span>, pallet_bar)]
|
||||
<a href=#37 id=37 data-nosnippet>37</a></span><span class="doccomment">//!
|
||||
<a href=#38 id=38 data-nosnippet>38</a>//! Let's explore how each of these affect the [`RuntimeCall`], [`RuntimeOrigin`] and
|
||||
<a href=#39 id=39 data-nosnippet>39</a>//! [`RuntimeGenesisConfig`] generated in [`runtime`] respectively.
|
||||
<a href=#40 id=40 data-nosnippet>40</a>//!
|
||||
<a href=#41 id=41 data-nosnippet>41</a>//! As observed, [`RuntimeCall`] has 3 variants, one for each pallet and one for `frame_system`. If
|
||||
<a href=#42 id=42 data-nosnippet>42</a>//! you explore further, you will soon realize that each variant is merely a pointer to the `Call`
|
||||
<a href=#43 id=43 data-nosnippet>43</a>//! type in each pallet, for example [`pallet_foo::Call`].
|
||||
<a href=#44 id=44 data-nosnippet>44</a>//!
|
||||
<a href=#45 id=45 data-nosnippet>45</a>//! [`RuntimeOrigin`]'s [`OriginCaller`] has two variants, one for system, and one for `pallet_foo`
|
||||
<a href=#46 id=46 data-nosnippet>46</a>//! which utilized [`frame::pallet_macros::origin`].
|
||||
<a href=#47 id=47 data-nosnippet>47</a>//!
|
||||
<a href=#48 id=48 data-nosnippet>48</a>//! Finally, [`RuntimeGenesisConfig`] is composed of `frame_system` and a variant for `pallet_bar`'s
|
||||
<a href=#49 id=49 data-nosnippet>49</a>//! [`pallet_bar::GenesisConfig`].
|
||||
<a href=#50 id=50 data-nosnippet>50</a>//!
|
||||
<a href=#51 id=51 data-nosnippet>51</a>//! You can find other composite enums by scanning [`runtime`] for other types who's name starts
|
||||
<a href=#52 id=52 data-nosnippet>52</a>//! with `Runtime`. Some of the more noteworthy ones are:
|
||||
<a href=#53 id=53 data-nosnippet>53</a>//!
|
||||
<a href=#54 id=54 data-nosnippet>54</a>//! - [`RuntimeEvent`]
|
||||
<a href=#55 id=55 data-nosnippet>55</a>//! - [`RuntimeError`]
|
||||
<a href=#56 id=56 data-nosnippet>56</a>//! - [`RuntimeHoldReason`]
|
||||
<a href=#57 id=57 data-nosnippet>57</a>//!
|
||||
<a href=#58 id=58 data-nosnippet>58</a>//! ### Adding Further Constraints to Runtime Composite Enums
|
||||
<a href=#59 id=59 data-nosnippet>59</a>//!
|
||||
<a href=#60 id=60 data-nosnippet>60</a>//! This section explores a common scenario where a pallet has access to one of these runtime
|
||||
<a href=#61 id=61 data-nosnippet>61</a>//! composite enums, but it wishes to further specify it by adding more trait bounds to it.
|
||||
<a href=#62 id=62 data-nosnippet>62</a>//!
|
||||
<a href=#63 id=63 data-nosnippet>63</a>//! Let's take the example of `RuntimeCall`. This is an associated type in
|
||||
<a href=#64 id=64 data-nosnippet>64</a>//! [`frame_system::Config::RuntimeCall`], and all pallets have access to this type, because they
|
||||
<a href=#65 id=65 data-nosnippet>65</a>//! have access to [`frame_system::Config`]. Finally, this type is meant to be set to outer call of
|
||||
<a href=#66 id=66 data-nosnippet>66</a>//! the entire runtime.
|
||||
<a href=#67 id=67 data-nosnippet>67</a>//!
|
||||
<a href=#68 id=68 data-nosnippet>68</a>//! But, let's not forget that this is information that *we know*, and the Rust compiler does not.
|
||||
<a href=#69 id=69 data-nosnippet>69</a>//! All that the rust compiler knows about this type is *ONLY* what the trait bounds of
|
||||
<a href=#70 id=70 data-nosnippet>70</a>//! [`frame_system::Config::RuntimeCall`] are specifying:
|
||||
<a href=#71 id=71 data-nosnippet>71</a></span><span class="attr">#![doc = <span class="macro">docify::embed!</span>(<span class="string">"../../substrate/frame/system/src/lib.rs"</span>, system_runtime_call)]
|
||||
<a href=#72 id=72 data-nosnippet>72</a></span><span class="doccomment">//!
|
||||
<a href=#73 id=73 data-nosnippet>73</a>//! So, when at a given pallet, one accesses `<T as frame_system::Config>::RuntimeCall`, the type is
|
||||
<a href=#74 id=74 data-nosnippet>74</a>//! extremely opaque from the perspective of the Rust compiler.
|
||||
<a href=#75 id=75 data-nosnippet>75</a>//!
|
||||
<a href=#76 id=76 data-nosnippet>76</a>//! How can a pallet access the `RuntimeCall` type with further constraints? For example, each
|
||||
<a href=#77 id=77 data-nosnippet>77</a>//! pallet has its own `enum Call`, and knows that its local `Call` is a part of `RuntimeCall`,
|
||||
<a href=#78 id=78 data-nosnippet>78</a>//! therefore there should be a `impl From<Call<_>> for RuntimeCall`.
|
||||
<a href=#79 id=79 data-nosnippet>79</a>//!
|
||||
<a href=#80 id=80 data-nosnippet>80</a>//! The only way to express this using Rust's associated types is for the pallet to **define its own
|
||||
<a href=#81 id=81 data-nosnippet>81</a>//! associated type `RuntimeCall`, and further specify what it thinks `RuntimeCall` should be**.
|
||||
<a href=#82 id=82 data-nosnippet>82</a>//!
|
||||
<a href=#83 id=83 data-nosnippet>83</a>//! In this case, we will want to assert the existence of [`frame::traits::IsSubType`], which is
|
||||
<a href=#84 id=84 data-nosnippet>84</a>//! very similar to [`TryFrom`].
|
||||
<a href=#85 id=85 data-nosnippet>85</a></span><span class="attr">#![doc = <span class="macro">docify::embed!</span>(<span class="string">"./src/reference_docs/frame_runtime_types.rs"</span>, custom_runtime_call)]
|
||||
<a href=#86 id=86 data-nosnippet>86</a></span><span class="doccomment">//!
|
||||
<a href=#87 id=87 data-nosnippet>87</a>//! And indeed, at the runtime level, this associated type would be the same `RuntimeCall` that is
|
||||
<a href=#88 id=88 data-nosnippet>88</a>//! passed to `frame_system`.
|
||||
<a href=#89 id=89 data-nosnippet>89</a></span><span class="attr">#![doc = <span class="macro">docify::embed!</span>(<span class="string">"./src/reference_docs/frame_runtime_types.rs"</span>, pallet_with_specific_runtime_call_impl)]
|
||||
<a href=#90 id=90 data-nosnippet>90</a></span><span class="doccomment">//!
|
||||
<a href=#91 id=91 data-nosnippet>91</a>//! > In other words, the degree of specificity that [`frame_system::Config::RuntimeCall`] has is
|
||||
<a href=#92 id=92 data-nosnippet>92</a>//! > not enough for the pallet to work with. Therefore, the pallet has to define its own associated
|
||||
<a href=#93 id=93 data-nosnippet>93</a>//! > type representing `RuntimeCall`.
|
||||
<a href=#94 id=94 data-nosnippet>94</a>//!
|
||||
<a href=#95 id=95 data-nosnippet>95</a>//! Another way to look at this is:
|
||||
<a href=#96 id=96 data-nosnippet>96</a>//!
|
||||
<a href=#97 id=97 data-nosnippet>97</a>//! `pallet_with_specific_runtime_call::Config::RuntimeCall` and `frame_system::Config::RuntimeCall`
|
||||
<a href=#98 id=98 data-nosnippet>98</a>//! are two different representations of the same concrete type that is only known when the runtime
|
||||
<a href=#99 id=99 data-nosnippet>99</a>//! is being constructed.
|
||||
<a href=#100 id=100 data-nosnippet>100</a>//!
|
||||
<a href=#101 id=101 data-nosnippet>101</a>//! Now, within this pallet, this new `RuntimeCall` can be used, and it can use its new trait
|
||||
<a href=#102 id=102 data-nosnippet>102</a>//! bounds, such as being [`frame::traits::IsSubType`]:
|
||||
<a href=#103 id=103 data-nosnippet>103</a></span><span class="attr">#![doc = <span class="macro">docify::embed!</span>(<span class="string">"./src/reference_docs/frame_runtime_types.rs"</span>, custom_runtime_call_usages)]
|
||||
<a href=#104 id=104 data-nosnippet>104</a></span><span class="doccomment">//!
|
||||
<a href=#105 id=105 data-nosnippet>105</a>//! > Once Rust's "_Associated Type Bounds RFC_" is usable, this syntax can be used to
|
||||
<a href=#106 id=106 data-nosnippet>106</a>//! > simplify the above scenario. See [this](https://github.com/pezkuwichain/pezkuwi-sdk/issues/133)
|
||||
<a href=#107 id=107 data-nosnippet>107</a>//! > issue for more information.
|
||||
<a href=#108 id=108 data-nosnippet>108</a>//!
|
||||
<a href=#109 id=109 data-nosnippet>109</a>//! ### Asserting Equality of Multiple Runtime Composite Enums
|
||||
<a href=#110 id=110 data-nosnippet>110</a>//!
|
||||
<a href=#111 id=111 data-nosnippet>111</a>//! Recall that in the above example, `<T as Config>::RuntimeCall` and `<T as
|
||||
<a href=#112 id=112 data-nosnippet>112</a>//! frame_system::Config>::RuntimeCall` are expected to be equal types, but at the compile-time we
|
||||
<a href=#113 id=113 data-nosnippet>113</a>//! have to represent them with two different associated types with different bounds. Would it not
|
||||
<a href=#114 id=114 data-nosnippet>114</a>//! be cool if we had a test to make sure they actually resolve to the same concrete type once the
|
||||
<a href=#115 id=115 data-nosnippet>115</a>//! runtime is constructed? The following snippet exactly does that:
|
||||
<a href=#116 id=116 data-nosnippet>116</a></span><span class="attr">#![doc = <span class="macro">docify::embed!</span>(<span class="string">"./src/reference_docs/frame_runtime_types.rs"</span>, assert_equality)]
|
||||
<a href=#117 id=117 data-nosnippet>117</a></span><span class="doccomment">//!
|
||||
<a href=#118 id=118 data-nosnippet>118</a>//! We leave it to the reader to further explore what [`frame::traits::Hooks::integrity_test`] is,
|
||||
<a href=#119 id=119 data-nosnippet>119</a>//! and what [`core::any::TypeId`] is. Another way to assert this is using
|
||||
<a href=#120 id=120 data-nosnippet>120</a>//! [`frame::traits::IsType`].
|
||||
<a href=#121 id=121 data-nosnippet>121</a>//!
|
||||
<a href=#122 id=122 data-nosnippet>122</a>//! ## Type Aliases
|
||||
<a href=#123 id=123 data-nosnippet>123</a>//!
|
||||
<a href=#124 id=124 data-nosnippet>124</a>//! A number of type aliases are generated by the `construct_runtime` which are also noteworthy:
|
||||
<a href=#125 id=125 data-nosnippet>125</a>//!
|
||||
<a href=#126 id=126 data-nosnippet>126</a>//! * [`runtime::PalletFoo`] is an alias to [`pallet_foo::Pallet`]. Same for `PalletBar`, and
|
||||
<a href=#127 id=127 data-nosnippet>127</a>//! `System`
|
||||
<a href=#128 id=128 data-nosnippet>128</a>//! * [`runtime::AllPalletsWithSystem`] is an alias for a tuple of all of the above. This type is
|
||||
<a href=#129 id=129 data-nosnippet>129</a>//! important to FRAME internals such as `executive`, as it implements traits such as
|
||||
<a href=#130 id=130 data-nosnippet>130</a>//! [`frame::traits::Hooks`].
|
||||
<a href=#131 id=131 data-nosnippet>131</a>//!
|
||||
<a href=#132 id=132 data-nosnippet>132</a>//! ## Further Details
|
||||
<a href=#133 id=133 data-nosnippet>133</a>//!
|
||||
<a href=#134 id=134 data-nosnippet>134</a>//! * [`crate::reference_docs::frame_origin`] explores further details about the usage of
|
||||
<a href=#135 id=135 data-nosnippet>135</a>//! `RuntimeOrigin`.
|
||||
<a href=#136 id=136 data-nosnippet>136</a>//! * [`RuntimeCall`] is a particularly interesting composite enum as it dictates the encoding of an
|
||||
<a href=#137 id=137 data-nosnippet>137</a>//! extrinsic. See [`crate::reference_docs::transaction_extensions`] for more information.
|
||||
<a href=#138 id=138 data-nosnippet>138</a>//! * See the documentation of [`construct_runtime`].
|
||||
<a href=#139 id=139 data-nosnippet>139</a>//! * See the corresponding lecture in the [PBA Lectures](https://www.youtube.com/watch?v=OCBC1pMYPoc&list=PL-w_i5kwVqbni1Ch2j_RwTIXiB-bwnYqq&index=11).
|
||||
<a href=#140 id=140 data-nosnippet>140</a>//!
|
||||
<a href=#141 id=141 data-nosnippet>141</a>//!
|
||||
<a href=#142 id=142 data-nosnippet>142</a>//! [`construct_runtime`]: frame::runtime::prelude::construct_runtime
|
||||
<a href=#143 id=143 data-nosnippet>143</a>//! [`runtime::PalletFoo`]: crate::reference_docs::frame_runtime_types::runtime::PalletFoo
|
||||
<a href=#144 id=144 data-nosnippet>144</a>//! [`runtime::AllPalletsWithSystem`]: crate::reference_docs::frame_runtime_types::runtime::AllPalletsWithSystem
|
||||
<a href=#145 id=145 data-nosnippet>145</a>//! [`runtime`]: crate::reference_docs::frame_runtime_types::runtime
|
||||
<a href=#146 id=146 data-nosnippet>146</a>//! [`pallet_foo`]: crate::reference_docs::frame_runtime_types::pallet_foo
|
||||
<a href=#147 id=147 data-nosnippet>147</a>//! [`pallet_foo::Call`]: crate::reference_docs::frame_runtime_types::pallet_foo::Call
|
||||
<a href=#148 id=148 data-nosnippet>148</a>//! [`pallet_foo::Pallet`]: crate::reference_docs::frame_runtime_types::pallet_foo::Pallet
|
||||
<a href=#149 id=149 data-nosnippet>149</a>//! [`pallet_bar`]: crate::reference_docs::frame_runtime_types::pallet_bar
|
||||
<a href=#150 id=150 data-nosnippet>150</a>//! [`pallet_bar::GenesisConfig`]: crate::reference_docs::frame_runtime_types::pallet_bar::GenesisConfig
|
||||
<a href=#151 id=151 data-nosnippet>151</a>//! [`RuntimeEvent`]: crate::reference_docs::frame_runtime_types::runtime::RuntimeEvent
|
||||
<a href=#152 id=152 data-nosnippet>152</a>//! [`RuntimeGenesisConfig`]:
|
||||
<a href=#153 id=153 data-nosnippet>153</a>//! crate::reference_docs::frame_runtime_types::runtime::RuntimeGenesisConfig
|
||||
<a href=#154 id=154 data-nosnippet>154</a>//! [`RuntimeOrigin`]: crate::reference_docs::frame_runtime_types::runtime::RuntimeOrigin
|
||||
<a href=#155 id=155 data-nosnippet>155</a>//! [`OriginCaller`]: crate::reference_docs::frame_runtime_types::runtime::OriginCaller
|
||||
<a href=#156 id=156 data-nosnippet>156</a>//! [`RuntimeError`]: crate::reference_docs::frame_runtime_types::runtime::RuntimeError
|
||||
<a href=#157 id=157 data-nosnippet>157</a>//! [`RuntimeCall`]: crate::reference_docs::frame_runtime_types::runtime::RuntimeCall
|
||||
<a href=#158 id=158 data-nosnippet>158</a>//! [`RuntimeHoldReason`]: crate::reference_docs::frame_runtime_types::runtime::RuntimeHoldReason
|
||||
<a href=#159 id=159 data-nosnippet>159</a>
|
||||
<a href=#160 id=160 data-nosnippet>160</a></span><span class="kw">use </span>frame::prelude::<span class="kw-2">*</span>;
|
||||
<a href=#161 id=161 data-nosnippet>161</a>
|
||||
<a href=#162 id=162 data-nosnippet>162</a><span class="attr">#[docify::export]
|
||||
<a href=#163 id=163 data-nosnippet>163</a>#[frame::pallet(dev_mode)]
|
||||
<a href=#164 id=164 data-nosnippet>164</a></span><span class="kw">pub mod </span>pallet_foo {
|
||||
<a href=#165 id=165 data-nosnippet>165</a> <span class="kw">use super</span>::<span class="kw-2">*</span>;
|
||||
<a href=#166 id=166 data-nosnippet>166</a>
|
||||
<a href=#167 id=167 data-nosnippet>167</a> <span class="attr">#[pallet::config]
|
||||
<a href=#168 id=168 data-nosnippet>168</a> </span><span class="kw">pub trait </span>Config: frame_system::Config {}
|
||||
<a href=#169 id=169 data-nosnippet>169</a>
|
||||
<a href=#170 id=170 data-nosnippet>170</a> <span class="attr">#[pallet::origin]
|
||||
<a href=#171 id=171 data-nosnippet>171</a> #[derive(
|
||||
<a href=#172 id=172 data-nosnippet>172</a> PartialEq,
|
||||
<a href=#173 id=173 data-nosnippet>173</a> Eq,
|
||||
<a href=#174 id=174 data-nosnippet>174</a> Clone,
|
||||
<a href=#175 id=175 data-nosnippet>175</a> RuntimeDebug,
|
||||
<a href=#176 id=176 data-nosnippet>176</a> Encode,
|
||||
<a href=#177 id=177 data-nosnippet>177</a> Decode,
|
||||
<a href=#178 id=178 data-nosnippet>178</a> DecodeWithMemTracking,
|
||||
<a href=#179 id=179 data-nosnippet>179</a> TypeInfo,
|
||||
<a href=#180 id=180 data-nosnippet>180</a> MaxEncodedLen,
|
||||
<a href=#181 id=181 data-nosnippet>181</a> )]
|
||||
<a href=#182 id=182 data-nosnippet>182</a> </span><span class="kw">pub enum </span>Origin {
|
||||
<a href=#183 id=183 data-nosnippet>183</a> A,
|
||||
<a href=#184 id=184 data-nosnippet>184</a> B,
|
||||
<a href=#185 id=185 data-nosnippet>185</a> }
|
||||
<a href=#186 id=186 data-nosnippet>186</a>
|
||||
<a href=#187 id=187 data-nosnippet>187</a> <span class="attr">#[pallet::pallet]
|
||||
<a href=#188 id=188 data-nosnippet>188</a> </span><span class="kw">pub struct </span>Pallet<T>(<span class="kw">_</span>);
|
||||
<a href=#189 id=189 data-nosnippet>189</a>
|
||||
<a href=#190 id=190 data-nosnippet>190</a> <span class="attr">#[pallet::call]
|
||||
<a href=#191 id=191 data-nosnippet>191</a> </span><span class="kw">impl</span><T: Config> Pallet<T> {
|
||||
<a href=#192 id=192 data-nosnippet>192</a> <span class="kw">pub fn </span>foo(_origin: OriginFor<T>) -> DispatchResult {
|
||||
<a href=#193 id=193 data-nosnippet>193</a> <span class="macro">todo!</span>();
|
||||
<a href=#194 id=194 data-nosnippet>194</a> }
|
||||
<a href=#195 id=195 data-nosnippet>195</a>
|
||||
<a href=#196 id=196 data-nosnippet>196</a> <span class="kw">pub fn </span>other(_origin: OriginFor<T>) -> DispatchResult {
|
||||
<a href=#197 id=197 data-nosnippet>197</a> <span class="macro">todo!</span>();
|
||||
<a href=#198 id=198 data-nosnippet>198</a> }
|
||||
<a href=#199 id=199 data-nosnippet>199</a> }
|
||||
<a href=#200 id=200 data-nosnippet>200</a>}
|
||||
<a href=#201 id=201 data-nosnippet>201</a>
|
||||
<a href=#202 id=202 data-nosnippet>202</a><span class="attr">#[docify::export]
|
||||
<a href=#203 id=203 data-nosnippet>203</a>#[frame::pallet(dev_mode)]
|
||||
<a href=#204 id=204 data-nosnippet>204</a></span><span class="kw">pub mod </span>pallet_bar {
|
||||
<a href=#205 id=205 data-nosnippet>205</a> <span class="kw">use super</span>::<span class="kw-2">*</span>;
|
||||
<a href=#206 id=206 data-nosnippet>206</a>
|
||||
<a href=#207 id=207 data-nosnippet>207</a> <span class="attr">#[pallet::config]
|
||||
<a href=#208 id=208 data-nosnippet>208</a> </span><span class="kw">pub trait </span>Config: frame_system::Config {}
|
||||
<a href=#209 id=209 data-nosnippet>209</a>
|
||||
<a href=#210 id=210 data-nosnippet>210</a> <span class="attr">#[pallet::pallet]
|
||||
<a href=#211 id=211 data-nosnippet>211</a> </span><span class="kw">pub struct </span>Pallet<T>(<span class="kw">_</span>);
|
||||
<a href=#212 id=212 data-nosnippet>212</a>
|
||||
<a href=#213 id=213 data-nosnippet>213</a> <span class="attr">#[pallet::genesis_config]
|
||||
<a href=#214 id=214 data-nosnippet>214</a> #[derive(DefaultNoBound)]
|
||||
<a href=#215 id=215 data-nosnippet>215</a> </span><span class="kw">pub struct </span>GenesisConfig<T: Config> {
|
||||
<a href=#216 id=216 data-nosnippet>216</a> <span class="kw">pub </span>initial_account: <span class="prelude-ty">Option</span><T::AccountId>,
|
||||
<a href=#217 id=217 data-nosnippet>217</a> }
|
||||
<a href=#218 id=218 data-nosnippet>218</a>
|
||||
<a href=#219 id=219 data-nosnippet>219</a> <span class="attr">#[pallet::genesis_build]
|
||||
<a href=#220 id=220 data-nosnippet>220</a> </span><span class="kw">impl</span><T: Config> BuildGenesisConfig <span class="kw">for </span>GenesisConfig<T> {
|
||||
<a href=#221 id=221 data-nosnippet>221</a> <span class="kw">fn </span>build(<span class="kw-2">&</span><span class="self">self</span>) {}
|
||||
<a href=#222 id=222 data-nosnippet>222</a> }
|
||||
<a href=#223 id=223 data-nosnippet>223</a>
|
||||
<a href=#224 id=224 data-nosnippet>224</a> <span class="attr">#[pallet::call]
|
||||
<a href=#225 id=225 data-nosnippet>225</a> </span><span class="kw">impl</span><T: Config> Pallet<T> {
|
||||
<a href=#226 id=226 data-nosnippet>226</a> <span class="kw">pub fn </span>bar(_origin: OriginFor<T>) -> DispatchResult {
|
||||
<a href=#227 id=227 data-nosnippet>227</a> <span class="macro">todo!</span>();
|
||||
<a href=#228 id=228 data-nosnippet>228</a> }
|
||||
<a href=#229 id=229 data-nosnippet>229</a> }
|
||||
<a href=#230 id=230 data-nosnippet>230</a>}
|
||||
<a href=#231 id=231 data-nosnippet>231</a>
|
||||
<a href=#232 id=232 data-nosnippet>232</a><span class="kw">pub mod </span>runtime {
|
||||
<a href=#233 id=233 data-nosnippet>233</a> <span class="kw">use super</span>::{pallet_bar, pallet_foo};
|
||||
<a href=#234 id=234 data-nosnippet>234</a> <span class="kw">use </span>frame::{runtime::prelude::<span class="kw-2">*</span>, testing_prelude::<span class="kw-2">*</span>};
|
||||
<a href=#235 id=235 data-nosnippet>235</a>
|
||||
<a href=#236 id=236 data-nosnippet>236</a> <span class="attr">#[docify::export(runtime_exp)]
|
||||
<a href=#237 id=237 data-nosnippet>237</a> </span><span class="macro">construct_runtime!</span>(
|
||||
<a href=#238 id=238 data-nosnippet>238</a> <span class="kw">pub struct </span>Runtime {
|
||||
<a href=#239 id=239 data-nosnippet>239</a> System: frame_system,
|
||||
<a href=#240 id=240 data-nosnippet>240</a> PalletFoo: pallet_foo,
|
||||
<a href=#241 id=241 data-nosnippet>241</a> PalletBar: pallet_bar,
|
||||
<a href=#242 id=242 data-nosnippet>242</a> }
|
||||
<a href=#243 id=243 data-nosnippet>243</a> );
|
||||
<a href=#244 id=244 data-nosnippet>244</a>
|
||||
<a href=#245 id=245 data-nosnippet>245</a> <span class="attr">#[derive_impl(frame_system::config_preludes::TestDefaultConfig)]
|
||||
<a href=#246 id=246 data-nosnippet>246</a> </span><span class="kw">impl </span>frame_system::Config <span class="kw">for </span>Runtime {
|
||||
<a href=#247 id=247 data-nosnippet>247</a> <span class="kw">type </span>Block = MockBlock<<span class="self">Self</span>>;
|
||||
<a href=#248 id=248 data-nosnippet>248</a> }
|
||||
<a href=#249 id=249 data-nosnippet>249</a>
|
||||
<a href=#250 id=250 data-nosnippet>250</a> <span class="kw">impl </span>pallet_foo::Config <span class="kw">for </span>Runtime {}
|
||||
<a href=#251 id=251 data-nosnippet>251</a> <span class="kw">impl </span>pallet_bar::Config <span class="kw">for </span>Runtime {}
|
||||
<a href=#252 id=252 data-nosnippet>252</a>}
|
||||
<a href=#253 id=253 data-nosnippet>253</a>
|
||||
<a href=#254 id=254 data-nosnippet>254</a><span class="attr">#[frame::pallet(dev_mode)]
|
||||
<a href=#255 id=255 data-nosnippet>255</a></span><span class="kw">pub mod </span>pallet_with_specific_runtime_call {
|
||||
<a href=#256 id=256 data-nosnippet>256</a> <span class="kw">use super</span>::<span class="kw-2">*</span>;
|
||||
<a href=#257 id=257 data-nosnippet>257</a> <span class="kw">use </span>frame::traits::IsSubType;
|
||||
<a href=#258 id=258 data-nosnippet>258</a>
|
||||
<a href=#259 id=259 data-nosnippet>259</a> <span class="attr">#[docify::export(custom_runtime_call)]
|
||||
<a href=#260 id=260 data-nosnippet>260</a> </span><span class="doccomment">/// A pallet that wants to further narrow down what `RuntimeCall` is.
|
||||
<a href=#261 id=261 data-nosnippet>261</a> </span><span class="attr">#[pallet::config]
|
||||
<a href=#262 id=262 data-nosnippet>262</a> </span><span class="kw">pub trait </span>Config: frame_system::Config {
|
||||
<a href=#263 id=263 data-nosnippet>263</a> <span class="kw">type </span>RuntimeCall: IsSubType<Call<<span class="self">Self</span>>>;
|
||||
<a href=#264 id=264 data-nosnippet>264</a> }
|
||||
<a href=#265 id=265 data-nosnippet>265</a>
|
||||
<a href=#266 id=266 data-nosnippet>266</a> <span class="attr">#[pallet::pallet]
|
||||
<a href=#267 id=267 data-nosnippet>267</a> </span><span class="kw">pub struct </span>Pallet<T>(<span class="kw">_</span>);
|
||||
<a href=#268 id=268 data-nosnippet>268</a>
|
||||
<a href=#269 id=269 data-nosnippet>269</a> <span class="comment">// note that this pallet needs some `call` to have a `enum Call`.
|
||||
<a href=#270 id=270 data-nosnippet>270</a> </span><span class="attr">#[pallet::call]
|
||||
<a href=#271 id=271 data-nosnippet>271</a> </span><span class="kw">impl</span><T: Config> Pallet<T> {
|
||||
<a href=#272 id=272 data-nosnippet>272</a> <span class="kw">pub fn </span>foo(_origin: OriginFor<T>) -> DispatchResult {
|
||||
<a href=#273 id=273 data-nosnippet>273</a> <span class="macro">todo!</span>();
|
||||
<a href=#274 id=274 data-nosnippet>274</a> }
|
||||
<a href=#275 id=275 data-nosnippet>275</a> }
|
||||
<a href=#276 id=276 data-nosnippet>276</a>
|
||||
<a href=#277 id=277 data-nosnippet>277</a> <span class="attr">#[docify::export(custom_runtime_call_usages)]
|
||||
<a href=#278 id=278 data-nosnippet>278</a> </span><span class="kw">impl</span><T: Config> Pallet<T> {
|
||||
<a href=#279 id=279 data-nosnippet>279</a> <span class="kw">fn </span>_do_something_useful_with_runtime_call(call: <T <span class="kw">as </span>Config>::RuntimeCall) {
|
||||
<a href=#280 id=280 data-nosnippet>280</a> <span class="comment">// check if the runtime call given is of this pallet's variant.
|
||||
<a href=#281 id=281 data-nosnippet>281</a> </span><span class="kw">let </span>_maybe_my_call: <span class="prelude-ty">Option</span><<span class="kw-2">&</span>Call<T>> = call.is_sub_type();
|
||||
<a href=#282 id=282 data-nosnippet>282</a> <span class="macro">todo!</span>();
|
||||
<a href=#283 id=283 data-nosnippet>283</a> }
|
||||
<a href=#284 id=284 data-nosnippet>284</a> }
|
||||
<a href=#285 id=285 data-nosnippet>285</a>
|
||||
<a href=#286 id=286 data-nosnippet>286</a> <span class="attr">#[docify::export(assert_equality)]
|
||||
<a href=#287 id=287 data-nosnippet>287</a> #[pallet::hooks]
|
||||
<a href=#288 id=288 data-nosnippet>288</a> </span><span class="kw">impl</span><T: Config> Hooks<BlockNumberFor<T>> <span class="kw">for </span>Pallet<T> {
|
||||
<a href=#289 id=289 data-nosnippet>289</a> <span class="kw">fn </span>integrity_test() {
|
||||
<a href=#290 id=290 data-nosnippet>290</a> <span class="kw">use </span>core::any::TypeId;
|
||||
<a href=#291 id=291 data-nosnippet>291</a> <span class="macro">assert_eq!</span>(
|
||||
<a href=#292 id=292 data-nosnippet>292</a> TypeId::of::<<T <span class="kw">as </span>Config>::RuntimeCall>(),
|
||||
<a href=#293 id=293 data-nosnippet>293</a> TypeId::of::<<T <span class="kw">as </span>frame_system::Config>::RuntimeCall>()
|
||||
<a href=#294 id=294 data-nosnippet>294</a> );
|
||||
<a href=#295 id=295 data-nosnippet>295</a> }
|
||||
<a href=#296 id=296 data-nosnippet>296</a> }
|
||||
<a href=#297 id=297 data-nosnippet>297</a>}
|
||||
<a href=#298 id=298 data-nosnippet>298</a>
|
||||
<a href=#299 id=299 data-nosnippet>299</a><span class="kw">pub mod </span>runtime_with_specific_runtime_call {
|
||||
<a href=#300 id=300 data-nosnippet>300</a> <span class="kw">use </span><span class="kw">super</span>::pallet_with_specific_runtime_call;
|
||||
<a href=#301 id=301 data-nosnippet>301</a> <span class="kw">use </span>frame::{runtime::prelude::<span class="kw-2">*</span>, testing_prelude::<span class="kw-2">*</span>};
|
||||
<a href=#302 id=302 data-nosnippet>302</a>
|
||||
<a href=#303 id=303 data-nosnippet>303</a> <span class="macro">construct_runtime!</span>(
|
||||
<a href=#304 id=304 data-nosnippet>304</a> <span class="kw">pub struct </span>Runtime {
|
||||
<a href=#305 id=305 data-nosnippet>305</a> System: frame_system,
|
||||
<a href=#306 id=306 data-nosnippet>306</a> PalletWithSpecificRuntimeCall: pallet_with_specific_runtime_call,
|
||||
<a href=#307 id=307 data-nosnippet>307</a> }
|
||||
<a href=#308 id=308 data-nosnippet>308</a> );
|
||||
<a href=#309 id=309 data-nosnippet>309</a>
|
||||
<a href=#310 id=310 data-nosnippet>310</a> <span class="attr">#[derive_impl(frame_system::config_preludes::TestDefaultConfig)]
|
||||
<a href=#311 id=311 data-nosnippet>311</a> </span><span class="kw">impl </span>frame_system::Config <span class="kw">for </span>Runtime {
|
||||
<a href=#312 id=312 data-nosnippet>312</a> <span class="kw">type </span>Block = MockBlock<<span class="self">Self</span>>;
|
||||
<a href=#313 id=313 data-nosnippet>313</a> }
|
||||
<a href=#314 id=314 data-nosnippet>314</a>
|
||||
<a href=#315 id=315 data-nosnippet>315</a> <span class="attr">#[docify::export(pallet_with_specific_runtime_call_impl)]
|
||||
<a href=#316 id=316 data-nosnippet>316</a> </span><span class="kw">impl </span>pallet_with_specific_runtime_call::Config <span class="kw">for </span>Runtime {
|
||||
<a href=#317 id=317 data-nosnippet>317</a> <span class="comment">// an implementation of `IsSubType` is provided by `construct_runtime`.
|
||||
<a href=#318 id=318 data-nosnippet>318</a> </span><span class="kw">type </span>RuntimeCall = RuntimeCall;
|
||||
<a href=#319 id=319 data-nosnippet>319</a> }
|
||||
<a href=#320 id=320 data-nosnippet>320</a>}</code></pre></div></section></main></body></html>
|
||||
+134
@@ -0,0 +1,134 @@
|
||||
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `docs/sdk/src/reference_docs/frame_runtime_upgrades_and_migrations.rs`."><title>frame_runtime_upgrades_and_migrations.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2"href="../../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../../../static.files/rustdoc-e56847b5.css"><meta name="rustdoc-vars" data-root-path="../../../" data-static-root-path="../../../static.files/" data-current-crate="pezkuwi_sdk_docs" data-themes="" data-resource-suffix="" data-rustdoc-version="1.91.1 (ed61e7d7e 2025-11-07)" data-channel="1.91.1" data-search-js="search-e256b49e.js" data-stringdex-js="stringdex-c3e638e9.js" data-settings-js="settings-c38705f0.js" ><script src="../../../static.files/storage-e2aeef58.js"></script><script defer src="../../../static.files/src-script-813739b1.js"></script><script defer src="../../../src-files.js"></script><script defer src="../../../static.files/main-6dc2a7f3.js"></script><noscript><link rel="stylesheet" href="../../../static.files/noscript-263c88ec.css"></noscript><link rel="icon" href="https://pezkuwichain.io/favicon.ico"></head><body class="rustdoc src"><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer" title="Drag to resize sidebar"></div><main><section id="main-content" class="content"><div class="main-heading"><h1><div class="sub-heading">pezkuwi_sdk_docs/reference_docs/</div>frame_runtime_upgrades_and_migrations.rs</h1><rustdoc-toolbar></rustdoc-toolbar></div><div class="example-wrap digits-3"><pre class="rust"><code><a href=#1 id=1 data-nosnippet>1</a><span class="doccomment">//! # Runtime Upgrades
|
||||
<a href=#2 id=2 data-nosnippet>2</a>//!
|
||||
<a href=#3 id=3 data-nosnippet>3</a>//! At their core, blockchain logic consists of
|
||||
<a href=#4 id=4 data-nosnippet>4</a>//!
|
||||
<a href=#5 id=5 data-nosnippet>5</a>//! 1. on-chain state,
|
||||
<a href=#6 id=6 data-nosnippet>6</a>//! 2. a state transition function.
|
||||
<a href=#7 id=7 data-nosnippet>7</a>//!
|
||||
<a href=#8 id=8 data-nosnippet>8</a>//! In Substrate-based blockchains, state transition functions are referred to as
|
||||
<a href=#9 id=9 data-nosnippet>9</a>//! [runtimes](https://docs.pezkuwichain.io/sdk/master/pezkuwi_sdk_docs/reference_docs/blockchain_state_machines/index.html).
|
||||
<a href=#10 id=10 data-nosnippet>10</a>//!
|
||||
<a href=#11 id=11 data-nosnippet>11</a>//! Traditionally, before Substrate, upgrading state transition functions required node
|
||||
<a href=#12 id=12 data-nosnippet>12</a>//! operators to download new software and restart their nodes in a process called
|
||||
<a href=#13 id=13 data-nosnippet>13</a>//! [forking](https://en.wikipedia.org/wiki/Fork_(blockchain)).
|
||||
<a href=#14 id=14 data-nosnippet>14</a>//!
|
||||
<a href=#15 id=15 data-nosnippet>15</a>//! Substrate-based blockchains do not require forking, and instead upgrade runtimes
|
||||
<a href=#16 id=16 data-nosnippet>16</a>//! in a process called "Runtime Upgrades".
|
||||
<a href=#17 id=17 data-nosnippet>17</a>//!
|
||||
<a href=#18 id=18 data-nosnippet>18</a>//! Forkless runtime upgrades are a defining feature of the Substrate framework. Updating the
|
||||
<a href=#19 id=19 data-nosnippet>19</a>//! runtime logic without forking the code base enables your blockchain to seamlessly evolve
|
||||
<a href=#20 id=20 data-nosnippet>20</a>//! over time in a deterministic, rules-based manner. It also removes ambiguity for node operators
|
||||
<a href=#21 id=21 data-nosnippet>21</a>//! and other participants in the network about what is the canonical runtime.
|
||||
<a href=#22 id=22 data-nosnippet>22</a>//!
|
||||
<a href=#23 id=23 data-nosnippet>23</a>//! This capability is possible due to the runtime of a blockchain existing in on-chain storage.
|
||||
<a href=#24 id=24 data-nosnippet>24</a>//!
|
||||
<a href=#25 id=25 data-nosnippet>25</a>//! ## Performing a Runtime Upgrade
|
||||
<a href=#26 id=26 data-nosnippet>26</a>//!
|
||||
<a href=#27 id=27 data-nosnippet>27</a>//! To upgrade a runtime, an [`Origin`](frame_system::RawOrigin) with the necessary permissions
|
||||
<a href=#28 id=28 data-nosnippet>28</a>//! (usually via governance) changes the `:code` storage. Usually, this is performed via a call to
|
||||
<a href=#29 id=29 data-nosnippet>29</a>//! [`set_code`] (or [`set_code_without_checks`]) with the desired new runtime blob, scheduled
|
||||
<a href=#30 id=30 data-nosnippet>30</a>//! using [`pallet_scheduler`].
|
||||
<a href=#31 id=31 data-nosnippet>31</a>//!
|
||||
<a href=#32 id=32 data-nosnippet>32</a>//! Prior to building the new runtime, don't forget to update the
|
||||
<a href=#33 id=33 data-nosnippet>33</a>//! [`RuntimeVersion`](sp_version::RuntimeVersion).
|
||||
<a href=#34 id=34 data-nosnippet>34</a>//!
|
||||
<a href=#35 id=35 data-nosnippet>35</a>//! # Migrations
|
||||
<a href=#36 id=36 data-nosnippet>36</a>//!
|
||||
<a href=#37 id=37 data-nosnippet>37</a>//! It is often desirable to define logic to execute immediately after runtime upgrades (see
|
||||
<a href=#38 id=38 data-nosnippet>38</a>//! [this diagram](frame::traits::Hooks)).
|
||||
<a href=#39 id=39 data-nosnippet>39</a>//!
|
||||
<a href=#40 id=40 data-nosnippet>40</a>//! Self-contained pieces of logic that execute after a runtime upgrade are called "Migrations".
|
||||
<a href=#41 id=41 data-nosnippet>41</a>//!
|
||||
<a href=#42 id=42 data-nosnippet>42</a>//! The typical use case of a migration is to 'migrate' pallet storage from one layout to another,
|
||||
<a href=#43 id=43 data-nosnippet>43</a>//! for example when the encoding of a storage item is changed. However, they can also execute
|
||||
<a href=#44 id=44 data-nosnippet>44</a>//! arbitrary logic such as:
|
||||
<a href=#45 id=45 data-nosnippet>45</a>//!
|
||||
<a href=#46 id=46 data-nosnippet>46</a>//! - Calling arbitrary pallet methods.
|
||||
<a href=#47 id=47 data-nosnippet>47</a>//! - Mutating arbitrary on-chain state.
|
||||
<a href=#48 id=48 data-nosnippet>48</a>//! - Cleaning up some old storage items that are no longer needed.
|
||||
<a href=#49 id=49 data-nosnippet>49</a>//!
|
||||
<a href=#50 id=50 data-nosnippet>50</a>//! ## Single Block Migrations
|
||||
<a href=#51 id=51 data-nosnippet>51</a>//!
|
||||
<a href=#52 id=52 data-nosnippet>52</a>//! - Execute immediately and entirely at the beginning of the block following
|
||||
<a href=#53 id=53 data-nosnippet>53</a>//! a runtime upgrade.
|
||||
<a href=#54 id=54 data-nosnippet>54</a>//! - Are suitable for migrations which are guaranteed to not exceed the block weight.
|
||||
<a href=#55 id=55 data-nosnippet>55</a>//! - Are simply implementations of [`OnRuntimeUpgrade`].
|
||||
<a href=#56 id=56 data-nosnippet>56</a>//!
|
||||
<a href=#57 id=57 data-nosnippet>57</a>//! To learn best practices for writing single block pallet storage migrations, see the
|
||||
<a href=#58 id=58 data-nosnippet>58</a>//! [Single Block Migration Example Pallet](pallet_example_single_block_migrations).
|
||||
<a href=#59 id=59 data-nosnippet>59</a>//!
|
||||
<a href=#60 id=60 data-nosnippet>60</a>//! ### Scheduling the Single Block Migrations to Run Next Runtime Upgrade
|
||||
<a href=#61 id=61 data-nosnippet>61</a>//!
|
||||
<a href=#62 id=62 data-nosnippet>62</a>//! Schedule migrations to run next runtime upgrade passing them as a parameter to your
|
||||
<a href=#63 id=63 data-nosnippet>63</a>//! [`Config`](frame_system) pallet:
|
||||
<a href=#64 id=64 data-nosnippet>64</a>//!
|
||||
<a href=#65 id=65 data-nosnippet>65</a>//! ```ignore
|
||||
<a href=#66 id=66 data-nosnippet>66</a>//! /// Tuple of migrations (structs that implement `OnRuntimeUpgrade`)
|
||||
<a href=#67 id=67 data-nosnippet>67</a>//! type Migrations = (
|
||||
<a href=#68 id=68 data-nosnippet>68</a>//! pallet_example_storage_migration::migrations::v1::versioned::MigrateV0ToV1,
|
||||
<a href=#69 id=69 data-nosnippet>69</a>//! MyCustomMigration,
|
||||
<a href=#70 id=70 data-nosnippet>70</a>//! // ...more migrations here
|
||||
<a href=#71 id=71 data-nosnippet>71</a>//! );
|
||||
<a href=#72 id=72 data-nosnippet>72</a>//! impl frame_system::Config for Runtime {
|
||||
<a href=#73 id=73 data-nosnippet>73</a>//! type SingleBlockMigrations = Migrations;
|
||||
<a href=#74 id=74 data-nosnippet>74</a>//! }
|
||||
<a href=#75 id=75 data-nosnippet>75</a>//! ```
|
||||
<a href=#76 id=76 data-nosnippet>76</a>//!
|
||||
<a href=#77 id=77 data-nosnippet>77</a>//! ### Ensuring Single Block Migration Safety
|
||||
<a href=#78 id=78 data-nosnippet>78</a>//!
|
||||
<a href=#79 id=79 data-nosnippet>79</a>//! "My migration unit tests pass, so it should be safe to deploy right?"
|
||||
<a href=#80 id=80 data-nosnippet>80</a>//!
|
||||
<a href=#81 id=81 data-nosnippet>81</a>//! No! Unit tests execute the migration in a very simple test environment, and cannot account
|
||||
<a href=#82 id=82 data-nosnippet>82</a>//! for the complexities of a real runtime or real on-chain state.
|
||||
<a href=#83 id=83 data-nosnippet>83</a>//!
|
||||
<a href=#84 id=84 data-nosnippet>84</a>//! Prior to deploying migrations, it is critical to perform additional checks to ensure that when
|
||||
<a href=#85 id=85 data-nosnippet>85</a>//! run in our real runtime they will not brick the chain due to:
|
||||
<a href=#86 id=86 data-nosnippet>86</a>//! - Panicking.
|
||||
<a href=#87 id=87 data-nosnippet>87</a>//! - Touching too many storage keys and resulting in an excessively large PoV.
|
||||
<a href=#88 id=88 data-nosnippet>88</a>//! - Taking too long to execute.
|
||||
<a href=#89 id=89 data-nosnippet>89</a>//!
|
||||
<a href=#90 id=90 data-nosnippet>90</a>//! [`try-runtime-cli`](https://github.com/paritytech/try-runtime-cli) has a sub-command
|
||||
<a href=#91 id=91 data-nosnippet>91</a>//! [`on-runtime-upgrade`](https://paritytech.github.io/try-runtime-cli/try_runtime_core/commands/enum.Action.html#variant.OnRuntimeUpgrade)
|
||||
<a href=#92 id=92 data-nosnippet>92</a>//! which is designed to help with exactly this.
|
||||
<a href=#93 id=93 data-nosnippet>93</a>//!
|
||||
<a href=#94 id=94 data-nosnippet>94</a>//! Developers MUST run this command before deploying migrations to ensure they will not
|
||||
<a href=#95 id=95 data-nosnippet>95</a>//! inadvertently result in a bricked chain.
|
||||
<a href=#96 id=96 data-nosnippet>96</a>//!
|
||||
<a href=#97 id=97 data-nosnippet>97</a>//! It is recommended to run as part of your CI pipeline. See the
|
||||
<a href=#98 id=98 data-nosnippet>98</a>//! [pezkuwi-sdk check-runtime-migration job](https://github.com/pezkuwichain/pezkuwi-sdk/blob/4a293bc5a25be637c06ce950a34490706597615b/.gitlab/pipeline/check.yml#L103-L124)
|
||||
<a href=#99 id=99 data-nosnippet>99</a>//! for an example of how to configure this.
|
||||
<a href=#100 id=100 data-nosnippet>100</a>//!
|
||||
<a href=#101 id=101 data-nosnippet>101</a>//! ### Note on the Manipulability of PoV Size and Execution Time
|
||||
<a href=#102 id=102 data-nosnippet>102</a>//!
|
||||
<a href=#103 id=103 data-nosnippet>103</a>//! While [`try-runtime-cli`](https://github.com/paritytech/try-runtime-cli) can help ensure with
|
||||
<a href=#104 id=104 data-nosnippet>104</a>//! very high certainty that a migration will succeed given **existing** on-chain state, it cannot
|
||||
<a href=#105 id=105 data-nosnippet>105</a>//! prevent a malicious actor from manipulating state in a way that will cause the migration to take
|
||||
<a href=#106 id=106 data-nosnippet>106</a>//! longer or produce a PoV much larger than previously measured.
|
||||
<a href=#107 id=107 data-nosnippet>107</a>//!
|
||||
<a href=#108 id=108 data-nosnippet>108</a>//! Therefore, it is important to write migrations in such a way that the execution time or PoV size
|
||||
<a href=#109 id=109 data-nosnippet>109</a>//! it adds to the block cannot be easily manipulated. e.g., do not iterate over storage that can
|
||||
<a href=#110 id=110 data-nosnippet>110</a>//! quickly or cheaply be bloated.
|
||||
<a href=#111 id=111 data-nosnippet>111</a>//!
|
||||
<a href=#112 id=112 data-nosnippet>112</a>//! If writing your migration in such a way is not possible, a multi block migration should be used
|
||||
<a href=#113 id=113 data-nosnippet>113</a>//! instead.
|
||||
<a href=#114 id=114 data-nosnippet>114</a>//!
|
||||
<a href=#115 id=115 data-nosnippet>115</a>//! ### Other useful tools
|
||||
<a href=#116 id=116 data-nosnippet>116</a>//!
|
||||
<a href=#117 id=117 data-nosnippet>117</a>//! [`Chopsticks`](https://github.com/AcalaNetwork/chopsticks) is another tool in the Substrate
|
||||
<a href=#118 id=118 data-nosnippet>118</a>//! ecosystem which developers may find useful to use in addition to `try-runtime-cli` when testing
|
||||
<a href=#119 id=119 data-nosnippet>119</a>//! their single block migrations.
|
||||
<a href=#120 id=120 data-nosnippet>120</a>//!
|
||||
<a href=#121 id=121 data-nosnippet>121</a>//! ## Multi Block Migrations
|
||||
<a href=#122 id=122 data-nosnippet>122</a>//!
|
||||
<a href=#123 id=123 data-nosnippet>123</a>//! Safely and easily execute long-running migrations across multiple blocks.
|
||||
<a href=#124 id=124 data-nosnippet>124</a>//!
|
||||
<a href=#125 id=125 data-nosnippet>125</a>//! Suitable for migrations which could use arbitrary amounts of block weight.
|
||||
<a href=#126 id=126 data-nosnippet>126</a>//!
|
||||
<a href=#127 id=127 data-nosnippet>127</a>//! See the
|
||||
<a href=#128 id=128 data-nosnippet>128</a>//! [multi-block-migrations example](https://github.com/pezkuwichain/pezkuwi-sdk/tree/0d7d2177807ec6b3094f4491a45b0bc0d74d3c8b/substrate/frame/examples/multi-block-migrations)
|
||||
<a href=#129 id=129 data-nosnippet>129</a>//! for reference.
|
||||
<a href=#130 id=130 data-nosnippet>130</a>//!
|
||||
<a href=#131 id=131 data-nosnippet>131</a>//! [`OnRuntimeUpgrade`]: frame_support::traits::OnRuntimeUpgrade
|
||||
<a href=#132 id=132 data-nosnippet>132</a>//! [`StorageVersion`]: frame_support::traits::StorageVersion
|
||||
<a href=#133 id=133 data-nosnippet>133</a>//! [`set_code`]: frame_system::Call::set_code
|
||||
<a href=#134 id=134 data-nosnippet>134</a>//! [`set_code_without_checks`]: frame_system::Call::set_code_without_checks</span></code></pre></div></section></main></body></html>
|
||||
+202
@@ -0,0 +1,202 @@
|
||||
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `docs/sdk/src/reference_docs/frame_storage_derives.rs`."><title>frame_storage_derives.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2"href="../../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../../../static.files/rustdoc-e56847b5.css"><meta name="rustdoc-vars" data-root-path="../../../" data-static-root-path="../../../static.files/" data-current-crate="pezkuwi_sdk_docs" data-themes="" data-resource-suffix="" data-rustdoc-version="1.91.1 (ed61e7d7e 2025-11-07)" data-channel="1.91.1" data-search-js="search-e256b49e.js" data-stringdex-js="stringdex-c3e638e9.js" data-settings-js="settings-c38705f0.js" ><script src="../../../static.files/storage-e2aeef58.js"></script><script defer src="../../../static.files/src-script-813739b1.js"></script><script defer src="../../../src-files.js"></script><script defer src="../../../static.files/main-6dc2a7f3.js"></script><noscript><link rel="stylesheet" href="../../../static.files/noscript-263c88ec.css"></noscript><link rel="icon" href="https://pezkuwichain.io/favicon.ico"></head><body class="rustdoc src"><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer" title="Drag to resize sidebar"></div><main><section id="main-content" class="content"><div class="main-heading"><h1><div class="sub-heading">pezkuwi_sdk_docs/reference_docs/</div>frame_storage_derives.rs</h1><rustdoc-toolbar></rustdoc-toolbar></div><div class="example-wrap digits-3"><pre class="rust"><code><a href=#1 id=1 data-nosnippet>1</a><span class="doccomment">//! # Frame storage derives
|
||||
<a href=#2 id=2 data-nosnippet>2</a>//!
|
||||
<a href=#3 id=3 data-nosnippet>3</a>//! > **Note:**
|
||||
<a href=#4 id=4 data-nosnippet>4</a>//! >
|
||||
<a href=#5 id=5 data-nosnippet>5</a>//! > In all examples, a few lines of boilerplate have been hidden from each snippet for
|
||||
<a href=#6 id=6 data-nosnippet>6</a>//! > conciseness.
|
||||
<a href=#7 id=7 data-nosnippet>7</a>//!
|
||||
<a href=#8 id=8 data-nosnippet>8</a>//! Let's begin by starting to store a `NewType` in a storage item:
|
||||
<a href=#9 id=9 data-nosnippet>9</a>//!
|
||||
<a href=#10 id=10 data-nosnippet>10</a>//! ```compile_fail
|
||||
<a href=#11 id=11 data-nosnippet>11</a>//! #[frame::pallet]
|
||||
<a href=#12 id=12 data-nosnippet>12</a>//! pub mod pallet {
|
||||
<a href=#13 id=13 data-nosnippet>13</a>//! # use frame::prelude::*;
|
||||
<a href=#14 id=14 data-nosnippet>14</a>//! # #[pallet::config]
|
||||
<a href=#15 id=15 data-nosnippet>15</a>//! # pub trait Config: frame_system::Config {}
|
||||
<a href=#16 id=16 data-nosnippet>16</a>//! # #[pallet::pallet]
|
||||
<a href=#17 id=17 data-nosnippet>17</a>//! # pub struct Pallet<T>(_);
|
||||
<a href=#18 id=18 data-nosnippet>18</a>//! pub struct NewType(u32);
|
||||
<a href=#19 id=19 data-nosnippet>19</a></span><span class="comment">//
|
||||
<a href=#20 id=20 data-nosnippet>20</a></span><span class="doccomment">//! #[pallet::storage]
|
||||
<a href=#21 id=21 data-nosnippet>21</a>//! pub type Something<T> = StorageValue<_, NewType>;
|
||||
<a href=#22 id=22 data-nosnippet>22</a>//! }
|
||||
<a href=#23 id=23 data-nosnippet>23</a>//! ```
|
||||
<a href=#24 id=24 data-nosnippet>24</a>//!
|
||||
<a href=#25 id=25 data-nosnippet>25</a>//! This raises a number of compiler errors, like:
|
||||
<a href=#26 id=26 data-nosnippet>26</a>//! ```text
|
||||
<a href=#27 id=27 data-nosnippet>27</a>//! the trait `MaxEncodedLen` is not implemented for `NewType`, which is required by
|
||||
<a href=#28 id=28 data-nosnippet>28</a>//! `frame::prelude::StorageValue<_GeneratedPrefixForStorageSomething<T>, NewType>:
|
||||
<a href=#29 id=29 data-nosnippet>29</a>//! StorageInfoTrait`
|
||||
<a href=#30 id=30 data-nosnippet>30</a>//! ```
|
||||
<a href=#31 id=31 data-nosnippet>31</a>//!
|
||||
<a href=#32 id=32 data-nosnippet>32</a>//! This implies the following set of traits that need to be derived for a type to be stored in
|
||||
<a href=#33 id=33 data-nosnippet>33</a>//! `frame` storage:
|
||||
<a href=#34 id=34 data-nosnippet>34</a>//! ```rust
|
||||
<a href=#35 id=35 data-nosnippet>35</a>//! #[frame::pallet]
|
||||
<a href=#36 id=36 data-nosnippet>36</a>//! pub mod pallet {
|
||||
<a href=#37 id=37 data-nosnippet>37</a>//! # use frame::prelude::*;
|
||||
<a href=#38 id=38 data-nosnippet>38</a>//! # #[pallet::config]
|
||||
<a href=#39 id=39 data-nosnippet>39</a>//! # pub trait Config: frame_system::Config {}
|
||||
<a href=#40 id=40 data-nosnippet>40</a>//! # #[pallet::pallet]
|
||||
<a href=#41 id=41 data-nosnippet>41</a>//! # pub struct Pallet<T>(_);
|
||||
<a href=#42 id=42 data-nosnippet>42</a>//! #[derive(codec::Encode, codec::Decode, codec::MaxEncodedLen, scale_info::TypeInfo)]
|
||||
<a href=#43 id=43 data-nosnippet>43</a>//! pub struct NewType(u32);
|
||||
<a href=#44 id=44 data-nosnippet>44</a>//!
|
||||
<a href=#45 id=45 data-nosnippet>45</a>//! #[pallet::storage]
|
||||
<a href=#46 id=46 data-nosnippet>46</a>//! pub type Something<T> = StorageValue<_, NewType>;
|
||||
<a href=#47 id=47 data-nosnippet>47</a>//! }
|
||||
<a href=#48 id=48 data-nosnippet>48</a>//! ```
|
||||
<a href=#49 id=49 data-nosnippet>49</a>//!
|
||||
<a href=#50 id=50 data-nosnippet>50</a>//! Next, let's look at how this will differ if we are to store a type that is derived from `T` in
|
||||
<a href=#51 id=51 data-nosnippet>51</a>//! storage, such as [`frame::prelude::BlockNumberFor`]:
|
||||
<a href=#52 id=52 data-nosnippet>52</a>//! ```compile_fail
|
||||
<a href=#53 id=53 data-nosnippet>53</a>//! #[frame::pallet]
|
||||
<a href=#54 id=54 data-nosnippet>54</a>//! pub mod pallet {
|
||||
<a href=#55 id=55 data-nosnippet>55</a>//! # use frame::prelude::*;
|
||||
<a href=#56 id=56 data-nosnippet>56</a>//! # #[pallet::config]
|
||||
<a href=#57 id=57 data-nosnippet>57</a>//! # pub trait Config: frame_system::Config {}
|
||||
<a href=#58 id=58 data-nosnippet>58</a>//! # #[pallet::pallet]
|
||||
<a href=#59 id=59 data-nosnippet>59</a>//! # pub struct Pallet<T>(_);
|
||||
<a href=#60 id=60 data-nosnippet>60</a>//! #[derive(codec::Encode, codec::Decode, codec::MaxEncodedLen, scale_info::TypeInfo)]
|
||||
<a href=#61 id=61 data-nosnippet>61</a>//! pub struct NewType<T: Config>(BlockNumberFor<T>);
|
||||
<a href=#62 id=62 data-nosnippet>62</a>//!
|
||||
<a href=#63 id=63 data-nosnippet>63</a>//! #[pallet::storage]
|
||||
<a href=#64 id=64 data-nosnippet>64</a>//! pub type Something<T: Config> = StorageValue<_, NewType<T>>;
|
||||
<a href=#65 id=65 data-nosnippet>65</a>//! }
|
||||
<a href=#66 id=66 data-nosnippet>66</a>//! ```
|
||||
<a href=#67 id=67 data-nosnippet>67</a>//!
|
||||
<a href=#68 id=68 data-nosnippet>68</a>//! Surprisingly, this will also raise a number of errors, like:
|
||||
<a href=#69 id=69 data-nosnippet>69</a>//! ```text
|
||||
<a href=#70 id=70 data-nosnippet>70</a>//! the trait `TypeInfo` is not implemented for `T`, which is required
|
||||
<a href=#71 id=71 data-nosnippet>71</a>//! by`frame_support::pallet_prelude::StorageValue<pallet_2::_GeneratedPrefixForStorageSomething<T>,
|
||||
<a href=#72 id=72 data-nosnippet>72</a>//! pallet_2::NewType<T>>:StorageEntryMetadataBuilder
|
||||
<a href=#73 id=73 data-nosnippet>73</a>//! ```
|
||||
<a href=#74 id=74 data-nosnippet>74</a>//!
|
||||
<a href=#75 id=75 data-nosnippet>75</a>//! Why is that? The underlying reason is that the `TypeInfo` `derive` macro will only work for
|
||||
<a href=#76 id=76 data-nosnippet>76</a>//! `NewType` if all of `NewType`'s generics also implement `TypeInfo`. This is not the case for `T`
|
||||
<a href=#77 id=77 data-nosnippet>77</a>//! in the example above.
|
||||
<a href=#78 id=78 data-nosnippet>78</a>//!
|
||||
<a href=#79 id=79 data-nosnippet>79</a>//! If you expand an instance of the derive, you will find something along the lines of:
|
||||
<a href=#80 id=80 data-nosnippet>80</a>//! `impl<T> TypeInfo for NewType<T> where T: TypeInfo { ... }`. This is the reason why the
|
||||
<a href=#81 id=81 data-nosnippet>81</a>//! `TypeInfo` trait is required for `T`.
|
||||
<a href=#82 id=82 data-nosnippet>82</a>//!
|
||||
<a href=#83 id=83 data-nosnippet>83</a>//! To fix this, we need to add a `#[scale_info(skip_type_params(T))]`
|
||||
<a href=#84 id=84 data-nosnippet>84</a>//! attribute to `NewType`. This additional macro will instruct the `derive` to skip the bound on
|
||||
<a href=#85 id=85 data-nosnippet>85</a>//! `T`.
|
||||
<a href=#86 id=86 data-nosnippet>86</a>//! ```rust
|
||||
<a href=#87 id=87 data-nosnippet>87</a>//! #[frame::pallet]
|
||||
<a href=#88 id=88 data-nosnippet>88</a>//! pub mod pallet {
|
||||
<a href=#89 id=89 data-nosnippet>89</a>//! # use frame::prelude::*;
|
||||
<a href=#90 id=90 data-nosnippet>90</a>//! # #[pallet::config]
|
||||
<a href=#91 id=91 data-nosnippet>91</a>//! # pub trait Config: frame_system::Config {}
|
||||
<a href=#92 id=92 data-nosnippet>92</a>//! # #[pallet::pallet]
|
||||
<a href=#93 id=93 data-nosnippet>93</a>//! # pub struct Pallet<T>(_);
|
||||
<a href=#94 id=94 data-nosnippet>94</a>//! #[derive(codec::Encode, codec::Decode, codec::MaxEncodedLen, scale_info::TypeInfo)]
|
||||
<a href=#95 id=95 data-nosnippet>95</a>//! #[scale_info(skip_type_params(T))]
|
||||
<a href=#96 id=96 data-nosnippet>96</a>//! pub struct NewType<T: Config>(BlockNumberFor<T>);
|
||||
<a href=#97 id=97 data-nosnippet>97</a>//!
|
||||
<a href=#98 id=98 data-nosnippet>98</a>//! #[pallet::storage]
|
||||
<a href=#99 id=99 data-nosnippet>99</a>//! pub type Something<T: Config> = StorageValue<_, NewType<T>>;
|
||||
<a href=#100 id=100 data-nosnippet>100</a>//! }
|
||||
<a href=#101 id=101 data-nosnippet>101</a>//! ```
|
||||
<a href=#102 id=102 data-nosnippet>102</a>//!
|
||||
<a href=#103 id=103 data-nosnippet>103</a>//! Next, let's say we wish to store `NewType` as [`frame::prelude::ValueQuery`], which means it
|
||||
<a href=#104 id=104 data-nosnippet>104</a>//! must also implement `Default`. This should be as simple as adding `derive(Default)` to it,
|
||||
<a href=#105 id=105 data-nosnippet>105</a>//! right?
|
||||
<a href=#106 id=106 data-nosnippet>106</a>//! ```compile_fail
|
||||
<a href=#107 id=107 data-nosnippet>107</a>//! #[frame::pallet]
|
||||
<a href=#108 id=108 data-nosnippet>108</a>//! pub mod pallet {
|
||||
<a href=#109 id=109 data-nosnippet>109</a>//! # use frame::prelude::*;
|
||||
<a href=#110 id=110 data-nosnippet>110</a>//! # #[pallet::config]
|
||||
<a href=#111 id=111 data-nosnippet>111</a>//! # pub trait Config: frame_system::Config {}
|
||||
<a href=#112 id=112 data-nosnippet>112</a>//! # #[pallet::pallet]
|
||||
<a href=#113 id=113 data-nosnippet>113</a>//! # pub struct Pallet<T>(_);
|
||||
<a href=#114 id=114 data-nosnippet>114</a>//! #[derive(codec::Encode, codec::Decode, codec::MaxEncodedLen, scale_info::TypeInfo, Default)]
|
||||
<a href=#115 id=115 data-nosnippet>115</a>//! #[scale_info(skip_type_params(T))]
|
||||
<a href=#116 id=116 data-nosnippet>116</a>//! pub struct NewType<T: Config>(BlockNumberFor<T>);
|
||||
<a href=#117 id=117 data-nosnippet>117</a>//!
|
||||
<a href=#118 id=118 data-nosnippet>118</a>//! #[pallet::storage]
|
||||
<a href=#119 id=119 data-nosnippet>119</a>//! pub type Something<T: Config> = StorageValue<_, NewType<T>, ValueQuery>;
|
||||
<a href=#120 id=120 data-nosnippet>120</a>//! }
|
||||
<a href=#121 id=121 data-nosnippet>121</a>//! ```
|
||||
<a href=#122 id=122 data-nosnippet>122</a>//!
|
||||
<a href=#123 id=123 data-nosnippet>123</a>//! Under the hood, the expansion of the `derive(Default)` will suffer from the same restriction as
|
||||
<a href=#124 id=124 data-nosnippet>124</a>//! before: it will only work if `T: Default`, and `T` is not `Default`. Note that this is an
|
||||
<a href=#125 id=125 data-nosnippet>125</a>//! expected issue: `T` is merely a wrapper of many other types, such as `BlockNumberFor<T>`.
|
||||
<a href=#126 id=126 data-nosnippet>126</a>//! `BlockNumberFor<T>` should indeed implement `Default`, but `T` implementing `Default` is rather
|
||||
<a href=#127 id=127 data-nosnippet>127</a>//! meaningless.
|
||||
<a href=#128 id=128 data-nosnippet>128</a>//!
|
||||
<a href=#129 id=129 data-nosnippet>129</a>//! To fix this, frame provides a set of macros that are analogous to normal rust derive macros, but
|
||||
<a href=#130 id=130 data-nosnippet>130</a>//! work nicely on top of structs that are generic over `T: Config`. These macros are:
|
||||
<a href=#131 id=131 data-nosnippet>131</a>//!
|
||||
<a href=#132 id=132 data-nosnippet>132</a>//! - [`frame::prelude::DefaultNoBound`]
|
||||
<a href=#133 id=133 data-nosnippet>133</a>//! - [`frame::prelude::DebugNoBound`]
|
||||
<a href=#134 id=134 data-nosnippet>134</a>//! - [`frame::prelude::PartialEqNoBound`]
|
||||
<a href=#135 id=135 data-nosnippet>135</a>//! - [`frame::prelude::EqNoBound`]
|
||||
<a href=#136 id=136 data-nosnippet>136</a>//! - [`frame::prelude::CloneNoBound`]
|
||||
<a href=#137 id=137 data-nosnippet>137</a>//! - [`frame::prelude::PartialOrdNoBound`]
|
||||
<a href=#138 id=138 data-nosnippet>138</a>//! - [`frame::prelude::OrdNoBound`]
|
||||
<a href=#139 id=139 data-nosnippet>139</a>//!
|
||||
<a href=#140 id=140 data-nosnippet>140</a>//! The above traits are almost certainly needed for your tests - to print your type, assert equality
|
||||
<a href=#141 id=141 data-nosnippet>141</a>//! or clone it.
|
||||
<a href=#142 id=142 data-nosnippet>142</a>//!
|
||||
<a href=#143 id=143 data-nosnippet>143</a>//! We can fix the following example by using [`frame::prelude::DefaultNoBound`].
|
||||
<a href=#144 id=144 data-nosnippet>144</a>//! ```rust
|
||||
<a href=#145 id=145 data-nosnippet>145</a>//! #[frame::pallet]
|
||||
<a href=#146 id=146 data-nosnippet>146</a>//! pub mod pallet {
|
||||
<a href=#147 id=147 data-nosnippet>147</a>//! # use frame::prelude::*;
|
||||
<a href=#148 id=148 data-nosnippet>148</a>//! # #[pallet::config]
|
||||
<a href=#149 id=149 data-nosnippet>149</a>//! # pub trait Config: frame_system::Config {}
|
||||
<a href=#150 id=150 data-nosnippet>150</a>//! # #[pallet::pallet]
|
||||
<a href=#151 id=151 data-nosnippet>151</a>//! # pub struct Pallet<T>(_);
|
||||
<a href=#152 id=152 data-nosnippet>152</a>//! #[derive(
|
||||
<a href=#153 id=153 data-nosnippet>153</a>//! codec::Encode,
|
||||
<a href=#154 id=154 data-nosnippet>154</a>//! codec::Decode,
|
||||
<a href=#155 id=155 data-nosnippet>155</a>//! codec::MaxEncodedLen,
|
||||
<a href=#156 id=156 data-nosnippet>156</a>//! scale_info::TypeInfo,
|
||||
<a href=#157 id=157 data-nosnippet>157</a>//! DefaultNoBound
|
||||
<a href=#158 id=158 data-nosnippet>158</a>//! )]
|
||||
<a href=#159 id=159 data-nosnippet>159</a>//! #[scale_info(skip_type_params(T))]
|
||||
<a href=#160 id=160 data-nosnippet>160</a>//! pub struct NewType<T:Config>(BlockNumberFor<T>);
|
||||
<a href=#161 id=161 data-nosnippet>161</a>//!
|
||||
<a href=#162 id=162 data-nosnippet>162</a>//! #[pallet::storage]
|
||||
<a href=#163 id=163 data-nosnippet>163</a>//! pub type Something<T: Config> = StorageValue<_, NewType<T>, ValueQuery>;
|
||||
<a href=#164 id=164 data-nosnippet>164</a>//! }
|
||||
<a href=#165 id=165 data-nosnippet>165</a>//! ```
|
||||
<a href=#166 id=166 data-nosnippet>166</a>//!
|
||||
<a href=#167 id=167 data-nosnippet>167</a>//! Finally, if a custom type that is provided through `Config` is to be stored in the storage, it
|
||||
<a href=#168 id=168 data-nosnippet>168</a>//! is subject to the same trait requirements. The following does not work:
|
||||
<a href=#169 id=169 data-nosnippet>169</a>//! ```compile_fail
|
||||
<a href=#170 id=170 data-nosnippet>170</a>//! #[frame::pallet]
|
||||
<a href=#171 id=171 data-nosnippet>171</a>//! pub mod pallet {
|
||||
<a href=#172 id=172 data-nosnippet>172</a>//! use frame::prelude::*;
|
||||
<a href=#173 id=173 data-nosnippet>173</a>//! #[pallet::config]
|
||||
<a href=#174 id=174 data-nosnippet>174</a>//! pub trait Config: frame_system::Config {
|
||||
<a href=#175 id=175 data-nosnippet>175</a>//! type CustomType;
|
||||
<a href=#176 id=176 data-nosnippet>176</a>//! }
|
||||
<a href=#177 id=177 data-nosnippet>177</a>//! #[pallet::pallet]
|
||||
<a href=#178 id=178 data-nosnippet>178</a>//! pub struct Pallet<T>(_);
|
||||
<a href=#179 id=179 data-nosnippet>179</a>//! #[pallet::storage]
|
||||
<a href=#180 id=180 data-nosnippet>180</a>//! pub type Something<T: Config> = StorageValue<_, T::CustomType>;
|
||||
<a href=#181 id=181 data-nosnippet>181</a>//! }
|
||||
<a href=#182 id=182 data-nosnippet>182</a>//! ```
|
||||
<a href=#183 id=183 data-nosnippet>183</a>//!
|
||||
<a href=#184 id=184 data-nosnippet>184</a>//! But adding the right trait bounds will fix it.
|
||||
<a href=#185 id=185 data-nosnippet>185</a>//! ```rust
|
||||
<a href=#186 id=186 data-nosnippet>186</a>//! #[frame::pallet]
|
||||
<a href=#187 id=187 data-nosnippet>187</a>//! pub mod pallet {
|
||||
<a href=#188 id=188 data-nosnippet>188</a>//! use frame::prelude::*;
|
||||
<a href=#189 id=189 data-nosnippet>189</a>//! #[pallet::config]
|
||||
<a href=#190 id=190 data-nosnippet>190</a>//! pub trait Config: frame_system::Config {
|
||||
<a href=#191 id=191 data-nosnippet>191</a>//! type CustomType: codec::FullCodec
|
||||
<a href=#192 id=192 data-nosnippet>192</a>//! + codec::MaxEncodedLen
|
||||
<a href=#193 id=193 data-nosnippet>193</a>//! + scale_info::TypeInfo
|
||||
<a href=#194 id=194 data-nosnippet>194</a>//! + Debug
|
||||
<a href=#195 id=195 data-nosnippet>195</a>//! + Default;
|
||||
<a href=#196 id=196 data-nosnippet>196</a>//! }
|
||||
<a href=#197 id=197 data-nosnippet>197</a>//! #[pallet::pallet]
|
||||
<a href=#198 id=198 data-nosnippet>198</a>//! pub struct Pallet<T>(_);
|
||||
<a href=#199 id=199 data-nosnippet>199</a>//! #[pallet::storage]
|
||||
<a href=#200 id=200 data-nosnippet>200</a>//! pub type Something<T: Config> = StorageValue<_, T::CustomType>;
|
||||
<a href=#201 id=201 data-nosnippet>201</a>//! }
|
||||
<a href=#202 id=202 data-nosnippet>202</a>//! ```</span></code></pre></div></section></main></body></html>
|
||||
@@ -0,0 +1,10 @@
|
||||
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `docs/sdk/src/reference_docs/frame_system_accounts.rs`."><title>frame_system_accounts.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2"href="../../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../../../static.files/rustdoc-e56847b5.css"><meta name="rustdoc-vars" data-root-path="../../../" data-static-root-path="../../../static.files/" data-current-crate="pezkuwi_sdk_docs" data-themes="" data-resource-suffix="" data-rustdoc-version="1.91.1 (ed61e7d7e 2025-11-07)" data-channel="1.91.1" data-search-js="search-e256b49e.js" data-stringdex-js="stringdex-c3e638e9.js" data-settings-js="settings-c38705f0.js" ><script src="../../../static.files/storage-e2aeef58.js"></script><script defer src="../../../static.files/src-script-813739b1.js"></script><script defer src="../../../src-files.js"></script><script defer src="../../../static.files/main-6dc2a7f3.js"></script><noscript><link rel="stylesheet" href="../../../static.files/noscript-263c88ec.css"></noscript><link rel="icon" href="https://pezkuwichain.io/favicon.ico"></head><body class="rustdoc src"><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer" title="Drag to resize sidebar"></div><main><section id="main-content" class="content"><div class="main-heading"><h1><div class="sub-heading">pezkuwi_sdk_docs/reference_docs/</div>frame_system_accounts.rs</h1><rustdoc-toolbar></rustdoc-toolbar></div><div class="example-wrap digits-2"><pre class="rust"><code><a href=#1 id=1 data-nosnippet>1</a><span class="doccomment">//! # FRAME Accounts
|
||||
<a href=#2 id=2 data-nosnippet>2</a>//!
|
||||
<a href=#3 id=3 data-nosnippet>3</a>//! 🚧 Work In Progress 🚧
|
||||
<a href=#4 id=4 data-nosnippet>4</a>//!
|
||||
<a href=#5 id=5 data-nosnippet>5</a>//! How `frame_system` handles accountIds. Nonce. Consumers and Providers, reference counting.
|
||||
<a href=#6 id=6 data-nosnippet>6</a>
|
||||
<a href=#7 id=7 data-nosnippet>7</a></span><span class="comment">// - poorly understood topics, needs one great article to rul them all.
|
||||
<a href=#8 id=8 data-nosnippet>8</a>// - https://github.com/paritytech/substrate/issues/14425
|
||||
<a href=#9 id=9 data-nosnippet>9</a>// - https://github.com/paritytech/substrate/pull/12951
|
||||
<a href=#10 id=10 data-nosnippet>10</a>// - https://exchange.pezkuwichain.app/questions/263/what-is-the-meaning-of-the-account-provider-sufficients-and-consumer</span></code></pre></div></section></main></body></html>
|
||||
@@ -0,0 +1,129 @@
|
||||
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `docs/sdk/src/reference_docs/frame_tokens.rs`."><title>frame_tokens.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2"href="../../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../../../static.files/rustdoc-e56847b5.css"><meta name="rustdoc-vars" data-root-path="../../../" data-static-root-path="../../../static.files/" data-current-crate="pezkuwi_sdk_docs" data-themes="" data-resource-suffix="" data-rustdoc-version="1.91.1 (ed61e7d7e 2025-11-07)" data-channel="1.91.1" data-search-js="search-e256b49e.js" data-stringdex-js="stringdex-c3e638e9.js" data-settings-js="settings-c38705f0.js" ><script src="../../../static.files/storage-e2aeef58.js"></script><script defer src="../../../static.files/src-script-813739b1.js"></script><script defer src="../../../src-files.js"></script><script defer src="../../../static.files/main-6dc2a7f3.js"></script><noscript><link rel="stylesheet" href="../../../static.files/noscript-263c88ec.css"></noscript><link rel="icon" href="https://pezkuwichain.io/favicon.ico"></head><body class="rustdoc src"><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer" title="Drag to resize sidebar"></div><main><section id="main-content" class="content"><div class="main-heading"><h1><div class="sub-heading">pezkuwi_sdk_docs/reference_docs/</div>frame_tokens.rs</h1><rustdoc-toolbar></rustdoc-toolbar></div><div class="example-wrap digits-3"><pre class="rust"><code><a href=#1 id=1 data-nosnippet>1</a><span class="comment">// This file is part of pezkuwi-sdk.
|
||||
<a href=#2 id=2 data-nosnippet>2</a>//
|
||||
<a href=#3 id=3 data-nosnippet>3</a>// Copyright (C) Parity Technologies (UK) Ltd.
|
||||
<a href=#4 id=4 data-nosnippet>4</a>// SPDX-License-Identifier: Apache-2.0
|
||||
<a href=#5 id=5 data-nosnippet>5</a>//
|
||||
<a href=#6 id=6 data-nosnippet>6</a>// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
<a href=#7 id=7 data-nosnippet>7</a>// you may not use this file except in compliance with the License.
|
||||
<a href=#8 id=8 data-nosnippet>8</a>// You may obtain a copy of the License at
|
||||
<a href=#9 id=9 data-nosnippet>9</a>//
|
||||
<a href=#10 id=10 data-nosnippet>10</a>// http://www.apache.org/licenses/LICENSE-2.0
|
||||
<a href=#11 id=11 data-nosnippet>11</a>//
|
||||
<a href=#12 id=12 data-nosnippet>12</a>// Unless required by applicable law or agreed to in writing, software
|
||||
<a href=#13 id=13 data-nosnippet>13</a>// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
<a href=#14 id=14 data-nosnippet>14</a>// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
<a href=#15 id=15 data-nosnippet>15</a>// See the License for the specific language governing permissions and
|
||||
<a href=#16 id=16 data-nosnippet>16</a>// limitations under the License.
|
||||
<a href=#17 id=17 data-nosnippet>17</a>
|
||||
<a href=#18 id=18 data-nosnippet>18</a></span><span class="doccomment">//! # FRAME Tokens
|
||||
<a href=#19 id=19 data-nosnippet>19</a>//!
|
||||
<a href=#20 id=20 data-nosnippet>20</a>//! This reference doc serves as a high-level overview of the token-related logic in FRAME, and
|
||||
<a href=#21 id=21 data-nosnippet>21</a>//! how to properly apply it to your use case.
|
||||
<a href=#22 id=22 data-nosnippet>22</a>//!
|
||||
<a href=#23 id=23 data-nosnippet>23</a>//! On completion of reading this doc, you should have a good understanding of:
|
||||
<a href=#24 id=24 data-nosnippet>24</a>//! - The distinction between token traits and trait implementations in FRAME, and why this
|
||||
<a href=#25 id=25 data-nosnippet>25</a>//! distinction is helpful.
|
||||
<a href=#26 id=26 data-nosnippet>26</a>//! - Token-related traits available in FRAME.
|
||||
<a href=#27 id=27 data-nosnippet>27</a>//! - Token-related trait implementations in FRAME.
|
||||
<a href=#28 id=28 data-nosnippet>28</a>//! - How to choose the right trait or trait implementation for your use case.
|
||||
<a href=#29 id=29 data-nosnippet>29</a>//! - Where to go next.
|
||||
<a href=#30 id=30 data-nosnippet>30</a>//!
|
||||
<a href=#31 id=31 data-nosnippet>31</a>//! ## Getting Started
|
||||
<a href=#32 id=32 data-nosnippet>32</a>//!
|
||||
<a href=#33 id=33 data-nosnippet>33</a>//! The most ubiquitous way to add a token to a FRAME runtime is [`pallet_balances`]. Read
|
||||
<a href=#34 id=34 data-nosnippet>34</a>//! more about pallets [here](crate::pezkuwi_sdk::frame_runtime#pallets).
|
||||
<a href=#35 id=35 data-nosnippet>35</a>//!
|
||||
<a href=#36 id=36 data-nosnippet>36</a>//! You may then write custom pallets that interact with [`pallet_balances`]. The fastest way to
|
||||
<a href=#37 id=37 data-nosnippet>37</a>//! get started with that is by
|
||||
<a href=#38 id=38 data-nosnippet>38</a>//! [tightly coupling](crate::reference_docs::frame_pallet_coupling#tight-coupling-pallets) your
|
||||
<a href=#39 id=39 data-nosnippet>39</a>//! custom pallet to [`pallet_balances`].
|
||||
<a href=#40 id=40 data-nosnippet>40</a>//!
|
||||
<a href=#41 id=41 data-nosnippet>41</a>//! However, to keep pallets flexible and modular, it is often preferred to
|
||||
<a href=#42 id=42 data-nosnippet>42</a>//! [loosely couple](crate::reference_docs::frame_pallet_coupling#loosely--coupling-pallets).
|
||||
<a href=#43 id=43 data-nosnippet>43</a>//!
|
||||
<a href=#44 id=44 data-nosnippet>44</a>//! To achieve loose coupling,
|
||||
<a href=#45 id=45 data-nosnippet>45</a>//! we separate token logic into traits and trait implementations.
|
||||
<a href=#46 id=46 data-nosnippet>46</a>//!
|
||||
<a href=#47 id=47 data-nosnippet>47</a>//! ## Traits and Trait Implementations
|
||||
<a href=#48 id=48 data-nosnippet>48</a>//!
|
||||
<a href=#49 id=49 data-nosnippet>49</a>//! Broadly speaking, token logic in FRAME can be divided into two categories: traits and
|
||||
<a href=#50 id=50 data-nosnippet>50</a>//! trait implementations.
|
||||
<a href=#51 id=51 data-nosnippet>51</a>//!
|
||||
<a href=#52 id=52 data-nosnippet>52</a>//! **Traits** define common interfaces that types of tokens should implement. For example, the
|
||||
<a href=#53 id=53 data-nosnippet>53</a>//! [`fungible::Inspect`](`frame_support::traits::fungible::Inspect`) trait specifies an interface
|
||||
<a href=#54 id=54 data-nosnippet>54</a>//! for *inspecting* token state such as the total issuance of the token, the balance of individual
|
||||
<a href=#55 id=55 data-nosnippet>55</a>//! accounts, etc.
|
||||
<a href=#56 id=56 data-nosnippet>56</a>//!
|
||||
<a href=#57 id=57 data-nosnippet>57</a>//! **Trait implementations** are concrete implementations of these traits. For example, one of the
|
||||
<a href=#58 id=58 data-nosnippet>58</a>//! many traits [`pallet_balances`] implements is
|
||||
<a href=#59 id=59 data-nosnippet>59</a>//! [`fungible::Inspect`](`frame_support::traits::fungible::Inspect`)[^1]. It provides the concrete
|
||||
<a href=#60 id=60 data-nosnippet>60</a>//! way of inspecting the total issuance, balance of accounts, etc. There can be many
|
||||
<a href=#61 id=61 data-nosnippet>61</a>//! implementations of the same traits.
|
||||
<a href=#62 id=62 data-nosnippet>62</a>//!
|
||||
<a href=#63 id=63 data-nosnippet>63</a>//! [^1]: Rust Advanced Tip: The knowledge that [`pallet_balances`] implements
|
||||
<a href=#64 id=64 data-nosnippet>64</a>//! [`fungible::Inspect`](`frame_support::traits::fungible::Inspect`) is not some arcane knowledge
|
||||
<a href=#65 id=65 data-nosnippet>65</a>//! that you have to know by heart or memorize. One can simply look at the list of the implementors
|
||||
<a href=#66 id=66 data-nosnippet>66</a>//! of any trait in the Rust Doc to find all implementors (e.g.
|
||||
<a href=#67 id=67 data-nosnippet>67</a>//! [Mutate trait implementors](https://docs.pezkuwichain.io/sdk/master/frame_support/traits/tokens/fungible/trait.Mutate.html#implementors)),
|
||||
<a href=#68 id=68 data-nosnippet>68</a>//! or use the `rust-analyzer`'s `Implementations` action.
|
||||
<a href=#69 id=69 data-nosnippet>69</a>//!
|
||||
<a href=#70 id=70 data-nosnippet>70</a>//! The distinction between traits and trait implementations is helpful because it allows pallets
|
||||
<a href=#71 id=71 data-nosnippet>71</a>//! and other logic to be generic over their dependencies, avoiding tight coupling.
|
||||
<a href=#72 id=72 data-nosnippet>72</a>//!
|
||||
<a href=#73 id=73 data-nosnippet>73</a>//! To illustrate this with an example let's consider [`pallet_preimage`]. This pallet takes a
|
||||
<a href=#74 id=74 data-nosnippet>74</a>//! deposit in exchange for storing a preimage for later use. A naive implementation of the
|
||||
<a href=#75 id=75 data-nosnippet>75</a>//! pallet may use [`pallet_balances`] in a tightly coupled manner, directly calling methods
|
||||
<a href=#76 id=76 data-nosnippet>76</a>//! on the pallet to reserve and unreserve deposits. This approach works well,
|
||||
<a href=#77 id=77 data-nosnippet>77</a>//! until someone has a use case requiring that an asset from a different pallet such as
|
||||
<a href=#78 id=78 data-nosnippet>78</a>//! [`pallet_assets`] is used for the deposit. Rather than tightly coupling [`pallet_preimage`] to
|
||||
<a href=#79 id=79 data-nosnippet>79</a>//! [`pallet_balances`], [`pallet_assets`], and every other token-handling pallet, a user
|
||||
<a href=#80 id=80 data-nosnippet>80</a>//! could possibly specify that [`pallet_preimage`] does not specify a concrete pallet as a
|
||||
<a href=#81 id=81 data-nosnippet>81</a>//! dependency, but instead accepts any dependency which implements the
|
||||
<a href=#82 id=82 data-nosnippet>82</a>//! [`currency::ReservableCurrency`](`frame_support::traits::tokens::currency::ReservableCurrency`)
|
||||
<a href=#83 id=83 data-nosnippet>83</a>//! trait, namely via its [`Config::Currency`](`pallet_preimage::pallet::Config::Currency`)
|
||||
<a href=#84 id=84 data-nosnippet>84</a>//! associated type. This allows [`pallet_preimage`] to support any arbitrary pallet implementing
|
||||
<a href=#85 id=85 data-nosnippet>85</a>//! this trait, without needing any knowledge of what those pallets may be or requiring changes to
|
||||
<a href=#86 id=86 data-nosnippet>86</a>//! support new pallets which may be written in the future.
|
||||
<a href=#87 id=87 data-nosnippet>87</a>//!
|
||||
<a href=#88 id=88 data-nosnippet>88</a>//! Read more about coupling, and the benefits of loose coupling
|
||||
<a href=#89 id=89 data-nosnippet>89</a>//! [here](crate::reference_docs::frame_pallet_coupling).
|
||||
<a href=#90 id=90 data-nosnippet>90</a>//!
|
||||
<a href=#91 id=91 data-nosnippet>91</a>//! ## Fungible Token Traits in FRAME
|
||||
<a href=#92 id=92 data-nosnippet>92</a>//!
|
||||
<a href=#93 id=93 data-nosnippet>93</a>//! The [`fungible`](`frame_support::traits::fungible`) crate contains the latest set of FRAME
|
||||
<a href=#94 id=94 data-nosnippet>94</a>//! fungible token traits, and is recommended to use for all new logic requiring a fungible token.
|
||||
<a href=#95 id=95 data-nosnippet>95</a>//! See the crate documentation for more info about these fungible traits.
|
||||
<a href=#96 id=96 data-nosnippet>96</a>//!
|
||||
<a href=#97 id=97 data-nosnippet>97</a>//! [`fungibles`](`frame_support::traits::fungibles`) provides very similar functionality to
|
||||
<a href=#98 id=98 data-nosnippet>98</a>//! [`fungible`](`frame_support::traits::fungible`), except it supports managing multiple tokens.
|
||||
<a href=#99 id=99 data-nosnippet>99</a>//!
|
||||
<a href=#100 id=100 data-nosnippet>100</a>//! You may notice the trait [`Currency`](`frame_support::traits::Currency`) with similar
|
||||
<a href=#101 id=101 data-nosnippet>101</a>//! functionality is also used in the codebase, however this trait is deprecated and existing logic
|
||||
<a href=#102 id=102 data-nosnippet>102</a>//! is in the process of being migrated to [`fungible`](`frame_support::traits::fungible`) ([tracking issue](https://github.com/pezkuwichain/pezkuwi-sdk/issues/102)).
|
||||
<a href=#103 id=103 data-nosnippet>103</a>//!
|
||||
<a href=#104 id=104 data-nosnippet>104</a>//! ## Fungible Token Trait Implementations in FRAME
|
||||
<a href=#105 id=105 data-nosnippet>105</a>//!
|
||||
<a href=#106 id=106 data-nosnippet>106</a>//! [`pallet_balances`] implements [`fungible`](`frame_support::traits::fungible`), and is the most
|
||||
<a href=#107 id=107 data-nosnippet>107</a>//! commonly used fungible implementation in FRAME. Most of the time, it's used for managing the
|
||||
<a href=#108 id=108 data-nosnippet>108</a>//! native token of the blockchain network it's used in.
|
||||
<a href=#109 id=109 data-nosnippet>109</a>//!
|
||||
<a href=#110 id=110 data-nosnippet>110</a>//! [`pallet_assets`] implements [`fungibles`](`frame_support::traits::fungibles`), and is another
|
||||
<a href=#111 id=111 data-nosnippet>111</a>//! popular fungible token implementation. It supports the creation and management of multiple
|
||||
<a href=#112 id=112 data-nosnippet>112</a>//! assets in a single crate, making it a good choice when a network requires more assets in
|
||||
<a href=#113 id=113 data-nosnippet>113</a>//! addition to its native token.
|
||||
<a href=#114 id=114 data-nosnippet>114</a>//!
|
||||
<a href=#115 id=115 data-nosnippet>115</a>//! ## Non-Fungible Tokens in FRAME
|
||||
<a href=#116 id=116 data-nosnippet>116</a>//!
|
||||
<a href=#117 id=117 data-nosnippet>117</a>//! [`pallet_nfts`] is recommended to use for all NFT use cases in FRAME.
|
||||
<a href=#118 id=118 data-nosnippet>118</a>//! See the crate documentation for more info about this pallet.
|
||||
<a href=#119 id=119 data-nosnippet>119</a>//!
|
||||
<a href=#120 id=120 data-nosnippet>120</a>//! [`pallet_uniques`] is deprecated and should not be used.
|
||||
<a href=#121 id=121 data-nosnippet>121</a>//!
|
||||
<a href=#122 id=122 data-nosnippet>122</a>//!
|
||||
<a href=#123 id=123 data-nosnippet>123</a>//! # What Next?
|
||||
<a href=#124 id=124 data-nosnippet>124</a>//!
|
||||
<a href=#125 id=125 data-nosnippet>125</a>//! - If you are interested in implementing a single fungible token, continue reading the
|
||||
<a href=#126 id=126 data-nosnippet>126</a>//! [`fungible`](`frame_support::traits::fungible`) and [`pallet_balances`] docs.
|
||||
<a href=#127 id=127 data-nosnippet>127</a>//! - If you are interested in implementing a set of fungible tokens, continue reading the
|
||||
<a href=#128 id=128 data-nosnippet>128</a>//! [`fungibles`](`frame_support::traits::fungibles`) trait and [`pallet_assets`] docs.
|
||||
<a href=#129 id=129 data-nosnippet>129</a>//! - If you are interested in implementing an NFT, continue reading the [`pallet_nfts`] docs.</span></code></pre></div></section></main></body></html>
|
||||
@@ -0,0 +1,120 @@
|
||||
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `docs/sdk/src/reference_docs/glossary.rs`."><title>glossary.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2"href="../../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../../../static.files/rustdoc-e56847b5.css"><meta name="rustdoc-vars" data-root-path="../../../" data-static-root-path="../../../static.files/" data-current-crate="pezkuwi_sdk_docs" data-themes="" data-resource-suffix="" data-rustdoc-version="1.91.1 (ed61e7d7e 2025-11-07)" data-channel="1.91.1" data-search-js="search-e256b49e.js" data-stringdex-js="stringdex-c3e638e9.js" data-settings-js="settings-c38705f0.js" ><script src="../../../static.files/storage-e2aeef58.js"></script><script defer src="../../../static.files/src-script-813739b1.js"></script><script defer src="../../../src-files.js"></script><script defer src="../../../static.files/main-6dc2a7f3.js"></script><noscript><link rel="stylesheet" href="../../../static.files/noscript-263c88ec.css"></noscript><link rel="icon" href="https://pezkuwichain.io/favicon.ico"></head><body class="rustdoc src"><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer" title="Drag to resize sidebar"></div><main><section id="main-content" class="content"><div class="main-heading"><h1><div class="sub-heading">pezkuwi_sdk_docs/reference_docs/</div>glossary.rs</h1><rustdoc-toolbar></rustdoc-toolbar></div><div class="example-wrap digits-3"><pre class="rust"><code><a href=#1 id=1 data-nosnippet>1</a><span class="doccomment">//! # Glossary
|
||||
<a href=#2 id=2 data-nosnippet>2</a>//!
|
||||
<a href=#3 id=3 data-nosnippet>3</a>//! #### State
|
||||
<a href=#4 id=4 data-nosnippet>4</a>//!
|
||||
<a href=#5 id=5 data-nosnippet>5</a>//! The data around which the blockchain network wishes to come to consensus. Also
|
||||
<a href=#6 id=6 data-nosnippet>6</a>//! referred to as "onchain data", "onchain storage" or sometimes just "storage". In UTXO based
|
||||
<a href=#7 id=7 data-nosnippet>7</a>//! blockchains, is referred to as "ledger".
|
||||
<a href=#8 id=8 data-nosnippet>8</a>//!
|
||||
<a href=#9 id=9 data-nosnippet>9</a>//! **Synonyms**: Onchain data, Onchain storage, Storage, Ledger
|
||||
<a href=#10 id=10 data-nosnippet>10</a>//!
|
||||
<a href=#11 id=11 data-nosnippet>11</a>//! #### State Transition Function
|
||||
<a href=#12 id=12 data-nosnippet>12</a>//!
|
||||
<a href=#13 id=13 data-nosnippet>13</a>//! The WASM Blob that dictates how the blockchain should transition its state upon encountering new
|
||||
<a href=#14 id=14 data-nosnippet>14</a>//! blocks.
|
||||
<a href=#15 id=15 data-nosnippet>15</a>//!
|
||||
<a href=#16 id=16 data-nosnippet>16</a>//! #### Host
|
||||
<a href=#17 id=17 data-nosnippet>17</a>//!
|
||||
<a href=#18 id=18 data-nosnippet>18</a>//! The environment that hosts and executes the [state transition function's WASM
|
||||
<a href=#19 id=19 data-nosnippet>19</a>//! blob](#state-transition-function).
|
||||
<a href=#20 id=20 data-nosnippet>20</a>//!
|
||||
<a href=#21 id=21 data-nosnippet>21</a>//! #### Node
|
||||
<a href=#22 id=22 data-nosnippet>22</a>//!
|
||||
<a href=#23 id=23 data-nosnippet>23</a>//! The full software artifact that contains the [host](#host), but importantly also all the other
|
||||
<a href=#24 id=24 data-nosnippet>24</a>//! modules needed to be part of a blockchain network, such as peer-to-peer networking, database and
|
||||
<a href=#25 id=25 data-nosnippet>25</a>//! such.
|
||||
<a href=#26 id=26 data-nosnippet>26</a>//!
|
||||
<a href=#27 id=27 data-nosnippet>27</a>//! **Synonyms**: Client
|
||||
<a href=#28 id=28 data-nosnippet>28</a>//!
|
||||
<a href=#29 id=29 data-nosnippet>29</a>//! #### Light Node
|
||||
<a href=#30 id=30 data-nosnippet>30</a>//!
|
||||
<a href=#31 id=31 data-nosnippet>31</a>//! Same as [node](#nodes), but when capable of following the network only through listening to
|
||||
<a href=#32 id=32 data-nosnippet>32</a>//! block headers. Usually capable of running in more constrained environments, such as an embedded
|
||||
<a href=#33 id=33 data-nosnippet>33</a>//! device, phone, or a web browser.
|
||||
<a href=#34 id=34 data-nosnippet>34</a>//!
|
||||
<a href=#35 id=35 data-nosnippet>35</a>//! **Synonyms**: Light Client
|
||||
<a href=#36 id=36 data-nosnippet>36</a>//!
|
||||
<a href=#37 id=37 data-nosnippet>37</a>//! #### Offchain
|
||||
<a href=#38 id=38 data-nosnippet>38</a>//!
|
||||
<a href=#39 id=39 data-nosnippet>39</a>//! Refers to operations conducted outside the blockchain's consensus mechanism. They are essential
|
||||
<a href=#40 id=40 data-nosnippet>40</a>//! for enhancing scalability and efficiency, enabling activities like data fetching and computation
|
||||
<a href=#41 id=41 data-nosnippet>41</a>//! without bloating the blockchain state.
|
||||
<a href=#42 id=42 data-nosnippet>42</a>//!
|
||||
<a href=#43 id=43 data-nosnippet>43</a>//! #### Host Functions:
|
||||
<a href=#44 id=44 data-nosnippet>44</a>//!
|
||||
<a href=#45 id=45 data-nosnippet>45</a>//! Host functions are the node's API, these are functions provided by the runtime environment (the
|
||||
<a href=#46 id=46 data-nosnippet>46</a>//! [host](#host)) to the Wasm runtime. These functions allow the Wasm code to interact with and
|
||||
<a href=#47 id=47 data-nosnippet>47</a>//! perform operations on the [node](#node), like accessing the blockchain state.
|
||||
<a href=#48 id=48 data-nosnippet>48</a>//!
|
||||
<a href=#49 id=49 data-nosnippet>49</a>//! #### Runtime API:
|
||||
<a href=#50 id=50 data-nosnippet>50</a>//!
|
||||
<a href=#51 id=51 data-nosnippet>51</a>//! This is the API of the runtime, it acts as a communication bridge between the runtime and the
|
||||
<a href=#52 id=52 data-nosnippet>52</a>//! node, serving as the exposed interface that facilitates their interactions.
|
||||
<a href=#53 id=53 data-nosnippet>53</a>//!
|
||||
<a href=#54 id=54 data-nosnippet>54</a>//! #### Dispatchable:
|
||||
<a href=#55 id=55 data-nosnippet>55</a>//!
|
||||
<a href=#56 id=56 data-nosnippet>56</a>//! Dispatchables are [function objects](https://en.wikipedia.org/wiki/Function_object) that act as
|
||||
<a href=#57 id=57 data-nosnippet>57</a>//! the entry points in [FRAME](frame) pallets. They can be called by internal or external entities
|
||||
<a href=#58 id=58 data-nosnippet>58</a>//! to interact with the blockchain's state. They are a core aspect of the runtime logic, handling
|
||||
<a href=#59 id=59 data-nosnippet>59</a>//! transactions and other state-changing operations.
|
||||
<a href=#60 id=60 data-nosnippet>60</a>//!
|
||||
<a href=#61 id=61 data-nosnippet>61</a>//! **Synonyms**: Callable
|
||||
<a href=#62 id=62 data-nosnippet>62</a>//!
|
||||
<a href=#63 id=63 data-nosnippet>63</a>//! #### Extrinsic
|
||||
<a href=#64 id=64 data-nosnippet>64</a>//!
|
||||
<a href=#65 id=65 data-nosnippet>65</a>//! An extrinsic is a general term for a piece of data that is originated outside of the runtime,
|
||||
<a href=#66 id=66 data-nosnippet>66</a>//! included into a block and leads to some action. This includes user-initiated transactions as
|
||||
<a href=#67 id=67 data-nosnippet>67</a>//! well as inherents which are placed into the block by the block-builder.
|
||||
<a href=#68 id=68 data-nosnippet>68</a>//!
|
||||
<a href=#69 id=69 data-nosnippet>69</a>//! #### Pallet
|
||||
<a href=#70 id=70 data-nosnippet>70</a>//!
|
||||
<a href=#71 id=71 data-nosnippet>71</a>//! Similar to software modules in traditional programming, [FRAME](frame) pallets in Substrate are
|
||||
<a href=#72 id=72 data-nosnippet>72</a>//! modular components that encapsulate distinct functionalities or business logic. Just as
|
||||
<a href=#73 id=73 data-nosnippet>73</a>//! libraries or modules are used to build and extend the capabilities of a software application,
|
||||
<a href=#74 id=74 data-nosnippet>74</a>//! pallets are the foundational building blocks for constructing a blockchain's runtime with frame.
|
||||
<a href=#75 id=75 data-nosnippet>75</a>//! They enable the creation of customizable and upgradeable networks, offering a composable
|
||||
<a href=#76 id=76 data-nosnippet>76</a>//! framework for a Substrate-based blockchain. Each pallet can be thought of as a plug-and-play
|
||||
<a href=#77 id=77 data-nosnippet>77</a>//! module, enhancing the blockchain's functionality in a cohesive and integrated manner.
|
||||
<a href=#78 id=78 data-nosnippet>78</a>//!
|
||||
<a href=#79 id=79 data-nosnippet>79</a>//! #### Full Node
|
||||
<a href=#80 id=80 data-nosnippet>80</a>//!
|
||||
<a href=#81 id=81 data-nosnippet>81</a>//! It is a node that prunes historical states, keeping only recent finalized block states to reduce
|
||||
<a href=#82 id=82 data-nosnippet>82</a>//! storage needs. Full nodes provide current chain state access and allow direct submission and
|
||||
<a href=#83 id=83 data-nosnippet>83</a>//! validation of extrinsics, maintaining network decentralization.
|
||||
<a href=#84 id=84 data-nosnippet>84</a>//!
|
||||
<a href=#85 id=85 data-nosnippet>85</a>//! #### Archive Node
|
||||
<a href=#86 id=86 data-nosnippet>86</a>//!
|
||||
<a href=#87 id=87 data-nosnippet>87</a>//! An archive node is a specialized node that maintains a complete history of all block states and
|
||||
<a href=#88 id=88 data-nosnippet>88</a>//! transactions. Unlike a full node, it does not prune historical data, ensuring full access to the
|
||||
<a href=#89 id=89 data-nosnippet>89</a>//! entire blockchain history. This makes it essential for detailed blockchain analysis and
|
||||
<a href=#90 id=90 data-nosnippet>90</a>//! historical queries, but requires significantly more storage capacity.
|
||||
<a href=#91 id=91 data-nosnippet>91</a>//!
|
||||
<a href=#92 id=92 data-nosnippet>92</a>//! #### Validator
|
||||
<a href=#93 id=93 data-nosnippet>93</a>//!
|
||||
<a href=#94 id=94 data-nosnippet>94</a>//! A validator is a node that participates in the consensus mechanism of the network.
|
||||
<a href=#95 id=95 data-nosnippet>95</a>//! Its role includes block production, transaction validation, network integrity and security
|
||||
<a href=#96 id=96 data-nosnippet>96</a>//! maintenance.
|
||||
<a href=#97 id=97 data-nosnippet>97</a>//!
|
||||
<a href=#98 id=98 data-nosnippet>98</a>//! #### Collator
|
||||
<a href=#99 id=99 data-nosnippet>99</a>//!
|
||||
<a href=#100 id=100 data-nosnippet>100</a>//! A collator is a node that is responsible for producing candidate blocks for the validators.
|
||||
<a href=#101 id=101 data-nosnippet>101</a>//! Collators are similar to validators on any other blockchain but, they do not need to provide
|
||||
<a href=#102 id=102 data-nosnippet>102</a>//! security guarantees as the Relay Chain handles this.
|
||||
<a href=#103 id=103 data-nosnippet>103</a>//!
|
||||
<a href=#104 id=104 data-nosnippet>104</a>//! #### Teyrchain
|
||||
<a href=#105 id=105 data-nosnippet>105</a>//!
|
||||
<a href=#106 id=106 data-nosnippet>106</a>//! Short for "parallelized chain" a teyrchain is a specialized blockchain that runs in parallel to
|
||||
<a href=#107 id=107 data-nosnippet>107</a>//! the Relay Chain (Pezkuwi, Kusama, etc.), benefiting from the shared security and
|
||||
<a href=#108 id=108 data-nosnippet>108</a>//! interoperability features of it.
|
||||
<a href=#109 id=109 data-nosnippet>109</a>//!
|
||||
<a href=#110 id=110 data-nosnippet>110</a>//! **Synonyms**: AppChain
|
||||
<a href=#111 id=111 data-nosnippet>111</a>//!
|
||||
<a href=#112 id=112 data-nosnippet>112</a>//! #### PVF
|
||||
<a href=#113 id=113 data-nosnippet>113</a>//! The Teyrchain Validation Function (PVF) is the current runtime Wasm for a teyrchain that is
|
||||
<a href=#114 id=114 data-nosnippet>114</a>//! stored on the Relay chain. It is an essential component in the Pezkuwi ecosystem, encapsulating
|
||||
<a href=#115 id=115 data-nosnippet>115</a>//! the validation logic for each teyrchain. The PVF is executed by validators to verify the
|
||||
<a href=#116 id=116 data-nosnippet>116</a>//! correctness of teyrchain blocks. This is critical for ensuring that each block follows the logic
|
||||
<a href=#117 id=117 data-nosnippet>117</a>//! set by its respective teyrchain, thus maintaining the integrity and security of the entire
|
||||
<a href=#118 id=118 data-nosnippet>118</a>//! network.
|
||||
<a href=#119 id=119 data-nosnippet>119</a>//!
|
||||
<a href=#120 id=120 data-nosnippet>120</a>//! **Synonyms**: Teyrchain Validation Function</span></code></pre></div></section></main></body></html>
|
||||
@@ -0,0 +1,25 @@
|
||||
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `docs/sdk/src/reference_docs/metadata.rs`."><title>metadata.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2"href="../../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../../../static.files/rustdoc-e56847b5.css"><meta name="rustdoc-vars" data-root-path="../../../" data-static-root-path="../../../static.files/" data-current-crate="pezkuwi_sdk_docs" data-themes="" data-resource-suffix="" data-rustdoc-version="1.91.1 (ed61e7d7e 2025-11-07)" data-channel="1.91.1" data-search-js="search-e256b49e.js" data-stringdex-js="stringdex-c3e638e9.js" data-settings-js="settings-c38705f0.js" ><script src="../../../static.files/storage-e2aeef58.js"></script><script defer src="../../../static.files/src-script-813739b1.js"></script><script defer src="../../../src-files.js"></script><script defer src="../../../static.files/main-6dc2a7f3.js"></script><noscript><link rel="stylesheet" href="../../../static.files/noscript-263c88ec.css"></noscript><link rel="icon" href="https://pezkuwichain.io/favicon.ico"></head><body class="rustdoc src"><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer" title="Drag to resize sidebar"></div><main><section id="main-content" class="content"><div class="main-heading"><h1><div class="sub-heading">pezkuwi_sdk_docs/reference_docs/</div>metadata.rs</h1><rustdoc-toolbar></rustdoc-toolbar></div><div class="example-wrap digits-2"><pre class="rust"><code><a href=#1 id=1 data-nosnippet>1</a><span class="doccomment">//! # Metadata
|
||||
<a href=#2 id=2 data-nosnippet>2</a>//!
|
||||
<a href=#3 id=3 data-nosnippet>3</a>//! The existence of metadata in pezkuwi-sdk goes back to the (forkless) upgrade-ability of all
|
||||
<a href=#4 id=4 data-nosnippet>4</a>//! Substrate-based blockchains, which is achieved through
|
||||
<a href=#5 id=5 data-nosnippet>5</a>//! [`crate::reference_docs::wasm_meta_protocol`]. You can learn more about the details of how to
|
||||
<a href=#6 id=6 data-nosnippet>6</a>//! deal with these upgrades in [`crate::reference_docs::frame_runtime_upgrades_and_migrations`].
|
||||
<a href=#7 id=7 data-nosnippet>7</a>//!
|
||||
<a href=#8 id=8 data-nosnippet>8</a>//! Another consequence of upgrade-ability is that as a UI, wallet, or generally an offchain entity,
|
||||
<a href=#9 id=9 data-nosnippet>9</a>//! it is hard to know the types internal to the runtime, specifically in light of the fact that
|
||||
<a href=#10 id=10 data-nosnippet>10</a>//! they can change at any point in time.
|
||||
<a href=#11 id=11 data-nosnippet>11</a>//!
|
||||
<a href=#12 id=12 data-nosnippet>12</a>//! This is why all Substrate-based runtimes must expose a [`sp_api::Metadata`] api, which mandates
|
||||
<a href=#13 id=13 data-nosnippet>13</a>//! the runtime to return a description of itself. The return type of this api is `Vec<u8>`, meaning
|
||||
<a href=#14 id=14 data-nosnippet>14</a>//! that it is up to the runtime developer to decide on the format of this.
|
||||
<a href=#15 id=15 data-nosnippet>15</a>//!
|
||||
<a href=#16 id=16 data-nosnippet>16</a>//! All [`crate::pezkuwi_sdk::frame_runtime`] based runtimes expose a specific metadata language,
|
||||
<a href=#17 id=17 data-nosnippet>17</a>//! maintained in <https://github.com/paritytech/frame-metadata> which is adopted in the Pezkuwi
|
||||
<a href=#18 id=18 data-nosnippet>18</a>//! ecosystem.
|
||||
<a href=#19 id=19 data-nosnippet>19</a>//!
|
||||
<a href=#20 id=20 data-nosnippet>20</a>//! ## Metadata Explorers:
|
||||
<a href=#21 id=21 data-nosnippet>21</a>//!
|
||||
<a href=#22 id=22 data-nosnippet>22</a>//! A few noteworthy tools that inspect the (FRAME-based) metadata of a chain:
|
||||
<a href=#23 id=23 data-nosnippet>23</a>//!
|
||||
<a href=#24 id=24 data-nosnippet>24</a>//! - <https://wiki.network.pezkuwichain.io/docs/metadata>
|
||||
<a href=#25 id=25 data-nosnippet>25</a>//! - <https://paritytech.github.io/subxt-explorer/></span></code></pre></div></section></main></body></html>
|
||||
@@ -0,0 +1,116 @@
|
||||
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `docs/sdk/src/reference_docs/mod.rs`."><title>mod.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2"href="../../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../../../static.files/rustdoc-e56847b5.css"><meta name="rustdoc-vars" data-root-path="../../../" data-static-root-path="../../../static.files/" data-current-crate="pezkuwi_sdk_docs" data-themes="" data-resource-suffix="" data-rustdoc-version="1.91.1 (ed61e7d7e 2025-11-07)" data-channel="1.91.1" data-search-js="search-e256b49e.js" data-stringdex-js="stringdex-c3e638e9.js" data-settings-js="settings-c38705f0.js" ><script src="../../../static.files/storage-e2aeef58.js"></script><script defer src="../../../static.files/src-script-813739b1.js"></script><script defer src="../../../src-files.js"></script><script defer src="../../../static.files/main-6dc2a7f3.js"></script><noscript><link rel="stylesheet" href="../../../static.files/noscript-263c88ec.css"></noscript><link rel="icon" href="https://pezkuwichain.io/favicon.ico"></head><body class="rustdoc src"><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer" title="Drag to resize sidebar"></div><main><section id="main-content" class="content"><div class="main-heading"><h1><div class="sub-heading">pezkuwi_sdk_docs/reference_docs/</div>mod.rs</h1><rustdoc-toolbar></rustdoc-toolbar></div><div class="example-wrap digits-3"><pre class="rust"><code><a href=#1 id=1 data-nosnippet>1</a><span class="doccomment">//! # Pezkuwi SDK Reference Docs.
|
||||
<a href=#2 id=2 data-nosnippet>2</a>//!
|
||||
<a href=#3 id=3 data-nosnippet>3</a>//! This is the entry point for all reference documents that enhance one's learning experience in
|
||||
<a href=#4 id=4 data-nosnippet>4</a>//! the Pezkuwi SDK.
|
||||
<a href=#5 id=5 data-nosnippet>5</a>//!
|
||||
<a href=#6 id=6 data-nosnippet>6</a>//! Note that this module also contains the [glossary](crate::reference_docs::glossary).
|
||||
<a href=#7 id=7 data-nosnippet>7</a>//!
|
||||
<a href=#8 id=8 data-nosnippet>8</a>//! ## What is a "reference document"?
|
||||
<a href=#9 id=9 data-nosnippet>9</a>//!
|
||||
<a href=#10 id=10 data-nosnippet>10</a>//! First, see [why we use rust-docs for everything](crate::meta_contributing#why-rust-docs) and our
|
||||
<a href=#11 id=11 data-nosnippet>11</a>//! documentation [principles](crate::meta_contributing#principles). We acknowledge that as much of
|
||||
<a href=#12 id=12 data-nosnippet>12</a>//! the crucial information should be embedded in the low level rust-docs. Then, high level
|
||||
<a href=#13 id=13 data-nosnippet>13</a>//! scenarios should be covered in [`crate::guides`]. Finally, we acknowledge that there is a
|
||||
<a href=#14 id=14 data-nosnippet>14</a>//! category of information that is:
|
||||
<a href=#15 id=15 data-nosnippet>15</a>//!
|
||||
<a href=#16 id=16 data-nosnippet>16</a>//! 1. Crucial to know.
|
||||
<a href=#17 id=17 data-nosnippet>17</a>//! 2. Is too high level to be in the rust-doc of any one `type`, `trait` or `fn`.
|
||||
<a href=#18 id=18 data-nosnippet>18</a>//! 3. Is too low level to be encompassed in a [`crate::guides`].
|
||||
<a href=#19 id=19 data-nosnippet>19</a>//!
|
||||
<a href=#20 id=20 data-nosnippet>20</a>//! We call this class of documents "reference documents". Our goal should be to minimize the number
|
||||
<a href=#21 id=21 data-nosnippet>21</a>//! of "reference" docs, as they incur maintenance burden.
|
||||
<a href=#22 id=22 data-nosnippet>22</a>
|
||||
<a href=#23 id=23 data-nosnippet>23</a>/// Learn how Substrate and FRAME use traits and associated types to make modules generic in a
|
||||
<a href=#24 id=24 data-nosnippet>24</a>/// type-safe manner.
|
||||
<a href=#25 id=25 data-nosnippet>25</a></span><span class="kw">pub mod </span>trait_based_programming;
|
||||
<a href=#26 id=26 data-nosnippet>26</a>
|
||||
<a href=#27 id=27 data-nosnippet>27</a><span class="doccomment">/// Learn about the way Substrate and FRAME view their blockchains as state machines.
|
||||
<a href=#28 id=28 data-nosnippet>28</a></span><span class="kw">pub mod </span>blockchain_state_machines;
|
||||
<a href=#29 id=29 data-nosnippet>29</a>
|
||||
<a href=#30 id=30 data-nosnippet>30</a><span class="doccomment">/// The glossary.
|
||||
<a href=#31 id=31 data-nosnippet>31</a></span><span class="kw">pub mod </span>glossary;
|
||||
<a href=#32 id=32 data-nosnippet>32</a>
|
||||
<a href=#33 id=33 data-nosnippet>33</a><span class="doccomment">/// Learn about the WASM meta-protocol of all Substrate-based chains.
|
||||
<a href=#34 id=34 data-nosnippet>34</a></span><span class="kw">pub mod </span>wasm_meta_protocol;
|
||||
<a href=#35 id=35 data-nosnippet>35</a>
|
||||
<a href=#36 id=36 data-nosnippet>36</a><span class="doccomment">/// Learn about the differences between smart contracts and a FRAME-based runtime. They are both
|
||||
<a href=#37 id=37 data-nosnippet>37</a>/// "code stored onchain", but how do they differ?
|
||||
<a href=#38 id=38 data-nosnippet>38</a></span><span class="kw">pub mod </span>runtime_vs_smart_contract;
|
||||
<a href=#39 id=39 data-nosnippet>39</a>
|
||||
<a href=#40 id=40 data-nosnippet>40</a><span class="doccomment">/// Learn about how extrinsics are encoded to be transmitted to a node and stored in blocks.
|
||||
<a href=#41 id=41 data-nosnippet>41</a></span><span class="kw">pub mod </span>extrinsic_encoding;
|
||||
<a href=#42 id=42 data-nosnippet>42</a>
|
||||
<a href=#43 id=43 data-nosnippet>43</a><span class="doccomment">/// Deprecated in favor of transaction extensions.
|
||||
<a href=#44 id=44 data-nosnippet>44</a></span><span class="kw">pub mod </span>signed_extensions;
|
||||
<a href=#45 id=45 data-nosnippet>45</a>
|
||||
<a href=#46 id=46 data-nosnippet>46</a><span class="doccomment">/// Learn about the transaction extensions that form a part of extrinsics.
|
||||
<a href=#47 id=47 data-nosnippet>47</a></span><span class="kw">pub mod </span>transaction_extensions;
|
||||
<a href=#48 id=48 data-nosnippet>48</a>
|
||||
<a href=#49 id=49 data-nosnippet>49</a><span class="doccomment">/// Learn about *Origins*, a topic in FRAME that enables complex account abstractions to be built.
|
||||
<a href=#50 id=50 data-nosnippet>50</a></span><span class="kw">pub mod </span>frame_origin;
|
||||
<a href=#51 id=51 data-nosnippet>51</a>
|
||||
<a href=#52 id=52 data-nosnippet>52</a><span class="doccomment">/// Learn about the details of what derives are needed for a type to be store-able in `frame`
|
||||
<a href=#53 id=53 data-nosnippet>53</a>/// storage.
|
||||
<a href=#54 id=54 data-nosnippet>54</a></span><span class="kw">pub mod </span>frame_storage_derives;
|
||||
<a href=#55 id=55 data-nosnippet>55</a>
|
||||
<a href=#56 id=56 data-nosnippet>56</a><span class="doccomment">/// Learn about how to write safe and defensive code in your FRAME runtime.
|
||||
<a href=#57 id=57 data-nosnippet>57</a></span><span class="kw">pub mod </span>defensive_programming;
|
||||
<a href=#58 id=58 data-nosnippet>58</a>
|
||||
<a href=#59 id=59 data-nosnippet>59</a><span class="doccomment">/// Learn about composite enums and other runtime level types, such as `RuntimeEvent` and
|
||||
<a href=#60 id=60 data-nosnippet>60</a>/// `RuntimeCall`.
|
||||
<a href=#61 id=61 data-nosnippet>61</a></span><span class="kw">pub mod </span>frame_runtime_types;
|
||||
<a href=#62 id=62 data-nosnippet>62</a>
|
||||
<a href=#63 id=63 data-nosnippet>63</a><span class="doccomment">/// Learn about how to make a pallet/runtime that is fee-less and instead uses another mechanism to
|
||||
<a href=#64 id=64 data-nosnippet>64</a>/// control usage and sybil attacks.
|
||||
<a href=#65 id=65 data-nosnippet>65</a></span><span class="kw">pub mod </span>fee_less_runtime;
|
||||
<a href=#66 id=66 data-nosnippet>66</a>
|
||||
<a href=#67 id=67 data-nosnippet>67</a><span class="doccomment">/// Learn about metadata, the main means through which an upgradeable runtime communicates its
|
||||
<a href=#68 id=68 data-nosnippet>68</a>/// properties to the outside world.
|
||||
<a href=#69 id=69 data-nosnippet>69</a></span><span class="kw">pub mod </span>metadata;
|
||||
<a href=#70 id=70 data-nosnippet>70</a>
|
||||
<a href=#71 id=71 data-nosnippet>71</a><span class="doccomment">/// Learn about how to add custom host functions to the node.
|
||||
<a href=#72 id=72 data-nosnippet>72</a></span><span class="kw">pub mod </span>custom_host_functions;
|
||||
<a href=#73 id=73 data-nosnippet>73</a>
|
||||
<a href=#74 id=74 data-nosnippet>74</a><span class="doccomment">/// Learn about how frame-system handles `account-ids`, nonces, consumers and providers.
|
||||
<a href=#75 id=75 data-nosnippet>75</a></span><span class="kw">pub mod </span>frame_system_accounts;
|
||||
<a href=#76 id=76 data-nosnippet>76</a>
|
||||
<a href=#77 id=77 data-nosnippet>77</a><span class="doccomment">/// Advice for configuring your development environment for Substrate development.
|
||||
<a href=#78 id=78 data-nosnippet>78</a></span><span class="kw">pub mod </span>development_environment_advice;
|
||||
<a href=#79 id=79 data-nosnippet>79</a>
|
||||
<a href=#80 id=80 data-nosnippet>80</a><span class="doccomment">/// Learn about benchmarking and weight.
|
||||
<a href=#81 id=81 data-nosnippet>81</a></span><span class="kw">pub mod </span>frame_benchmarking_weight;
|
||||
<a href=#82 id=82 data-nosnippet>82</a>
|
||||
<a href=#83 id=83 data-nosnippet>83</a><span class="doccomment">/// Learn about the token-related logic in FRAME and how to apply it to your use case.
|
||||
<a href=#84 id=84 data-nosnippet>84</a></span><span class="kw">pub mod </span>frame_tokens;
|
||||
<a href=#85 id=85 data-nosnippet>85</a>
|
||||
<a href=#86 id=86 data-nosnippet>86</a><span class="doccomment">/// Learn about chain specification file and the genesis state of the blockchain.
|
||||
<a href=#87 id=87 data-nosnippet>87</a></span><span class="kw">pub mod </span>chain_spec_genesis;
|
||||
<a href=#88 id=88 data-nosnippet>88</a>
|
||||
<a href=#89 id=89 data-nosnippet>89</a><span class="doccomment">/// Learn about Substrate's CLI, and how it can be extended.
|
||||
<a href=#90 id=90 data-nosnippet>90</a></span><span class="kw">pub mod </span>cli;
|
||||
<a href=#91 id=91 data-nosnippet>91</a>
|
||||
<a href=#92 id=92 data-nosnippet>92</a><span class="doccomment">/// Learn about Runtime Upgrades and best practices for writing Migrations.
|
||||
<a href=#93 id=93 data-nosnippet>93</a></span><span class="kw">pub mod </span>frame_runtime_upgrades_and_migrations;
|
||||
<a href=#94 id=94 data-nosnippet>94</a>
|
||||
<a href=#95 id=95 data-nosnippet>95</a><span class="doccomment">/// Learn about the offchain workers, how they function, and how to use them, as provided by the
|
||||
<a href=#96 id=96 data-nosnippet>96</a>/// [`frame`] APIs.
|
||||
<a href=#97 id=97 data-nosnippet>97</a></span><span class="kw">pub mod </span>frame_offchain_workers;
|
||||
<a href=#98 id=98 data-nosnippet>98</a>
|
||||
<a href=#99 id=99 data-nosnippet>99</a><span class="doccomment">/// Learn about the different ways through which multiple [`frame`] pallets can be combined to work
|
||||
<a href=#100 id=100 data-nosnippet>100</a>/// together.
|
||||
<a href=#101 id=101 data-nosnippet>101</a></span><span class="kw">pub mod </span>frame_pallet_coupling;
|
||||
<a href=#102 id=102 data-nosnippet>102</a>
|
||||
<a href=#103 id=103 data-nosnippet>103</a><span class="doccomment">/// Learn about how to do logging in FRAME-based runtimes.
|
||||
<a href=#104 id=104 data-nosnippet>104</a></span><span class="kw">pub mod </span>frame_logging;
|
||||
<a href=#105 id=105 data-nosnippet>105</a>
|
||||
<a href=#106 id=106 data-nosnippet>106</a><span class="doccomment">/// Learn about the Pezkuwi Umbrella crate that re-exports all other crates.
|
||||
<a href=#107 id=107 data-nosnippet>107</a></span><span class="kw">pub mod </span>umbrella_crate;
|
||||
<a href=#108 id=108 data-nosnippet>108</a>
|
||||
<a href=#109 id=109 data-nosnippet>109</a><span class="doccomment">/// Learn about how to create custom RPC endpoints and runtime APIs.
|
||||
<a href=#110 id=110 data-nosnippet>110</a></span><span class="kw">pub mod </span>custom_runtime_api_rpc;
|
||||
<a href=#111 id=111 data-nosnippet>111</a>
|
||||
<a href=#112 id=112 data-nosnippet>112</a><span class="doccomment">/// The [`pezkuwi-omni-node`](https://crates.io/crates/pezkuwi-omni-node) and its related binaries.
|
||||
<a href=#113 id=113 data-nosnippet>113</a></span><span class="kw">pub mod </span>omni_node;
|
||||
<a href=#114 id=114 data-nosnippet>114</a>
|
||||
<a href=#115 id=115 data-nosnippet>115</a><span class="doccomment">/// Learn about the state in Substrate.
|
||||
<a href=#116 id=116 data-nosnippet>116</a></span><span class="kw">pub mod </span>state;</code></pre></div></section></main></body></html>
|
||||
@@ -0,0 +1,201 @@
|
||||
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `docs/sdk/src/reference_docs/omni_node.rs`."><title>omni_node.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2"href="../../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../../../static.files/rustdoc-e56847b5.css"><meta name="rustdoc-vars" data-root-path="../../../" data-static-root-path="../../../static.files/" data-current-crate="pezkuwi_sdk_docs" data-themes="" data-resource-suffix="" data-rustdoc-version="1.91.1 (ed61e7d7e 2025-11-07)" data-channel="1.91.1" data-search-js="search-e256b49e.js" data-stringdex-js="stringdex-c3e638e9.js" data-settings-js="settings-c38705f0.js" ><script src="../../../static.files/storage-e2aeef58.js"></script><script defer src="../../../static.files/src-script-813739b1.js"></script><script defer src="../../../src-files.js"></script><script defer src="../../../static.files/main-6dc2a7f3.js"></script><noscript><link rel="stylesheet" href="../../../static.files/noscript-263c88ec.css"></noscript><link rel="icon" href="https://pezkuwichain.io/favicon.ico"></head><body class="rustdoc src"><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer" title="Drag to resize sidebar"></div><main><section id="main-content" class="content"><div class="main-heading"><h1><div class="sub-heading">pezkuwi_sdk_docs/reference_docs/</div>omni_node.rs</h1><rustdoc-toolbar></rustdoc-toolbar></div><div class="example-wrap digits-3"><pre class="rust"><code><a href=#1 id=1 data-nosnippet>1</a><span class="doccomment">//! # (Omni) Node
|
||||
<a href=#2 id=2 data-nosnippet>2</a>//!
|
||||
<a href=#3 id=3 data-nosnippet>3</a>//! This reference doc elaborates on what a Pezkuwi-SDK/Substrate node software is, and what
|
||||
<a href=#4 id=4 data-nosnippet>4</a>//! various ways exist to run one.
|
||||
<a href=#5 id=5 data-nosnippet>5</a>//!
|
||||
<a href=#6 id=6 data-nosnippet>6</a>//! The node software, as denoted in [`crate::reference_docs::wasm_meta_protocol`], is everything in
|
||||
<a href=#7 id=7 data-nosnippet>7</a>//! a blockchain other than the WASM runtime. It contains common components such as the database,
|
||||
<a href=#8 id=8 data-nosnippet>8</a>//! networking, RPC server and consensus. Substrate-based nodes are native binaries that are
|
||||
<a href=#9 id=9 data-nosnippet>9</a>//! compiled down from the Rust source code. The `node` folder in any of the [`templates`] are
|
||||
<a href=#10 id=10 data-nosnippet>10</a>//! examples of this source.
|
||||
<a href=#11 id=11 data-nosnippet>11</a>//!
|
||||
<a href=#12 id=12 data-nosnippet>12</a>//! > Note: A typical node also contains a lot of other tools (exposed as subcommands) that are
|
||||
<a href=#13 id=13 data-nosnippet>13</a>//! > useful for operating a blockchain, such as the ones noted in
|
||||
<a href=#14 id=14 data-nosnippet>14</a>//! > [`pezkuwi_omni_node_lib::cli::Cli::subcommand`].
|
||||
<a href=#15 id=15 data-nosnippet>15</a>//!
|
||||
<a href=#16 id=16 data-nosnippet>16</a>//! ## Node <> Runtime Interdependence
|
||||
<a href=#17 id=17 data-nosnippet>17</a>//!
|
||||
<a href=#18 id=18 data-nosnippet>18</a>//! While in principle the node can be mostly independent of the runtime, for various reasons, such
|
||||
<a href=#19 id=19 data-nosnippet>19</a>//! as the [native runtime](crate::reference_docs::wasm_meta_protocol#native-runtime), the node and
|
||||
<a href=#20 id=20 data-nosnippet>20</a>//! runtime were historically tightly linked together. Another reason is that the node and the
|
||||
<a href=#21 id=21 data-nosnippet>21</a>//! runtime need to be in agreement about which consensus algorithm they use, as described
|
||||
<a href=#22 id=22 data-nosnippet>22</a>//! [below](#consensus-engine).
|
||||
<a href=#23 id=23 data-nosnippet>23</a>//!
|
||||
<a href=#24 id=24 data-nosnippet>24</a>//! Specifically, the node relied on the existence of a linked runtime, and *could only reliably run
|
||||
<a href=#25 id=25 data-nosnippet>25</a>//! that runtime*. This is why if you look at any of the [`templates`], they are all composed of a
|
||||
<a href=#26 id=26 data-nosnippet>26</a>//! node, and a runtime.
|
||||
<a href=#27 id=27 data-nosnippet>27</a>//!
|
||||
<a href=#28 id=28 data-nosnippet>28</a>//! Moreover, the code and API of each of these nodes was historically very advanced, and tailored
|
||||
<a href=#29 id=29 data-nosnippet>29</a>//! towards those who wish to customize many of the node components at depth.
|
||||
<a href=#30 id=30 data-nosnippet>30</a>//!
|
||||
<a href=#31 id=31 data-nosnippet>31</a>//! > The notorious `service.rs` in any node template is a good example of this.
|
||||
<a href=#32 id=32 data-nosnippet>32</a>//!
|
||||
<a href=#33 id=33 data-nosnippet>33</a>//! A [trend](https://github.com/pezkuwichain/pezkuwi-sdk/issues/97) has already been undergoing in
|
||||
<a href=#34 id=34 data-nosnippet>34</a>//! order to de-couple the node and the runtime for a long time. The north star of this effort is
|
||||
<a href=#35 id=35 data-nosnippet>35</a>//! twofold :
|
||||
<a href=#36 id=36 data-nosnippet>36</a>//!
|
||||
<a href=#37 id=37 data-nosnippet>37</a>//! 1. develop what can be described as an "omni-node": A node that can run most runtimes.
|
||||
<a href=#38 id=38 data-nosnippet>38</a>//! 2. provide a cleaner abstraction for creating a custom node.
|
||||
<a href=#39 id=39 data-nosnippet>39</a>//!
|
||||
<a href=#40 id=40 data-nosnippet>40</a>//! While a single omni-node running *all possible runtimes* is not feasible, the
|
||||
<a href=#41 id=41 data-nosnippet>41</a>//! [`pezkuwi-omni-node`] is an attempt at creating the former, and the [`pezkuwi_omni_node_lib`]
|
||||
<a href=#42 id=42 data-nosnippet>42</a>//! is the latter.
|
||||
<a href=#43 id=43 data-nosnippet>43</a>//!
|
||||
<a href=#44 id=44 data-nosnippet>44</a>//! > Note: The OmniNodes are mainly focused on the development needs of **Pezkuwi
|
||||
<a href=#45 id=45 data-nosnippet>45</a>//! > teyrchains ONLY**, not (Substrate) solo-chains. For the time being, solo-chains are not
|
||||
<a href=#46 id=46 data-nosnippet>46</a>//! > supported by the OmniNodes. This might change in the future.
|
||||
<a href=#47 id=47 data-nosnippet>47</a>//!
|
||||
<a href=#48 id=48 data-nosnippet>48</a>//! ## Types of Nodes
|
||||
<a href=#49 id=49 data-nosnippet>49</a>//!
|
||||
<a href=#50 id=50 data-nosnippet>50</a>//! With the emergence of the OmniNodes, let's look at the various Node options available to a
|
||||
<a href=#51 id=51 data-nosnippet>51</a>//! builder.
|
||||
<a href=#52 id=52 data-nosnippet>52</a>//!
|
||||
<a href=#53 id=53 data-nosnippet>53</a>//! ### [`pezkuwi-omni-node`]
|
||||
<a href=#54 id=54 data-nosnippet>54</a>//!
|
||||
<a href=#55 id=55 data-nosnippet>55</a>//! [`pezkuwi-omni-node`] is a white-labeled binary, released as a part of Pezkuwi SDK that is
|
||||
<a href=#56 id=56 data-nosnippet>56</a>//! capable of meeting the needs of most Pezkuwi teyrchains.
|
||||
<a href=#57 id=57 data-nosnippet>57</a>//!
|
||||
<a href=#58 id=58 data-nosnippet>58</a>//! It can act as the collator of a teyrchain in production, with all the related auxillary
|
||||
<a href=#59 id=59 data-nosnippet>59</a>//! functionalities that a normal collator node has: RPC server, archiving state, etc. Moreover, it
|
||||
<a href=#60 id=60 data-nosnippet>60</a>//! can also run the wasm blob of the teyrchain locally for testing and development.
|
||||
<a href=#61 id=61 data-nosnippet>61</a>//!
|
||||
<a href=#62 id=62 data-nosnippet>62</a>//! ### [`pezkuwi_omni_node_lib`]
|
||||
<a href=#63 id=63 data-nosnippet>63</a>//!
|
||||
<a href=#64 id=64 data-nosnippet>64</a>//! [`pezkuwi_omni_node_lib`] is the library version of the above, which can be used to create a
|
||||
<a href=#65 id=65 data-nosnippet>65</a>//! fresh teyrchain node, with a some limited configuration options using a lean API.
|
||||
<a href=#66 id=66 data-nosnippet>66</a>//!
|
||||
<a href=#67 id=67 data-nosnippet>67</a>//! ### Old School Nodes
|
||||
<a href=#68 id=68 data-nosnippet>68</a>//!
|
||||
<a href=#69 id=69 data-nosnippet>69</a>//! The existing node architecture, as seen in the [`templates`], is still available for those who
|
||||
<a href=#70 id=70 data-nosnippet>70</a>//! want to have full control over the node software.
|
||||
<a href=#71 id=71 data-nosnippet>71</a>//!
|
||||
<a href=#72 id=72 data-nosnippet>72</a>//! ### Summary
|
||||
<a href=#73 id=73 data-nosnippet>73</a>//!
|
||||
<a href=#74 id=74 data-nosnippet>74</a>//! We can summarize the choices for the node software of any given user of Pezkuwi-SDK, wishing to
|
||||
<a href=#75 id=75 data-nosnippet>75</a>//! deploy a teyrchain into 3 categories:
|
||||
<a href=#76 id=76 data-nosnippet>76</a>//!
|
||||
<a href=#77 id=77 data-nosnippet>77</a>//! 1. **Use the [`pezkuwi-omni-node`]**: This is the easiest way to get started, and is the most
|
||||
<a href=#78 id=78 data-nosnippet>78</a>//! likely to be the best choice for most users.
|
||||
<a href=#79 id=79 data-nosnippet>79</a>//! * can run almost any runtime with [`--dev-block-time`]
|
||||
<a href=#80 id=80 data-nosnippet>80</a>//! 2. **Use the [`pezkuwi_omni_node_lib`]**: This is the best choice for those who want to have
|
||||
<a href=#81 id=81 data-nosnippet>81</a>//! slightly more control over the node software, such as embedding a custom chain-spec.
|
||||
<a href=#82 id=82 data-nosnippet>82</a>//! 3. **Use the old school nodes**: This is the best choice for those who want to have full control
|
||||
<a href=#83 id=83 data-nosnippet>83</a>//! over the node software, such as changing the consensus engine, altering the transaction pool,
|
||||
<a href=#84 id=84 data-nosnippet>84</a>//! and so on.
|
||||
<a href=#85 id=85 data-nosnippet>85</a>//!
|
||||
<a href=#86 id=86 data-nosnippet>86</a>//! ## _OmniTools_: User Journey
|
||||
<a href=#87 id=87 data-nosnippet>87</a>//!
|
||||
<a href=#88 id=88 data-nosnippet>88</a>//! All in all, the user journey of a team/builder, in the OmniNode world is as follows:
|
||||
<a href=#89 id=89 data-nosnippet>89</a>//!
|
||||
<a href=#90 id=90 data-nosnippet>90</a>//! * The [`templates`], most notably the [`teyrchain-template`] is the canonical starting point.
|
||||
<a href=#91 id=91 data-nosnippet>91</a>//! That being said, the node code of the templates (which may be eventually
|
||||
<a href=#92 id=92 data-nosnippet>92</a>//! removed/feature-gated) is no longer of relevance. The only focus is in the runtime, and
|
||||
<a href=#93 id=93 data-nosnippet>93</a>//! obtaining a `.wasm` file. References:
|
||||
<a href=#94 id=94 data-nosnippet>94</a>//! * [`crate::guides::your_first_pallet`]
|
||||
<a href=#95 id=95 data-nosnippet>95</a>//! * [`crate::guides::your_first_runtime`]
|
||||
<a href=#96 id=96 data-nosnippet>96</a>//! * If need be, the weights of the runtime need to be updated using `frame-omni-bencher`.
|
||||
<a href=#97 id=97 data-nosnippet>97</a>//! References:
|
||||
<a href=#98 id=98 data-nosnippet>98</a>//! * [`crate::reference_docs::frame_benchmarking_weight`]
|
||||
<a href=#99 id=99 data-nosnippet>99</a>//! * Next, [`chain-spec-builder`] is used to generate a `chain_spec.json`, either for development,
|
||||
<a href=#100 id=100 data-nosnippet>100</a>//! or for production. References:
|
||||
<a href=#101 id=101 data-nosnippet>101</a>//! * [`crate::reference_docs::chain_spec_genesis`]
|
||||
<a href=#102 id=102 data-nosnippet>102</a>//! * For local development, the following options are available:
|
||||
<a href=#103 id=103 data-nosnippet>103</a>//! * `pezkuwi-omni-node` (notably, with [`--dev-block-time`]). References:
|
||||
<a href=#104 id=104 data-nosnippet>104</a>//! * [`crate::guides::your_first_node`]
|
||||
<a href=#105 id=105 data-nosnippet>105</a>//! * External tools such as `chopsticks`, `zombienet`.
|
||||
<a href=#106 id=106 data-nosnippet>106</a>//! * See the `README.md` file of the `pezkuwi-sdk-teyrchain-template`.
|
||||
<a href=#107 id=107 data-nosnippet>107</a>//! * For production `pezkuwi-omni-node` can be used out of the box.
|
||||
<a href=#108 id=108 data-nosnippet>108</a>//! * For further customization [`pezkuwi_omni_node_lib`] can be used.
|
||||
<a href=#109 id=109 data-nosnippet>109</a>//!
|
||||
<a href=#110 id=110 data-nosnippet>110</a>//! ## Appendix
|
||||
<a href=#111 id=111 data-nosnippet>111</a>//!
|
||||
<a href=#112 id=112 data-nosnippet>112</a>//! This section describes how the interdependence between the node and the runtime is related to
|
||||
<a href=#113 id=113 data-nosnippet>113</a>//! the consensus engine. This information is useful for those who want to understand the
|
||||
<a href=#114 id=114 data-nosnippet>114</a>//! historical context of the node and the runtime.
|
||||
<a href=#115 id=115 data-nosnippet>115</a>//!
|
||||
<a href=#116 id=116 data-nosnippet>116</a>//! ### Consensus Engine
|
||||
<a href=#117 id=117 data-nosnippet>117</a>//!
|
||||
<a href=#118 id=118 data-nosnippet>118</a>//! In any given substrate-based chain, both the node and the runtime will have their own
|
||||
<a href=#119 id=119 data-nosnippet>119</a>//! opinion/information about what consensus engine is going to be used.
|
||||
<a href=#120 id=120 data-nosnippet>120</a>//!
|
||||
<a href=#121 id=121 data-nosnippet>121</a>//! In practice, the majority of the implementation of any consensus engine is in the node side, but
|
||||
<a href=#122 id=122 data-nosnippet>122</a>//! the runtime also typically needs to expose a custom runtime-api to enable the particular
|
||||
<a href=#123 id=123 data-nosnippet>123</a>//! consensus engine to work, and that particular runtime-api is implemented by a pallet
|
||||
<a href=#124 id=124 data-nosnippet>124</a>//! corresponding to that consensus engine.
|
||||
<a href=#125 id=125 data-nosnippet>125</a>//!
|
||||
<a href=#126 id=126 data-nosnippet>126</a>//! For example, taking a snippet from [`solochain_template_runtime`], the runtime has to provide
|
||||
<a href=#127 id=127 data-nosnippet>127</a>//! this additional runtime-api (compared to [`minimal_template_runtime`]), if the node software is
|
||||
<a href=#128 id=128 data-nosnippet>128</a>//! configured to use the Aura consensus engine:
|
||||
<a href=#129 id=129 data-nosnippet>129</a>//!
|
||||
<a href=#130 id=130 data-nosnippet>130</a>//! ```text
|
||||
<a href=#131 id=131 data-nosnippet>131</a>//! impl sp_consensus_aura::AuraApi<Block, AuraId> for Runtime {
|
||||
<a href=#132 id=132 data-nosnippet>132</a>//! fn slot_duration() -> sp_consensus_aura::SlotDuration {
|
||||
<a href=#133 id=133 data-nosnippet>133</a>//! ...
|
||||
<a href=#134 id=134 data-nosnippet>134</a>//! }
|
||||
<a href=#135 id=135 data-nosnippet>135</a>//! fn authorities() -> Vec<AuraId> {
|
||||
<a href=#136 id=136 data-nosnippet>136</a>//! ...
|
||||
<a href=#137 id=137 data-nosnippet>137</a>//! }
|
||||
<a href=#138 id=138 data-nosnippet>138</a>//! }
|
||||
<a href=#139 id=139 data-nosnippet>139</a>//! ```
|
||||
<a href=#140 id=140 data-nosnippet>140</a>//!
|
||||
<a href=#141 id=141 data-nosnippet>141</a>//! For simplicity, we can break down "consensus" into two main parts:
|
||||
<a href=#142 id=142 data-nosnippet>142</a>//!
|
||||
<a href=#143 id=143 data-nosnippet>143</a>//! * Block Authoring: Deciding who gets to produce the next block.
|
||||
<a href=#144 id=144 data-nosnippet>144</a>//! * Finality: Deciding when a block is considered final.
|
||||
<a href=#145 id=145 data-nosnippet>145</a>//!
|
||||
<a href=#146 id=146 data-nosnippet>146</a>//! For block authoring, there are a number of options:
|
||||
<a href=#147 id=147 data-nosnippet>147</a>//!
|
||||
<a href=#148 id=148 data-nosnippet>148</a>//! * [`sc_consensus_manual_seal`]: Useful for testing, where any node can produce a block at any
|
||||
<a href=#149 id=149 data-nosnippet>149</a>//! time. This is often combined with a fixed interval at which a block is produced.
|
||||
<a href=#150 id=150 data-nosnippet>150</a>//! * [`sc_consensus_aura`]/[`pallet_aura`]: A simple round-robin block authoring mechanism.
|
||||
<a href=#151 id=151 data-nosnippet>151</a>//! * [`sc_consensus_babe`]/[`pallet_babe`]: A more advanced block authoring mechanism, capable of
|
||||
<a href=#152 id=152 data-nosnippet>152</a>//! anonymizing the next block author.
|
||||
<a href=#153 id=153 data-nosnippet>153</a>//! * [`sc_consensus_pow`]: Proof of Work block authoring.
|
||||
<a href=#154 id=154 data-nosnippet>154</a>//!
|
||||
<a href=#155 id=155 data-nosnippet>155</a>//! For finality, there is one main option shipped with pezkuwi-sdk:
|
||||
<a href=#156 id=156 data-nosnippet>156</a>//!
|
||||
<a href=#157 id=157 data-nosnippet>157</a>//! * [`sc_consensus_grandpa`]/[`pallet_grandpa`]: A finality gadget that uses a voting mechanism to
|
||||
<a href=#158 id=158 data-nosnippet>158</a>//! decide when a block
|
||||
<a href=#159 id=159 data-nosnippet>159</a>//!
|
||||
<a href=#160 id=160 data-nosnippet>160</a>//! **The most important lesson here is that the node and the runtime must have matching consensus
|
||||
<a href=#161 id=161 data-nosnippet>161</a>//! components.**
|
||||
<a href=#162 id=162 data-nosnippet>162</a>//!
|
||||
<a href=#163 id=163 data-nosnippet>163</a>//! ### Consequences for OmniNode
|
||||
<a href=#164 id=164 data-nosnippet>164</a>//!
|
||||
<a href=#165 id=165 data-nosnippet>165</a>//!
|
||||
<a href=#166 id=166 data-nosnippet>166</a>//! The consequence of the above is that anyone using the OmniNode must also be aware of the
|
||||
<a href=#167 id=167 data-nosnippet>167</a>//! consensus system used in the runtime, and be aware if it is matching that of the OmniNode or
|
||||
<a href=#168 id=168 data-nosnippet>168</a>//! not. For the time being, [`pezkuwi-omni-node`] only supports:
|
||||
<a href=#169 id=169 data-nosnippet>169</a>//!
|
||||
<a href=#170 id=170 data-nosnippet>170</a>//! * Teyrchain-based Aura consensus, with 6s async-backing block-time, and before full elastic
|
||||
<a href=#171 id=171 data-nosnippet>171</a>//! scaling). [`pezkuwi_omni_node_lib::cli::Cli::experimental_use_slot_based`] for fixed factor
|
||||
<a href=#172 id=172 data-nosnippet>172</a>//! scaling (a step
|
||||
<a href=#173 id=173 data-nosnippet>173</a>//! * Ability to run any runtime with [`--dev-block-time`] flag. This uses
|
||||
<a href=#174 id=174 data-nosnippet>174</a>//! [`sc_consensus_manual_seal`] under the hood, and has no restrictions on the runtime's
|
||||
<a href=#175 id=175 data-nosnippet>175</a>//! consensus.
|
||||
<a href=#176 id=176 data-nosnippet>176</a>//!
|
||||
<a href=#177 id=177 data-nosnippet>177</a>//! [This](https://github.com/pezkuwichain/pezkuwi-sdk/issues/143) future improvement to OmniNode
|
||||
<a href=#178 id=178 data-nosnippet>178</a>//! aims to make such checks automatic.
|
||||
<a href=#179 id=179 data-nosnippet>179</a>//!
|
||||
<a href=#180 id=180 data-nosnippet>180</a>//! ### Runtime conventions
|
||||
<a href=#181 id=181 data-nosnippet>181</a>//!
|
||||
<a href=#182 id=182 data-nosnippet>182</a>//! The Omni Node needs to make some assumptions about the runtime. During startup, the node fetches
|
||||
<a href=#183 id=183 data-nosnippet>183</a>//! the runtime metadata and asserts that the runtime represents a compatible teyrchain.
|
||||
<a href=#184 id=184 data-nosnippet>184</a>//! The checks are best effort and will generate warning level logs in the Omni Node log file on
|
||||
<a href=#185 id=185 data-nosnippet>185</a>//! failure.
|
||||
<a href=#186 id=186 data-nosnippet>186</a>//!
|
||||
<a href=#187 id=187 data-nosnippet>187</a>//! The list of checks may evolve in the future and for now only few rules are implemented:
|
||||
<a href=#188 id=188 data-nosnippet>188</a>//! * runtimes must define a type for [`cumulus-pallet-teyrchain-system`], which is recommended to
|
||||
<a href=#189 id=189 data-nosnippet>189</a>//! be named as `TeyrchainSystem`.
|
||||
<a href=#190 id=190 data-nosnippet>190</a>//! * runtimes must define a type for [`frame-system`] pallet, which is recommended to be named as
|
||||
<a href=#191 id=191 data-nosnippet>191</a>//! `System`. The configured [`block number`] here will be used by Omni Node to configure AURA
|
||||
<a href=#192 id=192 data-nosnippet>192</a>//! accordingly.
|
||||
<a href=#193 id=193 data-nosnippet>193</a>//!
|
||||
<a href=#194 id=194 data-nosnippet>194</a>//! [`templates`]: crate::pezkuwi_sdk::templates
|
||||
<a href=#195 id=195 data-nosnippet>195</a>//! [`teyrchain-template`]: https://github.com/pezkuwichain/pezkuwi-sdk-teyrchain-template
|
||||
<a href=#196 id=196 data-nosnippet>196</a>//! [`--dev-block-time`]: pezkuwi_omni_node_lib::cli::Cli::dev_block_time
|
||||
<a href=#197 id=197 data-nosnippet>197</a>//! [`pezkuwi-omni-node`]: https://crates.io/crates/pezkuwi-omni-node
|
||||
<a href=#198 id=198 data-nosnippet>198</a>//! [`chain-spec-builder`]: https://crates.io/crates/staging-chain-spec-builder
|
||||
<a href=#199 id=199 data-nosnippet>199</a>//! [`cumulus-pallet-teyrchain-system`]: https://docs.rs/cumulus-pallet-teyrchain-system/latest/cumulus_pallet_teyrchain_system/
|
||||
<a href=#200 id=200 data-nosnippet>200</a>//! [`frame-system`]: https://docs.rs/frame-system/latest/frame_system/
|
||||
<a href=#201 id=201 data-nosnippet>201</a>//! [`block number`]: https://docs.rs/frame-system/latest/frame_system/pallet/storage_types/struct.Number.html</span></code></pre></div></section></main></body></html>
|
||||
+209
@@ -0,0 +1,209 @@
|
||||
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `docs/sdk/src/reference_docs/runtime_vs_smart_contract.rs`."><title>runtime_vs_smart_contract.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2"href="../../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../../../static.files/rustdoc-e56847b5.css"><meta name="rustdoc-vars" data-root-path="../../../" data-static-root-path="../../../static.files/" data-current-crate="pezkuwi_sdk_docs" data-themes="" data-resource-suffix="" data-rustdoc-version="1.91.1 (ed61e7d7e 2025-11-07)" data-channel="1.91.1" data-search-js="search-e256b49e.js" data-stringdex-js="stringdex-c3e638e9.js" data-settings-js="settings-c38705f0.js" ><script src="../../../static.files/storage-e2aeef58.js"></script><script defer src="../../../static.files/src-script-813739b1.js"></script><script defer src="../../../src-files.js"></script><script defer src="../../../static.files/main-6dc2a7f3.js"></script><noscript><link rel="stylesheet" href="../../../static.files/noscript-263c88ec.css"></noscript><link rel="icon" href="https://pezkuwichain.io/favicon.ico"></head><body class="rustdoc src"><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer" title="Drag to resize sidebar"></div><main><section id="main-content" class="content"><div class="main-heading"><h1><div class="sub-heading">pezkuwi_sdk_docs/reference_docs/</div>runtime_vs_smart_contract.rs</h1><rustdoc-toolbar></rustdoc-toolbar></div><div class="example-wrap digits-3"><pre class="rust"><code><a href=#1 id=1 data-nosnippet>1</a><span class="doccomment">//! # Runtime vs. Smart Contracts
|
||||
<a href=#2 id=2 data-nosnippet>2</a>//!
|
||||
<a href=#3 id=3 data-nosnippet>3</a>//! *TL;DR*: If you need to create a *Blockchain*, then write a runtime. If you need to create a
|
||||
<a href=#4 id=4 data-nosnippet>4</a>//! *DApp*, then write a Smart Contract.
|
||||
<a href=#5 id=5 data-nosnippet>5</a>//!
|
||||
<a href=#6 id=6 data-nosnippet>6</a>//! This is a comparative analysis of Substrate-based Runtimes and Smart Contracts, highlighting
|
||||
<a href=#7 id=7 data-nosnippet>7</a>//! their main differences. Our aim is to equip you with a clear understanding of how these two
|
||||
<a href=#8 id=8 data-nosnippet>8</a>//! methods of deploying on-chain logic diverge in their design, usage, and implications.
|
||||
<a href=#9 id=9 data-nosnippet>9</a>//!
|
||||
<a href=#10 id=10 data-nosnippet>10</a>//! Both Runtimes and Smart Contracts serve distinct purposes. Runtimes offer deep customization for
|
||||
<a href=#11 id=11 data-nosnippet>11</a>//! blockchain development, while Smart Contracts provide a more accessible approach for
|
||||
<a href=#12 id=12 data-nosnippet>12</a>//! decentralized applications. Understanding their differences is crucial in choosing the right
|
||||
<a href=#13 id=13 data-nosnippet>13</a>//! approach for a specific solution.
|
||||
<a href=#14 id=14 data-nosnippet>14</a>//!
|
||||
<a href=#15 id=15 data-nosnippet>15</a>//! ## Substrate
|
||||
<a href=#16 id=16 data-nosnippet>16</a>//! Substrate is a modular framework that enables the creation of purpose-specific blockchains. In
|
||||
<a href=#17 id=17 data-nosnippet>17</a>//! the Pezkuwi ecosystem you can find two distinct approaches for on-chain code execution:
|
||||
<a href=#18 id=18 data-nosnippet>18</a>//! [Runtime Development](#runtime-in-substrate) and [Smart Contracts](#smart-contracts).
|
||||
<a href=#19 id=19 data-nosnippet>19</a>//!
|
||||
<a href=#20 id=20 data-nosnippet>20</a>//! #### Smart Contracts in Substrate
|
||||
<a href=#21 id=21 data-nosnippet>21</a>//! Smart Contracts are autonomous, programmable constructs deployed on the blockchain.
|
||||
<a href=#22 id=22 data-nosnippet>22</a>//! In [FRAME](frame), Smart Contracts infrastructure is implemented by the
|
||||
<a href=#23 id=23 data-nosnippet>23</a>//! [`pallet_contracts`] for WASM-based contracts or the
|
||||
<a href=#24 id=24 data-nosnippet>24</a>//! [`pallet_evm`](https://github.com/pezkuwi-evm/frontier/tree/master/frame/evm) for EVM-compatible contracts. These pallets
|
||||
<a href=#25 id=25 data-nosnippet>25</a>//! enable Smart Contract developers to build applications and systems on top of a Substrate-based
|
||||
<a href=#26 id=26 data-nosnippet>26</a>//! blockchain.
|
||||
<a href=#27 id=27 data-nosnippet>27</a>//!
|
||||
<a href=#28 id=28 data-nosnippet>28</a>//! #### Runtime in Substrate
|
||||
<a href=#29 id=29 data-nosnippet>29</a>//! The Runtime is the state transition function of a Substrate-based blockchain. It defines the
|
||||
<a href=#30 id=30 data-nosnippet>30</a>//! rules for processing transactions and blocks, essentially governing the behavior and
|
||||
<a href=#31 id=31 data-nosnippet>31</a>//! capabilities of a blockchain.
|
||||
<a href=#32 id=32 data-nosnippet>32</a>//!
|
||||
<a href=#33 id=33 data-nosnippet>33</a>//! ## Comparative Table
|
||||
<a href=#34 id=34 data-nosnippet>34</a>//!
|
||||
<a href=#35 id=35 data-nosnippet>35</a>//! | Aspect | Runtime | Smart Contracts |
|
||||
<a href=#36 id=36 data-nosnippet>36</a>//! |-----------------------|-------------------------------------------------------------------------|----------------------------------------------------------------------|
|
||||
<a href=#37 id=37 data-nosnippet>37</a>//! | **Design Philosophy** | Core logic of a blockchain, allowing broad and deep customization. | Designed for DApps deployed on the blockchain runtime. |
|
||||
<a href=#38 id=38 data-nosnippet>38</a>//! | **Development Complexity** | Requires in-depth knowledge of Rust and Substrate. Suitable for complex blockchain architectures. | Easier to develop with knowledge of Smart Contract languages like Solidity or [ink!](https://use.ink/). |
|
||||
<a href=#39 id=39 data-nosnippet>39</a>//! | **Upgradeability and Flexibility** | Offers comprehensive upgradeability with migration logic and on-chain governance, allowing modifications to the entire blockchain logic without hard forks. | Less flexible in upgrade migrations but offers more straightforward deployment and iteration. |
|
||||
<a href=#40 id=40 data-nosnippet>40</a>//! | **Performance and Efficiency** | More efficient, optimized for specific needs of the blockchain. | Can be less efficient due to its generic nature (e.g. the overhead of a virtual machine). |
|
||||
<a href=#41 id=41 data-nosnippet>41</a>//! | **Security Considerations** | Security flaws can affect the entire blockchain. | Security risks usually localized to the individual contract. |
|
||||
<a href=#42 id=42 data-nosnippet>42</a>//! | **Weighing and Metering** | Operations can be weighed, allowing for precise benchmarking. | Execution is metered, allowing for measurement of resource consumption. |
|
||||
<a href=#43 id=43 data-nosnippet>43</a>//!
|
||||
<a href=#44 id=44 data-nosnippet>44</a>//! We will now explore these differences in more detail.
|
||||
<a href=#45 id=45 data-nosnippet>45</a>//!
|
||||
<a href=#46 id=46 data-nosnippet>46</a>//! ## Design Philosophy
|
||||
<a href=#47 id=47 data-nosnippet>47</a>//! Runtimes and Smart Contracts are designed for different purposes. Runtimes are the core logic
|
||||
<a href=#48 id=48 data-nosnippet>48</a>//! of a blockchain, while Smart Contracts are designed for DApps on top of the blockchain.
|
||||
<a href=#49 id=49 data-nosnippet>49</a>//! Runtimes can be more complex, but also more flexible and efficient, while Smart Contracts are
|
||||
<a href=#50 id=50 data-nosnippet>50</a>//! easier to develop and deploy.
|
||||
<a href=#51 id=51 data-nosnippet>51</a>//!
|
||||
<a href=#52 id=52 data-nosnippet>52</a>//! #### Runtime Design Philosophy
|
||||
<a href=#53 id=53 data-nosnippet>53</a>//! - **Core Blockchain Logic**: Runtimes are essentially the backbone of a blockchain. They define
|
||||
<a href=#54 id=54 data-nosnippet>54</a>//! the fundamental rules, operations, and state transitions of the blockchain network.
|
||||
<a href=#55 id=55 data-nosnippet>55</a>//! - **Broad and Deep Customization**: Runtimes allow for extensive customization and flexibility.
|
||||
<a href=#56 id=56 data-nosnippet>56</a>//! Developers can tailor the most fundamental aspects of the blockchain, like introducing an
|
||||
<a href=#57 id=57 data-nosnippet>57</a>//! efficient transaction fee model to eliminating transaction fees completely. This level of
|
||||
<a href=#58 id=58 data-nosnippet>58</a>//! control is essential for creating specialized or application-specific blockchains.
|
||||
<a href=#59 id=59 data-nosnippet>59</a>//!
|
||||
<a href=#60 id=60 data-nosnippet>60</a>//! #### Smart Contract Design Philosophy
|
||||
<a href=#61 id=61 data-nosnippet>61</a>//! - **DApps Development**: Smart contracts are designed primarily for developing DApps. They
|
||||
<a href=#62 id=62 data-nosnippet>62</a>//! operate on top of the blockchain's infrastructure.
|
||||
<a href=#63 id=63 data-nosnippet>63</a>//! - **Modularity and Isolation**: Smart contracts offer a more modular approach. Each contract is
|
||||
<a href=#64 id=64 data-nosnippet>64</a>//! an isolated piece of code, executing predefined operations when triggered. This isolation
|
||||
<a href=#65 id=65 data-nosnippet>65</a>//! simplifies development and enhances security, as flaws in one contract do not directly
|
||||
<a href=#66 id=66 data-nosnippet>66</a>//! compromise the entire network.
|
||||
<a href=#67 id=67 data-nosnippet>67</a>//!
|
||||
<a href=#68 id=68 data-nosnippet>68</a>//! ## Development Complexity
|
||||
<a href=#69 id=69 data-nosnippet>69</a>//! Runtimes and Smart Contracts differ in their development complexity, largely due to their
|
||||
<a href=#70 id=70 data-nosnippet>70</a>//! differing purposes and technical requirements.
|
||||
<a href=#71 id=71 data-nosnippet>71</a>//!
|
||||
<a href=#72 id=72 data-nosnippet>72</a>//! #### Runtime Development Complexity
|
||||
<a href=#73 id=73 data-nosnippet>73</a>//! - **In-depth Knowledge Requirements**: Developing a Runtime in Substrate requires a
|
||||
<a href=#74 id=74 data-nosnippet>74</a>//! comprehensive understanding of Rust, Substrate's framework, and blockchain principles.
|
||||
<a href=#75 id=75 data-nosnippet>75</a>//! - **Complex Blockchain Architectures**: Runtime development is suitable for creating complex
|
||||
<a href=#76 id=76 data-nosnippet>76</a>//! blockchain architectures. Developers must consider aspects like security, scalability, and
|
||||
<a href=#77 id=77 data-nosnippet>77</a>//! network efficiency.
|
||||
<a href=#78 id=78 data-nosnippet>78</a>//!
|
||||
<a href=#79 id=79 data-nosnippet>79</a>//! #### Smart Contract Development Complexity
|
||||
<a href=#80 id=80 data-nosnippet>80</a>//! - **Accessibility**: Smart Contract development is generally more accessible, especially for
|
||||
<a href=#81 id=81 data-nosnippet>81</a>//! those already familiar with programming concepts. Knowledge of smart contract-specific
|
||||
<a href=#82 id=82 data-nosnippet>82</a>//! languages like Solidity or ink! is required.
|
||||
<a href=#83 id=83 data-nosnippet>83</a>//! - **Focused on Application Logic**: The development here is focused on the application logic
|
||||
<a href=#84 id=84 data-nosnippet>84</a>//! only. This includes writing functions that execute when certain conditions are met, managing
|
||||
<a href=#85 id=85 data-nosnippet>85</a>//! state within the contract, and ensuring security against common Smart Contract
|
||||
<a href=#86 id=86 data-nosnippet>86</a>//! vulnerabilities.
|
||||
<a href=#87 id=87 data-nosnippet>87</a>//!
|
||||
<a href=#88 id=88 data-nosnippet>88</a>//! ## Upgradeability and Flexibility
|
||||
<a href=#89 id=89 data-nosnippet>89</a>//! Runtimes and Smart Contracts differ significantly in how they handle upgrades and flexibility,
|
||||
<a href=#90 id=90 data-nosnippet>90</a>//! each with its own advantages and constraints. Runtimes are more flexible, allowing for writing
|
||||
<a href=#91 id=91 data-nosnippet>91</a>//! migration logic for upgrades, while Smart Contracts are less flexible but offer easier
|
||||
<a href=#92 id=92 data-nosnippet>92</a>//! deployment and iteration.
|
||||
<a href=#93 id=93 data-nosnippet>93</a>//!
|
||||
<a href=#94 id=94 data-nosnippet>94</a>//! #### Runtime Upgradeability and Flexibility
|
||||
<a href=#95 id=95 data-nosnippet>95</a>//! - **Migration Logic**: One of the key strengths of runtime development is the ability to define
|
||||
<a href=#96 id=96 data-nosnippet>96</a>//! migration logic. This allows developers to implement changes in the state or structure of the
|
||||
<a href=#97 id=97 data-nosnippet>97</a>//! blockchain during an upgrade. Such migrations can adapt the existing state to fit new
|
||||
<a href=#98 id=98 data-nosnippet>98</a>//! requirements or features seamlessly.
|
||||
<a href=#99 id=99 data-nosnippet>99</a>//! - **On-Chain Governance**: Upgrades in a Runtime environment are typically governed on-chain,
|
||||
<a href=#100 id=100 data-nosnippet>100</a>//! involving validators or a governance mechanism. This allows for a democratic and transparent
|
||||
<a href=#101 id=101 data-nosnippet>101</a>//! process for making substantial changes to the blockchain.
|
||||
<a href=#102 id=102 data-nosnippet>102</a>//! - **Broad Impact of Changes**: Changes made in Runtime affect the entire blockchain. This gives
|
||||
<a href=#103 id=103 data-nosnippet>103</a>//! developers the power to introduce significant improvements or changes but also necessitates a
|
||||
<a href=#104 id=104 data-nosnippet>104</a>//! high level of responsibility and scrutiny, we will talk further about it in the [Security
|
||||
<a href=#105 id=105 data-nosnippet>105</a>//! Considerations](#security-considerations) section.
|
||||
<a href=#106 id=106 data-nosnippet>106</a>//!
|
||||
<a href=#107 id=107 data-nosnippet>107</a>//! #### Smart Contract Upgradeability and Flexibility
|
||||
<a href=#108 id=108 data-nosnippet>108</a>//! - **Deployment and Iteration**: Smart Contracts, by nature, are designed for more
|
||||
<a href=#109 id=109 data-nosnippet>109</a>//! straightforward deployment and iteration. Developers can quickly deploy contracts.
|
||||
<a href=#110 id=110 data-nosnippet>110</a>//! - **Contract Code Updates**: Once deployed, although typically immutable, Smart Contracts can be
|
||||
<a href=#111 id=111 data-nosnippet>111</a>//! upgraded, but lack of migration logic. The [`pallet_contracts`]
|
||||
<a href=#112 id=112 data-nosnippet>112</a>//! allows for contracts to be upgraded by exposing the `set_code` dispatchable. More details on this
|
||||
<a href=#113 id=113 data-nosnippet>113</a>//! can be found in [Ink! documentation on upgradeable contracts](https://use.ink/basics/upgradeable-contracts).
|
||||
<a href=#114 id=114 data-nosnippet>114</a>//! - **Isolated Impact**: Upgrades or changes to a smart contract generally impact only that
|
||||
<a href=#115 id=115 data-nosnippet>115</a>//! contract and its users, unlike Runtime upgrades that have a network-wide effect.
|
||||
<a href=#116 id=116 data-nosnippet>116</a>//! - **Simplicity and Rapid Development**: The development cycle for Smart Contracts is usually
|
||||
<a href=#117 id=117 data-nosnippet>117</a>//! faster and less complex than Runtime development, allowing for rapid prototyping and
|
||||
<a href=#118 id=118 data-nosnippet>118</a>//! deployment.
|
||||
<a href=#119 id=119 data-nosnippet>119</a>//!
|
||||
<a href=#120 id=120 data-nosnippet>120</a>//! ## Performance and Efficiency
|
||||
<a href=#121 id=121 data-nosnippet>121</a>//! Runtimes and Smart Contracts have distinct characteristics in terms of performance and
|
||||
<a href=#122 id=122 data-nosnippet>122</a>//! efficiency due to their inherent design and operational contexts. Runtimes are more efficient
|
||||
<a href=#123 id=123 data-nosnippet>123</a>//! and optimized for specific needs, while Smart Contracts are more generic and less efficient.
|
||||
<a href=#124 id=124 data-nosnippet>124</a>//!
|
||||
<a href=#125 id=125 data-nosnippet>125</a>//! #### Runtime Performance and Efficiency
|
||||
<a href=#126 id=126 data-nosnippet>126</a>//! - **Optimized for Specific Needs**: Runtime modules in Substrate are tailored to meet the
|
||||
<a href=#127 id=127 data-nosnippet>127</a>//! specific needs of the blockchain. They are integrated directly into the blockchain's core,
|
||||
<a href=#128 id=128 data-nosnippet>128</a>//! allowing them to operate with high efficiency and minimal overhead.
|
||||
<a href=#129 id=129 data-nosnippet>129</a>//! - **Direct Access to Blockchain State**: Runtime has direct access to the blockchain's state.
|
||||
<a href=#130 id=130 data-nosnippet>130</a>//! This direct access enables more efficient data processing and transaction handling, as there
|
||||
<a href=#131 id=131 data-nosnippet>131</a>//! is no additional layer between the runtime logic and the blockchain's core.
|
||||
<a href=#132 id=132 data-nosnippet>132</a>//! - **Resource Management**: Resource management is integral to runtime development to ensure that
|
||||
<a href=#133 id=133 data-nosnippet>133</a>//! the blockchain operates smoothly and efficiently.
|
||||
<a href=#134 id=134 data-nosnippet>134</a>//!
|
||||
<a href=#135 id=135 data-nosnippet>135</a>//! #### Smart Contract Performance and Efficiency
|
||||
<a href=#136 id=136 data-nosnippet>136</a>//! - **Generic Nature and Overhead**: Smart Contracts, particularly those running in virtual
|
||||
<a href=#137 id=137 data-nosnippet>137</a>//! machine environments, can be less efficient due to the generic nature of their execution
|
||||
<a href=#138 id=138 data-nosnippet>138</a>//! environment. The overhead of the virtual machine can lead to increased computational and
|
||||
<a href=#139 id=139 data-nosnippet>139</a>//! resource costs.
|
||||
<a href=#140 id=140 data-nosnippet>140</a>//! - **Isolation and Security Constraints**: Smart Contracts operate in an isolated environment to
|
||||
<a href=#141 id=141 data-nosnippet>141</a>//! ensure security and prevent unwanted interactions with the blockchain's state. This isolation,
|
||||
<a href=#142 id=142 data-nosnippet>142</a>//! while crucial for security, can introduce additional computational overhead.
|
||||
<a href=#143 id=143 data-nosnippet>143</a>//! - **Gas Mechanism and Metering**: The gas mechanism in Smart Contracts, used for metering
|
||||
<a href=#144 id=144 data-nosnippet>144</a>//! computational resources, ensures that contracts don't consume excessive resources. However,
|
||||
<a href=#145 id=145 data-nosnippet>145</a>//! this metering itself requires computational power, adding to the overall cost of contract
|
||||
<a href=#146 id=146 data-nosnippet>146</a>//! execution.
|
||||
<a href=#147 id=147 data-nosnippet>147</a>//!
|
||||
<a href=#148 id=148 data-nosnippet>148</a>//! ## Security Considerations
|
||||
<a href=#149 id=149 data-nosnippet>149</a>//! These two methodologies, while serving different purposes, come with their own unique security
|
||||
<a href=#150 id=150 data-nosnippet>150</a>//! considerations.
|
||||
<a href=#151 id=151 data-nosnippet>151</a>//!
|
||||
<a href=#152 id=152 data-nosnippet>152</a>//! #### Runtime Security Aspects
|
||||
<a href=#153 id=153 data-nosnippet>153</a>//! Runtimes, being at the core of blockchain functionality, have profound implications for the
|
||||
<a href=#154 id=154 data-nosnippet>154</a>//! security of the entire network:
|
||||
<a href=#155 id=155 data-nosnippet>155</a>//!
|
||||
<a href=#156 id=156 data-nosnippet>156</a>//! - **Broad Impact**: Security flaws in the runtime can compromise the entire blockchain,
|
||||
<a href=#157 id=157 data-nosnippet>157</a>//! affecting all network participants.
|
||||
<a href=#158 id=158 data-nosnippet>158</a>//! - **Governance and Upgradeability**: Runtime upgrades, while powerful, need rigorous governance
|
||||
<a href=#159 id=159 data-nosnippet>159</a>//! and testing to ensure security. Improperly executed upgrades can introduce vulnerabilities or
|
||||
<a href=#160 id=160 data-nosnippet>160</a>//! disrupt network operations.
|
||||
<a href=#161 id=161 data-nosnippet>161</a>//! - **Complexity and Expertise**: Developing and maintaining runtime requires a higher level of
|
||||
<a href=#162 id=162 data-nosnippet>162</a>//! expertise in blockchain architecture and security, as mistakes can be far-reaching.
|
||||
<a href=#163 id=163 data-nosnippet>163</a>//!
|
||||
<a href=#164 id=164 data-nosnippet>164</a>//! #### Smart Contract Security Aspects
|
||||
<a href=#165 id=165 data-nosnippet>165</a>//! Smart contracts, while more isolated, bring their own set of security challenges:
|
||||
<a href=#166 id=166 data-nosnippet>166</a>//!
|
||||
<a href=#167 id=167 data-nosnippet>167</a>//! - **Isolated Impact**: Security issues in a smart contract typically affect the contract itself
|
||||
<a href=#168 id=168 data-nosnippet>168</a>//! and its users, rather than the whole network.
|
||||
<a href=#169 id=169 data-nosnippet>169</a>//! - **Contract-specific Risks**: Common issues like reentrancy
|
||||
<a href=#170 id=170 data-nosnippet>170</a>//! attacks, improper handling of external calls, and gas limit vulnerabilities are specific to
|
||||
<a href=#171 id=171 data-nosnippet>171</a>//! smart contract development.
|
||||
<a href=#172 id=172 data-nosnippet>172</a>//! - **Permissionless Deployment**: Since anyone can deploy a smart contract,
|
||||
<a href=#173 id=173 data-nosnippet>173</a>//! the ecosystem is more open to potentially malicious or vulnerable code.
|
||||
<a href=#174 id=174 data-nosnippet>174</a>//!
|
||||
<a href=#175 id=175 data-nosnippet>175</a>//! ## Weighing and Metering
|
||||
<a href=#176 id=176 data-nosnippet>176</a>//! Weighing and metering are mechanisms designed to limit the resources used by external actors.
|
||||
<a href=#177 id=177 data-nosnippet>177</a>//! However, there are fundamental differences in how these resources are handled in FRAME-based
|
||||
<a href=#178 id=178 data-nosnippet>178</a>//! Runtimes and how they are handled in Smart Contracts, while Runtime operations are weighed,
|
||||
<a href=#179 id=179 data-nosnippet>179</a>//! Smart Contract executions must be metered.
|
||||
<a href=#180 id=180 data-nosnippet>180</a>//!
|
||||
<a href=#181 id=181 data-nosnippet>181</a>//! #### Weighing
|
||||
<a href=#182 id=182 data-nosnippet>182</a>//! In FRAME-based Runtimes, operations are *weighed*. This means that each operation in the Runtime
|
||||
<a href=#183 id=183 data-nosnippet>183</a>//! has a fixed upper cost, known in advance, determined through
|
||||
<a href=#184 id=184 data-nosnippet>184</a>//! [benchmarking](crate::reference_docs::frame_benchmarking_weight). Weighing is practical here
|
||||
<a href=#185 id=185 data-nosnippet>185</a>//! because:
|
||||
<a href=#186 id=186 data-nosnippet>186</a>//!
|
||||
<a href=#187 id=187 data-nosnippet>187</a>//! - *Predictability*: Runtime operations are part of the blockchain's core logic, which is static
|
||||
<a href=#188 id=188 data-nosnippet>188</a>//! until an upgrade occurs. This predictability allows for precise
|
||||
<a href=#189 id=189 data-nosnippet>189</a>//! [benchmarking](crate::reference_docs::frame_benchmarking_weight).
|
||||
<a href=#190 id=190 data-nosnippet>190</a>//! - *Prevention of Abuse*: By having a fixed upper cost that corresponds to the worst-case
|
||||
<a href=#191 id=191 data-nosnippet>191</a>//! complexity scenario of its execution (and a mechanism to refund unused weight), it becomes
|
||||
<a href=#192 id=192 data-nosnippet>192</a>//! infeasible for an attacker to create transactions that could unpredictably consume excessive
|
||||
<a href=#193 id=193 data-nosnippet>193</a>//! resources.
|
||||
<a href=#194 id=194 data-nosnippet>194</a>//!
|
||||
<a href=#195 id=195 data-nosnippet>195</a>//! #### Metering
|
||||
<a href=#196 id=196 data-nosnippet>196</a>//! For Smart Contracts resource consumption is metered. This is essential due to:
|
||||
<a href=#197 id=197 data-nosnippet>197</a>//!
|
||||
<a href=#198 id=198 data-nosnippet>198</a>//! - **Untrusted Nature**: Unlike Runtime operations, Smart Contracts can be deployed by any user,
|
||||
<a href=#199 id=199 data-nosnippet>199</a>//! and their behavior isn’t known in advance. Metering dynamically measures resource consumption
|
||||
<a href=#200 id=200 data-nosnippet>200</a>//! as the contract executes.
|
||||
<a href=#201 id=201 data-nosnippet>201</a>//! - **Safety Against Infinite Loops**: Metering protects the blockchain from poorly designed
|
||||
<a href=#202 id=202 data-nosnippet>202</a>//! contracts that might run into infinite loops, consuming an indefinite amount of resources.
|
||||
<a href=#203 id=203 data-nosnippet>203</a>//!
|
||||
<a href=#204 id=204 data-nosnippet>204</a>//! #### Implications for Developers and Users
|
||||
<a href=#205 id=205 data-nosnippet>205</a>//! - **For Runtime Developers**: Understanding the cost of each operation is essential. Misjudging
|
||||
<a href=#206 id=206 data-nosnippet>206</a>//! the weight of operations can lead to network congestion or vulnerability exploitation.
|
||||
<a href=#207 id=207 data-nosnippet>207</a>//! - **For Smart Contract Developers**: Being mindful of the gas cost associated with contract
|
||||
<a href=#208 id=208 data-nosnippet>208</a>//! execution is crucial. Efficiently written contracts save costs and are less likely to hit gas
|
||||
<a href=#209 id=209 data-nosnippet>209</a>//! limits, ensuring smoother execution on the blockchain.</span></code></pre></div></section></main></body></html>
|
||||
@@ -0,0 +1,2 @@
|
||||
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `docs/sdk/src/reference_docs/signed_extensions.rs`."><title>signed_extensions.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2"href="../../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../../../static.files/rustdoc-e56847b5.css"><meta name="rustdoc-vars" data-root-path="../../../" data-static-root-path="../../../static.files/" data-current-crate="pezkuwi_sdk_docs" data-themes="" data-resource-suffix="" data-rustdoc-version="1.91.1 (ed61e7d7e 2025-11-07)" data-channel="1.91.1" data-search-js="search-e256b49e.js" data-stringdex-js="stringdex-c3e638e9.js" data-settings-js="settings-c38705f0.js" ><script src="../../../static.files/storage-e2aeef58.js"></script><script defer src="../../../static.files/src-script-813739b1.js"></script><script defer src="../../../src-files.js"></script><script defer src="../../../static.files/main-6dc2a7f3.js"></script><noscript><link rel="stylesheet" href="../../../static.files/noscript-263c88ec.css"></noscript><link rel="icon" href="https://pezkuwichain.io/favicon.ico"></head><body class="rustdoc src"><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer" title="Drag to resize sidebar"></div><main><section id="main-content" class="content"><div class="main-heading"><h1><div class="sub-heading">pezkuwi_sdk_docs/reference_docs/</div>signed_extensions.rs</h1><rustdoc-toolbar></rustdoc-toolbar></div><div class="example-wrap digits-1"><pre class="rust"><code><a href=#1 id=1 data-nosnippet>1</a><span class="doccomment">//! `SignedExtension`s are deprecated in favor of
|
||||
<a href=#2 id=2 data-nosnippet>2</a>//! [`TransactionExtension`s](crate::reference_docs::transaction_extensions).</span></code></pre></div></section></main></body></html>
|
||||
@@ -0,0 +1,12 @@
|
||||
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `docs/sdk/src/reference_docs/state.rs`."><title>state.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2"href="../../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../../../static.files/rustdoc-e56847b5.css"><meta name="rustdoc-vars" data-root-path="../../../" data-static-root-path="../../../static.files/" data-current-crate="pezkuwi_sdk_docs" data-themes="" data-resource-suffix="" data-rustdoc-version="1.91.1 (ed61e7d7e 2025-11-07)" data-channel="1.91.1" data-search-js="search-e256b49e.js" data-stringdex-js="stringdex-c3e638e9.js" data-settings-js="settings-c38705f0.js" ><script src="../../../static.files/storage-e2aeef58.js"></script><script defer src="../../../static.files/src-script-813739b1.js"></script><script defer src="../../../src-files.js"></script><script defer src="../../../static.files/main-6dc2a7f3.js"></script><noscript><link rel="stylesheet" href="../../../static.files/noscript-263c88ec.css"></noscript><link rel="icon" href="https://pezkuwichain.io/favicon.ico"></head><body class="rustdoc src"><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer" title="Drag to resize sidebar"></div><main><section id="main-content" class="content"><div class="main-heading"><h1><div class="sub-heading">pezkuwi_sdk_docs/reference_docs/</div>state.rs</h1><rustdoc-toolbar></rustdoc-toolbar></div><div class="example-wrap digits-2"><pre class="rust"><code><a href=#1 id=1 data-nosnippet>1</a><span class="doccomment">//! # State
|
||||
<a href=#2 id=2 data-nosnippet>2</a>//!
|
||||
<a href=#3 id=3 data-nosnippet>3</a>//! The state is abstracted as a key-value like database. Every item that
|
||||
<a href=#4 id=4 data-nosnippet>4</a>//! needs to be persisted by the [State Transition
|
||||
<a href=#5 id=5 data-nosnippet>5</a>//! Function](crate::reference_docs::blockchain_state_machines) is written to the state.
|
||||
<a href=#6 id=6 data-nosnippet>6</a>//!
|
||||
<a href=#7 id=7 data-nosnippet>7</a>//! ## Special keys
|
||||
<a href=#8 id=8 data-nosnippet>8</a>//!
|
||||
<a href=#9 id=9 data-nosnippet>9</a>//! The key-value pairs in the state are represented as byte sequences. The node
|
||||
<a href=#10 id=10 data-nosnippet>10</a>//! doesn't know how to interpret most the key-value pairs. However, there exist some
|
||||
<a href=#11 id=11 data-nosnippet>11</a>//! special keys and its values that are known to the node, the so-called
|
||||
<a href=#12 id=12 data-nosnippet>12</a>//! [`well-known-keys`](sp_storage::well_known_keys).</span></code></pre></div></section></main></body></html>
|
||||
+229
@@ -0,0 +1,229 @@
|
||||
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `docs/sdk/src/reference_docs/trait_based_programming.rs`."><title>trait_based_programming.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2"href="../../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../../../static.files/rustdoc-e56847b5.css"><meta name="rustdoc-vars" data-root-path="../../../" data-static-root-path="../../../static.files/" data-current-crate="pezkuwi_sdk_docs" data-themes="" data-resource-suffix="" data-rustdoc-version="1.91.1 (ed61e7d7e 2025-11-07)" data-channel="1.91.1" data-search-js="search-e256b49e.js" data-stringdex-js="stringdex-c3e638e9.js" data-settings-js="settings-c38705f0.js" ><script src="../../../static.files/storage-e2aeef58.js"></script><script defer src="../../../static.files/src-script-813739b1.js"></script><script defer src="../../../src-files.js"></script><script defer src="../../../static.files/main-6dc2a7f3.js"></script><noscript><link rel="stylesheet" href="../../../static.files/noscript-263c88ec.css"></noscript><link rel="icon" href="https://pezkuwichain.io/favicon.ico"></head><body class="rustdoc src"><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer" title="Drag to resize sidebar"></div><main><section id="main-content" class="content"><div class="main-heading"><h1><div class="sub-heading">pezkuwi_sdk_docs/reference_docs/</div>trait_based_programming.rs</h1><rustdoc-toolbar></rustdoc-toolbar></div><div class="example-wrap digits-3"><pre class="rust"><code><a href=#1 id=1 data-nosnippet>1</a><span class="doccomment">//! # Trait-based Programming
|
||||
<a href=#2 id=2 data-nosnippet>2</a>//!
|
||||
<a href=#3 id=3 data-nosnippet>3</a>//! This document walks you over a peculiar way of using Rust's `trait` items. This pattern is
|
||||
<a href=#4 id=4 data-nosnippet>4</a>//! abundantly used within [`frame`] and is therefore paramount important for a smooth transition
|
||||
<a href=#5 id=5 data-nosnippet>5</a>//! into it.
|
||||
<a href=#6 id=6 data-nosnippet>6</a>//!
|
||||
<a href=#7 id=7 data-nosnippet>7</a>//! The rest of this document assumes familiarity with the
|
||||
<a href=#8 id=8 data-nosnippet>8</a>//! [Rust book's Advanced Traits](https://doc.rust-lang.org/book/ch19-03-advanced-traits.html)
|
||||
<a href=#9 id=9 data-nosnippet>9</a>//! section.
|
||||
<a href=#10 id=10 data-nosnippet>10</a>//! Moreover, we use the [`frame::traits::Get`].
|
||||
<a href=#11 id=11 data-nosnippet>11</a>//!
|
||||
<a href=#12 id=12 data-nosnippet>12</a>//! First, imagine we are writing a FRAME pallet. We represent this pallet with a `struct Pallet`,
|
||||
<a href=#13 id=13 data-nosnippet>13</a>//! and this pallet wants to implement the functionalities of that pallet, for example a simple
|
||||
<a href=#14 id=14 data-nosnippet>14</a>//! `transfer` function. For the sake of education, we are interested in having a `MinTransfer`
|
||||
<a href=#15 id=15 data-nosnippet>15</a>//! amount, expressed as a [`frame::traits::Get`], which will dictate what is the minimum amount
|
||||
<a href=#16 id=16 data-nosnippet>16</a>//! that can be transferred.
|
||||
<a href=#17 id=17 data-nosnippet>17</a>//!
|
||||
<a href=#18 id=18 data-nosnippet>18</a>//! We can foremost write this as simple as the following snippet:
|
||||
<a href=#19 id=19 data-nosnippet>19</a></span><span class="attr">#![doc = <span class="macro">docify::embed!</span>(<span class="string">"./src/reference_docs/trait_based_programming.rs"</span>, basic)]
|
||||
<a href=#20 id=20 data-nosnippet>20</a></span><span class="doccomment">//!
|
||||
<a href=#21 id=21 data-nosnippet>21</a>//!
|
||||
<a href=#22 id=22 data-nosnippet>22</a>//! In this example, we use arbitrary choices for `AccountId`, `Balance` and the `MinTransfer` type.
|
||||
<a href=#23 id=23 data-nosnippet>23</a>//! This works great for **one team's purposes** but we have to remember that Substrate and FRAME
|
||||
<a href=#24 id=24 data-nosnippet>24</a>//! are written as generic frameworks, intended to be highly configurable.
|
||||
<a href=#25 id=25 data-nosnippet>25</a>//!
|
||||
<a href=#26 id=26 data-nosnippet>26</a>//! In a broad sense, there are two avenues in exposing configurability:
|
||||
<a href=#27 id=27 data-nosnippet>27</a>//!
|
||||
<a href=#28 id=28 data-nosnippet>28</a>//! 1. For *values* that need to be generic, for example `MinTransfer`, we attach them to the
|
||||
<a href=#29 id=29 data-nosnippet>29</a>//! `Pallet` struct as fields:
|
||||
<a href=#30 id=30 data-nosnippet>30</a>//!
|
||||
<a href=#31 id=31 data-nosnippet>31</a>//! ```
|
||||
<a href=#32 id=32 data-nosnippet>32</a>//! struct Pallet {
|
||||
<a href=#33 id=33 data-nosnippet>33</a>//! min_transfer: u128,
|
||||
<a href=#34 id=34 data-nosnippet>34</a>//! }
|
||||
<a href=#35 id=35 data-nosnippet>35</a>//! ```
|
||||
<a href=#36 id=36 data-nosnippet>36</a>//!
|
||||
<a href=#37 id=37 data-nosnippet>37</a>//! 2. For *types* that need to be generic, we would have to use generic or associated types, such
|
||||
<a href=#38 id=38 data-nosnippet>38</a>//! as:
|
||||
<a href=#39 id=39 data-nosnippet>39</a>//!
|
||||
<a href=#40 id=40 data-nosnippet>40</a>//! ```
|
||||
<a href=#41 id=41 data-nosnippet>41</a>//! struct Pallet<AccountId> {
|
||||
<a href=#42 id=42 data-nosnippet>42</a>//! min_transfer: u128,
|
||||
<a href=#43 id=43 data-nosnippet>43</a>//! _marker: std::marker::PhantomData<AccountId>,
|
||||
<a href=#44 id=44 data-nosnippet>44</a>//! }
|
||||
<a href=#45 id=45 data-nosnippet>45</a>//! ```
|
||||
<a href=#46 id=46 data-nosnippet>46</a>//!
|
||||
<a href=#47 id=47 data-nosnippet>47</a>//! Substrate and FRAME, for various reasons (performance, correctness, type safety) has opted to
|
||||
<a href=#48 id=48 data-nosnippet>48</a>//! use *types* to declare both *values* and *types* as generic. This is the essence of why the
|
||||
<a href=#49 id=49 data-nosnippet>49</a>//! `Get` trait exists.
|
||||
<a href=#50 id=50 data-nosnippet>50</a>//!
|
||||
<a href=#51 id=51 data-nosnippet>51</a>//! This would bring us to the second iteration of the pallet, which would look like:
|
||||
<a href=#52 id=52 data-nosnippet>52</a></span><span class="attr">#![doc = <span class="macro">docify::embed!</span>(<span class="string">"./src/reference_docs/trait_based_programming.rs"</span>, generic)]
|
||||
<a href=#53 id=53 data-nosnippet>53</a></span><span class="doccomment">//!
|
||||
<a href=#54 id=54 data-nosnippet>54</a>//! In this example, we managed to make all 3 of our types generic. Taking the example of the
|
||||
<a href=#55 id=55 data-nosnippet>55</a>//! `AccountId`, one should read the above as following:
|
||||
<a href=#56 id=56 data-nosnippet>56</a>//!
|
||||
<a href=#57 id=57 data-nosnippet>57</a>//! > The `Pallet` does not know what type `AccountId` concretely is, but it knows that it is
|
||||
<a href=#58 id=58 data-nosnippet>58</a>//! > something that adheres to being `From<[u8; 32]>`.
|
||||
<a href=#59 id=59 data-nosnippet>59</a>//!
|
||||
<a href=#60 id=60 data-nosnippet>60</a>//! This method would work, but it suffers from two downsides:
|
||||
<a href=#61 id=61 data-nosnippet>61</a>//!
|
||||
<a href=#62 id=62 data-nosnippet>62</a>//! 1. It is verbose, each `impl` block would have to reiterate all of the trait bounds.
|
||||
<a href=#63 id=63 data-nosnippet>63</a>//! 2. It cannot easily share/inherit generic types. Imagine multiple pallets wanting to be generic
|
||||
<a href=#64 id=64 data-nosnippet>64</a>//! over a single `AccountId`. There is no easy way to express that in this model.
|
||||
<a href=#65 id=65 data-nosnippet>65</a>//!
|
||||
<a href=#66 id=66 data-nosnippet>66</a>//! Finally, this brings us to using traits and associated types on traits to express the above.
|
||||
<a href=#67 id=67 data-nosnippet>67</a>//! Trait associated types have the benefit of:
|
||||
<a href=#68 id=68 data-nosnippet>68</a>//!
|
||||
<a href=#69 id=69 data-nosnippet>69</a>//! 1. Being less verbose, as in effect they can *group multiple `type`s together*.
|
||||
<a href=#70 id=70 data-nosnippet>70</a>//! 2. Can inherit from one another by declaring
|
||||
<a href=#71 id=71 data-nosnippet>71</a>//! [supertraits](https://doc.rust-lang.org/rust-by-example/trait/supertraits.html).
|
||||
<a href=#72 id=72 data-nosnippet>72</a>//!
|
||||
<a href=#73 id=73 data-nosnippet>73</a>//! > Interestingly, one downside of associated types is that declaring defaults on them is not
|
||||
<a href=#74 id=74 data-nosnippet>74</a>//! > stable yet. In the meantime, we have built our own custom mechanics around declaring defaults
|
||||
<a href=#75 id=75 data-nosnippet>75</a>//! for associated types, see [`pallet_default_config_example`].
|
||||
<a href=#76 id=76 data-nosnippet>76</a>//!
|
||||
<a href=#77 id=77 data-nosnippet>77</a>//! The last iteration of our code would look like this:
|
||||
<a href=#78 id=78 data-nosnippet>78</a></span><span class="attr">#![doc = <span class="macro">docify::embed!</span>(<span class="string">"./src/reference_docs/trait_based_programming.rs"</span>, trait_based)]
|
||||
<a href=#79 id=79 data-nosnippet>79</a></span><span class="doccomment">//!
|
||||
<a href=#80 id=80 data-nosnippet>80</a>//! Notice how instead of having multiple generics, everything is generic over a single `<T:
|
||||
<a href=#81 id=81 data-nosnippet>81</a>//! Config>`, and all types are fetched through `T`, for example `T::AccountId`, `T::MinTransfer`.
|
||||
<a href=#82 id=82 data-nosnippet>82</a>//!
|
||||
<a href=#83 id=83 data-nosnippet>83</a>//! Finally, imagine all pallets wanting to be generic over `AccountId`. This can be achieved by
|
||||
<a href=#84 id=84 data-nosnippet>84</a>//! having individual `trait Configs` declare a shared `trait SystemConfig` as their
|
||||
<a href=#85 id=85 data-nosnippet>85</a>//! [supertrait](https://doc.rust-lang.org/rust-by-example/trait/supertraits.html).
|
||||
<a href=#86 id=86 data-nosnippet>86</a></span><span class="attr">#![doc = <span class="macro">docify::embed!</span>(<span class="string">"./src/reference_docs/trait_based_programming.rs"</span>, with_system)]
|
||||
<a href=#87 id=87 data-nosnippet>87</a></span><span class="doccomment">//! In FRAME, this shared supertrait is [`frame::prelude::frame_system`].
|
||||
<a href=#88 id=88 data-nosnippet>88</a>//!
|
||||
<a href=#89 id=89 data-nosnippet>89</a>//! Notice how this made no difference in the syntax of the rest of the code. `T::AccountId` is
|
||||
<a href=#90 id=90 data-nosnippet>90</a>//! still a valid type, since `T` implements `Config` and `Config` implies `SystemConfig`, which
|
||||
<a href=#91 id=91 data-nosnippet>91</a>//! has a `type AccountId`.
|
||||
<a href=#92 id=92 data-nosnippet>92</a>//!
|
||||
<a href=#93 id=93 data-nosnippet>93</a>//! Note, in some instances one would need to use what is known as the fully-qualified-syntax to
|
||||
<a href=#94 id=94 data-nosnippet>94</a>//! access a type to help the Rust compiler disambiguate.
|
||||
<a href=#95 id=95 data-nosnippet>95</a></span><span class="attr">#![doc = <span class="macro">docify::embed!</span>(<span class="string">"./src/reference_docs/trait_based_programming.rs"</span>, fully_qualified)]
|
||||
<a href=#96 id=96 data-nosnippet>96</a></span><span class="doccomment">//!
|
||||
<a href=#97 id=97 data-nosnippet>97</a>//! This syntax can sometimes become more complicated when you are dealing with nested traits.
|
||||
<a href=#98 id=98 data-nosnippet>98</a>//! Consider the following example, in which we fetch the `type Balance` from another trait
|
||||
<a href=#99 id=99 data-nosnippet>99</a>//! `CurrencyTrait`.
|
||||
<a href=#100 id=100 data-nosnippet>100</a></span><span class="attr">#![doc = <span class="macro">docify::embed!</span>(<span class="string">"./src/reference_docs/trait_based_programming.rs"</span>, fully_qualified_complicated)]
|
||||
<a href=#101 id=101 data-nosnippet>101</a></span><span class="doccomment">//!
|
||||
<a href=#102 id=102 data-nosnippet>102</a>//! Notice the final `type BalanceOf` and how it is defined. Using such aliases to shorten the
|
||||
<a href=#103 id=103 data-nosnippet>103</a>//! length of fully qualified syntax is a common pattern in FRAME.
|
||||
<a href=#104 id=104 data-nosnippet>104</a>//!
|
||||
<a href=#105 id=105 data-nosnippet>105</a>//! The above example is almost identical to the well-known (and somewhat notorious) `type
|
||||
<a href=#106 id=106 data-nosnippet>106</a>//! BalanceOf` that is often used in the context of [`frame::traits::fungible`].
|
||||
<a href=#107 id=107 data-nosnippet>107</a></span><span class="attr">#![doc = <span class="macro">docify::embed!</span>(<span class="string">"../../substrate/frame/fast-unstake/src/types.rs"</span>, BalanceOf)]
|
||||
<a href=#108 id=108 data-nosnippet>108</a></span><span class="doccomment">//!
|
||||
<a href=#109 id=109 data-nosnippet>109</a>//! ## Additional Resources
|
||||
<a href=#110 id=110 data-nosnippet>110</a>//!
|
||||
<a href=#111 id=111 data-nosnippet>111</a>//! - <https://github.com/paritytech/substrate/issues/13836>
|
||||
<a href=#112 id=112 data-nosnippet>112</a>//! - [Substrate Seminar - Traits and Generic Types](https://www.youtube.com/watch?v=6cp10jVWNl4)
|
||||
<a href=#113 id=113 data-nosnippet>113</a>//! - <https://exchange.pezkuwichain.app/questions/2228/type-casting-to-trait-t-as-config>
|
||||
<a href=#114 id=114 data-nosnippet>114</a></span><span class="attr">#![allow(unused)]
|
||||
<a href=#115 id=115 data-nosnippet>115</a>
|
||||
<a href=#116 id=116 data-nosnippet>116</a></span><span class="kw">use </span>frame::traits::Get;
|
||||
<a href=#117 id=117 data-nosnippet>117</a>
|
||||
<a href=#118 id=118 data-nosnippet>118</a><span class="attr">#[docify::export]
|
||||
<a href=#119 id=119 data-nosnippet>119</a></span><span class="kw">mod </span>basic {
|
||||
<a href=#120 id=120 data-nosnippet>120</a> <span class="kw">struct </span>Pallet;
|
||||
<a href=#121 id=121 data-nosnippet>121</a>
|
||||
<a href=#122 id=122 data-nosnippet>122</a> <span class="kw">type </span>AccountId = frame::deps::sp_runtime::AccountId32;
|
||||
<a href=#123 id=123 data-nosnippet>123</a> <span class="kw">type </span>Balance = u128;
|
||||
<a href=#124 id=124 data-nosnippet>124</a> <span class="kw">type </span>MinTransfer = frame::traits::ConstU128<<span class="number">10</span>>;
|
||||
<a href=#125 id=125 data-nosnippet>125</a>
|
||||
<a href=#126 id=126 data-nosnippet>126</a> <span class="kw">impl </span>Pallet {
|
||||
<a href=#127 id=127 data-nosnippet>127</a> <span class="kw">fn </span>transfer(_from: AccountId, _to: AccountId, _amount: Balance) {
|
||||
<a href=#128 id=128 data-nosnippet>128</a> <span class="macro">todo!</span>()
|
||||
<a href=#129 id=129 data-nosnippet>129</a> }
|
||||
<a href=#130 id=130 data-nosnippet>130</a> }
|
||||
<a href=#131 id=131 data-nosnippet>131</a>}
|
||||
<a href=#132 id=132 data-nosnippet>132</a>
|
||||
<a href=#133 id=133 data-nosnippet>133</a><span class="attr">#[docify::export]
|
||||
<a href=#134 id=134 data-nosnippet>134</a></span><span class="kw">mod </span>generic {
|
||||
<a href=#135 id=135 data-nosnippet>135</a> <span class="kw">use super</span>::<span class="kw-2">*</span>;
|
||||
<a href=#136 id=136 data-nosnippet>136</a>
|
||||
<a href=#137 id=137 data-nosnippet>137</a> <span class="kw">struct </span>Pallet<AccountId, Balance, MinTransfer> {
|
||||
<a href=#138 id=138 data-nosnippet>138</a> _marker: std::marker::PhantomData<(AccountId, Balance, MinTransfer)>,
|
||||
<a href=#139 id=139 data-nosnippet>139</a> }
|
||||
<a href=#140 id=140 data-nosnippet>140</a>
|
||||
<a href=#141 id=141 data-nosnippet>141</a> <span class="kw">impl</span><AccountId, Balance, MinTransfer> Pallet<AccountId, Balance, MinTransfer>
|
||||
<a href=#142 id=142 data-nosnippet>142</a> <span class="kw">where
|
||||
<a href=#143 id=143 data-nosnippet>143</a> </span>Balance: frame::traits::AtLeast32BitUnsigned,
|
||||
<a href=#144 id=144 data-nosnippet>144</a> MinTransfer: frame::traits::Get<Balance>,
|
||||
<a href=#145 id=145 data-nosnippet>145</a> AccountId: From<[u8; <span class="number">32</span>]>,
|
||||
<a href=#146 id=146 data-nosnippet>146</a> {
|
||||
<a href=#147 id=147 data-nosnippet>147</a> <span class="kw">fn </span>transfer(_from: AccountId, _to: AccountId, amount: Balance) {
|
||||
<a href=#148 id=148 data-nosnippet>148</a> <span class="macro">assert!</span>(amount >= MinTransfer::get());
|
||||
<a href=#149 id=149 data-nosnippet>149</a> <span class="macro">unimplemented!</span>();
|
||||
<a href=#150 id=150 data-nosnippet>150</a> }
|
||||
<a href=#151 id=151 data-nosnippet>151</a> }
|
||||
<a href=#152 id=152 data-nosnippet>152</a>}
|
||||
<a href=#153 id=153 data-nosnippet>153</a>
|
||||
<a href=#154 id=154 data-nosnippet>154</a><span class="attr">#[docify::export]
|
||||
<a href=#155 id=155 data-nosnippet>155</a></span><span class="kw">mod </span>trait_based {
|
||||
<a href=#156 id=156 data-nosnippet>156</a> <span class="kw">use super</span>::<span class="kw-2">*</span>;
|
||||
<a href=#157 id=157 data-nosnippet>157</a>
|
||||
<a href=#158 id=158 data-nosnippet>158</a> <span class="kw">trait </span>Config {
|
||||
<a href=#159 id=159 data-nosnippet>159</a> <span class="kw">type </span>AccountId: From<[u8; <span class="number">32</span>]>;
|
||||
<a href=#160 id=160 data-nosnippet>160</a> <span class="kw">type </span>Balance: frame::traits::AtLeast32BitUnsigned;
|
||||
<a href=#161 id=161 data-nosnippet>161</a> <span class="kw">type </span>MinTransfer: frame::traits::Get<<span class="self">Self</span>::Balance>;
|
||||
<a href=#162 id=162 data-nosnippet>162</a> }
|
||||
<a href=#163 id=163 data-nosnippet>163</a>
|
||||
<a href=#164 id=164 data-nosnippet>164</a> <span class="kw">struct </span>Pallet<T: Config>(std::marker::PhantomData<T>);
|
||||
<a href=#165 id=165 data-nosnippet>165</a> <span class="kw">impl</span><T: Config> Pallet<T> {
|
||||
<a href=#166 id=166 data-nosnippet>166</a> <span class="kw">fn </span>transfer(_from: T::AccountId, _to: T::AccountId, amount: T::Balance) {
|
||||
<a href=#167 id=167 data-nosnippet>167</a> <span class="macro">assert!</span>(amount >= T::MinTransfer::get());
|
||||
<a href=#168 id=168 data-nosnippet>168</a> <span class="macro">unimplemented!</span>();
|
||||
<a href=#169 id=169 data-nosnippet>169</a> }
|
||||
<a href=#170 id=170 data-nosnippet>170</a> }
|
||||
<a href=#171 id=171 data-nosnippet>171</a>}
|
||||
<a href=#172 id=172 data-nosnippet>172</a>
|
||||
<a href=#173 id=173 data-nosnippet>173</a><span class="attr">#[docify::export]
|
||||
<a href=#174 id=174 data-nosnippet>174</a></span><span class="kw">mod </span>with_system {
|
||||
<a href=#175 id=175 data-nosnippet>175</a> <span class="kw">use super</span>::<span class="kw-2">*</span>;
|
||||
<a href=#176 id=176 data-nosnippet>176</a>
|
||||
<a href=#177 id=177 data-nosnippet>177</a> <span class="kw">pub trait </span>SystemConfig {
|
||||
<a href=#178 id=178 data-nosnippet>178</a> <span class="kw">type </span>AccountId: From<[u8; <span class="number">32</span>]>;
|
||||
<a href=#179 id=179 data-nosnippet>179</a> }
|
||||
<a href=#180 id=180 data-nosnippet>180</a>
|
||||
<a href=#181 id=181 data-nosnippet>181</a> <span class="kw">pub trait </span>Config: SystemConfig {
|
||||
<a href=#182 id=182 data-nosnippet>182</a> <span class="kw">type </span>Balance: frame::traits::AtLeast32BitUnsigned;
|
||||
<a href=#183 id=183 data-nosnippet>183</a> <span class="kw">type </span>MinTransfer: frame::traits::Get<<span class="self">Self</span>::Balance>;
|
||||
<a href=#184 id=184 data-nosnippet>184</a> }
|
||||
<a href=#185 id=185 data-nosnippet>185</a>
|
||||
<a href=#186 id=186 data-nosnippet>186</a> <span class="kw">pub struct </span>Pallet<T: Config>(std::marker::PhantomData<T>);
|
||||
<a href=#187 id=187 data-nosnippet>187</a> <span class="kw">impl</span><T: Config> Pallet<T> {
|
||||
<a href=#188 id=188 data-nosnippet>188</a> <span class="kw">fn </span>transfer(_from: T::AccountId, _to: T::AccountId, amount: T::Balance) {
|
||||
<a href=#189 id=189 data-nosnippet>189</a> <span class="macro">assert!</span>(amount >= T::MinTransfer::get());
|
||||
<a href=#190 id=190 data-nosnippet>190</a> <span class="macro">unimplemented!</span>();
|
||||
<a href=#191 id=191 data-nosnippet>191</a> }
|
||||
<a href=#192 id=192 data-nosnippet>192</a> }
|
||||
<a href=#193 id=193 data-nosnippet>193</a>}
|
||||
<a href=#194 id=194 data-nosnippet>194</a>
|
||||
<a href=#195 id=195 data-nosnippet>195</a><span class="attr">#[docify::export]
|
||||
<a href=#196 id=196 data-nosnippet>196</a></span><span class="kw">mod </span>fully_qualified {
|
||||
<a href=#197 id=197 data-nosnippet>197</a> <span class="kw">use </span><span class="kw">super</span>::with_system::<span class="kw-2">*</span>;
|
||||
<a href=#198 id=198 data-nosnippet>198</a>
|
||||
<a href=#199 id=199 data-nosnippet>199</a> <span class="comment">// Example of using fully qualified syntax.
|
||||
<a href=#200 id=200 data-nosnippet>200</a> </span><span class="kw">type </span>AccountIdOf<T> = <T <span class="kw">as </span>SystemConfig>::AccountId;
|
||||
<a href=#201 id=201 data-nosnippet>201</a>}
|
||||
<a href=#202 id=202 data-nosnippet>202</a>
|
||||
<a href=#203 id=203 data-nosnippet>203</a><span class="attr">#[docify::export]
|
||||
<a href=#204 id=204 data-nosnippet>204</a></span><span class="kw">mod </span>fully_qualified_complicated {
|
||||
<a href=#205 id=205 data-nosnippet>205</a> <span class="kw">use </span><span class="kw">super</span>::with_system::<span class="kw-2">*</span>;
|
||||
<a href=#206 id=206 data-nosnippet>206</a>
|
||||
<a href=#207 id=207 data-nosnippet>207</a> <span class="kw">trait </span>CurrencyTrait {
|
||||
<a href=#208 id=208 data-nosnippet>208</a> <span class="kw">type </span>Balance: frame::traits::AtLeast32BitUnsigned;
|
||||
<a href=#209 id=209 data-nosnippet>209</a> <span class="kw">fn </span>more_stuff() {}
|
||||
<a href=#210 id=210 data-nosnippet>210</a> }
|
||||
<a href=#211 id=211 data-nosnippet>211</a>
|
||||
<a href=#212 id=212 data-nosnippet>212</a> <span class="kw">trait </span>Config: SystemConfig {
|
||||
<a href=#213 id=213 data-nosnippet>213</a> <span class="kw">type </span>Currency: CurrencyTrait;
|
||||
<a href=#214 id=214 data-nosnippet>214</a> }
|
||||
<a href=#215 id=215 data-nosnippet>215</a>
|
||||
<a href=#216 id=216 data-nosnippet>216</a> <span class="kw">struct </span>Pallet<T: Config>(std::marker::PhantomData<T>);
|
||||
<a href=#217 id=217 data-nosnippet>217</a> <span class="kw">impl</span><T: Config> Pallet<T> {
|
||||
<a href=#218 id=218 data-nosnippet>218</a> <span class="kw">fn </span>transfer(
|
||||
<a href=#219 id=219 data-nosnippet>219</a> _from: T::AccountId,
|
||||
<a href=#220 id=220 data-nosnippet>220</a> _to: T::AccountId,
|
||||
<a href=#221 id=221 data-nosnippet>221</a> _amount: <<T <span class="kw">as </span>Config>::Currency <span class="kw">as </span>CurrencyTrait>::Balance,
|
||||
<a href=#222 id=222 data-nosnippet>222</a> ) {
|
||||
<a href=#223 id=223 data-nosnippet>223</a> <span class="macro">unimplemented!</span>();
|
||||
<a href=#224 id=224 data-nosnippet>224</a> }
|
||||
<a href=#225 id=225 data-nosnippet>225</a> }
|
||||
<a href=#226 id=226 data-nosnippet>226</a>
|
||||
<a href=#227 id=227 data-nosnippet>227</a> <span class="doccomment">/// A common pattern in FRAME.
|
||||
<a href=#228 id=228 data-nosnippet>228</a> </span><span class="kw">type </span>BalanceOf<T> = <<T <span class="kw">as </span>Config>::Currency <span class="kw">as </span>CurrencyTrait>::Balance;
|
||||
<a href=#229 id=229 data-nosnippet>229</a>}</code></pre></div></section></main></body></html>
|
||||
+105
@@ -0,0 +1,105 @@
|
||||
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `docs/sdk/src/reference_docs/transaction_extensions.rs`."><title>transaction_extensions.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2"href="../../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../../../static.files/rustdoc-e56847b5.css"><meta name="rustdoc-vars" data-root-path="../../../" data-static-root-path="../../../static.files/" data-current-crate="pezkuwi_sdk_docs" data-themes="" data-resource-suffix="" data-rustdoc-version="1.91.1 (ed61e7d7e 2025-11-07)" data-channel="1.91.1" data-search-js="search-e256b49e.js" data-stringdex-js="stringdex-c3e638e9.js" data-settings-js="settings-c38705f0.js" ><script src="../../../static.files/storage-e2aeef58.js"></script><script defer src="../../../static.files/src-script-813739b1.js"></script><script defer src="../../../src-files.js"></script><script defer src="../../../static.files/main-6dc2a7f3.js"></script><noscript><link rel="stylesheet" href="../../../static.files/noscript-263c88ec.css"></noscript><link rel="icon" href="https://pezkuwichain.io/favicon.ico"></head><body class="rustdoc src"><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer" title="Drag to resize sidebar"></div><main><section id="main-content" class="content"><div class="main-heading"><h1><div class="sub-heading">pezkuwi_sdk_docs/reference_docs/</div>transaction_extensions.rs</h1><rustdoc-toolbar></rustdoc-toolbar></div><div class="example-wrap digits-3"><pre class="rust"><code><a href=#1 id=1 data-nosnippet>1</a><span class="doccomment">//! Transaction extensions are, briefly, a means for different chains to extend the "basic"
|
||||
<a href=#2 id=2 data-nosnippet>2</a>//! extrinsic format with custom data that can be checked by the runtime.
|
||||
<a href=#3 id=3 data-nosnippet>3</a>//!
|
||||
<a href=#4 id=4 data-nosnippet>4</a>//! # FRAME provided transaction extensions
|
||||
<a href=#5 id=5 data-nosnippet>5</a>//!
|
||||
<a href=#6 id=6 data-nosnippet>6</a>//! FRAME by default already provides the following transaction extensions:
|
||||
<a href=#7 id=7 data-nosnippet>7</a>//!
|
||||
<a href=#8 id=8 data-nosnippet>8</a>//! - [`CheckGenesis`](frame_system::CheckGenesis): Ensures that a transaction was sent for the same
|
||||
<a href=#9 id=9 data-nosnippet>9</a>//! network. Determined based on genesis.
|
||||
<a href=#10 id=10 data-nosnippet>10</a>//!
|
||||
<a href=#11 id=11 data-nosnippet>11</a>//! - [`CheckMortality`](frame_system::CheckMortality): Extends a transaction with a configurable
|
||||
<a href=#12 id=12 data-nosnippet>12</a>//! mortality.
|
||||
<a href=#13 id=13 data-nosnippet>13</a>//!
|
||||
<a href=#14 id=14 data-nosnippet>14</a>//! - [`CheckNonZeroSender`](frame_system::CheckNonZeroSender): Ensures that the sender of a
|
||||
<a href=#15 id=15 data-nosnippet>15</a>//! transaction is not the *all zero account* (all bytes of the accountid are zero).
|
||||
<a href=#16 id=16 data-nosnippet>16</a>//!
|
||||
<a href=#17 id=17 data-nosnippet>17</a>//! - [`CheckNonce`](frame_system::CheckNonce): Extends a transaction with a nonce to prevent replay
|
||||
<a href=#18 id=18 data-nosnippet>18</a>//! of transactions and to provide ordering of transactions.
|
||||
<a href=#19 id=19 data-nosnippet>19</a>//!
|
||||
<a href=#20 id=20 data-nosnippet>20</a>//! - [`CheckSpecVersion`](frame_system::CheckSpecVersion): Ensures that a transaction was built for
|
||||
<a href=#21 id=21 data-nosnippet>21</a>//! the currently active runtime.
|
||||
<a href=#22 id=22 data-nosnippet>22</a>//!
|
||||
<a href=#23 id=23 data-nosnippet>23</a>//! - [`CheckTxVersion`](frame_system::CheckTxVersion): Ensures that the transaction signer used the
|
||||
<a href=#24 id=24 data-nosnippet>24</a>//! correct encoding of the call.
|
||||
<a href=#25 id=25 data-nosnippet>25</a>//!
|
||||
<a href=#26 id=26 data-nosnippet>26</a>//! - [`CheckWeight`](frame_system::CheckWeight): Ensures that the transaction fits into the block
|
||||
<a href=#27 id=27 data-nosnippet>27</a>//! before dispatching it.
|
||||
<a href=#28 id=28 data-nosnippet>28</a>//!
|
||||
<a href=#29 id=29 data-nosnippet>29</a>//! - [`ChargeTransactionPayment`](pallet_transaction_payment::ChargeTransactionPayment): Charges
|
||||
<a href=#30 id=30 data-nosnippet>30</a>//! transaction fees from the signer based on the weight of the call using the native token.
|
||||
<a href=#31 id=31 data-nosnippet>31</a>//!
|
||||
<a href=#32 id=32 data-nosnippet>32</a>//! - [`ChargeAssetTxPayment`](pallet_asset_tx_payment::ChargeAssetTxPayment): Charges transaction
|
||||
<a href=#33 id=33 data-nosnippet>33</a>//! fees from the signer based on the weight of the call using any supported asset (including the
|
||||
<a href=#34 id=34 data-nosnippet>34</a>//! native token).
|
||||
<a href=#35 id=35 data-nosnippet>35</a>//!
|
||||
<a href=#36 id=36 data-nosnippet>36</a>//! - [`ChargeAssetTxPayment`(using
|
||||
<a href=#37 id=37 data-nosnippet>37</a>//! conversion)](pallet_asset_conversion_tx_payment::ChargeAssetTxPayment): Charges transaction
|
||||
<a href=#38 id=38 data-nosnippet>38</a>//! fees from the signer based on the weight of the call using any supported asset (including the
|
||||
<a href=#39 id=39 data-nosnippet>39</a>//! native token). The asset is converted to the native token using a pool.
|
||||
<a href=#40 id=40 data-nosnippet>40</a>//!
|
||||
<a href=#41 id=41 data-nosnippet>41</a>//! - [`SkipCheckIfFeeless`](pallet_skip_feeless_payment::SkipCheckIfFeeless): Allows transactions
|
||||
<a href=#42 id=42 data-nosnippet>42</a>//! to be processed without paying any fee. This requires that the `call` that should be
|
||||
<a href=#43 id=43 data-nosnippet>43</a>//! dispatched is augmented with the [`feeless_if`](frame_support::pallet_macros::feeless_if)
|
||||
<a href=#44 id=44 data-nosnippet>44</a>//! attribute.
|
||||
<a href=#45 id=45 data-nosnippet>45</a>//!
|
||||
<a href=#46 id=46 data-nosnippet>46</a>//! - [`CheckMetadataHash`](frame_metadata_hash_extension::CheckMetadataHash): Extends transactions
|
||||
<a href=#47 id=47 data-nosnippet>47</a>//! to include the so-called metadata hash. This is required by chains to support the generic
|
||||
<a href=#48 id=48 data-nosnippet>48</a>//! Ledger application and other similar offline wallets.
|
||||
<a href=#49 id=49 data-nosnippet>49</a>//!
|
||||
<a href=#50 id=50 data-nosnippet>50</a>//! - [`WeightReclaim`](frame_system::WeightReclaim): A transaction extension for the relay chain
|
||||
<a href=#51 id=51 data-nosnippet>51</a>//! that reclaims unused weight after executing a transaction.
|
||||
<a href=#52 id=52 data-nosnippet>52</a>//!
|
||||
<a href=#53 id=53 data-nosnippet>53</a>//! - [`StorageWeightReclaim`](cumulus_pallet_weight_reclaim::StorageWeightReclaim): A transaction
|
||||
<a href=#54 id=54 data-nosnippet>54</a>//! extension for teyrchains that reclaims unused storage weight after executing a transaction.
|
||||
<a href=#55 id=55 data-nosnippet>55</a>//!
|
||||
<a href=#56 id=56 data-nosnippet>56</a>//! For more information about these extensions, follow the link to the type documentation.
|
||||
<a href=#57 id=57 data-nosnippet>57</a>//!
|
||||
<a href=#58 id=58 data-nosnippet>58</a>//! # Building a custom transaction extension
|
||||
<a href=#59 id=59 data-nosnippet>59</a>//!
|
||||
<a href=#60 id=60 data-nosnippet>60</a>//! Defining a couple of very simple transaction extensions looks like the following:
|
||||
<a href=#61 id=61 data-nosnippet>61</a></span><span class="attr">#![doc = <span class="macro">docify::embed!</span>(<span class="string">"./src/reference_docs/transaction_extensions.rs"</span>, transaction_extensions_example)]
|
||||
<a href=#62 id=62 data-nosnippet>62</a>
|
||||
<a href=#63 id=63 data-nosnippet>63</a>#[docify::export]
|
||||
<a href=#64 id=64 data-nosnippet>64</a></span><span class="kw">pub mod </span>transaction_extensions_example {
|
||||
<a href=#65 id=65 data-nosnippet>65</a> <span class="kw">use </span>codec::{Decode, DecodeWithMemTracking, Encode};
|
||||
<a href=#66 id=66 data-nosnippet>66</a> <span class="kw">use </span>scale_info::TypeInfo;
|
||||
<a href=#67 id=67 data-nosnippet>67</a> <span class="kw">use </span>sp_runtime::{
|
||||
<a href=#68 id=68 data-nosnippet>68</a> impl_tx_ext_default,
|
||||
<a href=#69 id=69 data-nosnippet>69</a> traits::{Dispatchable, TransactionExtension},
|
||||
<a href=#70 id=70 data-nosnippet>70</a> transaction_validity::TransactionValidityError,
|
||||
<a href=#71 id=71 data-nosnippet>71</a> };
|
||||
<a href=#72 id=72 data-nosnippet>72</a>
|
||||
<a href=#73 id=73 data-nosnippet>73</a> <span class="comment">// This doesn't actually check anything, but simply allows
|
||||
<a href=#74 id=74 data-nosnippet>74</a> // some arbitrary `u32` to be added to the extrinsic payload
|
||||
<a href=#75 id=75 data-nosnippet>75</a> </span><span class="attr">#[derive(Debug, Encode, Decode, DecodeWithMemTracking, Clone, Eq, PartialEq, TypeInfo)]
|
||||
<a href=#76 id=76 data-nosnippet>76</a> </span><span class="kw">pub struct </span>AddToPayload(<span class="kw">pub </span>u32);
|
||||
<a href=#77 id=77 data-nosnippet>77</a>
|
||||
<a href=#78 id=78 data-nosnippet>78</a> <span class="kw">impl</span><Call: Dispatchable> TransactionExtension<Call> <span class="kw">for </span>AddToPayload {
|
||||
<a href=#79 id=79 data-nosnippet>79</a> <span class="kw">const </span>IDENTIFIER: <span class="kw-2">&</span><span class="lifetime">'static </span>str = <span class="string">"AddToPayload"</span>;
|
||||
<a href=#80 id=80 data-nosnippet>80</a> <span class="kw">type </span>Implicit = ();
|
||||
<a href=#81 id=81 data-nosnippet>81</a> <span class="kw">type </span>Pre = ();
|
||||
<a href=#82 id=82 data-nosnippet>82</a> <span class="kw">type </span>Val = ();
|
||||
<a href=#83 id=83 data-nosnippet>83</a>
|
||||
<a href=#84 id=84 data-nosnippet>84</a> <span class="macro">impl_tx_ext_default!</span>(Call; weight validate prepare);
|
||||
<a href=#85 id=85 data-nosnippet>85</a> }
|
||||
<a href=#86 id=86 data-nosnippet>86</a>
|
||||
<a href=#87 id=87 data-nosnippet>87</a> <span class="comment">// This is the opposite; nothing will be added to the extrinsic payload,
|
||||
<a href=#88 id=88 data-nosnippet>88</a> // but the Implicit type (`1234u32`) will be added to the
|
||||
<a href=#89 id=89 data-nosnippet>89</a> // payload to be signed.
|
||||
<a href=#90 id=90 data-nosnippet>90</a> </span><span class="attr">#[derive(Debug, Encode, Decode, DecodeWithMemTracking, Clone, Eq, PartialEq, TypeInfo)]
|
||||
<a href=#91 id=91 data-nosnippet>91</a> </span><span class="kw">pub struct </span>AddToSignaturePayload;
|
||||
<a href=#92 id=92 data-nosnippet>92</a>
|
||||
<a href=#93 id=93 data-nosnippet>93</a> <span class="kw">impl</span><Call: Dispatchable> TransactionExtension<Call> <span class="kw">for </span>AddToSignaturePayload {
|
||||
<a href=#94 id=94 data-nosnippet>94</a> <span class="kw">const </span>IDENTIFIER: <span class="kw-2">&</span><span class="lifetime">'static </span>str = <span class="string">"AddToSignaturePayload"</span>;
|
||||
<a href=#95 id=95 data-nosnippet>95</a> <span class="kw">type </span>Implicit = u32;
|
||||
<a href=#96 id=96 data-nosnippet>96</a>
|
||||
<a href=#97 id=97 data-nosnippet>97</a> <span class="kw">fn </span>implicit(<span class="kw-2">&</span><span class="self">self</span>) -> <span class="prelude-ty">Result</span><<span class="self">Self</span>::Implicit, TransactionValidityError> {
|
||||
<a href=#98 id=98 data-nosnippet>98</a> <span class="prelude-val">Ok</span>(<span class="number">1234</span>)
|
||||
<a href=#99 id=99 data-nosnippet>99</a> }
|
||||
<a href=#100 id=100 data-nosnippet>100</a> <span class="kw">type </span>Pre = ();
|
||||
<a href=#101 id=101 data-nosnippet>101</a> <span class="kw">type </span>Val = ();
|
||||
<a href=#102 id=102 data-nosnippet>102</a>
|
||||
<a href=#103 id=103 data-nosnippet>103</a> <span class="macro">impl_tx_ext_default!</span>(Call; weight validate prepare);
|
||||
<a href=#104 id=104 data-nosnippet>104</a> }
|
||||
<a href=#105 id=105 data-nosnippet>105</a>}</code></pre></div></section></main></body></html>
|
||||
@@ -0,0 +1,91 @@
|
||||
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `docs/sdk/src/reference_docs/umbrella_crate.rs`."><title>umbrella_crate.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2"href="../../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../../../static.files/rustdoc-e56847b5.css"><meta name="rustdoc-vars" data-root-path="../../../" data-static-root-path="../../../static.files/" data-current-crate="pezkuwi_sdk_docs" data-themes="" data-resource-suffix="" data-rustdoc-version="1.91.1 (ed61e7d7e 2025-11-07)" data-channel="1.91.1" data-search-js="search-e256b49e.js" data-stringdex-js="stringdex-c3e638e9.js" data-settings-js="settings-c38705f0.js" ><script src="../../../static.files/storage-e2aeef58.js"></script><script defer src="../../../static.files/src-script-813739b1.js"></script><script defer src="../../../src-files.js"></script><script defer src="../../../static.files/main-6dc2a7f3.js"></script><noscript><link rel="stylesheet" href="../../../static.files/noscript-263c88ec.css"></noscript><link rel="icon" href="https://pezkuwichain.io/favicon.ico"></head><body class="rustdoc src"><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer" title="Drag to resize sidebar"></div><main><section id="main-content" class="content"><div class="main-heading"><h1><div class="sub-heading">pezkuwi_sdk_docs/reference_docs/</div>umbrella_crate.rs</h1><rustdoc-toolbar></rustdoc-toolbar></div><div class="example-wrap digits-2"><pre class="rust"><code><a href=#1 id=1 data-nosnippet>1</a><span class="doccomment">//! # Umbrella Crate
|
||||
<a href=#2 id=2 data-nosnippet>2</a>//!
|
||||
<a href=#3 id=3 data-nosnippet>3</a>//! The Pezkuwi-SDK "umbrella" is a crate that re-exports all other published crates. This makes it
|
||||
<a href=#4 id=4 data-nosnippet>4</a>//! possible to have a very small `Cargo.toml` file that only has one dependency, the umbrella
|
||||
<a href=#5 id=5 data-nosnippet>5</a>//! crate. This helps with selecting the right combination of crate versions, since otherwise 3rd
|
||||
<a href=#6 id=6 data-nosnippet>6</a>//! party tools are needed to select a compatible set of versions.
|
||||
<a href=#7 id=7 data-nosnippet>7</a>//!
|
||||
<a href=#8 id=8 data-nosnippet>8</a>//!
|
||||
<a href=#9 id=9 data-nosnippet>9</a>//! ## Features
|
||||
<a href=#10 id=10 data-nosnippet>10</a>//!
|
||||
<a href=#11 id=11 data-nosnippet>11</a>//! The umbrella crate supports no-std builds and can therefore be used in the runtime and node.
|
||||
<a href=#12 id=12 data-nosnippet>12</a>//! There are two main features: `runtime` and `node`. The `runtime` feature enables all `no-std`
|
||||
<a href=#13 id=13 data-nosnippet>13</a>//! crates, while the `node` feature enables all `std` crates. It should be used like any other
|
||||
<a href=#14 id=14 data-nosnippet>14</a>//! crate in the repo, with `default-features = false`.
|
||||
<a href=#15 id=15 data-nosnippet>15</a>//!
|
||||
<a href=#16 id=16 data-nosnippet>16</a>//! For more fine-grained control, additionally, each crate can be enabled selectively. The umbrella
|
||||
<a href=#17 id=17 data-nosnippet>17</a>//! exposes one feature per dependency. For example, if you only want to use the `frame-support`
|
||||
<a href=#18 id=18 data-nosnippet>18</a>//! crate, you can enable the `frame-support` feature.
|
||||
<a href=#19 id=19 data-nosnippet>19</a>//!
|
||||
<a href=#20 id=20 data-nosnippet>20</a>//! The umbrella exposes a few more general features:
|
||||
<a href=#21 id=21 data-nosnippet>21</a>//! - `tuples-96`: Needs to be enabled for runtimes that have more than 64 pallets.
|
||||
<a href=#22 id=22 data-nosnippet>22</a>//! - `serde`: Specifically enable `serde` en/decoding support.
|
||||
<a href=#23 id=23 data-nosnippet>23</a>//! - `experimental`: Experimental enable experimental features - should not yet used in production.
|
||||
<a href=#24 id=24 data-nosnippet>24</a>//! - `with-tracing`: Enable tracing support.
|
||||
<a href=#25 id=25 data-nosnippet>25</a>//! - `try-runtime`, `runtime-benchmarks` and `std`: These follow the standard conventions.
|
||||
<a href=#26 id=26 data-nosnippet>26</a>//! - `runtime`: As described above, enable all `no-std` crates.
|
||||
<a href=#27 id=27 data-nosnippet>27</a>//! - `node`: As described above, enable all `std` crates.
|
||||
<a href=#28 id=28 data-nosnippet>28</a>//! - There does *not* exist a dedicated docs feature. To generate docs, enable the `runtime` and
|
||||
<a href=#29 id=29 data-nosnippet>29</a>//! `node` feature. For `docs.rs` the manifest contains specific configuration to make it show up
|
||||
<a href=#30 id=30 data-nosnippet>30</a>//! all re-exports.
|
||||
<a href=#31 id=31 data-nosnippet>31</a>//!
|
||||
<a href=#32 id=32 data-nosnippet>32</a>//! There is a specific [`zepter`](https://github.com/ggwpez/zepter) check in place to ensure that
|
||||
<a href=#33 id=33 data-nosnippet>33</a>//! the features of the umbrella are correctly configured. This check is run in CI and locally when
|
||||
<a href=#34 id=34 data-nosnippet>34</a>//! running `zepter`.
|
||||
<a href=#35 id=35 data-nosnippet>35</a>//!
|
||||
<a href=#36 id=36 data-nosnippet>36</a>//! ## Generation
|
||||
<a href=#37 id=37 data-nosnippet>37</a>//!
|
||||
<a href=#38 id=38 data-nosnippet>38</a>//! The umbrella crate needs to be updated every time when a new crate is added or removed from the
|
||||
<a href=#39 id=39 data-nosnippet>39</a>//! workspace. It is checked in CI by calling its generation script. The generation script is
|
||||
<a href=#40 id=40 data-nosnippet>40</a>//! located in `./scripts/generate-umbrella.py` and needs dependency `cargo_workspace`.
|
||||
<a href=#41 id=41 data-nosnippet>41</a>//!
|
||||
<a href=#42 id=42 data-nosnippet>42</a>//! Example: `python3 scripts/generate-umbrella.py --sdk . --version 1.9.0`
|
||||
<a href=#43 id=43 data-nosnippet>43</a>//!
|
||||
<a href=#44 id=44 data-nosnippet>44</a>//! ## Usage
|
||||
<a href=#45 id=45 data-nosnippet>45</a>//!
|
||||
<a href=#46 id=46 data-nosnippet>46</a>//! > Note: You can see a live example in the `staging-node-cli` and `kitchensink-runtime` crates.
|
||||
<a href=#47 id=47 data-nosnippet>47</a>//!
|
||||
<a href=#48 id=48 data-nosnippet>48</a>//! The umbrella crate can be added to your runtime crate like this:
|
||||
<a href=#49 id=49 data-nosnippet>49</a>//!
|
||||
<a href=#50 id=50 data-nosnippet>50</a>//! `pezkuwi-sdk = { path = "../../../../umbrella", features = ["runtime"], default-features =
|
||||
<a href=#51 id=51 data-nosnippet>51</a>//! false }`
|
||||
<a href=#52 id=52 data-nosnippet>52</a>//!
|
||||
<a href=#53 id=53 data-nosnippet>53</a>//! or for a node:
|
||||
<a href=#54 id=54 data-nosnippet>54</a>//!
|
||||
<a href=#55 id=55 data-nosnippet>55</a>//! `pezkuwi-sdk = { path = "../../../../umbrella", features = ["node"], default-features = false
|
||||
<a href=#56 id=56 data-nosnippet>56</a>//! }`
|
||||
<a href=#57 id=57 data-nosnippet>57</a>//!
|
||||
<a href=#58 id=58 data-nosnippet>58</a>//! In the code, it is then possible to bring all dependencies into scope via:
|
||||
<a href=#59 id=59 data-nosnippet>59</a>//!
|
||||
<a href=#60 id=60 data-nosnippet>60</a>//! `use pezkuwi_sdk::*;`
|
||||
<a href=#61 id=61 data-nosnippet>61</a>//!
|
||||
<a href=#62 id=62 data-nosnippet>62</a>//! ### Known Issues
|
||||
<a href=#63 id=63 data-nosnippet>63</a>//!
|
||||
<a href=#64 id=64 data-nosnippet>64</a>//! The only known issue so far is the fact that the `use` statement brings the dependencies only
|
||||
<a href=#65 id=65 data-nosnippet>65</a>//! into the outer module scope - not the global crate scope. For example, the following code would
|
||||
<a href=#66 id=66 data-nosnippet>66</a>//! need to be adjusted:
|
||||
<a href=#67 id=67 data-nosnippet>67</a>//!
|
||||
<a href=#68 id=68 data-nosnippet>68</a>//! ```rust
|
||||
<a href=#69 id=69 data-nosnippet>69</a>//! use pezkuwi_sdk::*;
|
||||
<a href=#70 id=70 data-nosnippet>70</a>//!
|
||||
<a href=#71 id=71 data-nosnippet>71</a>//! mod foo {
|
||||
<a href=#72 id=72 data-nosnippet>72</a>//! // This does sadly not compile:
|
||||
<a href=#73 id=73 data-nosnippet>73</a>//! frame_support::parameter_types! { }
|
||||
<a href=#74 id=74 data-nosnippet>74</a>//!
|
||||
<a href=#75 id=75 data-nosnippet>75</a>//! // Instead, we need to do this (or add an equivalent `use` statement):
|
||||
<a href=#76 id=76 data-nosnippet>76</a>//! pezkuwi_sdk::frame_support::parameter_types! { }
|
||||
<a href=#77 id=77 data-nosnippet>77</a>//! }
|
||||
<a href=#78 id=78 data-nosnippet>78</a>//! ```
|
||||
<a href=#79 id=79 data-nosnippet>79</a>//!
|
||||
<a href=#80 id=80 data-nosnippet>80</a>//! Apart from this, no issues are known. There could be some bugs with how macros locate their own
|
||||
<a href=#81 id=81 data-nosnippet>81</a>//! re-exports. Please [report issues](https://github.com/pezkuwichain/pezkuwi-sdk/issues) that arise from using this crate.
|
||||
<a href=#82 id=82 data-nosnippet>82</a>//!
|
||||
<a href=#83 id=83 data-nosnippet>83</a>//! ## Dependencies
|
||||
<a href=#84 id=84 data-nosnippet>84</a>//!
|
||||
<a href=#85 id=85 data-nosnippet>85</a>//! The umbrella crate re-exports all published crates, with a few exceptions:
|
||||
<a href=#86 id=86 data-nosnippet>86</a>//! - Runtime crates like `pezkuwichain-runtime` etc are not exported. This otherwise leads to very
|
||||
<a href=#87 id=87 data-nosnippet>87</a>//! weird compile errors and should not be needed anyway.
|
||||
<a href=#88 id=88 data-nosnippet>88</a>//! - Example and fuzzing crates are not exported. This is currently detected by checking the name
|
||||
<a href=#89 id=89 data-nosnippet>89</a>//! of the crate for these magic words. In the future, it will utilize custom metadata, as it is
|
||||
<a href=#90 id=90 data-nosnippet>90</a>//! done in the `pezkuwichain-runtime` crate.
|
||||
<a href=#91 id=91 data-nosnippet>91</a>//! - The umbrella crate itself. Should be obvious :)</span></code></pre></div></section></main></body></html>
|
||||
@@ -0,0 +1,158 @@
|
||||
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `docs/sdk/src/reference_docs/wasm_meta_protocol.rs`."><title>wasm_meta_protocol.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2"href="../../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../../../static.files/rustdoc-e56847b5.css"><meta name="rustdoc-vars" data-root-path="../../../" data-static-root-path="../../../static.files/" data-current-crate="pezkuwi_sdk_docs" data-themes="" data-resource-suffix="" data-rustdoc-version="1.91.1 (ed61e7d7e 2025-11-07)" data-channel="1.91.1" data-search-js="search-e256b49e.js" data-stringdex-js="stringdex-c3e638e9.js" data-settings-js="settings-c38705f0.js" ><script src="../../../static.files/storage-e2aeef58.js"></script><script defer src="../../../static.files/src-script-813739b1.js"></script><script defer src="../../../src-files.js"></script><script defer src="../../../static.files/main-6dc2a7f3.js"></script><noscript><link rel="stylesheet" href="../../../static.files/noscript-263c88ec.css"></noscript><link rel="icon" href="https://pezkuwichain.io/favicon.ico"></head><body class="rustdoc src"><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer" title="Drag to resize sidebar"></div><main><section id="main-content" class="content"><div class="main-heading"><h1><div class="sub-heading">pezkuwi_sdk_docs/reference_docs/</div>wasm_meta_protocol.rs</h1><rustdoc-toolbar></rustdoc-toolbar></div><div class="example-wrap digits-3"><pre class="rust"><code><a href=#1 id=1 data-nosnippet>1</a><span class="doccomment">//! # WASM Meta Protocol
|
||||
<a href=#2 id=2 data-nosnippet>2</a>//!
|
||||
<a href=#3 id=3 data-nosnippet>3</a>//! All Substrate based chains adhere to a unique architectural design novel to the Pezkuwi
|
||||
<a href=#4 id=4 data-nosnippet>4</a>//! ecosystem. We refer to this design as the "**WASM Meta Protocol**".
|
||||
<a href=#5 id=5 data-nosnippet>5</a>//!
|
||||
<a href=#6 id=6 data-nosnippet>6</a>//! Consider the fact that a traditional blockchain software is usually a monolithic artifact.
|
||||
<a href=#7 id=7 data-nosnippet>7</a>//! **Upgrading any part of the system implies upgrading the entire system**. This has historically
|
||||
<a href=#8 id=8 data-nosnippet>8</a>//! led to cumbersome forkful upgrades to be the status quo in blockchain ecosystems. In other
|
||||
<a href=#9 id=9 data-nosnippet>9</a>//! words, the entire node software is the specification of the blockchain's [`state transition
|
||||
<a href=#10 id=10 data-nosnippet>10</a>//! function`](crate::reference_docs::blockchain_state_machines).
|
||||
<a href=#11 id=11 data-nosnippet>11</a>//!
|
||||
<a href=#12 id=12 data-nosnippet>12</a>//! Moreover, the idea of "storing code in the state" is explored in the context of smart contracts
|
||||
<a href=#13 id=13 data-nosnippet>13</a>//! platforms, but has not been expanded further.
|
||||
<a href=#14 id=14 data-nosnippet>14</a>//!
|
||||
<a href=#15 id=15 data-nosnippet>15</a>//! Substrate mixes these two ideas together, and takes the novel approach of storing the
|
||||
<a href=#16 id=16 data-nosnippet>16</a>//! blockchain's main "state transition function" in the main blockchain state, in the same fashion
|
||||
<a href=#17 id=17 data-nosnippet>17</a>//! that a smart contract platform stores the code of individual contracts in its state. As noted in
|
||||
<a href=#18 id=18 data-nosnippet>18</a>//! [`crate::reference_docs::blockchain_state_machines`], this state transition function is called
|
||||
<a href=#19 id=19 data-nosnippet>19</a>//! the **Runtime**, and WASM is chosen as the bytecode. The Runtime is stored under a special key
|
||||
<a href=#20 id=20 data-nosnippet>20</a>//! in the state (see [`sp_core::storage::well_known_keys`]) and can be updated as a part of the
|
||||
<a href=#21 id=21 data-nosnippet>21</a>//! state transition function's execution, just like a user's account balance can be updated.
|
||||
<a href=#22 id=22 data-nosnippet>22</a>//!
|
||||
<a href=#23 id=23 data-nosnippet>23</a>//! > Note that while we drew an analogy between smart contracts and runtimes in the above, there
|
||||
<a href=#24 id=24 data-nosnippet>24</a>//! > are fundamental differences between the two, explained in
|
||||
<a href=#25 id=25 data-nosnippet>25</a>//! > [`crate::reference_docs::runtime_vs_smart_contract`].
|
||||
<a href=#26 id=26 data-nosnippet>26</a>//!
|
||||
<a href=#27 id=27 data-nosnippet>27</a>//! The rest of the system that is NOT the state transition function is called the
|
||||
<a href=#28 id=28 data-nosnippet>28</a>//! [**Node**](crate::reference_docs::glossary#node), and is a normal binary that is compiled from
|
||||
<a href=#29 id=29 data-nosnippet>29</a>//! Rust to different hardware targets.
|
||||
<a href=#30 id=30 data-nosnippet>30</a>//!
|
||||
<a href=#31 id=31 data-nosnippet>31</a>//! This design enables all Substrate-based chains to be fork-less-ly upgradeable, because the
|
||||
<a href=#32 id=32 data-nosnippet>32</a>//! Runtime can be updated on the fly, within the execution of a block, and the node is (for the
|
||||
<a href=#33 id=33 data-nosnippet>33</a>//! most part) oblivious to the change that is happening.
|
||||
<a href=#34 id=34 data-nosnippet>34</a>//!
|
||||
<a href=#35 id=35 data-nosnippet>35</a>//! Therefore, the high-level architecture of a any Substrate-based chain can be demonstrated as
|
||||
<a href=#36 id=36 data-nosnippet>36</a>//! follows:
|
||||
<a href=#37 id=37 data-nosnippet>37</a></span><span class="attr">#![doc = <span class="macro">simple_mermaid::mermaid!</span>(<span class="string">"../../../mermaid/substrate_simple.mmd"</span>)]
|
||||
<a href=#38 id=38 data-nosnippet>38</a></span><span class="doccomment">//!
|
||||
<a href=#39 id=39 data-nosnippet>39</a>//! The node and the runtime need to communicate. This is done through two concepts:
|
||||
<a href=#40 id=40 data-nosnippet>40</a>//!
|
||||
<a href=#41 id=41 data-nosnippet>41</a>//! 1. **Host functions**: a way for the (WASM) runtime to talk to the node. All host functions are
|
||||
<a href=#42 id=42 data-nosnippet>42</a>//! defined in [`sp_io`]. For example, [`sp_io::storage`] are the set of host functions that
|
||||
<a href=#43 id=43 data-nosnippet>43</a>//! allow the runtime to read and write data to the on-chain state.
|
||||
<a href=#44 id=44 data-nosnippet>44</a>//! 2. **Runtime APIs**: a way for the node to talk to the WASM runtime. Runtime APIs are defined
|
||||
<a href=#45 id=45 data-nosnippet>45</a>//! using macros and utilities in [`sp_api`]. For example, [`sp_api::Core`] is the most
|
||||
<a href=#46 id=46 data-nosnippet>46</a>//! fundamental runtime API that any blockchain must implement in order to be able to (re)
|
||||
<a href=#47 id=47 data-nosnippet>47</a>//! execute blocks.
|
||||
<a href=#48 id=48 data-nosnippet>48</a></span><span class="attr">#![doc = <span class="macro">simple_mermaid::mermaid!</span>(<span class="string">"../../../mermaid/substrate_client_runtime.mmd"</span>)]
|
||||
<a href=#49 id=49 data-nosnippet>49</a></span><span class="doccomment">//!
|
||||
<a href=#50 id=50 data-nosnippet>50</a>//! A runtime must have a set of runtime APIs in order to have any meaningful blockchain
|
||||
<a href=#51 id=51 data-nosnippet>51</a>//! functionality, but it can also expose more APIs. See
|
||||
<a href=#52 id=52 data-nosnippet>52</a>//! [`crate::reference_docs::custom_runtime_api_rpc`] as an example of how to add custom runtime
|
||||
<a href=#53 id=53 data-nosnippet>53</a>//! APIs to your FRAME-based runtime.
|
||||
<a href=#54 id=54 data-nosnippet>54</a>//!
|
||||
<a href=#55 id=55 data-nosnippet>55</a>//! Similarly, for a runtime to be "compatible" with a node, the node must implement the full set of
|
||||
<a href=#56 id=56 data-nosnippet>56</a>//! host functions that the runtime at any point in time requires. Given the fact that a runtime can
|
||||
<a href=#57 id=57 data-nosnippet>57</a>//! evolve in time, and a blockchain node (typically) wishes to be capable of re-executing all the
|
||||
<a href=#58 id=58 data-nosnippet>58</a>//! previous blocks, this means that a node must always maintain support for the old host functions.
|
||||
<a href=#59 id=59 data-nosnippet>59</a>//! **This implies that adding a new host function is a big commitment and should be done with
|
||||
<a href=#60 id=60 data-nosnippet>60</a>//! care**. This is why, for example, adding a new host function to Pezkuwi always requires an RFC.
|
||||
<a href=#61 id=61 data-nosnippet>61</a>//! Learn how to add a new host function to your runtime in
|
||||
<a href=#62 id=62 data-nosnippet>62</a>//! [`crate::reference_docs::custom_host_functions`].
|
||||
<a href=#63 id=63 data-nosnippet>63</a>//!
|
||||
<a href=#64 id=64 data-nosnippet>64</a>//! ## Node vs. Runtime
|
||||
<a href=#65 id=65 data-nosnippet>65</a>//!
|
||||
<a href=#66 id=66 data-nosnippet>66</a>//! A common question is: which components of the system end up being part of the node, and which
|
||||
<a href=#67 id=67 data-nosnippet>67</a>//! ones of the runtime?
|
||||
<a href=#68 id=68 data-nosnippet>68</a>//!
|
||||
<a href=#69 id=69 data-nosnippet>69</a>//! Recall from [`crate::reference_docs::blockchain_state_machines`] that the runtime is the state
|
||||
<a href=#70 id=70 data-nosnippet>70</a>//! transition function. Anything that needs to influence how your blockchain's state is updated,
|
||||
<a href=#71 id=71 data-nosnippet>71</a>//! should be a part of the runtime. For example, the logic around currency, governance, identity or
|
||||
<a href=#72 id=72 data-nosnippet>72</a>//! any other application-specific logic that has to do with the state is part of the runtime.
|
||||
<a href=#73 id=73 data-nosnippet>73</a>//!
|
||||
<a href=#74 id=74 data-nosnippet>74</a>//! Anything that does not have to do with the state-transition function and will only
|
||||
<a href=#75 id=75 data-nosnippet>75</a>//! facilitate/enable it is part of the node. For example, the database, networking, and even
|
||||
<a href=#76 id=76 data-nosnippet>76</a>//! consensus algorithm are all node-side components.
|
||||
<a href=#77 id=77 data-nosnippet>77</a>//!
|
||||
<a href=#78 id=78 data-nosnippet>78</a>//! > The consensus is to your runtime what HTTP is to a web-application. It is the underlying
|
||||
<a href=#79 id=79 data-nosnippet>79</a>//! > engine that enables trustless execution of the runtime in a distributed manner whilst
|
||||
<a href=#80 id=80 data-nosnippet>80</a>//! > maintaining a canonical outcome of that execution.
|
||||
<a href=#81 id=81 data-nosnippet>81</a></span><span class="attr">#![doc = <span class="macro">simple_mermaid::mermaid!</span>(<span class="string">"../../../mermaid/substrate_with_frame.mmd"</span>)]
|
||||
<a href=#82 id=82 data-nosnippet>82</a></span><span class="doccomment">//!
|
||||
<a href=#83 id=83 data-nosnippet>83</a>//! ## State
|
||||
<a href=#84 id=84 data-nosnippet>84</a>//!
|
||||
<a href=#85 id=85 data-nosnippet>85</a>//! From the previous sections, we know that the database component is part of the node, not the
|
||||
<a href=#86 id=86 data-nosnippet>86</a>//! runtime. We also hinted that a set of host functions ([`sp_io::storage`]) are how the runtime
|
||||
<a href=#87 id=87 data-nosnippet>87</a>//! issues commands to the node to read/write to the state. Let's dive deeper into this.
|
||||
<a href=#88 id=88 data-nosnippet>88</a>//!
|
||||
<a href=#89 id=89 data-nosnippet>89</a>//! The state of the blockchain, what we seek to come to consensus about, is indeed *kept* in the
|
||||
<a href=#90 id=90 data-nosnippet>90</a>//! node side. Nonetheless, the runtime is the only component that:
|
||||
<a href=#91 id=91 data-nosnippet>91</a>//!
|
||||
<a href=#92 id=92 data-nosnippet>92</a>//! 1. Can update the state.
|
||||
<a href=#93 id=93 data-nosnippet>93</a>//! 2. Can fully interpret the state.
|
||||
<a href=#94 id=94 data-nosnippet>94</a>//!
|
||||
<a href=#95 id=95 data-nosnippet>95</a>//! In fact, [`sp_core::storage::well_known_keys`] are the only state keys that the node side is
|
||||
<a href=#96 id=96 data-nosnippet>96</a>//! aware of. The rest of the state, including what logic the runtime has, what balance each user
|
||||
<a href=#97 id=97 data-nosnippet>97</a>//! has and such, are all only comprehensible to the runtime.
|
||||
<a href=#98 id=98 data-nosnippet>98</a></span><span class="attr">#![doc = <span class="macro">simple_mermaid::mermaid!</span>(<span class="string">"../../../mermaid/state.mmd"</span>)]
|
||||
<a href=#99 id=99 data-nosnippet>99</a></span><span class="doccomment">//!
|
||||
<a href=#100 id=100 data-nosnippet>100</a>//! In the above diagram, all of the state keys and values are opaque bytes to the node. The node
|
||||
<a href=#101 id=101 data-nosnippet>101</a>//! does not know what they mean, and it does not know what is the type of the corresponding value
|
||||
<a href=#102 id=102 data-nosnippet>102</a>//! (e.g. if it is a number of a vector). Contrary, the runtime knows both the meaning of their
|
||||
<a href=#103 id=103 data-nosnippet>103</a>//! keys, and the type of the values.
|
||||
<a href=#104 id=104 data-nosnippet>104</a>//!
|
||||
<a href=#105 id=105 data-nosnippet>105</a>//! This opaque-ness is the fundamental reason why Substrate-based chains can fork-less-ly upgrade:
|
||||
<a href=#106 id=106 data-nosnippet>106</a>//! because the node side code is kept oblivious to all of the details of the state transition
|
||||
<a href=#107 id=107 data-nosnippet>107</a>//! function. Therefore, the state transition function can freely upgrade without the node needing
|
||||
<a href=#108 id=108 data-nosnippet>108</a>//! to know.
|
||||
<a href=#109 id=109 data-nosnippet>109</a>//!
|
||||
<a href=#110 id=110 data-nosnippet>110</a>//! ## Native Runtime
|
||||
<a href=#111 id=111 data-nosnippet>111</a>//!
|
||||
<a href=#112 id=112 data-nosnippet>112</a>//! Historically, the node software also kept a native copy of the runtime at the time of
|
||||
<a href=#113 id=113 data-nosnippet>113</a>//! compilation within it. This used to be called the "Native Runtime". The main purpose of the
|
||||
<a href=#114 id=114 data-nosnippet>114</a>//! native runtime used to be leveraging the faster execution time and better debugging
|
||||
<a href=#115 id=115 data-nosnippet>115</a>//! infrastructure of native code. However, neither of the two arguments strongly hold and the
|
||||
<a href=#116 id=116 data-nosnippet>116</a>//! native runtime is being fully removed from the node-sdk.
|
||||
<a href=#117 id=117 data-nosnippet>117</a>//!
|
||||
<a href=#118 id=118 data-nosnippet>118</a>//! See: <https://github.com/pezkuwichain/pezkuwi-sdk/issues/97>
|
||||
<a href=#119 id=119 data-nosnippet>119</a>//!
|
||||
<a href=#120 id=120 data-nosnippet>120</a>//! > Also, note that the flags [`sc_cli::ExecutionStrategy::Native`] is already a noop and all
|
||||
<a href=#121 id=121 data-nosnippet>121</a>//! > chains built with Substrate only use WASM execution.
|
||||
<a href=#122 id=122 data-nosnippet>122</a>//!
|
||||
<a href=#123 id=123 data-nosnippet>123</a>//! ### Runtime Versions
|
||||
<a href=#124 id=124 data-nosnippet>124</a>//!
|
||||
<a href=#125 id=125 data-nosnippet>125</a>//! An important detail of the native execution worth learning about is that the node software,
|
||||
<a href=#126 id=126 data-nosnippet>126</a>//! obviously, only uses the native runtime if it is the same code as with the wasm blob stored
|
||||
<a href=#127 id=127 data-nosnippet>127</a>//! onchain. Else, nodes who run the native runtime will come to a different state transition. How
|
||||
<a href=#128 id=128 data-nosnippet>128</a>//! do nodes determine if two runtimes are the same? Through the very important
|
||||
<a href=#129 id=129 data-nosnippet>129</a>//! [`sp_version::RuntimeVersion`]. All runtimes expose their version via a runtime api
|
||||
<a href=#130 id=130 data-nosnippet>130</a>//! ([`sp_api::Core::version`]) that returns this struct. The node software, or other applications,
|
||||
<a href=#131 id=131 data-nosnippet>131</a>//! inspect this struct to examine the identity of a runtime, and to determine if two runtimes are
|
||||
<a href=#132 id=132 data-nosnippet>132</a>//! the same. Namely, [`sp_version::RuntimeVersion::spec_version`] is the main key that implies two
|
||||
<a href=#133 id=133 data-nosnippet>133</a>//! runtimes are the same.
|
||||
<a href=#134 id=134 data-nosnippet>134</a>//!
|
||||
<a href=#135 id=135 data-nosnippet>135</a>//! Therefore, it is utmost important to make sure before any runtime upgrade, the spec version is
|
||||
<a href=#136 id=136 data-nosnippet>136</a>//! updated.
|
||||
<a href=#137 id=137 data-nosnippet>137</a>//!
|
||||
<a href=#138 id=138 data-nosnippet>138</a>//! ## Example: Block Execution.
|
||||
<a href=#139 id=139 data-nosnippet>139</a>//!
|
||||
<a href=#140 id=140 data-nosnippet>140</a>//! As a final example to recap, let's look at how Substrate-based nodes execute blocks. Blocks are
|
||||
<a href=#141 id=141 data-nosnippet>141</a>//! received in the node side software as opaque blobs and in the networking layer.
|
||||
<a href=#142 id=142 data-nosnippet>142</a>//!
|
||||
<a href=#143 id=143 data-nosnippet>143</a>//! At some point, based on the consensus algorithm's rules, the node decides to import (aka.
|
||||
<a href=#144 id=144 data-nosnippet>144</a>//! *validate*) a block.
|
||||
<a href=#145 id=145 data-nosnippet>145</a>//!
|
||||
<a href=#146 id=146 data-nosnippet>146</a>//! * First, the node will fetch the state of the parent hash of the block that wishes to be
|
||||
<a href=#147 id=147 data-nosnippet>147</a>//! imported.
|
||||
<a href=#148 id=148 data-nosnippet>148</a>//! * The runtime is fetched from this state, and placed into a WASM execution environment.
|
||||
<a href=#149 id=149 data-nosnippet>149</a>//! * The [`sp_api::Core::execute_block`] runtime API is called and the block is passed in as an
|
||||
<a href=#150 id=150 data-nosnippet>150</a>//! argument.
|
||||
<a href=#151 id=151 data-nosnippet>151</a>//! * The runtime will then execute the block, and update the state accordingly. Any state update is
|
||||
<a href=#152 id=152 data-nosnippet>152</a>//! issued via the [`sp_io::storage`] host functions.
|
||||
<a href=#153 id=153 data-nosnippet>153</a>//! * Both the runtime and node will check the state-root of the state after the block execution to
|
||||
<a href=#154 id=154 data-nosnippet>154</a>//! match the one claimed in the block header.
|
||||
<a href=#155 id=155 data-nosnippet>155</a>//!
|
||||
<a href=#156 id=156 data-nosnippet>156</a>//! > Example taken from [this
|
||||
<a href=#157 id=157 data-nosnippet>157</a>//! > lecture](https://www.youtube.com/watch?v=v0cKuddbF_Q&list=PL-w_i5kwVqbkRmfDn5nzeuU1S_FFW8dDg&index=4)
|
||||
<a href=#158 id=158 data-nosnippet>158</a>//! > of the Pezkuwi Blockchain Academy.</span></code></pre></div></section></main></body></html>
|
||||
Reference in New Issue
Block a user