From entry to mastery of smart contracts: Features and internal mechanisms of Solidity

In the previous chapter , we have briefly introduced the basic concepts and features of the Solidity language. After understanding the basic knowledge and usage of Solidity, we can try to write some simple smart contracts on compilers such as Remix and JIDE , so as to better Be familiar with the environment and foundation required to develop smart contracts. So today, we will explain some Solidity language syntax in more detail here .

First, let's explain the source file mapping in the Solidity language. As part of the AST output, each compiler provides the source code ranges corresponding to the nodes in the AST . It can be used to detect AST static code, analyze errors, and can also be used to highlight local variables and corresponding debugging tools. The compiler can also generate a range mapping from bytecode to instruction source code, which plays an important role in static analysis tools. Analysis at the bytecode level can display the corresponding code location in the debugging tool. Breakpoint operations are also supported.

Next, let's take a look at the properties that are unique to the Solidity language. Solidity has some unique syntax, function types. In the Solidity language, function types can be used as local variables, that is, when using var  , you can assign different functions to var .

 

FunctionSelector contract {   

 

function select(bool useB, uint x) returns (uint z) {     

 

  var  f = a;     

 

  if (useB) f = b;     

 

    return f(x);   

 

  }    

 

  function a(uint x) returns (uint z) {     

 

    return x * x;   

 

  }    

 

  function b(uint x) returns (uint z) {     

 

    return 2 * x;   

 

  }

 

}

The Solidity language has two very interesting internal mechanisms: Cleaning Up Variables and The Optimizer .

Cleaning Up Variables : In Solidity , when a value occupies less than 32 bytes, useless bits will be cleared. The Solidity compiler can clear the useless data before it has any side effects. For example, before writing a value to the memory, the unneeded bytes need to be cleared first, because the memory is not used. Bits may also be used to compute hash values, and may also be called as messages as data storage. Likewise, the useless bytes stored in the storage also need to be dealt with, otherwise there will be some negative effects.

In addition, incorrect subsequent operations will also have side effects, and we will not actively deal with useless bytes. The Solidity compiler handles these useless bytes after the input data is loaded onto the stack. Different invalid values ​​have different processing rules:

Optimization ( The Optimizer ) : Solidity 's optimization is based on assembly, that is, Solidity can be used by other programming languages. The compiler splits the basic instruction sequence into basic blocks at JUMP and JUMPDEST . Within these code blocks, all instructions will be analyzed. All operations on the stack, memory or storage are recorded as expressions consisting of instructions and their arguments, which in turn point to another expression. The core purpose is to find some expressions that are identical for any input and then combine them into an expression class. The optimizer first tries to find some completely new expressions in a set of known expressions. If not found, the expression is simplified by some simple principles. At the end of the process, there will be an expression at the top of the stack, and there will be a series of modifications to memory or storage. This information exists with the basic blocks to easily connect them. Additionally, information about stack, storage and memory configuration is passed to the next block. If we know the targets of all JUMP and JUMPI instructions, we can build the complete control flow graph of the program.

In the final step, the code in each block is regenerated. At the end of a block, a dependency tree of expressions on the stack is generated, and operations that are not on the dependency tree are processed. In our original code, the code that wants to apply to memory and store the desired modification order is generated (the discarded modifications are judged to be completely unnecessary), and finally, all the needs to exist on the stack are generated. value.

These steps are applied to each basic block, and if the newly generated code is smaller, it will replace the existing code. If a block is split at JUMPI during analysis, and the condition proves to be a constant, JUMPI can be replaced based on the constant value, such as the following code:

 

 var  x = 7;

 

 data[7] = 9;

 

 if (data[x] != x + 2)   

 

  return 2;

 

else

 

  return 1;

 

The simplified code can be compiled to:  

 

 data[7] = 9;

 

  return 1;

 

 

For the full syntax of Solidity , stay tuned for a follow-up article. Some sources: http://www.tryblockchain.org/

 

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=324949688&siteId=291194637