Getting started with Solidity (1)

1. Simple smart contract

//关键字  pragmas(编译指令)是告知编译器如何处理源代码的指令的, 代码所适用的Solidity版本为>=0.4.16 及 <0.9.0 。这是为了确保合约不会在新的编译器版本中突然行为异常。
pragma solidity >=0.4.16 <0.9.0; 


//创建合约 contract

contract SimpleStorage {

//定义一个无符号整型256位
    uint storedData;

//创建函数,设置一个storedata
    function set(uint x) public {
        storedData = x;
    }
//创建函数,返回storedate

    function get() public view returns (uint) {
        return storedData;
    }
}

 2. Currency contracts

// 编译指令 solidity 版本>0.7.0 <0.9.0
pragma solidity  >=0.7.0 <0.9.0;
//创建合约 合约名:coin
contract Coin {
    // 关键字“public”让这些变量可以从外部读取
    address public minter;
    //mapping 映射 可视为指针 从address 映射到 uint
    mapping (address => uint) public balances;

    // 轻客户端可以通过事件针对变化作出高效的反应
    event Sent(address from, address to, uint amount);

    // 这是构造函数,只有当合约创建时运行
    constructor() {
        minter = msg.sender;
    }

    function mint(address receiver, uint amount) public {
        require(msg.sender == minter);
        require(amount < 1e60);
        balances[receiver] += amount;
    }

    function send(address receiver, uint amount) public {
        require(amount <= balances[msg.sender], "Insufficient balance.");
        balances[msg.sender] -= amount;
        balances[receiver] += amount;
        emit Sent(msg.sender, receiver, amount);
    }
}

The address type is a 160-bit value that does not allow any arithmetic operations. This type is suitable for storing contract addresses or key pairs for external parties.

The keyword public, allows you to access the current value of this state variable outside of this contract. Without this keyword, compilation will fail.

mapping mapping is to create a public state variable, mapping (address => uint) ... is to map address to an unsigned integer variable, Mappings can be seen as a hash table, it will perform virtual initialization, so that all possible Existing keys are mapped to a byte representation of all zero values. However, this analogy doesn't quite fit, since it's neither possible to get a list of all the keys nor all the values ​​of a map.

event Sent(address from,address to,uint amount); This line declares a so-called "event" that will be  send emitted in the last line of the function. The user interface (and of course the server application) can listen to events being sent on the blockchain without too much cost. Once it is emitted, all listeners listening to the event will be notified. And all events contain  from ,  to and  amount three parameters, which can facilitate tracking transactions. 

The special function constructor is a constructor that only runs during the creation of the contract and cannot be called afterwards. It permanently stores the address of the person who created the contract:  msg (and  tx and  block ) is a special global variable that contains some properties that allow access to the blockchain. msg.sender Always the source address of the current (external) function call.

The require function is used to confirm the validity of conditions, such as whether input variables, or contract state variables meet the conditions, or verify the value returned by an external contract call 

require has two parameters:

        The first parameter is a conditional judgment expression , which is required

        The second parameter is the exception message reminder to be returned, optional

If the judgment is true, continue to execute the statement below require, if it is false, execute the second parameter and not execute the following statement.

Finally, the methods that are actually called by users or other contracts to complete the functions of this contract are  mint and  send.

mint Nothing happens if  called by someone other than the contract creator. Functions , on the other hand,  send can be used by anyone to send coins to others (provided, of course, that the sender owns the coins). Remember, if you use a contract to send coins to an address, you won't see anything about that address when you view it on a blockchain explorer. Because, in fact, the information that you send coins and change the balance is only stored in the data memory of the specific contract. By using events, you can very simply create a "blockchain explorer" for your new coins to track transactions and balances.

3. The main structure of the contract:

  • State variables

State variables are values ​​permanently stored in contract storage.

pragma solidity >=0.4.0 <0.9.0;

contract TinyStorage {
    uint storedXlbData; // 状态变量
    // ...
}
  • function

A function is an executable unit of code. Functions are usually defined inside a contract, but they can also be defined outside a contract.

// SPDX-License-Identifier: GPL-3.0
pragma solidity >0.7.0 <0.9.0;

contract TinyAuction {
    function Mybid() public payable { // 定义函数
        // ...
    }
}

// Helper function defined outside of a contract
function helper(uint x) pure returns (uint) {
    return x * 2;
}

//函数调用 可发生在合约内部或外部,且函数对其他合约有不同程度的可见性

//函数,可以接受 (参数和返回值)。
  • function modifier

Function modifiers can be used to declaratively modify function semantics

pragma solidity >=0.4.22 <0.9.0;

