目录

  1. 1. 前言
  2. 2. 简介
    1. 2.1. 架构
    2. 2.2. 运行机制
    3. 2.3. 分类
    4. 2.4. 技术特征
  3. 3. 开发
    1. 3.1. Hello World
    2. 3.2. 子货币

LOADING

第一次加载文章图片可能会花费较长时间

要不挂个梯子试试?(x

加载过慢请开启缓存 浏览器默认开启

智能合约

2024/6/16 Blockchain
  |     |   总文章阅读量:

前言

参考:

《区块链技术与实践》—— 机械工业出版社

https://solidity-cn.readthedocs.io/zh/develop/introduction-to-smart-contracts.html

https://github.com/chaseSpace/learn_blockchain/blob/main/smart_contract.md


简介

一种在区块链上存储的、无须中介、自我验证、自动执行合约条款的计算机交易协议。一旦协议参与方达到执行协议的条件,计算机或计算机网络便会自动执行协议并输出相应的结果

例如:打麻将,这种活动无需参与方之外的力量参与就能按照规则自动进行,什么时候判定胜利,什么时候结束牌局,这些都是规则自己需要考虑的(

架构

合约模型(自底向上):基础设施层、合约层、运维层、智能层、表现层和应用层

  • 基础设施层:封装了分布式账本、共识机制、激励机制、开发环境等基础设施
  • 合约层:封装了静态的合约数据,包括合约各方达成一致的合约文本、合约代码、符合情景的响应规则和合约创建者指定的合约与外界以及合约之间的交互准则
  • 运维层:封装了一系列对合约层中静态合约数据的动态操作
  • 智能层:封装各类智能算法
  • 表现层:封装了智能合约在实际运用中的各类具体表现形式
  • 应用层:封装了智能合约及其表现形式的具体应用领域

运行机制

image-20240617001154780

分类

脚本型智能合约:比特币

图灵完备型智能合约:以太坊和 Hyperledger Fabric 中的智能合约,图灵完备是指能用编程语言模拟任何图灵机,以太坊主要使用 Solidity 和 Serpent 两种智能合约开发语言

可验证合约型智能合约:Kadena中的智能合约

技术特征

去信任化

自动性

防篡改

可追溯


开发

以 Solidity 为例

pragma solidity ^0.4.0;

contract SimpleStorage {
    uint storedData;

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

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

第一行代码:告诉大家源代码使用Solidity版本0.4.0写的(运行版本 < 0.5.0)。这是为了确保合约不会在新的编译器版本中突然行为异常。

pragma :告知编译器如何处理源代码的指令的(例如,C/C++中的 pragma once ,让所在的文件在一个单独的编译中只被包含一次,类似于php中的include_once

Solidity中合约的含义就是一组代码(它的 函数 )和数据(它的 状态 ),它们位于以太坊区块链的一个特定地址上。

uint storedData :声明一个类型为 uint (256位无符号整数)的状态变量,叫做 storedData 。 可以认为它是数据库里的一个位置,可以通过调用管理数据库代码的函数进行查询和变更。

对于以太坊来说,上述的合约就是拥有合约(owning contract)。在这种情况下,函数 setget 可以用来变更取出变量的值。


Hello World

参考:https://juejin.cn/post/7046041881913851912

在线IDE:https://remix.ethereum.org

对应的文档:https://remix-ide.readthedocs.io/zh-cn/latest/

// SPDX-License-Identifier: MIT
pragma solidity >=0.6.12 <0.9.0;

contract HelloWorld {
    /**
     * @dev Prints Hello World string
     */
    function print() public pure returns (string memory) {
        return "Hello World!";
    }
}

编译

image-20240617004945038

然后部署合约,deploy即可

image-20240617005633381

image-20240617005837792

此时就成功部署了

这是对应的选项:

image-20240617005709992

然后我们打开刚才部署成功的合约地址,点击执行print函数

image-20240617010109205

成功输出hello world


子货币

下面的合约实现了一个最简单的加密货币:

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.26;

contract Coin {
    // 关键字“public”让这些变量可以从外部读取
    address public minter;
    mapping (address => uint) public balances;

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

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

    function mint(address receiver, uint amount) public {
        if (msg.sender != minter) return;
        balances[receiver] += amount;
    }

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

注意,只有创建合约的人才能使货币无中生有,任何人都可以给其他人转币,不需要注册用户名和密码,所需要的只是以太坊密钥对

address public minter:这一行声明了一个可以被公开访问的 address 类型的状态变量。 address 类型是一个160位的值,且不允许任何算数操作,这种类型适合存储合约地址或外部人员的密钥对

public:自动生成一个函数,允许你在这个合约之外访问这个状态变量的当前值,如果没有这个关键字,其他的合约则没有办法访问这个变量

mapping (address => uint) public balances:创建一个公共状态变量,该类型将address映射为无符号整数

event Sent(address from, address to, uint amount):声明了一个所谓的” 事件(event)”,它会在 send 函数的最后一行被发出,其中所有的事件都包含了 fromtoamount 三个参数

特殊函数 Coin 是在创建合约期间运行的构造函数,不能在事后调用。 它永久存储创建合约的人的地址: msg ,这里是全局变量,其中包含一些允许访问区块链的属性。 msg.sender 始终是当前(外部)函数调用的来源地址。

最后,真正被用户或其他合约所调用的,以完成本合约功能的方法是 mintsend。 如果 mint 被合约创建者外的其他人调用则什么也不会发生。 另一方面, send 函数可被任何人用于向他人发送币 (当然,前提是发送者拥有这些币)

测试:

给两个节点设置币

传入参数receiver: 0x1234567890123456789012345678901234567890amount: 1

image-20240617013407385

receiver: 0x1234567890123456789012345678901234567891amount: 256

image-20240617013501643

现在给0x1234567890123456789012345678901234567891发送2个币(我们是minter 0x5B38Da6a701c568545dCfcB03FcB875f56beddC4,我这里已经设置了有448个币)

image-20240617014213176

balances 分别看一下0x12345678901234567890123456789012345678910x5B38Da6a701c568545dCfcB03FcB875f56beddC4

image-20240617014250726

image-20240617014305217

可以看到前者多了2个币,后者少了2个币

那么,如果我们往0x1234567890123456789012345678901234567891节点添加了超过446个币会发生什么?

image-20240617014446510

此时不会有输出,即执行失败