A method for optimizing wasm bytecode, an execution method, a computer device and a storage medium
Patent Information
- Authority / Receiving Office
- CN · China
- Patent Type
- Patents(China)
- Current Assignee / Owner
- Filing Date
- 2023-07-24
- Publication Date
- 2026-08-11
AI Technical Summary
[0003] The present invention aims to provide a method for optimizing Wasm bytecode, a method for executing the optimized Wasm bytecode, a computer device, and a storage medium, comprising:
Smart Images

Figure CN116931948B_ABST
Abstract
Description
Technical Field
[0001] The embodiments in this specification belong to the field of compilation technology, and in particular relate to a method and execution method for optimizing wasm bytecode, a computer device and a storage medium. Background Technology
[0002] WebAssembly, an open standard developed by the W3C community, is a secure, portable, low-level code format designed for efficient execution and compact representation. It offers near-native performance and provides a compilation target for languages such as C, C++, Java, and Go. The WASM virtual machine was initially designed to address the increasingly severe performance issues of web applications. Due to its superior characteristics, it has been adopted by a growing number of non-web projects, such as as an alternative to the EVM (Entity Virtual Machine) for blockchain smart contracts. Summary of the Invention
[0003] The present invention aims to provide a method for optimizing Wasm bytecode, a method for executing the optimized Wasm bytecode, a computer device, and a storage medium, comprising:
[0004] This application provides a method for deploying smart contracts, including:
[0005] Blockchain nodes receive transactions for deploying contracts, which include the unoptimized wasm bytecode of the contract;
[0006] The unoptimized Wasm bytecode is then optimized to obtain the optimized Wasm bytecode;
[0007] Blockchain nodes generate smart contract accounts on the blockchain and generate codehash in the smart contract account based on the optimized wasm bytecode;
[0008] The blockchain node stores the generated smart contract account on the blockchain ledger. The smart contract account includes the codehash and the corresponding optimized wasm bytecode.
[0009] This application provides a method for executing a smart contract deployed as described above, including:
[0010] A blockchain node receives a transaction that invokes a contract. The transaction specifies the address of the account to be invoked, the function to be invoked, and the parameters to be passed in. The contract is an optimized Wasm contract.
[0011] The blockchain node determines the codehash of the wasm contract through the contract account address and loads the wasm bytecode corresponding to the codehash into the wasm virtual machine.
[0012] The Wasm virtual machine reads and parses the optimized Wasm bytecode to obtain a Wasm module object;
[0013] The wasm virtual machine creates and fills linear memory based on the parsed wasm module object;
[0014] The wasm virtual machine executes the code segment in the wasm module object based on the linear memory obtained from the filling and the passed parameters.
[0015] A computer device, comprising:
[0016] processor;
[0017] and a memory containing a program, wherein when the processor executes the program, the following operations are performed:
[0018] Receive the transaction for deploying the contract, which includes the unoptimized wasm bytecode of the contract;
[0019] The unoptimized Wasm bytecode is then optimized to obtain the optimized Wasm bytecode;
[0020] Blockchain nodes generate smart contract accounts on the blockchain and generate codehash in the smart contract account based on the optimized wasm bytecode;
[0021] The blockchain node stores the generated smart contract account on the blockchain ledger. The smart contract account includes the codehash and the corresponding optimized wasm bytecode.
[0022] A storage medium for storing a program, wherein the program performs the following operations when executed:
[0023] The system receives a transaction that invokes a contract, the transaction specifying the address of the contract account being invoked, the function being invoked, and the parameters being passed in. The contract is an optimized Wasm contract.
[0024] The codehash of the wasm contract is determined by the contract account address, and the wasm bytecode corresponding to the codehash is loaded into the wasm virtual machine;
[0025] Read and parse the optimized wasm bytecode to obtain the wasm module object;
[0026] Create and fill linear memory based on the parsed wasm module object;
[0027] Based on the linear memory obtained from the filling and the passed parameters, the code segment in the wasm module object is executed. Attached Figure Description
[0028] To more clearly illustrate the technical solutions of the embodiments in this specification, the drawings used in the description of the embodiments will be briefly introduced below. Obviously, the drawings described below are only some embodiments recorded in this specification. For those skilled in the art, other drawings can be obtained based on these drawings without creative effort.
[0029] Figure 1 This is a schematic diagram illustrating the compilation and execution process of a Java program in one embodiment;
[0030] Figure 2 It is a flowchart of the process by which a compiler compiles Java source code into a wasm file;
[0031] Figure 3 This is a schematic diagram of the bytecode structure and virtual machine module in one embodiment;
[0032] Figure 4 This is a flowchart of a method in one embodiment;
[0033] Figure 5 This is a schematic diagram of a wasm file in linear memory and managed memory in one embodiment;
[0034] Figure 6 This is a schematic diagram of a wasm file in linear memory and managed memory in one embodiment;
[0035] Figure 7 This is a schematic diagram of a wasm file in linear memory and managed memory in one embodiment;
[0036] Figure 8 This is a schematic diagram of a wasm file in linear memory and managed memory in one embodiment;
[0037] Figure 9 This is a flowchart of a method in one embodiment;
[0038] Figure 10 This is a schematic diagram illustrating the creation and deployment of smart contracts in a blockchain network in one embodiment;
[0039] Figure 11 This is a schematic diagram illustrating the creation, deployment, and invocation of smart contracts in a blockchain network in one embodiment;
[0040] Figure 12 This is a schematic diagram illustrating the creation, deployment, and invocation of smart contracts in a blockchain network in one embodiment;
[0041] Figure 13 This is a schematic diagram of the bytecode structure and virtual machine module in one embodiment;
[0042] Figure 14 This is a flowchart of the method in the embodiment;
[0043] Figure 15 This is a flowchart of the method in the embodiment;
[0044] Figure 16 This is a flowchart of the method in the embodiment. Detailed Implementation
[0045] To enable those skilled in the art to better understand the technical solutions in this specification, the technical solutions in the embodiments of this specification will be clearly and completely described below with reference to the accompanying drawings. Obviously, the described embodiments are only some embodiments of this specification, and not all embodiments. Based on the embodiments in this specification, all other embodiments obtained by those skilled in the art without creative effort should fall within the scope of protection of this specification.
[0046] High-level computer languages are easier for humans to write, read, communicate, and maintain, while machine language is directly interpretable and run by computers. A compiler takes assembly or high-level computer language source programs as input and translates them into equivalent machine code in a target language. Source code is typically a high-level language, such as C or C++, while the target is the object code in machine language, sometimes also called machine code. This machine code (or "microprocessor instructions") can then be executed by the CPU. This process is generally called "compile-execution."
[0047] Compilation and execution generally lack cross-platform scalability. Because CPUs from different manufacturers, brands, and generations exist, and these CPUs often support different instruction sets (e.g., x86, ARM), and even CPUs from the same manufacturer and brand may support different instruction sets across generations, the same program code written in the same high-level language may result in different machine code on different CPUs. Specifically, during the conversion of high-level language code into machine code, the compiler optimizes the code based on the specific CPU instruction set (e.g., vector instruction sets) to improve execution speed. Such optimizations are often hardware-dependent. Thus, the same machine code might run on an x86 platform but not on an ARM platform. Even within the x86 platform, instruction sets have evolved and expanded over time, leading to different machine code execution times across different generations. Furthermore, since the operating system kernel schedules the CPU for machine code execution, even with the same hardware, different operating systems may support different machine code.
[0048] Unlike compiled execution, there is also a program execution method called "interpreted execution." For example, for high-level languages such as Java and C#, the compiler's function in this case is to compile the source code into bytecode of a general intermediate language.
[0049] For example, in the Java language, Java source code is compiled into standard bytecode by a Java compiler. This compiler doesn't target any specific hardware processor's instruction set; instead, it defines an abstract standard instruction set. The compiled standard bytecode generally cannot run directly on a hardware CPU, so a virtual machine, or JVM, is introduced. The JVM runs on a specific hardware processor to interpret and execute the compiled standard bytecode.
[0050] JVM stands for Java Virtual Machine, a virtual computer that is often implemented by simulating various computer functions on a real computer. The JVM shields Java programs from information related to specific hardware platforms and operating systems, allowing them to run on multiple platforms without modification, as long as the generated standard bytecode can run on the JVM.
[0051] A crucial characteristic of the Java language is its platform independence. The Java Virtual Machine (JVM) is key to achieving this. Most high-level languages require compilation into different target codebases to run on different platforms. However, with the JVM, Java does not need to be recompiled for different platforms. The JVM shields Java from platform-specific information, allowing the Java compiler to generate only bytecode that runs on the JVM, enabling it to run unmodified on various platforms. The JVM interprets the bytecode into machine instructions specific to each platform. This is why Java can "compile once, run anywhere." Thus, as long as the JVM can correctly execute the .class file, it can run on different operating system platforms such as Linux, Windows, and macOS.
[0052] The JVM runs on a specific hardware processor, responsible for interpreting and executing bytecode for that processor, shielding developers from these low-level differences and presenting them with standard development specifications. When executing bytecode, the JVM ultimately interprets it into machine instructions specific to the platform. Specifically, after receiving the input bytecode, the JVM interprets each instruction line by line, translating it into machine code suitable for the current machine. This process is handled by an interpreter called an interpreter. This way, Java developers don't need to consider the hardware platform their code will run on. The JVM itself is developed by professionals within the Java Development Community to adapt it to different processor architectures. Currently, there are only a limited number of mainstream processor architectures, such as x86, ARM, RISC-V, and MIPS. By porting the JVM to platforms supporting these specific hardware, Java programs can theoretically run on all machines. JVM porting is typically provided by professionals within the Java Development Community, greatly reducing the burden on Java application developers.
[0053] The brief process of compiling and executing the above Java program is as follows: Figure 1As shown. Java source code developed by developers typically uses the `.java` extension. The source file is compiled by a compiler to generate files with the `.class` extension; these `.class` files are bytecode. Bytecode includes bytecode instructions, also called opcode, and operands. The JVM executes the program by parsing these opcodes and operands. When you run a `.class` file using the `java` command, the Java Virtual Machine (JVM) actually loads and executes the bytecode in the `.class` file. The JVM is the core part of Java program execution, responsible for interpreting and executing Java bytecode. The JVM loading and executing the bytecode in the `.class` file is essentially equivalent to starting a JVM process in the operating system and requesting a portion of memory from the operating system. This memory is generally managed directly by the JVM and may include the method area, heap area, stack area, etc. The JVM interprets and executes the Java program line by line according to the bytecode instructions. During execution, the JVM performs garbage collection, memory allocation and release operations as needed to ensure the normal operation of the Java program. The JVM executes by translating the loaded bytecode, specifically through two execution methods. One common execution method is interpreted execution, which translates opcode and operands into machine code and then delivers it to the operating system for execution. The other execution method is JIT (Just In Time), which compiles bytecode into machine code under certain conditions before execution.
[0054] Interpreted execution brings cross-platform portability, but because the execution of bytecode involves an intermediate translation process by the JVM, its execution efficiency is not as high as that of compiled execution. This efficiency difference can sometimes be as much as tens of times.
[0055] As mentioned earlier, Java programs need to compile Java source code into Java bytecode (.class files) to run, which is then loaded and interpreted by the JVM. Therefore, the size of the .class file has a certain impact on the performance of a Java program. Smaller .class files generally mean faster loading speeds and less memory usage. When the Java Virtual Machine loads a .class file, it needs to parse it into internal data structures and then store it in memory. Smaller .class files can be parsed and loaded faster, reducing loading time and memory usage. Furthermore, smaller .class files can be transmitted and stored faster, thus contributing to improved overall Java program performance. When transmitting .class files over a network or storing them on disk, smaller files require less bandwidth and storage space, allowing for faster downloads or reads, thereby speeding up program startup and response times.
[0056] To reduce the size of .class files and provide a standardized API, the JVM integrates a large number of standard libraries that Java programs can depend on and use. For example, a developer's Java source code might include two files, Person.java and Main.java, with Main.java's header declaring an import of Person. In reality, Main and its dependent Person files involve even more dependent classes at runtime, such as default parent and ancestor classes (a concrete example being the indirectly dependent String.class class). If the JVM didn't integrate a large number of dependency libraries, Person, Main, and their dependent classes would need to be compiled together during compilation, resulting in more compiled .class files and a larger overall size. With the integration of a large number of standard libraries, the JVM needs to load fewer .class files externally via the class loader during Java program execution, and these smaller .class files still need to be loaded internally, for example, through local files or the network. Another factor is the JVM's dynamic loading feature. As mentioned earlier, when the JVM executes Java bytecode .class files, such as Person.class and Main.class in the example above, in addition to loading these two bytecode files, it also needs to load many dependent class files. Dynamic loading means that the JVM does not load all classes into memory at once, but loads classes on demand. Specifically, the JVM only loads a class when it needs it and it hasn't been loaded yet. This dynamic class loading feature allows Java programs to control the loading of different implementation classes based on conditions at runtime, thereby reducing memory usage. Memory usage directly affects the JVM's execution efficiency.
[0057] Languages like Java use virtual machines running on general-purpose hardware instruction sets like x86 to execute their own "assembly language" (such as Java bytecode). In fact, web platforms also use virtual machine environments similar to Java and Python in browsers. Browsers provide these virtual machine environments to execute JavaScript or other scripting languages, enabling interactive behaviors on HTML pages and specific page actions, such as embedding dynamic text. As business requirements become increasingly complex, front-end development logic also becomes more complex, resulting in a larger amount of code and longer project development cycles. Besides the complexity and large amount of code, another reason is the inherent flaw in JavaScript itself—JavaScript lacks static variable types, which reduces efficiency. Specifically, JavaScript engines cache and optimize frequently executed functions. For example, the JavaScript engine compiles such code into machine code, packages it, and sends it to the JIT Compiler, which compiles it into machine code. The next time this function is executed, the compiled machine code is executed directly. However, because JavaScript uses dynamic variables, a variable that was an array one time might become an object the next. In this way, the optimizations made by the JIT Compiler in the previous iteration become ineffective, and the optimizations must be redone in the next iteration.
[0058] In 2015, WebAssembly (also abbreviated as wasm) emerged. Developed by the W3C community, WebAssembly is an open standard, a secure, portable low-level code format designed for efficient execution and compact representation, achieving near-native performance. WebAssembly code is compiled by a compiler, resulting in a small size and fast start-up. It is syntactically completely separate from JavaScript and features a sandboxed execution environment. WebAssembly uses static typing, further improving execution efficiency. Furthermore, WebAssembly brings many programming languages to the Web. Moreover, WebAssembly further simplifies some execution processes, leading to significant performance improvements.
[0059] WebAssembly is a portable, small, fast-loading, and web-compatible new format that can be used as a compilation target for C / C++ / Rust / Java, etc. WebAssembly can be seen as a universal instruction set for x86 hardware on the web platform, acting as an intermediate language layer that interfaces with Java, Python, Rust, C++, etc., allowing these languages to be compiled into a unified format for execution on the web platform.
[0060] For example, source files developed in C++ typically have the .cpp extension. C++ files are compiled by a compiler to generate WASM bytecode. Similarly, source files developed in Java typically have the .java extension. Java files are compiled by a compiler to generate WASM bytecode. WASM bytecode can be encapsulated in a WASC file. A WASC file combines bytecode and an ABI (Application Binary Interface). The WebAssembly virtual machine (also known as the WASM virtual machine or WASM runtime environment, which is a virtual machine runtime environment that executes WASM bytecode), implemented according to the W3C community open standard, uses a runtime method to load and interpret WASM bytecode.
[0061] For example, if you want to develop an application and achieve cross-platform compatibility—for instance, using Java for Linux, Objective-C for iOS, and C# for Windows—with WebAssembly (WASM), you simply choose any language, compile it into a WASM file, and then distribute it to various platforms. For example... Figure 2 As shown, it is developed using Java and can be compiled by a compiler to obtain wasm bytecode, which can run on various platforms that integrate the wasm virtual machine.
[0062] The WASM virtual machine was originally designed to solve the increasingly serious performance problems of web applications. Due to its superior characteristics, it has been adopted by more and more non-web projects, such as replacing the EVM, the smart contract execution engine in blockchain.
[0063] Compilation generally includes two types: single-file compilation and multi-file combined compilation.
[0064] In single-file compilation, all program code is contained in a single source file, which can be written in any programming language. During compilation, the compiler compiles this source file into an object file. The object file can be a binary file containing machine code and metadata, or it can be a file with filenames like .class or .o. The linker then links this object file with other files (such as dependent static or dynamic libraries) to generate the final executable program or library file. The linker's main task here is to match and link undefined symbols (such as functions and variables) in the object file with their definitions in other files.
[0065] Multi-file compilation involves writing a program or library in multiple files and compiling them into a single executable or library file. Typically, each source file implements a specific function or a set of related functions. After each source file is compiled into an object file by a compiler, a linker links these object files together into an executable or library file. The linker's main task is to match and link undefined symbols (such as functions and variables) in the object files with their definitions in other object files or libraries. Compared to other methods, multi-file compilation offers better maintainability and scalability. Writing programs in multiple files allows for clearer code organization, encapsulating different functionalities in different files, making it easier to modify and maintain. Furthermore, multi-file compilation effectively avoids code duplication and dependency issues, and improves compilation efficiency and reusability.
[0066] In the development of many high-level languages, such as C++, multiple source files can be used to write code, which is then compiled into multiple object files and finally linked into an executable file or library file. In this process, only one source / object file contains the `main()` function, which serves as the program's entry point. Other object files contain various definitions, declarations, and implementations for the `main()` function to use. This approach allows for convenient modular programming and avoids code duplication and dependency issues. Java programs are similar; a Java program has only one entry point but can contain multiple classes and packages. When the program starts, the JVM automatically executes the `main()` function in the class containing the entry point (in Java, the entry point is `public static void main(String[] args)`, which is the starting point of the Java program). Methods in other classes can be called by the `main()` function in the `Main` class to implement various functionalities.
[0067] As mentioned earlier, Java programs can be compiled into WebAssembly bytecode, which can run on various platforms integrating the WebAssembly Virtual Machine. When a Java program is compiled into WebAssembly bytecode, the compiler can automatically generate a `start` function and place it within the WebAssembly bytecode. This `start` function serves as the entry point for the WebAssembly module, performing Java Virtual Machine initialization and preparing the runtime environment for the Java program (e.g., loading necessary class libraries). Furthermore, the compiler inserts the Java program's `main` function into the compiled WebAssembly bytecode's `start` function, so that calling the `start` function starts the Java program's `main` function, thus initiating the execution of the entire Java program. The `start` function in the aforementioned WebAssembly bytecode performs Java Virtual Machine initialization and prepares the runtime environment for the Java program, including initializing the Java heap, calling static constructors of various Java classes, and garbage collection initialization. Other high-level languages are similar; they can also be compiled into WebAssembly modules by the WebAssembly compiler, and the compiled WebAssembly modules include a `start` function.
[0068] In one example, source code written in a high-level language (such as Go, TypeScript, Python, etc.) could be like the following or similar code:
[0069]
[0070] As shown in the source code above, line 1 declares and defines the global variable `sum` in this high-level language, assigning it the value 0. Lines 3-6 are the `main` function, which includes executing the `print` function and returning the value of `sum`. Line 8 assigns the value 1 to `sum`. Line 8 is a global scope operation.
[0071] The wasm bytecode (pseudocode) generated after compiling the above source code is as follows:
[0072]
[0073] As shown in the wasm code above, line 2 assigns the value 0 to the variable at index 0 (represented by \0 in double quotes, corresponding to `sum` in the source code, since `sum` is at the beginning of the source code, hence its index is 0). Lines 3-5 are the `main` function, which includes executing the `print` function and returning the value of the variable at index 0 (i.e., `sum` in the source code). Lines 7-10 are the `start` function, which contains operations corresponding to the global scope in line 8 above, because such global scope operations are suitable to be executed first in the `start` function. Line 9 indicates that the `start` function is marked as the startup function of this wasm bytecode, i.e., the entry function. Line 3 contains other function code, which can generally be the wasm bytecode corresponding to the `main()` / `apply()` functions in the source code. After the entry function `start` finishes executing, the code starting from line 3 will continue to be executed.
[0074] As can be seen, although the `start` function is not explicitly present in the source code, it can be automatically generated during the compilation process into a Wasm module. The `start` function performs Java Virtual Machine initialization and prepares the runtime environment for the Java program. Since the Wasm specification stipulates that the `start` function is automatically executed after the module is loaded, the main entry point of the Java program is usually called within the `start` function. Thus, the `start` function acts as the program's entry point, allowing it to execute automatically after module instantiation without requiring explicit calling.
[0075] The wasm bytecode is loaded and run by the WebAssembly virtual machine during execution. Figure 3 The image shows the content and loading process of a wasm bytecode, with the contents of each segment (or section) as follows:
[0076]
[0077] The Memory Section (5) describes the basic information of the linear memory segment used within a wasm module, such as its initial size and maximum available size. The Data Section (11) describes metadata filled into the linear memory, storing data that various modules may use, such as strings and numeric values. In the wasm code example above, data 0 (corresponding to sum=0 in the source code) is part of the Data Section. Furthermore, the Data Section can also include underlying implementations of memory allocation from standard libraries, such as the malloc function, as well as initialization information related to constructor calls and garbage collection.
[0078] In general, WebAssembly linear memory primarily stores two types of content:
[0079] Heap: Used to store various data structures, such as objects and arrays.
[0080] Stack: Used to store local variables and other temporary information during function calls.
[0081] WebAssembly's linear memory is a contiguous memory space used to store data during program execution. WebAssembly's linear memory consists of multiple pages, each 64KB in size. Linear memory is allocated and managed in units of pages. When starting a WebAssembly module, the initial and maximum sizes of the linear memory must be specified. If the program requires more memory, more memory can be dynamically allocated by expanding the linear memory to a larger number of pages. Each byte in linear memory can be directly accessed by the WebAssembly virtual machine. WebAssembly provides various types of instructions to support read and write operations on linear memory, such as `i32.load`, `i32.store`, `i64.load`, and `i64.store`. These instructions can read or write data to memory at a specified address, and can also perform operations such as offsetting and alignment. Linear memory is one of the core mechanisms of WebAssembly, providing an efficient and reliable memory management method, making the WebAssembly module run more efficiently and stably.
[0082] After the wasm bytecode is loaded into the WebAssembly virtual machine, a linear memory space can be allocated for the WebAssembly bytecode. Specifically, a linear memory space can be allocated based on memory segment 5 in the wasm file mentioned above, and the contents of data segment 11 can be filled into the linear memory. Furthermore, much other content in the wasm file can be stored during loading in a memory area managed by the host environment (such as a browser or other application), rather than in the WebAssembly linear memory. The specific storage location depends on the implementation details of the host environment, and this memory area is usually not directly accessible to the WebAssembly code. This type of area is generally called managed memory. The code segment 10 in the wasm file contains the specific definition of each function, that is, a set of wasm instructions corresponding to the function body. The wasm instruction set of the start function can be stored in this code segment 10. In addition, the main() / apply() parts of the source code can also be stored in this code segment 10.
[0083] Based on the example above, line 2 (data 0 "\0") in the wasm bytecode belongs to the data segment; the parts within parentheses starting with func in lines 3 and 7 belong to the code segment.
[0084] A concrete example of the above content can be found as follows: Figure 3As shown. Furthermore, each time the wasm module is loaded into the virtual machine and executed, the contents of the start function will be repeatedly executed before the remaining code is executed. Specifically, after the wasm bytecode is loaded into the WebAssembly virtual machine, a linear memory space is allocated based on the contents of memory segment 5 in managed memory as the memory space used by the WebAssembly bytecode, and the contents of data segment 11 are filled into this linear memory. In the wasm code example above, the position at index 0 in line 2 is assigned the value 0, which is located in data segment 11. Then, the WebAssembly virtual machine executes the code in code segment 10 in managed memory, mainly the parts within the parentheses starting with func in lines 3 and 7. In this example, this includes the main and start functions. As mentioned earlier, the start function is equivalent to the code entry point, so the contents of the start function are executed first, followed by the other code (in this case, the code of the main function). During the execution of the start function, the data in the linear memory may be modified. For example, line 8 of the wasm bytecode above (corresponding to line 8 in the source code, "sum = 1;") modifies the variable at the same index position 0 in the data segment to 1.
[0085] The example above is relatively simple. In reality, there are likely more complex cases. For clarity and to keep things as concise as possible, the source code and wasm bytecode above have been modified as follows:
[0086]
[0087] As shown in the source code above, line 1 declares and defines the global variable `sum` in this high-level language, assigning it the value 0. Lines 3-6 are the `main` function, which executes the `print` function and returns the value of `sum`. Lines 7-10 define a Fibonacci function `fib(n)`, which calculates the nth term of the Fibonacci sequence based on the input parameter `n`. Line 11 assigns the value of `fib(5)` to `sum`. Similarly, lines 7-11 are global scope operations.
[0088] The wasm bytecode (pseudocode) generated after compiling the above source code is as follows:
[0089]
[0090] As shown in the wasm code above, line 2 also assigns the value 0 to the variable at index 0, located in the data segment. Lines 3-5 are the main function, which includes executing the print function and returning the value of the variable at index 0 (i.e., sum in the source code). The ellipsis in line 6 indicates the bytecode corresponding to the Fibonacci function in lines 7-10 of the source code. The start function in lines 7-10 contains the result of assigning fib(5) to the global variable, corresponding to the global scope operation in line 11 above. This type of global scope operation is suitable to be executed first in the start function. Line 9 indicates that the start function is marked as the startup function of this wasm bytecode, i.e., the entry function.
[0091] In this example, the calculation of the Fibonacci function becomes relatively complex. Repeatedly executing the code in the `start` function every time the wasm bytecode is loaded and run will incur significant time and performance overhead. This is especially true in many practical situations where the `start` function contains more complex code, such as the aforementioned code involving low-level implementations of the standard library, constructor calls, garbage collection initialization, etc.
[0092] The following combination Figure 4 This section describes how to provide optimized wasm bytecode in one embodiment.
[0093] S410: Reads and parses the wasm bytecode to obtain the wasm module object.
[0094] The Wasm bytecode to be optimized can be loaded using the Wasm virtual machine. Specifically, the Wasm bytecode can be binary data, obtained by compiling high-level language source code using a WebAssembly compiler. Furthermore, the loaded Wasm bytecode can be parsed using the Wasm virtual machine, primarily involving decoding. Wasm bytecode files are generally encoded binary files. Through decoding, the Section IDs (i.e., the IDs in Table 1 above) of the Wasm module can be obtained according to the Wasm standard, and then parsed to obtain the detailed content of the Section corresponding to each ID. Thus, by parsing the Wasm bytecode, a Wasm module object can be obtained, which may include the start function code in the memory segment, data segment, and code segment (only those closely related to this embodiment are listed here; the overall structure is as described in Table 1 above and will not be repeated).
[0095] In a specific implementation, such as the code example above that uses the Fibonacci function, the parsed wasm module object is as follows:
[0096]
[0097] The key point here is that in data segment 11, the value of the first 4 bytes is 0 (since sum is the first variable defined, and the int type occupies 4 bytes, so this is the first 4 bytes).
[0098] The result of loading Wasm bytecode is that the decoded Wasm bytecode binary file is stored in the managed memory of the Wasm virtual machine, such as... Figure 5 As shown in the image.
[0099] S420: Create and populate linear memory based on the parsed wasm module object.
[0100] During execution, a wasm instance is first created, and linear memory is created based on the memory segments in the wasm module object parsed from S410. As mentioned earlier, memory segment 5 can describe the basic information of the linear memory segment used within a wasm module, such as the initial size of this memory and the maximum available size, etc.
[0101] Can be combined Figure 3 and Figure 5 Let's understand this process. Data segment 11 in managed memory comes from data segment 11 in the wasm file. Of course, the contents of managed memory as a whole can be a copy of a binary file in wasm bytecode.
[0102] After creating a linear memory segment in the Wasm virtual machine based on the memory segment in managed memory, the contents of data segment 11 in managed memory can be filled into this linear memory. Thus, the linear memory contains the value 0 (bytes 0-3) from the example above. This value is the value of `sum` in the code example above. Furthermore, the linear memory can also include other constants and variables, depending on their definitions in the actual code.
[0103] S430: Execute the start function in the wasm module object and modify the linear memory according to the execution result of the start function.
[0104] After creating a wasm instance, it can be executed. The execution process includes executing the start function in code segment 10, which is copied into managed memory. As mentioned earlier, the start function is the entry point for the code each time the wasm module is loaded into the virtual machine and executed. Therefore, the contents of the start function are executed first, followed by the execution of the remaining code.
[0105] It should be noted that loading and executing instances are two separate processes. A single loading can correspond to multiple executions, meaning multiple instances can be started. After each instance is started, the corresponding linear memory for that instance can be created, and the process of filling the data segment content in managed memory into the linear memory and finding the entry point start function and executing the start function first can be performed.
[0106] In the code example above, the execution of the `start` function specifically involves calling the `fib()` function and setting the input parameter to 5. The execution result of `fib(5)` is 5 (the Fibonacci sequence starting from 1, where the first 5 terms are 1-1-2-3-5, meaning the 5th term is 5). Then, `i32.store 0 (call fib 5)` in the above wasm bytecode is executed, modifying the value of `sum` in the source code to 5. The modified `sum=fib(5)` is more complex than modifying the original `sum=1` because the call to `fib(5)` involves 5 iterations, requiring additional computational and time overhead. Figure 6 As shown, during the execution of the above wasm code in one instance, after executing the start function once, the result is that the value of bytes 0 to 3 in linear memory is modified to 5 (the execution result of calling the fib(5) function is 5).
[0107] S440: Replace the corresponding data segment in the wasm module object with the modified data in linear memory.
[0108] As described above, since the `start` function is executed from data segment 11 of managed memory each time an instance is started, and the result of executing the `start` function is fixed and the same each time, the corresponding data segment in the `wasm` module object can be replaced with the data in the modified linear memory. Specifically, if access to managed memory can be obtained, the corresponding data segment in the `wasm` module object can be replaced with the data in the modified linear memory; if access to managed memory cannot be obtained, the `wasm` module object parsed in S410 can be saved to a memory area with access, and then the corresponding data segment in the `wasm` module object can be replaced with the data in the modified linear memory in that memory area.
[0109] The former can be like Figure 7 As shown, with access to managed memory, the corresponding data segment stored in the managed memory's wasm module object can be replaced with the modified data from linear memory. The latter's overall structure is similar to... Figure 7Similar to the previous approach, the difference is that it's not managed memory without access permissions, but other memory with access permissions. Alternatively, the wasm module objects parsed from S410 can be stored in memory outside of managed memory, regardless of whether access permissions are granted.
[0110] In the modified example above that includes the Fibonacci function, since the result 5 after executing the Fibonacci function in the `start` function is the same type of `int` as the 0 before execution, both occupying 4 bytes, and the other constants and variables in linear memory remain consistent with those in the data segment, in one implementation, the part in linear memory that changes after the `start` function executes can replace the corresponding part in the data segment of the `wasm` module object. In this example, the value of bytes 0-3 in linear memory is replaced with the result 5 after the `start` function executes, instead of replacing the other constants and variables in the data segment with the other constants and variables in linear memory, thus saving the overhead of copying.
[0111] Of course, it's also possible that the result after executing the function in the `start` function is longer than the corresponding portion in the linear memory before execution. For example, consider a variable-length string type. The initial value might occupy 2 bytes, but after executing the `start` function, it might occupy 5 bytes. In this case, a better approach is to replace the corresponding data segment in the `wasm` module object with the modified entire data in the linear memory.
[0112] Furthermore, the result of executing the function within the `start` function might be longer than the corresponding portion in the linear memory before execution. For example, consider a variable-length string type. Initially, it might occupy 5 bytes, but after executing the `start` function, it might occupy 2 bytes. In this case, a better approach is to replace the corresponding data segment in the `wasm` module object with the entire modified data from the linear memory. This creates a 3-byte gap, which can be utilized by other code in subsequent code segments. Alternatively, one could remove the gapped area from the modified linear memory before replacing the corresponding data segment in the `wasm` module object, thus avoiding the low addressing efficiency caused by utilizing partially empty memory later.
[0113] S450: Encodes the wasm module object after replacing the data segment and saves it as wasm bytecode.
[0114] As mentioned earlier, Wasm bytecode files are generally encoded. Parsing Wasm bytecode includes a decoding process. After the S440 data segment replacement described above, the Wasm module object in memory can be further encoded to obtain Wasm bytecode, which can then be stored outside of memory, such as on a disk, or transmitted over a network. The Wasm bytecode obtained after this further encoding is the optimized Wasm bytecode.
[0115] A computer device may contain an execution device that performs the above. Figure 4 The virtual logic unit corresponding to the optimized wasm bytecode method can be called the optimizer. To distinguish it from subsequent optimizers, it is designated as optimizer 1 here.
[0116] Subsequently, loading the optimized Wasm bytecode allows direct parsing to obtain the Wasm module object in memory. Specifically, as mentioned earlier, the decoded and optimized Wasm module object is stored in the managed memory of the Wasm virtual machine. Figure 7 As shown in the diagram. Furthermore, linear memory can be created and filled based on the parsed wasm module object. Moreover, as mentioned earlier, since the current data segment's content is the result of loading linear memory after each instance startup before optimization, executing the start function, and modifying the linear memory based on the execution result, and since each such operation yields a fixed and identical result, it's unnecessary to execute the start function in managed memory again. Thus, the optimized wasm bytecode can further remove the start function, either by deleting the start flag (start$start) as shown in form 1 below; or by removing the entire content of the start function (depending on whether other code within the start function will be used), as shown in form 2 below. Both methods ensure that the code in the start function is not executed after starting the wasm instance, but instead, the code corresponding to the main() / apply() functions is executed directly.
[0117] Specifically, the start function in the wasm module object can be removed after S430 and before S450. Then, the wasm module after replacing the data segment and removing the start function is encoded and saved to obtain the wasm bytecode.
[0118] Thus, the wasm bytecode (pseudocode) generated after compiling the above source code includes two forms:
[0119]
[0120]
[0121] Correspondingly, such as Figure 8 As shown, the start function in managed memory can be removed, specifically in the two forms mentioned above.
[0122] The following describes an embodiment of a method for executing the optimized wasm bytecode according to this application, such as... Figure 9 As shown, it includes:
[0123] S910: Read and parse the optimized wasm bytecode to obtain the wasm module object;
[0124] S920: Create and fill linear memory based on the parsed wasm module object;
[0125] S930: Execute the code segment in the wasm module object.
[0126] Specifically, if the code segment in the wasm module object does not contain a start function, then the start function will not be executed; if the code segment in the wasm module object still contains a start function, that is, the optimized wasm bytecode has not removed the start function, but the code marked as the startup function has been removed, then the start function will be skipped and the code segment in the wasm module object will be executed directly.
[0127] In this way, the overhead of repeatedly executing the start function is eliminated during the subsequent loading and execution of the optimized wasm bytecode, thus improving the program's running performance.
[0128] The following describes an embodiment of a computer device according to this application, including:
[0129] processor;
[0130] and a memory containing a program, wherein when the processor executes the program, the following operations are performed:
[0131] Read and parse the optimized wasm bytecode to obtain the wasm module object;
[0132] Create and fill linear memory based on the parsed wasm module object;
[0133] Execute the code segment in the wasm module object.
[0134] The following describes an embodiment of a storage medium for storing a program, wherein the program performs the following operations when executed:
[0135] Read and parse the wasm bytecode to obtain the wasm module object;
[0136] Create and fill linear memory based on the parsed wasm module object;
[0137] Execute the start function in the wasm module object and modify the linear memory according to the execution result of the start function;
[0138] Replace the corresponding data segment in the wasm module object with the modified data in linear memory;
[0139] Encode the wasm module after replacing the data segment and save it as wasm bytecode.
[0140] The overall size of the Wasm bytecode obtained after the aforementioned optimization method may be large. One major reason is likely that the linear memory modified in step S420 is larger, therefore the corresponding data segment replaced in the Wasm module object after step S440 is also correspondingly larger, resulting in a larger Wasm bytecode after encoding.
[0141] One major reason for the large amount of linear memory usage is likely the initialization of variables performed in the `start` function, which generates a large amount of initialized data. These initializations include assigning initial values to global variables, calling constructors, and initializing Java's garbage collection functionality.
[0142] The result of executing the `start` function may include a large number of repeated values. For example, it could include a large number of repeated `int` values of 0, meaning that each value occupies 4 bytes of memory and is 0. Another example is a large number of repeated `int` values such as 1, 2, etc. Of course, besides `int`, it could also be a `long long` (8 bytes), a `float` (4 bytes), a `double` (8 bytes), etc.
[0143] For this type of data, it may repeat continuously in linear memory.
[0144] In addition, it can include a large number of repeated values of the same constructed type. Constructed types include, for example, struct, union, and enum types. This type of data may also be repeated consecutively in linear memory.
[0145] This application proposes a method for optimizing Wasm bytecode, such as Figure 14 As shown, it includes:
[0146] S141: Read and parse the wasm bytecode to obtain the wasm module object.
[0147] S143: Create and fill linear memory based on the parsed wasm module object.
[0148] S145: Execute the start function in the wasm module object, compress the execution result data of the start function, and modify the linear memory using the compressed execution result.
[0149] S147: Replace the corresponding data segment in the wasm module object with the modified data in linear memory.
[0150] S149: Encode the wasm module after the data segment is replaced and save it as wasm bytecode.
[0151] In S145 above, the compression mainly refers to compressing the data generated by the execution result of the start function in memory. Generally speaking, compressing data in memory mainly includes the following methods:
[0152] Encoding compression: This is the process of converting data into shorter binary code. The most common encoding compression methods are Huffman coding and arithmetic coding.
[0153] Dictionary compression: This technique breaks down data into unique fragments and then assigns each fragment an identifier from a dictionary. Data is then stored and transmitted using only these identifiers. LZ77 and LZ78 are typical dictionary compression algorithms.
[0154] Run-length encoding: This is a compression method for duplicate data. It replaces duplicate elements with a single element and the number of repetitions. This is very effective for situations with large amounts of duplicate data.
[0155] Transform compression: This method reduces the complexity of data by performing mathematical transformations. For example, the Discrete Cosine Transform (DCT) is widely used in image compression.
[0156] Predictive compression: This method uses historical data to predict future data and then stores only the prediction error. This method is particularly suitable for time series data, etc.
[0157] These are the main data compression methods that can be used in different situations. Different methods are suitable for different types and properties of data, and the appropriate compression method needs to be selected according to the specific situation.
[0158] For example, if the result of the `start` function contains a large number of repeating 0s, especially a large number of consecutive repeating 0s, run-length encoding (RLE) can be used. RLE is a very simple and effective compression method for data with consecutive repeating values. It replaces each consecutive repeating value with two numbers: the first number represents the value, and the second number represents the number of times the value appears consecutively. For example, if a memory segment contains 100 consecutive 0s, this data can be compressed to (0, 100). This method greatly reduces storage and transmission requirements. Of course, it can also compress large numbers of other consecutive and repeating values, such as the int type 1, 2, etc., mentioned above.
[0159] Similarly, it can be represented using a three-segment structure. For example, a string of data in memory might look like this:
[0160] 3333,3333,0000,3333,0000,0000,0000,0000,0000,2222,
[0161] The data in memory described above, for example, starting at position 0, can be represented by a table as follows:
[0162]
[0163] In the table above, the first row represents the position, and the second row represents the value.
[0164] Using a three-part structure (offset, length, value), where offset represents the starting position, length represents the length, and value represents the value, then for the above string of data (e.g., of type int), then:
[0165] The 16 consecutive bits from the 0th to the 15th can be represented as (0, 16, 3333333300003333);
[0166] The 20 consecutive bits from the 16th to the 35th can be represented as (16, 20, 0).
[0167] The 36th to 39th consecutive 4 bits can be represented as (36, 4, 2222);
[0168] Then, the above whole can be represented as (0, 16, 3333333300003333), (16, 20, 0), (36, 4, 2222).
[0169] Specifically, for consecutive 0s, the three-segment structure at these positions can be omitted to represent them. Then the whole above can be represented as (0, 16, 3333333300003333) and (36, 4, 2222), where the omitted 16th to 35th bits can represent the default value as 0.
[0170] By using the above method, optimizing data segments in a wasm bytecode file containing a large number of zero values using consecutive zeros as delimiters, the size of the wasm bytecode file can be reduced while maintaining complete functional consistency. Of course, other compression schemes can also reduce the size of wasm bytecode files while maintaining complete functional consistency, which will not be elaborated upon here.
[0171] Similarly, before the encoding, the process may include removing the start function from the wasm module object. Removing the start function from the wasm module object includes: deleting the start flag of the start function, or removing the entire content of the start function.
[0172] A computer device may contain an execution device that performs the above. Figure 14 The virtual logic unit corresponding to the optimized Wasm bytecode method can be called an optimizer. To distinguish it from the aforementioned optimizer, it is designated as optimizer 2 here.
[0173] The optimized and compressed wasm bytecode is executed as follows: Figure 9 As shown, it includes:
[0174] S910: Read and parse the optimized wasm bytecode to obtain the wasm module object;
[0175] S920: Create and fill linear memory based on the parsed wasm module object;
[0176] S930: Execute the code segment in the wasm module object.
[0177] In S910, for those including the above... Figure 14 The process of compressing bytecode includes: reading and parsing the optimized wasm bytecode, and restoring the compressed data contained therein by decompression to obtain a wasm module object.
[0178] For example, the data segment represented as (0, 16, 3333333300003333), (16, 20, 0), (36, 4, 2222) can be restored as follows:
[0179] 3333,3333,0000,3333,0000,0000,0000,0000,0000,2222,
[0180] Alternatively, the data segment represented as (0, 16, 3333333300003333), (36, 4, 2222) can be restored as follows:
[0181] 3333,3333,0000,3333,0000,0000,0000,0000,0000,2222,
[0182] By employing the above solution, the size of large Wasm files generated due to the large amount of linear memory can be reduced through compression. This reduces the copying time for data segments in the Wasm bytecode during startup for the Wasm virtual machine, thus reducing the time overhead of copying data segments to linear memory.
[0183] The following describes a computer device according to this application, comprising:
[0184] processor;
[0185] and a memory containing a program, wherein when the processor executes the program, the following operations are performed:
[0186] Read and parse the optimized wasm bytecode to obtain the wasm module object;
[0187] Create and fill linear memory based on the parsed wasm module object;
[0188] Execute the code segment in the wasm module object.
[0189] The present application describes a storage medium for storing a program, wherein the program performs the following operations when executed:
[0190] Read and parse the wasm bytecode to obtain the wasm module object;
[0191] Create and fill linear memory based on the parsed wasm module object;
[0192] The start function in the wasm module object is executed, the execution result data of the start function is compressed, and the compressed execution result is used to modify the linear memory;
[0193] Replace the corresponding data segment in the wasm module object with the modified data in linear memory;
[0194] Encode the wasm module after replacing the data segment and save it as wasm bytecode.
[0195] As mentioned earlier, the WASM virtual machine was originally designed to solve the increasingly serious performance problems of web applications. Due to its superior characteristics, it has been adopted by more and more non-web projects, such as replacing the blockchain smart contract execution engine EVM.
[0196] The Blockchain 1.0 era typically refers to the development phase of blockchain applications between 2009 and 2014, primarily focused on solving the problem of decentralization in currency and payment methods. Starting in 2014, developers increasingly focused on addressing technical and scalability shortcomings. In late 2013, Vitalik Buterin published the Ethereum white paper, "Ethereum: A Next-Generation Smart Contract and Decentralized Application Platform," introducing smart contracts to the blockchain and opening up applications beyond currency, thus ushering in the Blockchain 2.0 era.
[0197] A smart contract is a computer contract that executes automatically based on defined triggering rules; it can also be seen as a digital version of a traditional contract. The concept of smart contracts was first proposed in 1994 by Nick Szabo, a legal scholar and cryptographer working across disciplines. This technology was initially hindered from practical industrial applications due to a lack of programmable digital systems and related technologies, until the emergence of blockchain technology and Ethereum provided a reliable execution environment. Because blockchain technology uses a block-chain ledger, the generated data is immutable and cannot be deleted, and the entire ledger continuously adds data, ensuring the traceability of historical data; at the same time, the decentralized operating mechanism avoids the influence of centralized factors. Smart contracts based on blockchain technology not only leverage the advantages of smart contracts in terms of cost and efficiency but also prevent malicious interference with the normal execution of contracts. By writing smart contracts digitally into the blockchain, the characteristics of blockchain technology ensure that the entire process of storage, retrieval, and execution is transparent, traceable, and tamper-proof.
[0198] A smart contract is essentially a program that can be executed by a computer. Like widely used computer programs, smart contracts can be written in high-level languages. For example, Ethereum and some Ethereum-based consortium blockchains typically provide native smart contracts written in high-level languages such as Solidity, Serpent, and LLL. These high-level smart contracts can include various complex logics to implement various business functions. At the core of Ethereum as a programmable blockchain is the Ethereum Virtual Machine (EVM), which can be run by every Ethereum node. The EVM is a Turing-complete virtual machine, meaning that various complex logics can be implemented using it. Users publish and invoke smart contracts in Ethereum, which run on the EVM. In fact, the virtual machine directly runs virtual machine code (virtual machine bytecode, hereinafter referred to as "bytecode"). Smart contracts deployed on the blockchain can be in bytecode form.
[0199] Furthermore, as a decentralized distributed system, blockchain requires maintaining distributed consistency. Specifically, in a distributed system, each of the nodes in a group has a built-in state machine. Each state machine needs to start from the same initial state, execute the same instructions in the same order, and keep each state change the same to ensure a consistent final state. However, it's difficult for the devices of the nodes participating in the same blockchain network to have the same hardware configuration and software environment. Therefore, in Ethereum, a representative of blockchain 2.0, to ensure that the process and results of executing smart contracts on all nodes are the same, a virtual machine similar to the JVM—the Ethereum Virtual Machine (EVM)—is used. The EVM can shield the differences in hardware configuration and software environment among nodes, and this sandbox-like environment can also ensure that the execution of smart contracts does not affect the blockchain platform code, other programs, or operating system on the host machine. In this way, developers can develop a set of smart contract code, compile the smart contract code locally, and then upload the compiled bytecode to the blockchain. After each node executes the same bytecode through the same EVM with the same initial state, it can obtain the same final result and the same intermediate result, while shielding the differences in the underlying hardware and environment of different nodes.
[0200] For example Figure 10As shown, after Bob sends a transaction containing information about creating a smart contract to the Ethereum network, Node 1's EVM can execute the transaction and generate the corresponding contract instance. The transaction's `data` field can store the contract's bytecode, and the `to` field can be an empty address. After the nodes reach an agreement through the consensus mechanism, the smart contract can be successfully created on the blockchain. Figure 10 The "0x6f8ae93…" in the code represents the address of a successfully created smart contract, which users can subsequently use to invoke the contract. After the contract is created, a contract account corresponding to the "0x6f8ae93…" contract address appears on the blockchain. The contract code and account storage are stored in this contract account. The behavior of the smart contract is controlled by the contract code, while the smart contract's account storage preserves the contract's state. In other words, smart contracts enable the creation of a virtual account on the blockchain that contains both contract code and account storage.
[0201] As mentioned earlier, the `data` field of a transaction containing the creation of a smart contract can store the bytecode of that smart contract. Bytecode consists of a series of bytes, each byte representing an operation. For reasons of development efficiency and readability, developers can choose to write smart contract code in a high-level language instead of directly writing bytecode. The smart contract code written in a high-level language is compiled by a compiler to generate bytecode, which can then be packaged into the initiated transaction and deployed to the blockchain through the consensus and execution processes mentioned above. Figure 11 As shown.
[0202] like Figure 11 and 12 As shown, still using Ethereum as an example, after Bob sends a transaction containing information about calling a smart contract to the Ethereum network, the EVM of node 1 can execute this transaction and generate the corresponding contract instance. In Figure 12, the `from` field of the transaction is the address of the account initiating the smart contract call, the "0x6f8ae93…" in the `to` field represents the address of the called smart contract, the `value` field is the value in Ethereum, and the `data` field of the transaction stores the method and parameters for calling the smart contract. After calling the smart contract, the value of `balance` may change. Subsequently, a client can view the current value of `balance` through a specific blockchain node. Smart contracts can be executed independently on each node in the blockchain network in a prescribed manner. All execution records and data are stored on the blockchain, so when such a transaction is completed, the blockchain stores an immutable and unlost transaction certificate.
[0203] As mentioned earlier, the transaction for creating a smart contract is sent to the blockchain. After consensus is reached, each node on the blockchain can execute the transaction. Specifically, this can be done by the EVM virtual machine of the blockchain node. At this point, a contract account corresponding to the smart contract appears on the blockchain (including, for example, the account identifier, the contract's hash value Codehash, and the contract's storage root), and has a specific address. The contract code and account storage can be stored in the contract account's storage, such as... Figure 13 As shown. The behavior of a smart contract is controlled by its contract code, while the smart contract's account storage preserves the contract's state. In other words, smart contracts enable the creation of virtual accounts on the blockchain that contain contract code and account storage. For contract deployment or update transactions, the Codehash value is generated or changed. Subsequently, blockchain nodes can receive transaction requests to invoke the deployed smart contract. These requests can include the address of the invoked contract, the functions within the invoked contract, and the input parameters. Generally, after consensus is reached, each blockchain node can independently execute the specified invoked smart contract.
[0204] Figure 13 The left side shows an example of a smart contract written in Solidity. This smart contract is compiled by a compiler to generate bytecode. `solc` in the diagram is Solidity's command-line compiler. Ethereum smart contracts written in Solidity can be compiled using the `solc` command-line tool with parameters, thereby generating bytecode that can run on the EVM. After the above... Figure 10 , Figure 11 The process of deploying a contract involves successfully creating a smart contract on the blockchain. After deployment, a contract account corresponding to the smart contract is generated on the blockchain. This contract account includes elements such as an account identifier (Identity), the contract's hash value (Codehash), and the contract's storage root (StorageRoot), and has a specific address. The contract code and account storage can be stored in the contract account's storage. The Codehash is generally the hash value of the contract's bytecode. After the contract is deployed, the Codehash is the hash value of the contract's bytecode. When the contract is updated, the hash of the contract's bytecode generally changes, and the Codehash is also generally updated accordingly.
[0205] The execution of the contract can be specifically as follows: Figure 13As shown. For example, a transaction calling a contract is sent to the blockchain network, and after consensus is reached, each node can execute the transaction. The `to` field of the transaction indicates the address of the contract being called. Any node can find the storage of the contract account based on the contract address, and then read the Codehash from the storage of the contract account, thereby finding the corresponding contract bytecode based on the Codehash. The node can load the contract bytecode from storage into the virtual machine. Then, the interpreter interprets and executes it, including parsing the bytecode of the called contract (such as Push, Add, SGET, SSTORE, Pop, etc.), obtaining the opcode and function, and storing these opcodes in the memory space allocated by the virtual machine (alloc, corresponding to the memory release operation after program execution, as shown in Free in the figure), and also obtaining the jump code of the called function in the memory space. Generally, after calculating the Gas required to execute the contract and ensuring sufficient Gas, the system jumps to the corresponding address in Memory to retrieve the OPcode of the called function and begins execution. It then performs data computation, pushes / pops data from the stack, and other operations to complete the computation. During this process, some contract context information may be needed, such as the block number and information about the initiator of the call; this information can be obtained from the context (using a Get operation). Finally, the resulting state is stored in the database storage by calling the storage interface. It should be noted that during contract creation, certain functions within the contract may also be executed, such as initialization functions. In this case, code parsing, jump instructions are generated, data is stored in Memory, and data is manipulated within the stack.
[0206] In reality, high-level languages such as C, C++, Java, Go, and Python each have their own advantages. For example, C has higher execution efficiency; C++ and Java have a wide audience, a large number of developers, and mature communities and tools; Go is more modern; and Python is relatively simpler and easier to use. Currently, various blockchain platforms are expanding their smart contract types to support smart contracts developed in high-level languages such as C, C++, Java, Go, and Python. One way to achieve this expansion is by compiling the contract bytecode into the WASM (WebAssembly) format. WebAssembly is an open standard developed by the W3C community group. It is a secure, portable low-level code format designed for efficient execution and compact representation, achieving near-native performance and providing a compilation target for languages such as C, C++, Java, and Go. The WASM virtual machine was initially designed to solve the increasingly serious performance problems of web applications. Due to its superior characteristics, it has been increasingly adopted by non-web projects, such as replacing the EVM smart contract execution engine. The WebAssembly virtual machine (also known as the Wasm virtual machine or Wasm runtime environment, which is a virtual machine runtime environment that executes WASM bytecode), implemented according to the W3C community open standard, is implemented by loading Wasm bytecode at runtime and interpreting it for execution. The execution process of Wasm bytecode in the Wasm virtual machine is similar to the EVM process described above, such as... Figure 13 As shown in the image.
[0207] Based on the above optimization scheme for Wasm bytecode, this application provides a method for deploying smart contracts, see [link to relevant documentation]. Figure 15 The process shown includes the following:
[0208] S150: The blockchain node receives a transaction to deploy the contract, which includes the unoptimized wasm bytecode of the contract.
[0209] As mentioned earlier, smart contract source code developed using high-level languages such as C, C++, Java, and Go can be compiled by a compiler to generate contract bytecode in wasm format.
[0210] As mentioned earlier, a typical transaction for deploying a contract includes the address of the transaction initiator, a to address, and a data field. The address of the transaction initiator can exist implicitly or explicitly in the transaction. The to address and data field can be similar to some implementations, where the to field of the transaction is an empty address, indicating that the transaction is a deployment contract transaction; the data field of the transaction includes the bytecode of the wasm contract.
[0211] The transaction that creates a smart contract is sent to the blockchain. After consensus is reached, each node on the blockchain can execute the transaction. Specifically, for a Wasm contract, the transaction can be executed by the Wasm Virtual Machine (WVM) of the blockchain node. This WVM can be a thread within the running blockchain node process, or it can be a process independent of the blockchain node. The former can involve communication within the same process (IPC, Inter-Process Communication), while the latter can involve communication across processes (such as RPC, Remote Procedure Call). In some implementations, the WVM can be deployed on a different physical machine than the blockchain node; this is not a limitation here.
[0212] S152: Optimize the unoptimized wasm bytecode to obtain the optimized wasm bytecode.
[0213] The unoptimized Wasm bytecode can be optimized using the aforementioned optimizer 1 or optimizer 2 to obtain optimized Wasm bytecode, specifically including, as follows: Figure 4 The process shown, or including, is as follows Figure 14 The process is shown.
[0214] S154: The blockchain node generates a smart contract account on the blockchain and generates the codehash in the smart contract account based on the optimized wasm bytecode.
[0215] The account address of a smart contract can be generated using rules similar to those in Ethereum, such as based on the transaction initiator's address and nonce through a mapping function, or based on the contract name through a mapping function. There are no restrictions here, as long as the rules are fixed.
[0216] The codehash can be calculated based on the optimized Wasm bytecode. Specifically, it can be calculated using a hash algorithm such as SHA256. This codehash allows the corresponding Wasm bytecode to be found in the blockchain ledger database. Furthermore, the found Wasm bytecode can be subjected to the same hash operation, and its consistency with the codehash determines whether the Wasm bytecode corresponds to the codehash.
[0217] S156: The blockchain node stores the generated smart contract account on the blockchain ledger, and the smart contract account includes the codehash and the corresponding optimized wasm bytecode.
[0218] Based on the above Figure 15 For the corresponding deployed WASM contract, this application provides a method for executing smart contracts, see [link to WASM contract]. Figure 16 The process shown includes the following:
[0219] S160: The blockchain node receives a transaction that invokes the contract. The transaction specifies the address of the contract account being invoked, the function being invoked, and the parameters being passed in. The contract is an optimized Wasm contract.
[0220] The contract in question is an optimized Wasm contract, specifically including the aforementioned features. Figure 15 The optimized wasm bytecode described in the corresponding solution.
[0221] Furthermore, as mentioned earlier, in a transaction that invokes a contract, the `to` field can be used to specify the account address of the invoked contract. Additionally, in a transaction that invokes a contract, the `data` field can also specify the function being invoked and the parameters passed in.
[0222] S162: The blockchain node determines the codehash of the wasm contract through the contract account address and loads the wasm bytecode corresponding to the codehash into the wasm virtual machine.
[0223] As mentioned earlier, by using the contract account address specified in the transaction, the blockchain node can find the contract account and its codehash in the blockchain ledger, and can also find the contract bytecode corresponding to that codehash. This is as described above. Figure 15 The optimized wasm bytecode corresponding to the solution.
[0224] For a Wasm contract, the transaction can be executed by the Wasm Virtual Machine. This Wasm Virtual Machine can be a thread running within the blockchain node process, or it can be a process independent of the blockchain node. The former can involve communication within the same process (IPC, Inter-Process Communication), while the latter can involve communication across processes (such as RPC, Remote Procedure Call). In some implementations, the Wasm Virtual Machine can be deployed on a different physical machine than the blockchain node; this is not a limitation here.
[0225] The wasm virtual machine can first load the wasm bytecode.
[0226] S164: The wasm virtual machine reads and parses the optimized wasm bytecode to obtain a wasm module object.
[0227] S166: The wasm virtual machine creates and fills linear memory based on the parsed wasm module object.
[0228] S168: The wasm virtual machine executes the code segment in the wasm module object based on the linear memory obtained from the filling and the passed parameters.
[0229] Specifically, if the code segment in the wasm module object does not contain a start function, then the start function will not be executed; if the code segment in the wasm module object still contains a start function, that is, the optimized wasm bytecode has not removed the start function, but the code marked as the startup function has been removed, then the start function will be skipped and the code segment in the wasm module object will be executed directly.
[0230] In this way, the overhead of repeatedly executing the start function is eliminated during the subsequent loading and execution of the optimized wasm bytecode, thus improving the program's running performance.
[0231] The following describes a blockchain node according to this application, including:
[0232] processor;
[0233] and a memory containing a program, wherein when the processor executes the program, the following operations are performed:
[0234] Receive the transaction for deploying the contract, which includes the unoptimized wasm bytecode of the contract;
[0235] The unoptimized Wasm bytecode is then optimized to obtain the optimized Wasm bytecode;
[0236] Blockchain nodes generate smart contract accounts on the blockchain and generate codehash in the smart contract account based on the optimized wasm bytecode;
[0237] The blockchain node stores the generated smart contract account on the blockchain ledger. The smart contract account includes the codehash and the corresponding optimized wasm bytecode.
[0238] The present application describes a storage medium for storing a program, wherein the program performs the following operations when executed:
[0239] The system receives a transaction that invokes a contract, the transaction specifying the address of the contract account being invoked, the function being invoked, and the parameters being passed in. The contract is an optimized Wasm contract.
[0240] The codehash of the wasm contract is determined by the contract account address, and the wasm bytecode corresponding to the codehash is loaded into the wasm virtual machine;
[0241] Read and parse the optimized wasm bytecode to obtain the wasm module object;
[0242] Create and fill linear memory based on the parsed wasm module object;
[0243] Based on the linear memory obtained from the filling and the passed parameters, the code segment in the wasm module object is executed.
[0244] In the 1990s, improvements to a technology could be clearly distinguished as either hardware improvements (e.g., improvements to the circuit structure of diodes, transistors, switches, etc.) or software improvements (improvements to the methodology). However, with technological advancements, many methodological improvements today can be considered direct improvements to the hardware circuit structure. Designers almost always obtain the corresponding hardware circuit structure by programming the improved methodology into the hardware circuit. Therefore, it cannot be said that a methodological improvement cannot be implemented using hardware physical modules. For example, a Programmable Logic Device (PLD) (such as a Field Programmable Gate Array (FPGA)) is such an integrated circuit whose logic function is determined by the user programming the device. Designers can program and "integrate" a digital system onto a PLD themselves, without needing chip manufacturers to design and manufacture dedicated integrated circuit chips. Furthermore, nowadays, instead of manually manufacturing integrated circuit chips, this programming is mostly implemented using "logic compiler" software. Similar to the software compiler used in program development, the original code before compilation must also be written in a specific programming language, called a Hardware Description Language (HDL). There are many HDLs, such as ABEL (Advanced Boolean Expression Language), AHDL (Altera Hardware Description Language), Confluence, CUPL (Cornell University Programming Language), HDCal, JHDL (Java Hardware Description Language), Lava, Lola, MyHDL, PALASM, and RHDL (Ruby Hardware Description Language). Currently, the most commonly used are VHDL (Very-High-Speed Integrated Circuit Hardware Description Language) and Verilog. Those skilled in the art should also understand that by simply performing some logic programming on the method flow using one of these hardware description languages and programming it into an integrated circuit, the hardware circuit implementing the logical method flow can be easily obtained.
[0245] The controller can be implemented in any suitable manner. For example, it can take the form of a microprocessor or processor and a computer-readable medium storing computer-readable program code (e.g., software or firmware) executable by the (micro)processor, logic gates, switches, application-specific integrated circuits (ASICs), programmable logic controllers, and embedded microcontrollers. Examples of controllers include, but are not limited to, the following microcontrollers: ARC 625D, Atmel AT91SAM, Microchip PIC18F26K20, and Silicon Labs C8051F320. A memory controller can also be implemented as part of the control logic of the memory. Those skilled in the art will also recognize that, in addition to implementing the controller in purely computer-readable program code form, the same functionality can be achieved by logically programming the method steps to make the controller take the form of logic gates, switches, application-specific integrated circuits, programmable logic controllers, and embedded microcontrollers. Therefore, such a controller can be considered a hardware component, and the means included therein for implementing various functions can also be considered as structures within the hardware component. Alternatively, the means for implementing various functions can be considered as both software modules implementing the method and structures within the hardware component.
[0246] The systems, devices, modules, or units described in the above embodiments can be implemented by computer chips or physical entities, or by products with certain functions. A typical implementation device is a server system. Of course, this application does not exclude the possibility that, with the future development of computer technology, the computer implementing the functions of the above embodiments can be, for example, a personal computer, a laptop computer, an in-vehicle human-machine interaction device, a cellular phone, a camera phone, a smartphone, a personal digital assistant, a media player, a navigation device, an email device, a game console, a tablet computer, a wearable device, or any combination of these devices.
[0247] While one or more embodiments of this specification provide the operational steps of the methods described in the embodiments or flowcharts, more or fewer operational steps may be included based on conventional or non-inventive means. The order of steps listed in the embodiments is merely one possible order of execution among many steps and does not represent the only possible order. In actual device or end product execution, the methods shown in the embodiments or drawings may be executed sequentially or in parallel (e.g., in a parallel processor or multi-threaded processing environment, or even a distributed data processing environment). The terms "comprising," "including," or any other variations thereof are intended to cover non-exclusive inclusion, such that a process, method, product, or apparatus that comprises a list of elements includes not only those elements but also other elements not expressly listed, or elements inherent to such a process, method, product, or apparatus. Without further limitations, the presence of other identical or equivalent elements in the process, method, product, or apparatus that includes said elements is not excluded. For example, the use of terms such as "first," "second," etc., is to denote names and does not indicate any particular order.
[0248] For ease of description, the above devices are described in terms of function, divided into various modules. Of course, when implementing one or more of these specifications, the functions of each module can be implemented in one or more software and / or hardware components, or a module that performs the same function can be implemented by a combination of multiple sub-modules or sub-units. The device embodiments described above are merely illustrative. For example, the division of units is only a logical functional division; in actual implementation, there may be other division methods. For example, multiple units or components may be combined or integrated into another system, or some features may be ignored or not executed. Furthermore, the coupling or direct coupling or communication connection shown or discussed may be through some interfaces, indirect coupling or communication connection between devices or units, and may be electrical, mechanical, or other forms.
[0249] This invention is described with reference to flowchart illustrations and / or block diagrams of methods, apparatus (systems), and computer program products according to embodiments of the invention. It will be understood that each block of the flowchart illustrations and / or block diagrams, and combinations of blocks in the flowchart illustrations and / or block diagrams, can be implemented by computer program instructions. These computer program instructions can be provided to a processor of a general-purpose computer, special-purpose computer, embedded processor, or other programmable data processing apparatus to produce a machine, such that the instructions, which execute via the processor of the computer or other programmable data processing apparatus, generate instructions for implementing the flowchart illustrations and / or block diagrams. Figure 1 One or more processes and / or boxes Figure 1 A device that provides the functions specified in one or more boxes.
[0250] These computer program instructions may also be stored in a computer-readable storage medium that can direct a computer or other programmable data processing device to function in a particular manner, such that the instructions stored in the computer-readable storage medium produce an article of manufacture including instruction means, which are implemented in a process Figure 1 One or more processes and / or boxes Figure 1 The function specified in one or more boxes.
[0251] These computer program instructions may also be loaded onto a computer or other programmable data processing equipment to cause a series of operational steps to be performed on the computer or other programmable equipment to produce a computer-implemented process, thereby providing instructions that execute on the computer or other programmable equipment for implementing the process. Figure 1 One or more processes and / or boxes Figure 1 The steps of the function specified in one or more boxes.
[0252] In a typical configuration, a computing device includes one or more processors (CPU), input / output interfaces, network interfaces, and memory.
[0253] Memory may include non-persistent storage in computer-readable media, such as random access memory (RAM) and / or non-volatile memory, such as read-only memory (ROM) or flash RAM. Memory is an example of computer-readable media.
[0254] Computer-readable media, including both permanent and non-permanent, removable and non-removable media, can store information using any method or technology. Information can be computer-readable instructions, data structures, program modules, or other data. Examples of computer storage media include, but are not limited to, phase-change memory (PRAM), static random access memory (SRAM), dynamic random access memory (DRAM), other types of random access memory (RAM), read-only memory (ROM), electrically erasable programmable read-only memory (EEPROM), flash memory or other memory technologies, CD-ROM, digital versatile optical disc (DVD) or other optical storage, magnetic tape, magnetic magnetic disk storage, graphene storage or other magnetic storage devices, or any other non-transferable medium that can be used to store information accessible by a computing device. As defined herein, computer-readable media does not include transient computer-readable media, such as modulated data signals and carrier waves.
[0255] Those skilled in the art will understand that one or more embodiments of this specification can be provided as a method, system, or computer program product. Therefore, one or more embodiments of this specification may take the form of a completely hardware embodiment, a completely software embodiment, or an embodiment combining software and hardware aspects. Furthermore, one or more embodiments of this specification may take the form of a computer program product implemented on one or more computer-usable storage media (including, but not limited to, disk storage, CD-ROM, optical storage, etc.) containing computer-usable program code.
[0256] One or more embodiments of this specification can be described in the general context of computer-executable instructions, such as program modules, that are executed by a computer. Generally, program modules include routines, programs, objects, components, data structures, etc., that perform a particular task or implement a particular abstract data type. One or more embodiments of this specification can also be practiced in distributed computing environments where tasks are performed by remote processing devices connected via a communication network. In a distributed computing environment, program modules can reside in local and remote computer storage media, including storage devices.
[0257] The various embodiments in this specification are described in a progressive manner. Similar or identical parts between embodiments can be referred to mutually. Each embodiment focuses on describing the differences from other embodiments. In particular, system embodiments are basically similar to method embodiments, so the description is relatively simple; relevant parts can be referred to the descriptions in the method embodiments. In the description of this specification, the terms "one embodiment," "some embodiments," "example," "specific example," or "some examples," etc., refer to specific features, structures, materials, or characteristics described in connection with that embodiment or example, which are included in at least one embodiment or example of this specification. In this specification, the illustrative expressions of the above terms do not necessarily refer to the same embodiment or example. Furthermore, the specific features, structures, materials, or characteristics described can be combined in any suitable manner in one or more embodiments or examples. Moreover, without contradiction, those skilled in the art can combine and integrate the different embodiments or examples described in this specification and the features of different embodiments or examples.
[0258] The above description is merely an embodiment of one or more embodiments of this specification and is not intended to limit the scope of this specification. Various modifications and variations can be made to the one or more embodiments of this specification by those skilled in the art. Any modifications, equivalent substitutions, improvements, etc., made within the spirit and principles of this specification should be included within the scope of the claims.
Claims
1. A method for deploying smart contracts, comprising: Blockchain nodes receive transactions for deploying contracts, which include the unoptimized wasm bytecode of the contract; The unoptimized Wasm bytecode is optimized to obtain the optimized Wasm bytecode. The optimization includes: executing the start function in the Wasm module object corresponding to the unoptimized Wasm bytecode, and modifying the corresponding data segment in the Wasm module object according to the execution result of the start function, encoding the Wasm module after replacing the data segment and saving it as Wasm bytecode. Blockchain nodes generate smart contract accounts on the blockchain and generate codehash in the smart contract account based on the optimized wasm bytecode; The blockchain node stores the generated smart contract account on the blockchain ledger. The smart contract account includes the codehash and the corresponding optimized wasm bytecode.
2. The method as described in claim 1, wherein optimizing the unoptimized Wasm bytecode includes: Read and parse the unoptimized wasm bytecode to obtain the wasm module object; Create and fill linear memory based on the parsed wasm module object; Execute the start function in the wasm module object and modify the linear memory according to the execution result of the start function; Replace the corresponding data segment in the wasm module object with the modified data in linear memory; The wasm module after the data segment is replaced is encoded and saved as optimized wasm bytecode.
3. The method as described in claim 1, wherein optimizing the unoptimized Wasm bytecode includes: Read and parse the wasm bytecode to obtain the wasm module object; Create and fill linear memory based on the parsed wasm module object; The start function in the wasm module object is executed, the execution result data of the start function is compressed, and the compressed execution result is used to modify the linear memory; Replace the corresponding data segment in the wasm module object with the modified data in linear memory; Encode the wasm module after replacing the data segment and save it as wasm bytecode.
4. The method as described in claim 2 or 3, further comprising removing the start function from the wasm module object before the encoding.
5. A method for executing a smart contract, comprising: A blockchain node receives a transaction that invokes a contract, the transaction specifying the address of the contract account being invoked, the function being invoked, and the parameters being passed in. The contract is an optimized Wasm contract deployed using the method described in claim 1. The blockchain node determines the codehash of the wasm contract through the contract account address and loads the wasm bytecode corresponding to the codehash into the wasm virtual machine. The Wasm virtual machine reads and parses the optimized Wasm bytecode to obtain a Wasm module object; The wasm virtual machine creates and fills linear memory based on the parsed wasm module object; The wasm virtual machine executes the code segment in the wasm module object based on the linear memory obtained from the filling and the passed parameters.
6. The method as described in claim 5, wherein reading and parsing the optimized wasm bytecode to obtain the wasm module object includes: The optimized wasm bytecode is read and parsed, and the compressed data contained therein is decompressed to recover the wasm module object.
7. As described in claim 5, if the code segment in the wasm module object does not contain a start function, then the wasm virtual machine will not execute the start function during execution.
8. As described in claim 5, if a code segment in a wasm module object still contains a start function but the code marked as a startup function has been removed, then the wasm virtual machine skips the start function and directly executes the code segment in the wasm module object.
9. A computer device, comprising: processor; and a memory containing a program, wherein when the processor executes the program, the following operations are performed: Receive the transaction for deploying the contract, which includes the unoptimized wasm bytecode of the contract; The unoptimized Wasm bytecode is optimized to obtain the optimized Wasm bytecode. The optimization includes: executing the start function in the Wasm module object corresponding to the unoptimized Wasm bytecode, and modifying the corresponding data segment in the Wasm module object according to the execution result of the start function, encoding the Wasm module after replacing the data segment and saving it as Wasm bytecode. Blockchain nodes generate smart contract accounts on the blockchain and generate codehash in the smart contract account based on the optimized wasm bytecode; The blockchain node stores the generated smart contract account on the blockchain ledger. The smart contract account includes the codehash and the corresponding optimized wasm bytecode.
10. A storage medium for storing a program, wherein the program, when executed, performs the following operations: The transaction receives a call to the contract, the transaction specifying the address of the account to be called, the function to be called, and the parameters to be passed in, wherein the contract is an optimized wasm contract deployed through the computer device as described in claim 9; The codehash of the wasm contract is determined by the contract account address, and the wasm bytecode corresponding to the codehash is loaded into the wasm virtual machine. Read and parse the optimized wasm bytecode to obtain the wasm module object; Create and fill linear memory based on the parsed wasm module object; Based on the linear memory obtained from the filling and the passed parameters, the code segment in the wasm module object is executed.
Citation Information
Patent Citations
Method for executing intelligent contract, and blockchain node
CN111768184A
Method for deploying smart contract, blockchain node and storage medium
CN111770206A