contract MyPurchase {
    address public seller;

    modifier onlySeller() { // 修改器
        require(
            msg.sender == seller,
            "Only seller can call this."
        );
        _;
    }

    function abort() public onlySeller { // 修改器用法
        // ...
    }
}
  • Event Event

Event is an interface that can conveniently call the logging function of the Ethereum Virtual Machine.

pragma solidity >=0.4.21 <0.9.0;
contract TinyAuction {
    event HighestBidIncreased(address bidder, uint amount); // 事件

    function bid() public payable {
        // ...
        emit HighestBidIncreased(msg.sender, msg.value); // 触发事件
    }
}
  • structure

Structs are custom types that can group several variables.

pragma solidity >=0.4.0 <0.9.0;

contract TinyBallot {
    struct Voter { // 结构体
        uint weight;
        bool voted;
        address delegate;
        uint vote;
    }
}
  • enumerated type

Enumerations can be used to create custom types consisting of a number of "constant values"

pragma solidity >=0.4.0 <0.9.0;

contract Upchain {
    enum State { Created, Locked, InValid } // 枚举
}

-------------------------------------------------------------------------------------------------------------------------------- 

4. Source files

  • contract definition
  • import source file directive
  • Version Identification Directive
  • structure
  • enumerate
  • function
pragma solidity ^0.7.2;

Pragma , as mentioned earlier, identifies instructions and is used to enable certain compiler checks. Pragma is the abbreviation of pragmatic information

And ^0.7.2 is the version identifier. In order to avoid compiling with compilers that may introduce incompatible updates in the future, ^0.7.2 does not allow compilers with versions lower than 0.7.2 to compile, and compilers with versions higher than 0.8.0 are not allowed to compile compile. (^ flags are lower than 0.8.0)

import source file

The syntax of solidity is similar to JavaScript

import * as symbolName from "filename";
//将从 “filename” 中导入所有的全局符号到当前全局作用域中

import * as symbolName from "filename";
//其实也等价于
import "filename" as symbolName;
//创建了新的 symbolName 全局符号,他的成员都来自与导入的 "filename" 文件中的全局符号

import {symbol1 as alias, symbol2} from "filename";
//如果存在命名冲突,则可以在导入时重命名符号。例如代码创建了新的全局符号 alias 和 symbol2 ,引用的 symbol1 和 symbol2 来自 “filename” 。

path

The filename above will always be processed as a path, as a  / directory separator, to  . indicate the current directory, to  .. indicate the parent directory. When  . or  .. followed by the characters are  / , they can be regarded as the current directory or parent directory. Paths   are considered relative only if they start with the current directory . or a parent directory ..

import "./filename" as symbolName;
//同目录下的文件filename

import "filename" as symbolName;
//可能filename是不同目录下的

//实际过程中,编译器还可以指定路径前缀重映射。
import "github.com/ethereum/dapp-bin/library/iterable_mapping.sol" as it_mapping;
//运行编译器
solc github.com/ethereum/dapp-bin/=/usr/local/dapp-bin/ source.sol
//如果有多个重映射指向一个有效文件,那么具有最长公共前缀的重映射会被选用

 note

// 这是一个单行注释。

/*
这是一个
多行注释。
*/

///或者是/**....**/书写,是要放到函数申明或者是语句上使用,也可文档化函数

//和js一样

--------------------------------------------------------------------------------------

 

5. Additional knowledge:

Accounts: Ethereum has two columns of accounts:

  • External accounts: controlled by public-private key pairs (aka people)
  • Contract account: controlled by the code stored with the account.

The address of the external account: determined by the public key

The address of the contract account: It is determined when the contract is created (this address is calculated from the address of the contract creator and the number of transactions sent from this address, which is the so-called "nonce")

Both types of accounts have a persistent storage in the form of key-value pairs. The length of key and value are both 256 bits. we call it storage

And each account will have an ether balance (balance) unit is wei, 1 eth=10^18wei, the balance will change due to sending transactions containing ether.

trade

A transaction is a message sent from one account to another. It can contain a binary data (contract payload) and ether.

  1. If the target account contains code, the code will be executed with the payload as an input parameter.
  2. If the target account is a zero account (account address is  0 ), this transaction will create a  new contract  . As mentioned above, the address of a contract is not a zero address, but is calculated from the address of the creator of the contract and the number of transactions sent from this address (the so-called "nonce"). The payload of the transaction used to create the contract is converted to EVM bytecode and executed. The output of execution will be permanently stored as contract code. This means that, to create a contract, you don't need to send the actual contract code, but the code that generates the contract code.

Gas

