From 0ce38129a627cf078b5a859cedbcea11d968793a Mon Sep 17 00:00:00 2001 From: Karlo <88337245+Rqnsom@users.noreply.github.com> Date: Mon, 20 May 2024 15:44:17 +0200 Subject: [PATCH] doc: add gas-handling doc - added gas handling solution - updated obsolete docs with the latest info --- doc/final-design.md | 46 +++++++++++---------------------------- doc/gas-handling.md | 53 +++++++++++++++++++++++++++++++++++++++++++++ doc/stdlib-doc.md | 16 +++++++++----- 3 files changed, 76 insertions(+), 39 deletions(-) create mode 100644 doc/gas-handling.md diff --git a/doc/final-design.md b/doc/final-design.md index 1532e1b..1407b88 100644 --- a/doc/final-design.md +++ b/doc/final-design.md @@ -21,11 +21,11 @@ Scripts and modules have limited access to the balance transfer functionality vi ```rust /// Execute Move script transaction sent by the user. #[pallet::call_index(0)] - #[pallet::weight(T::WeightInfo::execute())] + #[pallet::weight(T::WeightInfo::execute(*gas_limit))] pub fn execute( origin: OriginFor, transaction_bc: Vec, - gas_limit: u64, + gas_limit: u32, cheque_limit: BalanceOf, ) -> DispatchResultWithPostInfo; ``` @@ -34,31 +34,33 @@ Scripts and modules have limited access to the balance transfer functionality vi /// Publish a Move module sent by the user. /// Module is published under its sender's address. #[pallet::call_index(1)] - #[pallet::weight(T::WeightInfo::publish_module())] + #[pallet::weight(T::WeightInfo::publish_module(*gas_limit))] pub fn publish_module( origin: OriginFor, bytecode: Vec, - gas_limit: u64, + gas_limit: u32, ) -> DispatchResultWithPostInfo; ``` ```rust /// Publish a Move bundle sent by the user. + /// + /// Bundle is just a set of multiple modules. #[pallet::call_index(2)] - #[pallet::weight(T::WeightInfo::publish_module_bundle())] + #[pallet::weight(T::WeightInfo::publish_module_bundle(*gas_limit))] pub fn publish_module_bundle( origin: OriginFor, bundle: Vec, - gas_limit: u64, + gas_limit: u32, ) -> DispatchResultWithPostInfo; ``` ```rust /// Publish a standard library bundle, e.g. Move-Stdlib or Substrate-Stdlib. Sudo user only. /// - /// It should be used carefully - and should not introduce backward, incompatible changes. + /// All standard libraries are published at their default address 0x1. #[pallet::call_index(3)] - #[pallet::weight(T::WeightInfo::update_stdlib())] + #[pallet::weight(T::WeightInfo::update_stdlib_bundle())] pub fn update_stdlib_bundle( origin: OriginFor, stdlib: Vec, @@ -67,30 +69,8 @@ Scripts and modules have limited access to the balance transfer functionality vi ## RPC -### Method `mvm_gasToWeight` -Convert gas to weight. - -**Parameters** - -`gas: u64` - Amount of gas. - -`at: Option` - Optional block. - ----------------------------------------------------------------- - -### Method `mvm_weightToGas` -Convert weight to gas. - -**Parameters** - -`weight: Weight` - Amount of weigth. - -`at: Option` - Optional block. - ----------------------------------------------------------------- - ### Method `mvm_estimateGasPublishModule` -Estimate gas for publishing a module. +Estimate gas and weight cost for publishing a module. **Parameters** @@ -103,7 +83,7 @@ Estimate gas for publishing a module. ---------------------------------------------------------------- ### Method `mvm_estimateGasPublishBundle` -Estimate gas for publishing a bundle. +Estimate gas and weight cost for publishing a bundle. **Parameters** @@ -116,7 +96,7 @@ Estimate gas for publishing a bundle. ---------------------------------------------------------------- ### Method `mvm_estimateGasExecuteScript` -Estimate gas for executing a Move script. +Estimate gas and weight cost for executing a Move script. **Parameters** diff --git a/doc/gas-handling.md b/doc/gas-handling.md new file mode 100644 index 0000000..1bcabf9 --- /dev/null +++ b/doc/gas-handling.md @@ -0,0 +1,53 @@ +# Gas Handling And Weight Costs In Pallet-Move + +The gas unit is an internal processing fee for publishing modules and executing scripts within the MoveVM. + +In Substrate-based blockchains, another unit, `Weight`, measures and manages the time it takes to validate a block. +Substrate defines one unit of weight as one picosecond of execution time on reference hardware. + +## Gas handling in Move layer + +From within the MoveVM, there are two different sources for gas costs: +- Cost for script execution, +- Cost for publishing modules and bundles. + +Script execution can broken down into: +- Gas cost per bytecode instruction - bytecode gas cost table can be found [here](https://github.com/eigerco/substrate-move/blob/d33762e0ec9ee82ca71d7c5991247eec135666d1/move-vm-backend-common/src/gas_schedule.rs#L39) +- Gas cost per native function call with variable gas cost depending on the input function arguments - native gas cost table can be found [here](https://github.com/eigerco/substrate-move/blob/d33762e0ec9ee82ca71d7c5991247eec135666d1/move-vm-backend-common/src/gas_schedule.rs#L166) + +It is possible to modify the table values to control the cost of script execution. +It is recommended that both tables be scaled by the same factor to preserve the proportional cost relationship between native functions and bytecode instructions. +These table values are less dependent on storage access and are more related to raw processing time. + +The cost for publishing modules and bundles is independently defined from the script execution costs and it can be controlled by modifying [gas-cost-per-byte constant](https://github.com/eigerco/substrate-move/blob/d33762e0ec9ee82ca71d7c5991247eec135666d1/move-vm-backend-common/src/gas_schedule.rs#L23). +This value was selected during the testing and benchmarks and it is an arbitrary choice specifically for the MoveVM instance running within the Substrate runtime. + +All internal MoveVM gas handling costs are defined in the same [gas schedule module](https://github.com/eigerco/substrate-move/blob/main/move-vm-backend-common/src/gas_schedule.rs) so that tweaking any gas-related factor can be done from within that module. + +## Extrinsic Weight Cost in Pallet layer + +Three main extrinsics interact with MoveVM, which stores its state within the Substrate storage: +- `publish_module` +- `publish_bundle` +- `execute` + +All above extrinsics have a `gas_limit` argument which is used as an input to the `MoveVM`. +Since the required minimum `gas_limit` can vary a lot between different extrinisic calls, the extrinsic weight cost formula also heavily depends on the `gas_limit` on top of the fixed base extrinisic cost. +That means that using more than the necessary amount of `gas_limit` leads to an unnecessarily more costly extrinsic. +For that reason, it is recommended to use `smove node rpc` estimation RPC commands which provide data about: +- the minimum required `gas_limit` to execute/publish a given script/module, +- an estimated weight cost for the extrinsic call for the given `gas_limit`. + +Previously executed Substrate benchmarks define conversion between gas limit and weight and can be found in the auto-generated file here. +To better understand the costs, it's best to use the estimation RPC methods. + +> [!NOTE] +> The same amount of `gas_limit` between different extrinsic doesn't necessarily add the equal weight cost. + +Future pallet users should monitor and observe gas handling costs once the pallet gets integrated into the actual blockchain and then recalibrate it according to their needs, if necessary, according to the info above. + +[move-stdlib]: https://github.com/eigerco/substrate-move/tree/main/language/move-stdlib +[substrate-move]: https://github.com/eigerco/substrate-move +[substrate-stdlib]: https://github.com/eigerco/substrate-stdlib +[native-fn]: https://move-language.github.io/move/functions.html?highlight=native#native-functions +[smove]: https://github.com/eigerco/smove diff --git a/doc/stdlib-doc.md b/doc/stdlib-doc.md index 5bb084e..c32c637 100644 --- a/doc/stdlib-doc.md +++ b/doc/stdlib-doc.md @@ -1,7 +1,7 @@ # Move Standard Library In Pallet-Move The standard library provides a set of common modules that should be available to every Move developer from the genesis block. -All modules within the standard library are published under the special account address 0x01 in the Move storage. +All modules within the standard library are published under the special account address `0x01` in the Move storage. The standard library is contained in two repositories: - [`move-stdlib`](move-stdlib) - commonly known set of standard library modules that can be found across all Move compatible ecosystems. @@ -15,13 +15,13 @@ Any new modules can be easily added once the end goal for the pallet user is cle In the following chapters, one can find a set of instructions that can be used to update the standard library when there is a clear need to do so. Before we delve into the next two chapters, we should mention the special kind of functions called [native functions](native-fn). -These functions don’t have a regular function body specified in Move source files like normal functions have, but instead, their implementation is integrated within the MoveVM itself. +These functions don't have a regular function body specified in Move source files like normal functions have, but instead, their implementation is integrated within the MoveVM itself. Native functions are only allowed in standard libraries, as updating them requires updating the MoveVM source code itself. ## Updates adding new Move source code modules Adding new modules to the standard library is pretty simple. -Add a module in the wanted repository and then build it as a bundle with `smove bundle` and also generate doc files with `smove docgen`. +Add a module to the wanted repository and then build it as a bundle with `smove bundle` and also generate doc files with `smove docgen`. If the standard library needs to be updated in post-genesis block settings, the `update_stdlib_bundle` extrinsic can achieve this. Note: This extrinsic can be used only by the root user. @@ -32,12 +32,16 @@ A simple example can be found in this [pull request](https://github.com/eigerco/ Adding new native functions to the standard library requires the implementation of a function body in Rust within the MoveVM code. -Feel free to use this PR as an example of how that can be done. - - TODO here +You can use these PRs as an example of how that can be done: + - in [`substrate-move`](substrate-move): [feat: add native functions for substrate_hash module](https://github.com/eigerco/substrate-move/pull/83) + - in [`substrate-stdlib`](substrate-stdlib): [feat: add new hash module with native functions](https://github.com/eigerco/substrate-stdlib/pull/4) -Hopefully, pallet users won’t need to add new native functions after the genesis block, otherwise the node's runtime will require and update containing the new version of the MoveVM instance with the latest code that includes added native functions. +Whenever native functions are added, [smove](smove) needs to update dependencies so it fetches the latest MoveVM changes and then a new version of `smove` should be published. + +Hopefully, pallet users won't need to add new native functions after the genesis block, otherwise the node's runtime will require and update containing the new version of the MoveVM instance with the latest code that includes added native functions. [move-stdlib]: https://github.com/eigerco/substrate-move/tree/main/language/move-stdlib [substrate-move]: https://github.com/eigerco/substrate-move [substrate-stdlib]: https://github.com/eigerco/substrate-stdlib [native-fn]: https://move-language.github.io/move/functions.html?highlight=native#native-functions +[smove]: https://github.com/eigerco/smove