In addition to Weibo, there is also WeChat
Please pay attention
WeChat public account
Shulou
2025-02-24 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Internet Technology >
Share
Shulou(Shulou.com)06/01 Report--
This article introduces the relevant knowledge of "what is the operation principle of Solidity". In the operation of actual cases, many people will encounter such a dilemma, so let the editor lead you to learn how to deal with these situations. I hope you can read it carefully and be able to achieve something!
Introduction
As a language for intelligent contracts, Solidity has both differences and similarities with other classical languages.
On the one hand, the attributes that serve the blockchain make it different from other languages. For example, the deployment and invocation of the contract need to be confirmed by the blockchain network; the execution cost needs to be strictly controlled to prevent malicious code from consuming node resources.
On the other hand, as a programming language, the implementation of Solidity is not separated from classical languages. For example, Solidity contains stack-like and stack-like designs, and uses stack virtual machines for bytecode processing.
Life cycle of Solidity
Like other languages, the code life cycle of Solidity is inseparable from the four stages of compilation, deployment, execution, and destruction. The following figure shows the complete life cycle of the Solidity program:
After compilation, the Solidity file generates bytecode. This is a kind of code similar to jvm bytecode. When deployed, the bytecode and construction parameters are constructed into a transaction, and the transaction is packaged into a block, and through the network consensus process, the contract is built on each block chain node, and the contract address is returned to the user.
When the user is ready to call the function on the contract, the call request will also go through the process of transaction, block and consensus, and finally be executed by the EVM virtual machine on each node.
Here is an example program that we explore its life cycle through remix.
Pragma solidity ^ 0.4.25 X contract Demo {uint private _ state; constructor (uint state) {_ state = state;} function set (uint state) public {_ state = state;}} compilation
After the source code has been compiled, you can get its binary through the ByteCode button:
608060405234801561001057600080fd5b506040516020806100ed83398101806040528101908080519060200190929190
You can also get the corresponding bytecode (OpCode):
PUSH1 0x80 PUSH1 0x40 MSTORE CALLVALUE DUP1 ISZERO PUSH2 0x10 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH1 0x40 MLOAD PUSH1 0x20 DUP1 PUSH2 0xED DUP4 CODECOPY DUP2 ADD DUP1 PUSH1 0x40 MSTORE DUP2 ADD SWAP1 DUP1 DUP1 MLOAD SWAP1 PUSH1 0x20 ADD SWAP1 SWAP3 SWAP2 SWAP1 POP POP POP DUP1 PUSH1 0x0 DUP2 SWAP1 SSTORE POP POP PUSH1 0xA4 DUP1 PUSH2 0x49 PUSH1 0x0 CODECOPY PUSH1 0x0 RETURN STOP PUSH1 0x80 PUSH1 0x40 MSTORE PUSH1 0x4 CALLDATASIZE LT PUSH1 0x3F JUMPI PUSH1 0x0 CALLDATALOAD PUSH29 0x100000000000000000000000000000000000000000000000000000000 SWAP1 DIV PUSH4 0xFFFFFFFF AND DUP1 PUSH4 0x60FE47B1 EQ PUSH1 0x44 JUMPI JUMPDEST PUSH1 0x0 DUP1 REVERT JUMPDEST CALLVALUE DUP1 ISZERO PUSH1 0x4F JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH1 0x6C PUSH1 0x4 DUP1 CALLDATASIZE SUB DUP2 ADD SWAP1 DUP1 DUP1 CALLDATALOAD SWAP1 PUSH1 0x20 ADD SWAP1 SWAP3 SWAP2 SWAP1 POP POP POP PUSH1 0x6E JUMP JUMPDEST STOP JUMPDEST DUP1 PUSH1 0x0 DUP2 SWAP1 SSTORE POP POP JUMP STOP LOG1 PUSH6 0x627A7A723058 KECCAK256 0x4e 0xd9 MOD DIFFICULTY 0x4c 0xc4 0xc9 0xaa 0xbd XOR EXTCODECOPY MSTORE 0xb2 0xd4 DUP7 0xdf 0xc5 0xde 0xa9 DUP1 SLT PUSH1 0xC3 CALLDATACOPY XOR 0x5d 0xad KECCAK256 0xe1 0x1f DUP2 SHL STOP 0x29
The following instruction set is the code for the set function, which will later explain how the set function works.
JUMPDEST DUP1 PUSH1 0x0 DUP2 SWAP1 SSTORE POP POP JUMP STOP deployment
After compilation, the code can be deployed on remix, and the construction parameters are passed in 0x123:
After the deployment is successful, you will get a transaction receipt:
Click input to see the specific transaction input data:
In the above data, the yellow part happens to be the contract binary in the previous article, while the purple part corresponds to the passed construction parameter 0x123.
All these indicate that the contract deployment takes the transaction as the medium. Combined with the knowledge of blockchain trading, we can restore the entire deployment process:
The client constructs a transaction by using the deployment request (contract binary, construction parameters) as input data for the transaction.
The transaction is encoded by rlp and then signed by the sender with the private key.
Signed transactions are pushed to nodes on the block chain
After the block chain node verifies the transaction, it is deposited in the transaction pool.
When it is the node's turn to leave the block, the transaction is packaged to build the block and broadcast to other nodes.
Other nodes verify the block and reach a consensus. Different chunk chains may use different consensus algorithms. PBFT is used in FISCO BCOS to reach a consensus, which requires three stages of submission (pre-prepare,prepare, commit)
The node executes the transaction, and the result is that the smart contract Demo is created, the storage space of the status field _ state is allocated and initialized to 0x123
Execution
Depending on whether there is a modifier view, we can divide functions into two categories: invocation and transaction. Since it is determined at the compilation time that the call will not cause the change of the contract state, for this kind of function call, the node can directly provide the query without confirming with other block chain nodes. Because the transaction may cause a change in status, it will be confirmed between networks.
Let's take a look at the specific running process on the assumption that the user called set (0x10).
First, the function set is not configured with the view/pure modifier, which means that it may change the contract state. Therefore, the call information will be put into a transaction, and finally handed over to the EVM of each node for execution through the process of transaction coding, transaction signature, transaction push, transaction pool cache, packing out block, network consensus and so on.
In EVM, the parameter 0xa is stored in the contract field _ state by the SSTORE bytecode. The bytecode first gets the address of the status field _ state and the new value 0xa from the stack, and then completes the actual storage.
The following figure shows the running process:
This is only a quick overview of how set (0xa) works, and the next section takes a closer look at how EVM works and how data is stored.
Destroy
Since the contract cannot be tampered with after it is wound up, the contract life can last until the underlying block chain is completely shut down. To destroy the contract manually, use the bytecode selfdestruct. The termination of a contract also requires transaction confirmation, so I will not repeat it here.
EVM principle
In the previous article, we introduced the operation principle of Solidity program. After the transaction is confirmed, the bytecode is finally executed by EVM. For EVM, the above is just a passing mention, and this section will describe in detail how it works.
Operation principle
EVM is a stack virtual machine, and its core feature is that all operands are stored on the stack. Let's take a look at how it works through a simple Solidity statement code:
Uint a = 1nteruint b = 2nteruint c = a + b
After this code is compiled, the bytecode is as follows:
PUSH1 0x1PUSH1 0x2ADD
In order for the reader to better understand the concept, it is reduced to the above three statements, but the actual bytecode may be more complex and mixed with statements such as SWAP and DUP.
We can see that in the above code, there are two instructions: PUSH1 and ADD, which have the following meanings:
PUSH1: push the data to the top of the stack.
ADD:POP the two top stack elements, add them together, and press them back to the top of the stack.
The execution process is explained in a semi-animated way here. In the following figure, sp represents the top pointer of the stack and pc represents the program counter. When the push2 0x1 is executed, both pc and sp move down:
Similarly, after push2 0x2 is executed, the pc and sp states are as follows:
Finally, when the add is executed, the two operands at the top of the stack are popped up as input to the add instruction, and the sum of the two is pushed onto the stack:
Storage exploration
In the development process, we often encounter confusing memory modifiers; when reading open source code, we also see a variety of assembly operations directly against memory. Developers who don't understand storage mechanisms will be confused when they encounter these situations, so this section will explore the storage principles of EVM.
In the previous article, "basic Features of Solidity written by Intelligent contracts", we introduced a piece of Solidity code that usually involves local variables and contract state variables.
There are differences in how these variables are stored, and the following code shows the relationship between the variables and the way they are stored.
Contract Demo {/ / StateStore uint private _ state; function set (uint state) public {/ / Stack storage uint I = 0; / / memory storage string memory str = "aaa";}} stack
The Operand used by the stack to store bytecode instructions. In Solidity, if local variables are integers, fixed-length byte arrays and so on, they will enter and exit the stack as the instruction runs.
For example, in the following simple statement, the variable value 1 is read out and pushed to the top of the stack by PUSH:
Uint I = 1
For such variables, you cannot forcibly change the way they are stored, and if you place a memory modifier before them, the compilation will report an error.
Memory
Memory is similar to the heap in java. It is used to store "objects". In Solidity programming, if a local variable belongs to a variable-length byte array, string, structure, etc., it is usually modified by the memory modifier to indicate that it is stored in memory.
In this section, we will take strings as an example to analyze how memory stores these objects.
1. Object storage structure
The following is an analysis of how complex objects are stored with assemble statements.
The assembly statement is used to invoke a bytecode operation. The mload instruction will be used to invoke these bytecodes. Mload (p) indicates that 32 bytes of data are read from address p. Developers can pass object variables directly into mload as pointers.
In the following code, the data variable holds the first 32 bytes of the string str in memory after a call to mload.
String memory str = "aaa"; bytes32 data;assembly {data: = mload (str)}
By mastering mload, you can use this to analyze how string variables are stored. The following code reveals how string data is stored:
Function strStorage () public view returns (bytes32, bytes32) {string memory str = "Hello"; bytes32 data; bytes32 data2; assembly {data: = mload (str) data2: = mload (add (str, 0x20))} return (data, data2);}
The data variable represents the 0'31 bytes of str, and the data2 represents 32'63 bytes of str. The result of running the strStorage function is as follows:
0: bytes32: 0x00000000000000000000000000000000000000000000000000000000000000061: bytes32: 0xe4bda0e5a5bd0000000000000000000000000000000000000000000000000000
As you can see, the value of the first data word is 6, which is exactly the number of bytes of the string "Hello" encoded by UTF-8. The second data word holds the UTF-8 code of "Hello" itself.
Once we have mastered the storage format of strings, we can use assembly to modify, copy, and concatenate strings. Readers can search Solidity's string library to learn how to implement string's concat.
two。 Memory allocation mode
Since memory is used to store objects, it must involve how memory is allocated.
The allocation of memory is very simple, that is, sequential allocation. Next we will assign two objects and look at their addresses:
Function memAlloc () public view returns (bytes32, bytes32) {string memory str = "aaa"; string memory str2 = "bbb"; bytes32 p1; bytes32 p2; assembly {p1: = str p2: = str2} return (p1, p2);}
After running this function, the returned result will contain two data words:
0: bytes32: 0x00000000000000000000000000000000000000000000000000000000000000801: bytes32: 0x00000000000000000000000000000000000000000000000000000000000000c0
This means that the starting address of the first string str1 is 0x80, and the starting address of the second string str2 is 0xc0, with 64 bytes in between, which is exactly the space occupied by str1 itself. The memory layout at this time is as follows, with one grid representing 32 bytes (a data word, EVM uses 32 bytes as a data word instead of 4 bytes):
0x40~0x60: free pointer to save the available address, in this case 0x100, indicating that the new object will be allocated from 0x100. You can use mload (0x40) to get the assigned address of the new object.
0x80~0xc0: the starting address assigned by the object. The string aaa is assigned here
0xc0~0x100: the string bbb is assigned
0x100 objects.: because it is a sequential allocation, the new objects will be assigned here.
State storage
As the name implies, the state store is used to store the status field of the contract.
In terms of the model, storage consists of multiple 32-byte slots. In the previous article, we introduced the set function of the Demo contract, where 0x0 represents the storage slot of the state variable _ state. All fixed-length variables are placed in this set of slots in order.
For mapping and arrays, the storage will be more complex, it will occupy one slot, and the data it contains will occupy other slots according to the corresponding rules. For example, in mapping, the storage slot of the data item is calculated by keccak from the key value k and the slot p of mapping itself.
In terms of implementation, different chains may use different implementations, and the more classic one is the MPT tree used in Etay Square. Due to the problems of MPT tree performance and scalability, FISCO BCOS abandons this structure and uses distributed storage to store state data through rocksdb or mysql, so that the performance and scalability of storage are improved.
This is the end of the content of "how Solidity works". Thank you for reading. If you want to know more about the industry, you can follow the website, the editor will output more high-quality practical articles for you!
Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.
Views: 0
*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.
Continue with the installation of the previous hadoop.First, install zookooper1. Decompress zookoope
"Every 5-10 years, there's a rare product, a really special, very unusual product that's the most un
© 2024 shulou.com SLNews company. All rights reserved.