[{"data":1,"prerenderedAt":21},["ShallowReactive",2],{"blog-detail:move-prover-tutorial":3},{"category":4,"article":5},null,{"slug":6,"category":7,"categoryLabel":8,"subcategoryLabel":9,"authorName":10,"title":11,"excerpt":12,"contentHtml":13,"coverUrl":4,"seoTitle":11,"seoDescription":14,"seoImageUrl":15,"publishedAt":16,"updatedAt":17,"readTime":18,"cover":4,"hasCover":19,"coverAlt":20},"move-prover-tutorial","research","Research","Industry Research","MoveBit","How to Verify Smart Contracts on the Sui Blockchain","Sui is the first permissionless Layer 1 blockchain designed from the ground up to enable creators and developers to build experiences that cater to the next billion users in web3. Sui is horizontally scalable to support a wide range of application development with unrivaled speed at low cost. Sui uses the Sui Move language as its smart contract language, which is derived from the Move programming language. Move, the next generation of smart contract programming language, takes security as the primary design objective. Move claims to be able to guarantee the security of smart contracts using th","\u003Cp>Sui is the first permissionless Layer 1 blockchain designed from the ground up to enable creators and developers to build experiences that cater to the next billion users in web3. Sui is horizontally scalable to support a wide range of application development with unrivaled speed at low cost. Sui uses the Sui Move language as its smart contract language, which is derived from the Move programming language. Move, the next generation of smart contract programming language, takes security as the primary design objective. Move claims to be able to guarantee the security of smart contracts using the Formal Verification tool–Move Prover (MVP). So how to use the Move Prover on Sui? Will the Move Prover become an indispensable tool for securing programming on Sui in the future?\u003C\u002Fp>\n\u003Ch2 id=\"What’s-Move-Prover\">\u003Cstrong>What’s Move Prover?\u003C\u002Fstrong>\u003C\u002Fh2>\n\u003Cp>Move Prover is a tool that uses Formal Verification to verify smart contracts written in the Move language. Formal Verification is a technique that uses rigorous mathematical methods to describe behavior and reason about the correctness of computer systems. Now it has been adopted in operating systems, compilers, and other fields where correctness is prioritized.\u003C\u002Fp>\n\u003Cp>Smart contracts deployed on the Sui blockchain manipulate various digital assets, and their correctness is also critical. Move Prover (MVP) is designed to prevent errors in smart contracts written in the Move language. Users can specify the functional properties of smart contracts using the Move Specification Language (MSL), then use the Move Prover to automatically and statically check them.\u003Cbr>Simply put, there can be two components in a Move file:\u003C\u002Fp>\n\u003Cul>\n\u003Cli>\n\u003Cp>One part is the program code, which is the part most of us are familiar with. It is written in the Move programming language (sometimes simply called the Move language). We use it to define data types, and functions.\u003C\u002Fp>\n\u003C\u002Fli>\n\u003Cli>\n\u003Cp>The other part is formal Specification. It is optional and written in the Move specification language. We use it to describe what properties the program code should satisfy. For example, describe the behavior of a function.\u003C\u002Fp>\n\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Cp>When we write formal specifications and fire up the Move Prover, it will verify whether the Move program meets these requirements according to the written specification, and help developers find potential problems as early as possible during the development stage, giving the users of the Move program confidence in the verified properties of the program.\u003Cbr>The Move Prover mainly specifies the following three aspects:\u003C\u002Fp>\n\u003Cul>\n\u003Cli>\n\u003Cp>\u003Cstrong>Struct Invariants\u003C\u002Fstrong>: Express what kind of state a structure should have throughout the time;\u003C\u002Fp>\n\u003C\u002Fli>\n\u003Cli>\n\u003Cp>\u003Cstrong>Unit Specification (per single function)\u003C\u002Fstrong>: Show what kind of specification should be followed by each function of each program;\u003C\u002Fp>\n\u003C\u002Fli>\n\u003Cli>\n\u003Cp>\u003Cstrong>State-machine Specification\u003C\u002Fstrong>: Express what kind of state specification the entire global state on the blockchain should follow.\u003C\u002Fp>\n\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Cp>Sui uses the Move language as its smart contract language. Naturally, Move Prover can also be used on Sui. Next, we will describe how to use Move Prover on Sui to verify the smart contract code.\u003C\u002Fp>\n\u003Cp>This section focuses on the Function Specifications. We will use the official core code of Sui-Framework as an example, The whole process （installation, writing specs, invoking） includes the following points:\u003C\u002Fp>\n\u003Cul>\n\u003Cli>\n\u003Cp>How to install and use Sui Move Prover;\u003C\u002Fp>\n\u003C\u002Fli>\n\u003Cli>\n\u003Cp>How to use aborts_ifto specify the possible abort conditions of functions;\u003C\u002Fp>\n\u003C\u002Fli>\n\u003Cli>\n\u003Cp>How to define the postconditions (functional properties) of functions through ensures;\u003C\u002Fp>\n\u003C\u002Fli>\n\u003Cli>\n\u003Cp>How to simplify redundant specifications through Schema.\u003C\u002Fp>\n\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Ch3 id=\"Contents-in-this-section\">\u003Cstrong>Contents in this section:\u003C\u002Fstrong>\u003C\u002Fh3>\n\u003Cp>This section focuses on the Function Specifications. We will use the official core code of Sui-Framework as an example, The whole process （installation, writing specs, invoking）includes the following points:\u003C\u002Fp>\n\u003Cul>\n\u003Cli>\n\u003Cp>How to install and use Sui Move Prover;\u003C\u002Fp>\n\u003C\u002Fli>\n\u003Cli>\n\u003Cp>How to use  \u003Ccode>aborts_if\u003C\u002Fcode> to specify the possible abort conditions of functions;\u003C\u002Fp>\n\u003C\u002Fli>\n\u003Cli>\n\u003Cp>How to define the postconditions (functional properties) of functions through \u003Ccode>ensures\u003C\u002Fcode> ；\u003C\u002Fp>\n\u003C\u002Fli>\n\u003Cli>\n\u003Cp>How to simplify redundant specifications through \u003Ccode>Schema\u003C\u002Fcode>.\u003C\u002Fp>\n\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Ch3 id=\"Install-the-dependencies-of-Move-Prover-for-Sui\">\u003Cstrong>Install the dependencies of Move Prover for Sui\u003C\u002Fstrong>\u003C\u002Fh3>\n\u003Cp>Before using Move Prover, we first install some of its external dependencies, including boogie, z3, etc. \u003Ca target=\"_blank\" rel=\"noopener\" href=\"https:\u002F\u002Fgithub.com\u002Fmove-language\u002Fmove\">The official GitHub repository of the Move language\u003C\u002Fa> provides us with files to install these commands, please execute the following command in the terminal. (If dependencies installation fails, please check if the terminal needs to be configured with a proxy.)\u003C\u002Fp>\n\u003Cpre>\u003Ccode>mkdir move_lang &amp;&amp; cd move_lang\ngit clone https:\u002F\u002Fgithub.com\u002Fmove-language\u002Fmove.git\ncd move\n.\u002Fscripts\u002Fdev_setup.sh -yp\n. ~\u002F.profile\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>After the above command is executed, type \u003Ccode>boogie \u002Fversion\u003C\u002Fcode> . If the output is something like “Boogie program verifier version X.X.X”, which means the installation has been successful.\u003C\u002Fp>\n\u003Cpre>\u003Ccode>boogie \u002Fversion\nBoogie program verifier version 2.15.8.0, Copyright (c) 2003-2014, Microsoft.\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>Secondly, install Sui Cli (installation guide: \u003Ca target=\"_blank\" rel=\"noopener\" href=\"https:\u002F\u002Fdocs.sui.io\u002Fbuild\u002Finstall\">https:\u002F\u002Fdocs.sui.io\u002Fbuild\u002Finstall\u003C\u002Fa>) and then type sui -V in the command line. If the output is similar to “sui xxx”, which means the installation has been successful.\u003C\u002Fp>\n\u003Cpre>\u003Ccode>sui -V\nsui 0.21.0\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch2 id=\"Start-Verification\">\u003Cstrong>Start Verification\u003C\u002Fstrong>\u003C\u002Fh2>\n\u003Ch3 id=\"Prepare-an-example-for-verifying\">\u003Cstrong>Prepare an example for verifying\u003C\u002Fstrong>\u003C\u002Fh3>\n\u003Ch3 id=\"Create-a-project\">\u003Cstrong>Create a project\u003C\u002Fstrong>\u003C\u002Fh3>\n\u003Cp>First, let’s create a new folder \u003Ccode>basic_balance\u003C\u002Fcode>, enter the folder and create a new Move project named \u003Ccode>BasicBalance\u003C\u002Fcode> through Sui official command \u003Ccode>sui move new BasicBalance\u003C\u002Fcode> :\u003C\u002Fp>\n\u003Cpre>\u003Ccode>mkdir basic_balance\ncd basic_balance\nsui move new BasicBalance\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>After creation, you can see that its directory structure is as follows:\u003C\u002Fp>\n\u003Cpre>\u003Ccode>BasicBalance\n|\n|---- Move.toml (text file: Project Configuration File)\n|\n`---- sources   (Directory: Source Files)\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>Now we create \u003Ccode>BasicBalance\u002Fsources\u002Fbalance.move\u003C\u002Fcode> .\u003C\u002Fp>\n\u003Cp>The content of “balance.move” is the \u003Ca target=\"_blank\" rel=\"noopener\" href=\"https:\u002F\u002Fgithub.com\u002FMystenLabs\u002Fsui\u002Fblob\u002Fmain\u002Fcrates\u002Fsui-framework\u002Fsources\u002Fbalance.move\">balance\u003C\u002Fa> module on Sui-Framework. We copy the code, delete the spec and add two new functions for the convenience of demonstration. The code is as follows:\u003C\u002Fp>\n\u003Cpre>\u003Ccode>\u002F\u002F Copyright (c) Mysten Labs, Inc.\n\u002F\u002F SPDX-License-Identifier: Apache-2.0\n\n\u002F\u002F\u002F A storable handler for Balances in general. Is used in the `Coin`\n\u002F\u002F\u002F module to allow balance operations and can be used to implement\n\u002F\u002F\u002F custom coins with `Supply` and `Balance`s.\nmodule basicbalance::balance {\n\u002F\u002F\u002F For when trying to destroy a non-zero balance.\nconst ENonZero: u64 = 0;\n\n\u002F\u002F\u002F For when an overflow is happening on Supply operations.\nconst EOverflow: u64 = 1;\n\n\u002F\u002F\u002F For when trying to withdraw more than there is.\nconst ENotEnough: u64 = 2;\n\n\u002F\u002F\u002F A Supply of T. Used for minting and burning.\n\u002F\u002F\u002F Wrapped into a `TreasuryCap` in the `Coin` module.\nstruct Supply&lt;phantom T&gt; has store {\n    value: u64\n}\n\n\u002F\u002F\u002F Storable balance - an inner struct of a Coin type.\n\u002F\u002F\u002F Can be used to store coins which don't need the key ability.\nstruct Balance&lt;phantom T&gt; has store {\n    value: u64\n}\n\n\u002F\u002F\u002F Get the amount stored in a `Balance`.\npublic fun value&lt;T&gt;(self: &amp;Balance&lt;T&gt;): u64 {\n    self.value\n}\n\n\u002F\u002F\u002F Get the `Supply` value.\npublic fun supply_value&lt;T&gt;(supply: &amp;Supply&lt;T&gt;): u64 {\n    supply.value\n}\n\n\u002F\u002F\u002F Create a new supply for type T.\npublic fun create_supply&lt;T: drop&gt;(_: T): Supply&lt;T&gt; {\n    Supply { value: 0 }\n}\n\n\u002F\u002F\u002F Increase supply by `value` and create a new `Balance&lt;T&gt;` with this value.\npublic fun increase_supply&lt;T&gt;(self: &amp;mut Supply&lt;T&gt;, value: u64): Balance&lt;T&gt; {\n    assert!(value &lt; (18446744073709551615u64 - self.value), EOverflow);\n    self.value = self.value + value;\n    Balance { value }\n}\n\n\u002F\u002F\u002F Burn a Balance&lt;T&gt; and decrease Supply&lt;T&gt;.\npublic fun decrease_supply&lt;T&gt;(self: &amp;mut Supply&lt;T&gt;, balance: Balance&lt;T&gt;): u64 {\n    let Balance { value } = balance;\n    assert!(self.value &gt;= value, EOverflow);\n    self.value = self.value - value;\n    value\n}\n\n\u002F\u002F\u002F Create a zero `Balance` for type `T`.\npublic fun zero&lt;T&gt;(): Balance&lt;T&gt; {\n    Balance { value: 0 }\n}\n\n\u002F\u002F\u002F Join two balances together.\npublic fun join&lt;T&gt;(self: &amp;mut Balance&lt;T&gt;, balance: Balance&lt;T&gt;): u64 {\n    let Balance { value } = balance;\n    self.value = self.value + value;\n    self.value\n}\n\n\u002F\u002F\u002F Split a `Balance` and take a sub balance from it.\npublic fun split&lt;T&gt;(self: &amp;mut Balance&lt;T&gt;, value: u64): Balance&lt;T&gt; {\n    assert!(self.value &gt;= value, ENotEnough);\n    self.value = self.value - value;\n    Balance { value }\n}\n\n\u002F\u002F\u002F Destroy a zero `Balance`.\npublic fun destroy_zero&lt;T&gt;(balance: Balance&lt;T&gt;) {\n    assert!(balance.value == 0, ENonZero);\n    let Balance { value: _ } = balance;\n}\n}\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>The main function of the above code is for creating \u003Ccode>Balance\u003C\u002Fcode> and \u003Ccode>Supply\u003C\u002Fcode> resources to increase, decrease, and split their values. The \u003Ccode>balance\u003C\u002Fcode> module is mainly used by the \u003Ccode>coin\u003C\u002Fcode> module, which is the core function of the Sui-Framework. Next, let’s see how to use the Move Prover to verify the functions of the \u003Ccode>balance\u003C\u002Fcode> module.\u003C\u002Fp>\n\u003Ch2 id=\"The-First-Verification-Code\">\u003Cstrong>The First Verification Code\u003C\u002Fstrong>\u003C\u002Fh2>\n\u003Cp>To give us an initial impression of the use of Move Prover, add the following code snippet to \u003Ccode>balance.move\u003C\u002Fcode> :\u003C\u002Fp>\n\u003Cpre>\u003Ccode>spec increase_supply {\npragma aborts_if_is_strict;\n}\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>Syntactically, this code can be added anywhere in the balance module, but in order to clearly understand the correspondence between the definition and the specification when reading the code, it is recommended to place it after the definition of the function \u003Ccode>increase_supply\u003C\u002Fcode> .\u003C\u002Fp>\n\u003Cp>In short, the code block \u003Ccode>spec increase_supply {...}\u003C\u002Fcode>  will contain our \u003Cstrong>property specification\u003C\u002Fstrong> for \u003Ccode>increase_supply\u003C\u002Fcode>. There are many types of property specifications, such as :\u003C\u002Fp>\n\u003Cul>\n\u003Cli>\n\u003Cp>Will this function abort? Under what circumstances it will abort abnormally?\u003C\u002Fp>\n\u003C\u002Fli>\n\u003Cli>\n\u003Cp>What conditions must be met for calling the parameters of this function?\u003C\u002Fp>\n\u003C\u002Fli>\n\u003Cli>\n\u003Cp>What is the return value of this function?\u003C\u002Fp>\n\u003C\u002Fli>\n\u003Cli>\n\u003Cp>After the function is executed, what changes will be made to the state of the virtual machine?\u003C\u002Fp>\n\u003C\u002Fli>\n\u003Cli>\n\u003Cp>What invariants will this function maintain?\u003C\u002Fp>\n\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Cp>For example, when we don’t specify any abort conditions, Move Prover allows all possible aborts by default. And in the simple snippet above, we tell the Prover with the indicator \u003Ccode>aborts_if_is_strict\u003C\u002Fcode> :\u003C\u002Fp>\n\u003Cp>\u003Ccode>I want this function to be strictly checked for possible aborts. Please report errors if any abort that is not listed by the programmer occurs.\u003C\u002Fcode>\u003C\u002Fp>\n\u003Cp>Enter the BasicBalance directory, and run the command  \u003Ccode>sui move prove -t   balance.move\u003C\u002Fcode>  ( If the dependencies installation fails, please check if the terminal needs to be configured with a proxy.), the \u003Ccode>-t\u003C\u002Fcode> in the command represents the object file that needs to be specified for verification, the \u003Ccode>balance.move\u003C\u002Fcode> is the file to be verified.\u003C\u002Fp>\n\u003Cpre>\u003Ccode>sui move prove -t balance.move\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>This command invokes Move Prover to check the code of the current module, and you can also use the command sui move prove to check the code of all modules in the directory. After running the command, we can see that Prover reported the following error message:\u003C\u002Fp>\n\u003Cpre>\u003Ccode>error: abort not covered by any of the `aborts_if` clauses\n   ┌─ .\u002Fsources\u002Fbalance.move:51:5\n   │\n46 │           assert!(value &lt; (18446744073709551615u64 - self.value), EOverflow);\n   │           ------------------------------------------------------------------ abort happened here with code 0x1\n   ·\n51 │ ╭     spec increase_supply {\n52 │ │         pragma aborts_if_is_strict;\n53 │ │     }\n   │ ╰─────^\n   │\n   =     at .\u002Fsources\u002Fbalance.move:45: increase_supply\n   =         self = &amp;balance.Supply{value = 18446744073709551615}\n   =         value = 18467\n   =     at .\u002Fsources\u002Fbalance.move:46: increase_supply\n   =         ABORTED\n\nexiting with verification errors\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>The Prover’s output tells us that it found a situation where function increase_supply would abort, but we don’t failed to explicitly indicate the possibility of this abort. Looking at the code that triggers the abort, we can find that the exception is caused by an assertion inside the function, which shows that the parameter \u003Ccode>value\u003C\u002Fcode> must be less than\u003Cbr>\u003Ccode>(18446744073709551615u64 - self.value)\u003C\u002Fcode>. According to the prompt of the error message, we can add the following \u003Ccode>aborts_if\u003C\u002Fcode> condition:\u003C\u002Fp>\n\u003Cpre class=\"line-numbers language-Rust\" data-language=\"Rust\">\u003Ccode class=\"language-Rust\">spec increase_supply {\n    pragma aborts_if_is_strict;\n    aborts_if value &gt;= (MAX_U64 - self.value);\n}\u003C\u002Fcode>\u003C\u002Fpre>\n\n\u003Cp>After adding this condition, try to call Prover again, and there are no more verification errors. Now we can confirm with confidence: the function \u003Ccode>increase_supply\u003C\u002Fcode> would abort if and only if \u003Ccode>value &gt;= (18446744073709551615u64 - self.value)\u003C\u002Fcode>.\u003C\u002Fp>\n\u003Ch2 id=\"Verify-the-function-decrease-supply\">\u003Cstrong>Verify the function decrease_supply\u003C\u002Fstrong>\u003C\u002Fh2>\n\u003Cp>The function \u003Ccode>decrease_supply\u003C\u002Fcode> is to subtract the value of the second parameter \u003Ccode>balance\u003C\u002Fcode> from the value of the first input parameter \u003Ccode>self\u003C\u002Fcode> and return the subtracted value.\u003C\u002Fp>\n\u003Cpre class=\"line-numbers language-Rust\" data-language=\"Rust\">\u003Ccode class=\"language-Rust\">public fun decrease_supply&lt;T&gt;(self: &amp;mut Supply&lt;T&gt;, balance: Balance&lt;T&gt;): u64 {\n    let Balance { value } = balance;\n    assert!(self.value &gt;= value, EOverflow);\n    self.value = self.value - value;\n    value\n}\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch3 id=\"Specify-the-termination-condition-of-decrease-supply\">\u003Cstrong>Specify the termination condition of decrease_supply\u003C\u002Fstrong>\u003C\u002Fh3>\n\u003Cp>The \u003Ccode>decrease_supply\u003C\u002Fcode> has a possibility of aborting:\u003C\u002Fp>\n\u003Cul>\n\u003Cli>\n\u003Ccode>Self.value\u003C\u002Fcode> is less than \u003Ccode>balance.value\u003C\u002Fcode>\n\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Cp>So we can define the termination condition according to the previous example of \u003Ccode>increase_supply\u003C\u002Fcode>：\u003C\u002Fp>\n\u003Cpre class=\"line-numbers language-Rust\" data-language=\"Rust\">\u003Ccode class=\"language-Rust\">spec decrease_supply {\n    let value = balance.value;\n    aborts_if self.value &lt; value;\n}\u003C\u002Fcode>\u003C\u002Fpre>\n\n\u003Cp>As you can see, a spec block can use \u003Ccode>let\u003C\u002Fcode> to define an expression to a name and can be used repeatedly.\u003C\u002Fp>\n\u003Cp>If the function has multiple \u003Ccode>aborts_if\u003C\u002Fcode> conditions, these conditions will be connected with logical OR. Let’s look at the following function, this function does not exist in file \u003Ccode>balance.move\u003C\u002Fcode>, it is just an example:\u003C\u002Fp>\n\u003Cpre class=\"line-numbers language-Rust\" data-language=\"Rust\">\u003Ccode class=\"language-Rust\">public fun mul_div(x: u64, y: u64, z: u64): u64 {\n    let r = x * y \u002F z;\n    r\n}\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>This function is very simple, first multiply and then divide, and return the final result.\u003Cbr>It is easy to observe two conditions where the program would abort:\u003C\u002Fp>\n\u003Cul>\n\u003Cli>\n\u003Cp>The divisor \u003Ccode>z\u003C\u002Fcode> cannot be equal to \u003Ccode>0\u003C\u002Fcode>\u003C\u002Fp>\n\u003C\u002Fli>\n\u003Cli>\n\u003Cp>\u003Ccode>x * y\u003C\u002Fcode>cannot be greater than the upper limit of \u003Ccode>u64\u003C\u002Fcode>\u003Cbr>So its termination condition should be like this:\u003C\u002Fp>\n\u003Cpre class=\"line-numbers language-Rust\" data-language=\"Rust\">\u003Ccode class=\"language-Rust\">spec mul_div {\n    aborts_if z == 0;\n    aborts_if x * y &gt; MAX_U64;\n}\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>The \u003Ccode>MAX_u64\u003C\u002Fcode> is a built-in variable in the Move Specification Language (MSL), representing the maximum upper limit of \u003Ccode>u64\u003C\u002Fcode>, and also includes \u003Ccode>MAX_U128\u003C\u002Fcode>. One thing worth noting: For example, the expression \u003Ccode>a + b &gt; MAX_U64\u003C\u002Fcode> is problematic in the Move program. Because the addition on the left may cause an overflow exception. If we want to write a similar check in the Move program, we should use an expression like \u003Ccode>a &gt; MAX_U64 - b\u003C\u002Fcode> to avoid the overflow problem.\u003C\u002Fp>\n\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Cp>However, this expression is perfectly fine in Move Specification Language (MSL). Since the spec block uses the MSL language, its type system is different from Move. In MSL, all integers are of type num, which is an integer in the mathematical sense. That is, it is signed and has no size limit. When referencing data of a Move program in MSL, all built-in integer types ( \u003Ccode>u8\u003C\u002Fcode>，\u003Ccode>u64\u003C\u002Fcode> ) are automatically converted to the \u003Ccode>num\u003C\u002Fcode> type. A more detailed description of the type of system can be found in the MSL documentation.\u003C\u002Fp>\n\u003Cp>As mentioned earlier, if we don’t specify any abort conditions, Prover will not impose any restrictions on aborts.\u003C\u002Fp>\n\u003Cp>But once we give any abort condition, Prover defaults that we want to strictly check all possible aborts, so we need to list all possible conditions, which is equivalent to implicitly adding the instruction \u003Ccode>pragma aborts_if_is_strict\u003C\u002Fcode>. If only some of the conditions for abnormal exit are listed, Prover will report a verification error. However, if \u003Ccode>pragma aborts_if_is_partial\u003C\u002Fcode> is defined in the spec block, it is equivalent to telling the Prover:\u003C\u002Fp>\n\u003Cp>‘ I just want to list some of the conditions that will cause an abort, please just verify if it will abort under these conditions. ’\u003C\u002Fp>\n\u003Cp>If you are interested, you can do such a set of experiments to verify:\u003C\u002Fp>\n\u003Cul>\n\u003Cli>\n\u003Cp>When any one of the above two conditions \u003Ccode>aborts_if\u003C\u002Fcode> is deleted, Prover will report an error;\u003C\u002Fp>\n\u003C\u002Fli>\n\u003Cli>\n\u003Cp>When all conditions \u003Ccode>aborts_if\u003C\u002Fcode> are deleted at the same time, Prover will not report an error;\u003C\u002Fp>\n\u003C\u002Fli>\n\u003Cli>\n\u003Cp>When \u003Ccode>pragma aborts_if_is_partial\u003C\u002Fcode> is added, no matter how many conditions \u003Ccode>aborts_if\u003C\u002Fcode> are kept, Prover will not report an error (Of course! the conditions themselves must be correct).\u003C\u002Fp>\n\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Cp>For a more detailed understanding, you can refer to \u003Ca target=\"_blank\" rel=\"noopener\" href=\"https:\u002F\u002Fgithub.com\u002Fmove-language\u002Fmove\u002Fblob\u002Fmain\u002Flanguage\u002Fmove-prover\u002Fdoc\u002Fuser\u002Fspec-lang.md\">the MSL documentation\u003C\u002Fa> for more information.\u003C\u002Fp>\n\u003Ch3 id=\"Specifies-the-functional-nature-of-decrease-supply\">\u003Cstrong>Specifies the functional nature of decrease_supply\u003C\u002Fstrong>\u003C\u002Fh3>\n\u003Cp>Next, we define functional properties. The below two statements \u003Ccode>ensures\u003C\u002Fcode> in the spec block gives us the functional expectation of \u003Ccode>decrease_supply\u003C\u002Fcode> :\u003C\u002Fp>\n\u003Cpre class=\"line-numbers language-Rust\" data-language=\"Rust\">\u003Ccode class=\"language-Rust\">spec decrease_supply {\n    let value = balance.value;\n    aborts_if self.value &lt; value with EOverflow;\n\n    let old_value = self.value;\n    let post new_value = self.value;\n    ensures new_value == old_value - value;\n    ensures result == balance.value;\n}\n\u003C\u002Fcode>\u003C\u002Fpre>\n\n\u003Cp>In this code, firstly using \u003Ccode>let post\u003C\u002Fcode> to define \u003Ccode>new_value\u003C\u002Fcode> as \u003Ccode>value\u003C\u002Fcode> of \u003Ccode>self\u003C\u002Fcode> after executing the function, which should be equal to \u003Ccode>self.value\u003C\u002Fcode> minus \u003Ccode>balance.value\u003C\u002Fcode> before function execution. Then, \u003Ccode>result\u003C\u002Fcode> is a special name and represents the return value, that is \u003Ccode>balance.value\u003C\u002Fcode> .\u003C\u002Fp>\n\u003Cp>The above spec block can also be replaced with the following:\u003C\u002Fp>\n\u003Cpre class=\"line-numbers language-Rust\" data-language=\"Rust\">\u003Ccode class=\"language-Rust\">spec decrease_supply {\n    let value = balance.value;\n    aborts_if self.value &lt; value with EOverflow;\n\n    ensures self.value == old(self.value) - value;\n    ensures result == balance.value;\n}\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>It can be seen that we have deleted the definitions of the two variables \u003Ccode>old_value\u003C\u002Fcode> and \u003Ccode>new_value\u003C\u002Fcode>, because \u003Ccode>ensures\u003C\u002Fcode> means that the function has been executed, so \u003Ccode>self.value\u003C\u002Fcode> which is after \u003Ccode>ensures\u003C\u002Fcode> means that the value has been subtracted from \u003Ccode>balance.value, old()\u003C\u002Fcode> Represents the value before the function is executed, so \u003Ccode>self.value\u003C\u002Fcode> is equivalent to the above \u003Ccode>new_value\u003C\u002Fcode>, and \u003Ccode>old(self.value)\u003C\u002Fcode> is equivalent to the above \u003Ccode>old_value\u003C\u002Fcode>.\u003C\u002Fp>\n\u003Ch2 id=\"Use-Schema-to-Simplify-Redundant-Specifications\">\u003Cstrong>Use Schema to Simplify Redundant Specifications\u003C\u002Fstrong>\u003C\u002Fh2>\n\u003Cp>Congratulations! So far, we have completed the termination conditions and property verification of some functions step by step. But there is a problem. Take function \u003Ccode>mul_div\u003C\u002Fcode> as an example. If another function calls function \u003Ccode>mul_div\u003C\u002Fcode>, how should the spec of this function be written? For example, the following function \u003Ccode>foo\u003C\u002Fcode>, the function \u003Ccode>foo\u003C\u002Fcode> , and \u003Ccode>mul_div\u003C\u002Fcode> both do not exist in \u003Ccode>balance.move\u003C\u002Fcode>, just a simple example is written for ease of illustration:\u003C\u002Fp>\n\u003Cpre class=\"line-numbers language-Rust\" data-language=\"Rust\">\u003Ccode class=\"language-Rust\">public fun mul_div(x: u64, y: u64, z: u64): u64 {\n    let r = x * y \u002F z;\n    r\n}\n\npublic fun foo(a: u64, b: u64, c: u64): u64 {\n    let r = mul_div(a,b,c);\n    r\n}\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>First of all, it is certain that the function \u003Ccode>foo\u003C\u002Fcode> will also have the termination condition and properties of the function \u003Ccode>mul_div\u003C\u002Fcode>. If you want to write the spec of \u003Ccode>foo\u003C\u002Fcode>, it is actually simple, just write the spec of \u003Ccode>mul_div\u003C\u002Fcode> in \u003Ccode>foo\u003C\u002Fcode> one more time, for example:\u003C\u002Fp>\n\u003Cpre class=\"line-numbers language-Rust\" data-language=\"Rust\">\u003Ccode class=\"language-Rust\">spec mul_div {\n    aborts_if z == 0;\n    aborts_if x * y &gt; MAX_U64;\n}\n\nspec foo {\n    aborts_if c == 0;\n    aborts_if a * b &gt; MAX_U64;\n}\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>The verification logic of the above two functions is basically the same, but it will be very cumbersome to write them separately, especially since many modules in the project will call each other, and the same function may be called by multiple functions of different modules, which is obviously not a reasonable way to write all of this function specs. We hope to make them more concise so that the file structure will be clearer.\u003C\u002Fp>\n\u003Cp>Schema is a means of building specifications by grouping attributes. Semantically, they are also syntactic sugar and used in spec blocks which is equivalent to expanding the conditions they contain to functions, structs, or modules.\u003C\u002Fp>\n\u003Cp>As the most obvious example, the spec blocks of \u003Ccode>mul_div\u003C\u002Fcode> and \u003Ccode>foo\u003C\u002Fcode> are slightly different except for the variable names, the overall structure can be said to be exactly the same. To simplify them, let’s create a Schema:\u003C\u002Fp>\n\u003Cpre class=\"line-numbers language-Rust\" data-language=\"Rust\">\u003Ccode class=\"language-Rust\">spec schema MulDivSchema {\n    x: u64;\n    y: u64;\n    z: u64;\n\n    aborts_if z == 0;\n    aborts_if x * y &gt; MAX_U64;\n}\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>This Schema declares three types of variables and some conditions that these variables should meet. When you want to use this Schema in other places, you need to use \u003Ccode>include MulDivSchema{x: XX, y: YY, z: ZZ};\u003C\u002Fcode> to import it. Among them, \u003Ccode>XX\u003C\u002Fcode> , \u003Ccode>YY\u003C\u002Fcode> , and \u003Ccode>ZZ\u003C\u002Fcode> are respectively the three parameters passed into the Schema. If the expression is exactly the same as the corresponding variable name, you can write the variable name, or omit it directly, but there is one thing to note: the function parameters in the move code can be directly passed to the Schema as parameters, but the variables defined in the function cannot be passed in directly.\u003C\u002Fp>\n\u003Cp>With the above Schema definition, we can now simplify the previous spec:\u003C\u002Fp>\n\u003Cpre class=\"line-numbers language-Rust\" data-language=\"Rust\">\u003Ccode class=\"language-Rust\">spec mul_div {\n    include MulDivSchema;\n}\n\nspec foo {\n    include MulDivSchema{x: a, y: b, z: c};\n}\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch2 id=\"Practice\">\u003Cstrong>Practice\u003C\u002Fstrong>\u003C\u002Fh2>\n\u003Col>\n\u003Cli>\n\u003Cp>In addition to the above example, find another spec block (such as \u003Ccode>decrease_supply\u003C\u002Fcode> ), and split it into a Schema declaration and a spec block that uses the corresponding Schema. As an exercise, the Schema you create may not be available in this code, It seems like there is no any benefit. But it will be more convenient if other functions call \u003Ccode>decrease_supply\u003C\u002Fcode> in later development.\u003C\u002Fp>\n\u003C\u002Fli>\n\u003Cli>\n\u003Cp>We have submitted the specs of the functions \u003Ccode>increase_supply\u003C\u002Fcode> and \u003Ccode>decrease_supply\u003C\u002Fcode> in the above example to the PR list of the Sui Official Codebase ( \u003Ca target=\"_blank\" rel=\"noopener\" href=\"https:\u002F\u002Fgithub.com\u002FMystenLabs\u002Fsui\u002Fpull\u002F7440\">https:\u002F\u002Fgithub.com\u002FMystenLabs\u002Fsui\u002Fpull\u002F7440\u003C\u002Fa> ), and there are still relatively few specs in the Sui-Framework official codebase. We also call on everyone to find some functions in Sui-Framework and try to write specs by themselves. If they can run successfully, you can submit them to the PR list of the Sui Official Codebase. We believe this will make you feel more fulfilled.\u003C\u002Fp>\n\u003C\u002Fli>\n\u003C\u002Fol>\n\u003Ch2 id=\"Conclusion\">\u003Cstrong>Conclusion\u003C\u002Fstrong>\u003C\u002Fh2>\n\u003Cp>So far, we have introduced in detail how to use the Move Prover for Formal Verification to provide protection for the security of smart contracts, and we have also initially realized the power of Move Prover.\u003C\u002Fp>\n\u003Cp>More and more developers are developing Move applications and deploying Move contracts on the Move ecosystem. We strongly recommend using Move Prover and other contract auditing tools to audit the application before launching the Move DApp. If you need help with the Move contract audit, please contact us (\u003Ca target=\"_blank\" rel=\"noopener\" href=\"https:\u002F\u002Fwww.movebit.xyz\u002F\">https:\u002F\u002Fwww.movebit.xyz\u002F\u003C\u002Fa>) !\u003C\u002Fp>\n\u003Ch2 id=\"MoveBit\">\u003Cstrong>MoveBit\u003C\u002Fstrong>\u003C\u002Fh2>\n\u003Cp>MoveBit is a blockchain security company focused on the Move Ecosystem. The team consists of security professionals from academia and enterprise with 10 years of security experience. they were one of the earliest contributors to the Move ecosystem, working with Move developers to set the standard for secure Move applications and make the Move ecosystem the most secure Web3 destination.\u003C\u002Fp>\n\u003Ch3 id=\"MoveBit-Social-Media-Platforms\">\n\u003Cstrong>MoveBit Social Media Platforms\u003C\u002Fstrong>:\u003C\u002Fh3>\n\u003Cp>Official Website: \u003Ca target=\"_blank\" rel=\"noopener\" href=\"https:\u002F\u002Fwww.movebit.xyz\u002F\">https:\u002F\u002Fwww.movebit.xyz\u002F\u003C\u002Fa>\u003C\u002Fp>\n\u003Cp>Twitter: \u003Ca target=\"_blank\" rel=\"noopener\" href=\"https:\u002F\u002Ftwitter.com\u002FMoveBit_\">https:\u002F\u002Ftwitter.com\u002FMoveBit_\u003C\u002Fa>\u003C\u002Fp>\n\u003Cp>GitHub: \u003Ca target=\"_blank\" rel=\"noopener\" href=\"https:\u002F\u002Fgithub.com\u002Fmovebit\">https:\u002F\u002Fgithub.com\u002Fmovebit\u003C\u002Fa>\u003C\u002Fp>\n\u003Cp>Discord: \u003Ca target=\"_blank\" rel=\"noopener\" href=\"https:\u002F\u002Fdiscord.com\u002Finvite\u002F7wM8VU9Gyj\">https:\u002F\u002Fdiscord.com\u002Finvite\u002F7wM8VU9Gyj\u003C\u002Fa>\u003C\u002Fp>","Sui is the first permissionless Layer 1 blockchain designed from the ground up to enable creators and developers to build experiences that cater to the next billion users in web3. Sui is horizontally scalable to support a wide range of application development with unrivaled speed at low cost. Sui uses the Sui Move lang","\u002Fmedia\u002Fmovebit\u002F2022\u002F09\u002F2b36c3a7da22b02f60e79524b16e5664.png","2023-05-31T03:15:00Z","2026-08-11T18:05:56Z","18 min read",false,"How to Verify Smart Contracts on the Sui Blockchain cover image",1792635795005]