3-智能合约介绍

存储合约示例

bash 复制代码
//说明源代码是根据GPL 3.0版本授权的
// SPDX-License-Identifier: GPL-3.0

//告诉编译器源代码所适用的Solidity版本为>=0.4.16 及 <0.9.0
pragma solidity >=0.4.16 <0.9.0;

contract SimpleStorage {
	//声明了一个名为storedData的状态变量,其类型为 uint (256位无符号整数)
    uint storedData;

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

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

在这个例子中,上述的合约定义了setget 函数,可以用来修改或检索变量的值。

要访问当前合约的成员(如:状态变量),通常不需要像添加 this. 这样的前缀,你只需要通过名字就可以直接访问它。

该合约能完成的事情并不多(由于以太坊构建的基础架构的原因):它能允许任何人在合约中存储一个单独的数字,并且这个数字可以被世界上任何人访问,且没有可行的办法阻止你发布这个数字。当然,任何人都可以再次调用 set ,传入不同的值,覆盖你的数字,但是这个数字仍会被存储在区块链的历史记录中。随后,我们会看到怎样施加访问限制,以确保只有你才能改变这个数字。

货币合约(Subcurrency)示例

下面的合约实现了一个最简单的加密货币。这里,币确实可以无中生有地产生,但是只有创建合约的人才能做到(实现一个不同的发行计划也不难)。而且,任何人都可以给其他人转币,不需要注册用户名和密码 ------ 所需要的只是以太坊密钥对。

bash 复制代码
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.4;

contract Coin {
    // 关键字"public"让这些变量可以从外部读取
    //声明了一个可以被公开访问的 address 类型的状态变量,
    //address 类型是一个160位的值,且不允许任何算数操作,这种类型适合存储合约地址或外部人员的密钥对
    //关键字 public 自动生成一个函数,允许你在这个合约之外访问这个状态变量的当前值,如果没有这个关键字,其他的合约没有办法访问这个变量
    address public minter;
    
    //创建一个公共状态变量,但它是一个更复杂的数据类型。 该类型将address映射为无符号整数
    //Mappings 可以看作是一个 哈希表 它会执行虚拟初始化,以使所有可能存在的键都映射到一个字节表示为全零的值
    //它既不能获得映射的所有键的列表,也不能获得所有值的列表
    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);
        balances[receiver] += amount;
    }

    // Errors allow you to provide information about
    // why an operation failed. They are returned
    // to the caller of the function.
    error InsufficientBalance(uint requested, uint available);


    function send(address receiver, uint amount) public {
        if (amount > balances[msg.sender])
            revert InsufficientBalance({
                requested: amount,
                available: balances[msg.sender]
            });

        balances[msg.sender] -= amount;
        balances[receiver] += amount;
        emit Sent(msg.sender, receiver, amount);
    }
}

address public minter;

关键字 public 自动生成一个函数,允许你在这个合约之外访问这个状态变量的当前值。如果没有这个关键字,其他的合约没有办法访问这个变量。由编译器生成的函数的代码大致如下所示(暂时忽略 external 和 view):

bash 复制代码
function minter() external view returns (address) { return minter; }

mapping (address => uint) public balances;

而由 public 关键字创建的getter函数 getter function 则是更复杂一些的情况, 它大致如下所示:

bash 复制代码
function balances(address account) external view returns (uint) {
    return balances[account];
}

event Sent(address from, address to, uint amount);

这行声明了一个所谓的"事件(event)",它会在 send 函数的最后一行被发出。用户界面(当然也包括服务器应用程序)可以监听区块链上正在发送的事件,而不会花费太多成本。一旦它被发出,监听该事件的listener都将收到通知。而所有的事件都包含了 from , to 和 amount 三个参数,可方便追踪交易。

bash 复制代码
constructor() {
	minter = msg.sender;
}

特殊函数 constructor 是仅在创建合约期间运行的构造函数,不能在创建之后调用。

构造函数永久存储创建合约的人的地址: msg (类似的还有 tx 和 block ) 是一个特殊的全局变量, 这些变量允许我们访问区块链的属性。

msg.sender 始终记录当前(外部)函数调用是来自于哪一个地址。

bash 复制代码
function mint(address receiver, uint amount) public {
    require(msg.sender == minter);
    balances[receiver] += amount;
}

mint 函数用来新发行一定数量的币到一个地址。

require 用来检查某些条件,如果不满足这些条件就会回推所有的状态变化。

在这个例子中, require(msg.sender == minter); 确保只有合约的创建者可以调用 mint。

一般来说,创建者可以随心所欲地铸造代币,但在某些时候,这将导致一种叫做 "溢出" 的现象。

请注意,由于默认的 算术检查模式 ,如果表达式 balances[receiver] += amount; 溢出交易将被还原。

即当任意精度算术中的 balances[receiver]+ amount 大于 uint (2**256 - 1)。

同样在在函数 send 中的 balances[receiver] += amount; 这对语句来说也是如此。

bash 复制代码
error InsufficientBalance(uint requested, uint available);

Errors 用来向调用者描述错误信息。Error与 revert 语句 一起使用。 revert 语句无条件地中止执行并回退所有的变化。

bash 复制代码
function send(address receiver, uint amount) public {
     if (amount > balances[msg.sender])
         revert InsufficientBalance({
             requested: amount,
             available: balances[msg.sender]
         });

     balances[msg.sender] -= amount;
     balances[receiver] += amount;
     emit Sent(msg.sender, receiver, amount);
 }

任何人(已经拥有一些代币)都可以使用 send 函数来向其他人发送代币。如果发送者没有足够的代币可以发送, if 条件为真 revert 将触发失败,并通过 InsufficientBalance 向发送者提供错误细节。

相关推荐
NFT_Research9 小时前
NFTScan | 11.18~11.24 NFT 市场热点汇总
web3·区块链·nft
程序猿阿伟2 天前
《C++智能合约与区块链底层交互全解析:构建坚实的去中心化应用桥梁》
c++·区块链·智能合约
天晟科技4 天前
GameFi的前景:游戏与金融的未来交汇点
游戏·金融·区块链
Roun34 天前
Web3和区块链如何促进数据透明与隐私保护的平衡
web3·区块链·隐私保护
The_Ticker4 天前
CFD平台如何接入实时行情源
java·大数据·数据库·人工智能·算法·区块链·软件工程
程序猿阿伟4 天前
《C++ 实现区块链:区块时间戳的存储与验证机制解析》
开发语言·c++·区块链
TechubNews4 天前
Helius:从数据出发,衡量 Solana 的真实去中心化程度
去中心化·区块链
dingzd954 天前
Web3的核心技术:区块链如何确保信息安全与共享
web3·去中心化·区块链
清 晨4 天前
Web3与智能合约:区块链技术下的数字信任体系
web3·区块链·智能合约
CertiK4 天前
Web3.0安全开发实践:Clarity最佳实践总结
web3·区块链·clarity