第四章 以太坊智能合约solidity介绍

本文介绍了Solidity,一种为以太坊智能合约设计的高级编程语言,涵盖基本概念如合约、状态变量、函数、事件、数据类型等。建议通过官方文档和实践案例学习。此外,文章还提到了以太币单位和时间单位的换算,以及合约中的特殊变量和函数,包括错误处理和地址成员。
摘要由CSDN通过智能技术生成

Solidity是一门面向合约的、为实现智能合约而创建的高级编程语言,设计的目的是能在以太坊虚拟机上运行。

本章大概介绍合约的基本信息,合约的组成,语法方面不做过多的介绍,个人建议多阅读官方文档效果更佳,后续的章节会开发ERC20代币合约案例以便于更好的学习智能合约的开发

官网文档:https://docs.soliditylang.org/en/v0.8.12/

中文文档:https://learnblockchain.cn/docs/solidity

1、第一个合约介绍

我们来看一个最简单的存取整形数据的合约代码

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

contract SimpleStorage {
    uint storedData;

    function set(uint x) public {
        storedData = x;
    }

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

第一行说明源代码在GPL 3.0版权许可,在代码中加入机器可读许可证说明很重要, 在发布源代码时在默认需要,直接照抄就行。

第二行是告诉编译器源代码适用的solidity版本为>=0.4.16 <0.9.0,如果是这样定义:pragma solidity ^0.5.2,则源文件将既不允许低于 0.5.2 版本的编译器编译, 也不允许高于(包含) 0.6.0 版本的编译器编译

contract声明一个合约,类似于java的class

uint storedData声明一个类型为 uint (256位无符号整数)的状态变量,叫做storedData,这边的变量可以认为是数据库表里面的一个字段,可以通过函数进行查询和变更。

函数set和get可以用来变更或取出变量的值,function用于定义一个函数。

2、合约组成

我们推荐使用在线remix来演示solidity的语法

https://remix.ethereum.org/

合约中可以包含注释、状态变量、函数、事件Event、结构体、和枚举类型的声明,且合约可以从其他合约继承。

注释
// 这是一个单行注释。

/*
这是一个
多行注释。
*/
状态变量

状态变量是永久地存储在合约存储中的值。

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

contract SimpleStorage {
    uint storedData; // 定义一个无符号整形的状态变量storedData
    // ...
}
函数(function)

函数是代码的可执行单元。函数通常在合约内部定义,但也可以在合约外定义。

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

contract SimpleAuction {
	// 在合约内部定义函数
    function bid() public payable { // Function
    }
}

// 在合约外部定义函数
function helper(uint x) pure returns (uint) {
    return x * 2;
}
函数修改器modifier

函数 修改器modifier可以用来以声明的方式修改函数语义,我们看下修改器的用法

// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.4.22 <0.9.0;
contract MyPurchase {
    address public seller;
    uint256 storedData;

    modifier onlySeller() { // 定义修改器
    	// 只有当合约的调用者==seller时才执行_;的语句,_;相当于占位符
        require(msg.sender == seller,"Only seller can call this.");
        _;
    }
    
    function abort() view public onlySeller {
    	require(msg.sender == seller,"Only seller can call this.");
    	storedData == 1;
    }
}

上面的效果等同于

// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.4.22 <0.9.0;
contract MyPurchase {
    address public seller;
    uint256 storedData;
    
    function abort() view public {
    	require(msg.sender == seller,"Only seller can call this.");
    	storedData == 1;
    }
}
事件

事件是能方便地调用以太坊虚拟机日志功能的接口,客户端调用的时候可以接收该事件。

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

contract SimpleAuction {
    
    event HighestBidIncreased(address bidder, uint amount); // Event,定义一个事件

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

结构体可以将几个变量封装起来

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

contract Ballot {
    struct Voter { // 结构体
        uint weight;
        bool voted;
        address delegate;
        uint vote;
    }
}
枚举类型

枚举可用来创建由一定数量的“常量值”构成的自定义类型

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

contract Purchase {
    enum State { Created, Locked, Inactive } // Enum
}
数据类型

Solidity 是一种静态类型语言,意味着每个变量(状态变量和局部变量)都需要在编译时指定变量的类型。

Solidity 提供了几种基本类型,并且基本类型可以用来组合出复杂类型。

值类型

值类型常用的包含:布尔类型,整形,浮点型,地址类型,枚举类型等

布尔类型:使用bool定义一个波尔类型的变量

bool isOwner;

整型

int/uint:分别表示有符号和无符号的不同位数的整型变量,支持关键字 uint8uint256 (无符号,从 8 位到 256 位)以及 int8int256

uint256 storedData;

地址类型

address:保存一个20字节的值

address payable:可支付地址,payable表示可以接受以太币,如果函数内部需要用到转账功能则需要加上payable

引用类型

数组

uint[] x;

bytes和string也是数组,bytes类似与byte[]

映射

映射类型在声明时的形式为mapping(keyType => valueType),其中 _KeyType 可以是任何基本类型,即可以是任何的内建类型, bytesstring 或合约类型、枚举类型。 而其他用户定义的类型或复杂的类型如:映射、结构体、即除 bytesstring 之外的数组类型是不可以作为 _KeyType 的类型的。

mapping (address => uint256) private _balances;

3、以太币单位

以太币(Ether) 单位之间的换算就是在数字后边加上 weigweiether 来实现的,如果后面没有单位,缺省为 wei

最⼩单位: Wei (伟)

10^9 Wei = 1 Gwei

10^18 Wei = 1 Ether

4、时间单位

秒是缺省时间单位,在时间单位之间,数字后面带有 secondsminuteshoursdaysweeks 的可以进行换算,基本换算关系如下

1 == 1 seconds
1 minutes == 60 seconds
1 hours == 60 minutes
1 days == 24 hours
1 weeks == 7 days

5、特殊变量和函数

区块和交易属性
blockhash(uint blockNumber) returns (bytes32):指定区块的区块哈希——仅可用于最新的 256 个区块且不包括当前区块
block.chainid (uint): 当前链 id
block.coinbase ( address ): 挖出当前区块的矿工地址
block.difficulty ( uint ): 当前区块难度
block.gaslimit ( uint ): 当前区块 gas 限额
block.number ( uint ): 当前区块号
block.timestamp ( uint): 自 unix epoch 起始当前区块以秒计的时间戳
gasleft() returns (uint256) :剩余的 gas
msg.data ( bytes ): 完整的 calldata
msg.sender ( address ): 消息发送者(当前调用)
msg.sig ( bytes4 ): calldata 的前 4 字节(也就是函数标识符)
msg.value ( uint ): 随消息发送的 wei 的数量
tx.gasprice (uint): 交易的 gas 价格
tx.origin (address payable): 交易发起者(完全的调用链)
ABI 编码及解码函数
abi.decode(bytes memory encodedData, (...)) returns (...): 对给定的数据进行ABI解码,而数据的类型在括号中第二个参数给出 。 例如: (uint a, uint[2] memory b, bytes memory c) = abi.decode(data, (uint, uint[2], bytes))

abi.encode(...) returns (bytes): ABI - 对给定参数进行编码

abi.encodePacked(...) returns (bytes):对给定参数执行 紧打包编码 ,注意,可以不明确打包编码。

abi.encodeWithSelector(bytes4 selector, ...) returns (bytes): ABI - 对给定第二个开始的参数进行编码,并以给定的函数选择器作为起始的 4 字节数据一起返回

abi.encodeWithSignature(string signature, ...) returns (bytes):等价于abi.encodeWithSelector(bytes4(keccak256(signature), ...)

错误处理
  • assert(bool condition)

    如果不满足条件,则会导致Panic 错误,则撤销状态更改 - 用于检查内部错误。

  • require(bool condition)

    如果条件不满足则撤销状态更改 - 用于检查由输入或者外部组件引起的错误。

  • require(bool condition, string memory message)

    如果条件不满足则撤销状态更改 - 用于检查由输入或者外部组件引起的错误,可以同时提供一个错误消息。

  • revert()

    终止运行并撤销状态更改。

  • revert(string memory reason)

    终止运行并撤销状态更改,可以同时提供一个解释性的字符串。

地址成员
  • <address>.balance (uint256)

    以 Wei 为单位的 地址类型 Address 的余额。

  • <address>.code (bytes memory)

    地址类型 Address 上的代码(可以为空)

  • <address>.codehash (bytes32)

    :ref:[](https://learnblockchain.cn/docs/solidity/units-and-global-variables.html#id9)address的codehash

  • <address payable>.transfer(uint256 amount)

    地址类型 Address 发送数量为 amount 的 Wei,失败时抛出异常,使用固定(不可调节)的 2300 gas 的矿工费。

  • <address payable>.send(uint256 amount) returns (bool)

    地址类型 Address 发送数量为 amount 的 Wei,失败时返回 false,发送 2300 gas 的矿工费用,不可调节。

  • <address>.call(bytes memory) returns (bool, bytes memory)

    用给定的有效载荷(payload)发出低级 CALL 调用,返回成功状态及返回数据,发送所有可用 gas,也可以调节 gas。

  • <address>.delegatecall(bytes memory) returns (bool, bytes memory)

    用给定的有效载荷 发出低级 DELEGATECALL 调用 ,返回成功状态并返回数据,发送所有可用 gas,也可以调节 gas。 发出低级函数 DELEGATECALL,失败时返回 false,发送所有可用 gas,可调节。

  • <address>.staticcall(bytes memory) returns (bool, bytes memory)

    用给定的有效载荷 发出低级 STATICCALL 调用 ,返回成功状态并返回数据,发送所有可用 gas,也可以调节 gas。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

晨晨晨晨晨晨晨

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值