Once created, each transaction is charged a certain amount of  gas (that is, a handling fee)  , the purpose of which is to limit the amount of work required to execute the transaction and pay the handling fee for the transaction. When the EVM executes a transaction, the gas will be gradually exhausted according to specific rules.

The gas price  is a value set by the transaction sender, and the sender's account needs to prepay the transaction fee =  gas_price * gas . If there is any remaining gas after the transaction is executed, the gas will be returned in the same way.

No matter where it is executed, once the gas is exhausted (such as falling to a negative value), an out-of-gas exception will be triggered. All state modifications made by the current call frame will be rolled back.

storage, memory and stack

Each account has a persistent memory area called  storage  . Storage is a key-value store that maps 256-bit words to 256-bit words. It is impossible to enumerate storage in a contract, and the relative overhead of reading storage is high, and the overhead of modifying storage is even higher. The contract can only read and write its own part of the storage area.

The second memory area is called  memory  , and the contract will try to obtain a wiped memory instance for each message call. The memory is linear and addressable at the byte level, but reads are limited to 256 bits in length, while writes can be 8 or 256 bits in length. When accessing (whether reading or writing) a word of memory that has never been accessed before (whether offset anywhere within that word), the memory is extended by word (each word is 256 bits). Expansion will also consume a certain amount of gas. As memory usage grows, so does its cost (squared).

The EVM is not register-based, but stack-based, so all calculations are performed in an area called the  stack  . The stack has a maximum of 1024 elements, and the length of each element is a word (256 bits). The access to the stack is limited to its top, and the restriction method is: it is allowed to copy one of the top 16 elements to the top of the stack, or exchange the top element of the stack and one of the following 16 elements. All other operations can only take the top two (or one, or more, depending on the specific operation) elements, and after the operation, push the result to the top of the stack. Of course, you can put the elements on the stack into storage or memory. But it is impossible to only access the element at the specified depth on the stack unless other elements are removed from the top of the stack first.

Instruction Set

The instruction set size of the EVM should be as small as possible to minimize the possibility of incorrect implementations that could cause consensus problems. All instructions operate on the basic data type of "256-bit word (word)". Commonly used arithmetic, bit, logic, and comparison operations are available. Conditional and unconditional jumps are also possible. Additionally, contracts can access relevant properties of the current block, such as its number and timestamp.

message call

Contracts can call other contracts or send Ether to non-contract accounts through message calls. Message calls are very similar to transactions, they both have a source, destination, data, ether, gas, and return data. In fact every transaction consists of a top-level message call, which in turn creates more message calls.

A contract can decide in its internal message calls how much of the remaining  gas  it should send and keep. If an out-of-gas exception (or any other exception) occurs during the internal message call, this will be indicated by an error value that is pushed onto the stack. At this point, only the gas sent with the internal message call will be consumed. Moreover, in Solidity, the contract that initiates the call will trigger a manual exception by default, so that the exception can "bubble out" from the call stack. As mentioned earlier, the called contract (which can be the same contract as the caller) gets a freshly cleared memory and has access to the calling payload—data provided by a separate area called calldata. After the call is executed, the returned data will be stored in a piece of memory pre-allocated by the caller. Call depth is  limited  to 1024, so for more complex operations we should use loops instead of recursion.

log

There is a special indexable data structure that stores data that can be mapped all the way down to the block level. This feature is called  logs  , and Solidity uses it to implement  events  . After the contract is created, the log data cannot be accessed, but the data can be efficiently accessed from outside the blockchain. Because part of the log data is stored in a bloom filter, we can efficiently and cryptographically securely search the logs, so those network nodes (light clients) that have not downloaded the entire blockchain can also find these logs.

contract creation

Contracts can even create other contracts through a special instruction (instead of simply calling zero addresses). The only difference between create calls to create a contract   and ordinary message calls is that the load will be executed, the result of the execution will be stored as the contract code, and the caller/creator will get the address of the new contract on the stack.

Fail and self-destruct

The only way for the contract code to be removed from the blockchain is for the contract to execute a self-destruct operation on the contract address  selfdestruct . The remaining ether in the contract account is sent to the specified destination, and its storage and code are removed from the state. Removing a contract sounds good, but it is potentially dangerous. If someone sends ether to the removed contract, those ethers will be lost forever.

Note: Even though a contract's code does not call it explicitly  selfdestruct , it is still possible for it to delegatecall or  callcode perform a self-destruct operation.

If you want to invalidate the contract, you should disable the contract by changing the internal state, so that you can revert when the function cannot be executed, so as to achieve the purpose of returning the ether.

Guess you like

Origin blog.csdn.net/weixin_49489840/article/details/124184205