写点什么

浅入浅出智能合约 - 概述(一)

  • 2019-12-05
  • 本文字数:3189 字

    阅读完需:约 10 分钟

浅入浅出智能合约 - 概述(一)


智能合约(Smart Contract)是时下非常热门的概念,但是它在 20 多年前就已经被非著名计算机科学家 Nick Szabo 提出了,它将智能合约描述为一种以信息化方式传播、验证或者执行合约的计算机协议,能够允许在没有第三方的情况下进行可信的交易,并且这些交易是无法被追踪、同时也是不可逆的。


A smart contract is a computer protocol intended to digitally facilitate, verify, or enforce the negotiation or performance of a contract. Smart contracts allow the performance of credible transactions without third parties. These transactions are trackable and irreversible.



作为区块链鼻祖的 Bitcoin 虽然通过 POW 实现了 分布式一致性,同时使用 UTXO 模型 存储和管理底层数据结构,实现了去中心化的分布式账本,并且在一定程度上实现了『可编程』这一特点,但是它的脚本机制非常简单,只是一个基于堆栈式的脚本语言,它不仅没有函数的功能,同时也不是图灵完备的,无法实现复杂的逻辑。


Ethereum 在今天一般被视为区块链 2.0 项目,与 Bitcoin 不同,Ethereum 平台实现了图灵完备的编程语言,这样我们就能够在 Ethereum 上编写和部署智能合约,利用 Ethereum 支持的编程语言 Solidity 以及 API 实现一些复杂的功能。

Solidity

在 Ethereum 上提到编写智能合约时,很难离开 Solidity 这门编程语言。想要系统、详细地学习 Solidity 建议直接阅读相关的 官方文档,文章并不会对详细展开介绍如何编写智能合约,而是会重点介绍这门编程语言是如何设计的。



虽然目前很多的基础链都使用 Solidity 作为平台支持的编程语言,但是也有一些基础链,例如 EOS 提供了 C++ 的 API 用于编写智能合约,这只是不同的平台基于不同目的之后做出的选择和权衡。不过在这篇文章中,我们会以 Ethereum 上的 Solidity 为例展开介绍。

组成

Solidity 是一门面向合约并且图灵完备的编程语言,这门编程语言总共包含四种不同的重要元素,ContractVariableFunctionEvent



其中合约(Contract)是 Solidity 中的核心概念,我们都知道 Ethereum 遵循 账户余额模型 实现底层的逻辑和设计数据结构,其中的账户总共分为两种,一种是被私钥控制的外部账户,这与 Bitcoin 中的地址非常相似,另一种就是被合约代码控制的账户,这些部署在 Ethereum 合约中的代码都使用 Solidity 进行编写,最终部署到整个网络中。


每一个合约账户中的代码都是一个 Contract,它与面向对象编程中类的概念非常类似,无论是合约还是类都可以有变量和函数,但是类是可以实例化的,合约并没有实例化这一功能,它的变量和函数可以直接在合约本身上访问或者调用。



变量、函数和事件其实都是属于某一个合约的,这些元素共同组成了一个合约的全部内容,其中变量和函数的功能相信也不需要过多解释,稍微有一些编程经验的人都会知道它们的作用,而事件就是面向合约编程语言中比较特殊的元素了。

事件

在区块链应用出现之前,绝大多数的代码都是运行在一个实例或者节点中的,如果一个服务想要在发生某些事件时对外界发出通知,往往都需要通过向消息队列中发送消息,订阅者可以订阅对应的主题并进行处理。



Ethereum 中对 Pub/Sub 的设计就是围绕事件进行的,事件是面向合约编程范式中语言层面就支持的元素,在我们使用其他编程语言,例如 C++、Golang 时,我们也可以在语言内部通过已有的元素定义一些事件,并向一些事件的相关方发出通知,由于合约需要保持逻辑尽可能简单、减少计算量消耗的特点,很多操作其实并不适合在链上直接执行,所以合约就在语言层面支持了事件,能够在期望的事件发生时直接通知相关方进行处理,不需要合约的开发者重复实现相同的逻辑。


在如下的合约中,我们定义了一个新的事件 Deposit


JavaScript


pragma solidity ^0.4.0;
contract ClientReceipt { event Deposit( address indexed _from, bytes32 indexed _id, uint _value );
function deposit(bytes32 _id) public payable { emit Deposit(msg.sender, _id, msg.value); }}
复制代码


当交易调用合约 ClientReceipt 中的 deposit 函数时,合约就会发出 Deposit 事件,这些事件就可以被 Javascript 的 API 检测到:


JavaScript


var abi = /* abi as generated by the compiler */;var ClientReceipt = web3.eth.contract(abi);var clientReceipt = ClientReceipt.at("0x1234...ab67" /* address */);
var event = clientReceipt.Deposit(function(error, result) { if (!error) console.log(result);});
复制代码


当事件被合约中的函数触发时,事件中的参数就会作为一种特殊的数据结构存储在交易日志中,但是这些日志是无法在智能合约内部访问的。在 Ethereum 由事件组成的 Pub/Sub 模型中,合约本身就像是消息队列,所有调用合约并触发事件的交易(或消息)就是生产者,监听事件的 Javascript API 可以理解为消费者。


ERC20 合约

Ethereum 中最常见的合约应该就是遵循 ERC20 接口的合约了,ERC20 合约的实现现在也非常成熟,在 Ethereum 发行一个新的 Token 的成本可能不到几十块钱。



在这里,我们可以简单看一下 ERC20 协议的一个简单实现:


JavaScript


contract EIP20 is EIP20Interface {    mapping (address => uint256) public balances;    string public name;    uint8 public decimals;    string public symbol;
function EIP20(uint256 _initialAmount, string, uint8 _decimalUnits, string _tokenSymbol) public { balances[msg.sender] = _initialAmount; totalSupply = _initialAmount; name = _tokenName; decimals = _decimalUnits; symbol = _tokenSymbol; }
function transfer(address _to, uint256 _value) public returns (bool success) { require(balances[msg.sender] >= _value); balances[msg.sender] -= _value; balances[_to] += _value; Transfer(msg.sender, _to, _value); return true; }
function balanceOf(address _owner) public view returns (uint256 balance) { return balances[_owner]; }
// ...}
复制代码


在这里省略了非常多的 ERC20 接口中规定的函数,我们就来看一下两个最简单、常用的函数 balanceOf 接受一个 address 参数就会从合约里存储余额的变量 balances 地址对应的余额,转账函数的实现也非常简单,通过 require 保证当前交易的发出者有足够的余额,然后在 balances 减去发出者的 value 增加接受者的 value,最后发出 Transfer 事件并返回。

总结

作为面向合约的编程语言 Solidity 的功能非常简单,但是其中的很多概念都是按照区块链网络的特点设计的,对于有经验的开发者来说,学习和编写 Solidity 并不会是一件特别困难和复杂的事情。


需要注意的是作为区块链上合约或者说 DApp,它一旦部署就无法像其他应用一样更新和升级,所以合约一旦出现 bug 就是非常严重的问题,在编写合约期间一定要认真考虑其中的漏洞,避免编写复杂的代码和逻辑,重要的合约一定要通过形式验证保证程序中不存在缺陷才可以部署发布。

相关文章

Reference

关于图片和转载

本作品采用知识共享署名 4.0 国际许可协议进行许可。


  转载时请注明原文链接,图片在使用时请保留图片中的全部内容,可适当缩放并在引用处附上图片所在的文章链接,图片使用 Sketch 进行绘制,你可以在 [](https://draveness.me/draveness.me/sketch-sketch) 一文中找到画图的方法和素材。
复制代码


本文转载自 Draveness 技术博客。


原文链接:https://draveness.me/smart-contract-intro


2019-12-05 18:17451

评论

发布
暂无评论
发现更多内容

CNCF社区首个!KubeEdge达到软件供应链SLSA L3等级

华为云开发者联盟

云原生 华为云 企业号 2 月 PK 榜 华为云开发者联盟

一文读懂Guava EventBus(订阅\发布事件)

京东科技开发者

架构 观察者模式 Guava EventBus 企业号 2 月 PK 榜

Linux安装elasticsearch-head

代码的路

elasticsearch

令人期待的 SysOM 2.0 OS 迁移、超异构计算系统直播又来了 | 第 63-64 期

OpenAnolis小助手

操作系统 系统运维 sig 龙蜥大讲堂 SysOM

ChatGPT时代的打工人众生相

脑极体

ChatGPT

最佳实践数据服务之设备数据格式ProtoBuf转JSON——实践类

阿里云AIoT

阿里云 物联网 IoT

软件测试 | 常用模拟器使用

测吧(北京)科技有限公司

测试

0源码基础学习Spring源码系列(二)——Spring如何解决循环依赖

京东科技开发者

spring 源码 初始化 二级缓存 企业号 2 月 PK 榜

Blender的布局和工作区

Finovy Cloud

Blende

大数据培训去哪学靠谱?

小谷哥

云小课|MRS基础操作之配置DataNode容量均衡

华为云开发者联盟

大数据 华为云 企业号 2 月 PK 榜 华为云开发者联盟

比Worktile好用的项目管理软件有哪些?

PingCode

项目管理 Worktile 项目管理工具

设计模式第六讲:责任链模式和迭代器模式详解

C++后台开发

设计模式 责任链模式 迭代器模式 后端开发 Linux服务器开发

软件测试/测试开发 | web自动化测试-PageObject 设计模式

测试人

软件测试 自动化测试 测试开发 Web自动化测试

为什么大多数团队推行自动化测试最后却不了了之?

Liam

测试 自动化测试 测试自动化

Bytebase 体验官之勇闯新手村

朱亚光

IoT设备数据业务价值洞察实践——实践类

阿里云AIoT

阿里云 物联网 IoT

企业降本增效的催化剂:敏捷迭代

FinFish

敏捷开发 敏捷迭代 敏捷项目管理

开心档之Java 流(Stream)、文件(File)和IOJava.io

雪奈椰子

Java 开心档

低代码如何快速提升客户体验

力软低代码开发平台

DR-AP40X9-A-Qualcomm-IPQ4019/IPQ4029-2.4G&5G

Cindy-wallys

IPQ4019 ipq4029

轻舟已过万重山:华为之路,平板PC之变

脑极体

华为 PC

IoT设备数据的存储、解析和价值挖掘实践——实践类

阿里云AIoT

阿里云 物联网 IoT

JS常见错误和解决方法集锦

观纵科技

前端 js 错误处理

新型掩码自编码器 AdaMAE,自适应采样

Zilliz

计算机视觉

数字货币现货合约秒合约交易所系统开发案例

开发微hkkf5566

浅入浅出智能合约 - 概述(一)_文化 & 方法_Draveness_InfoQ精选文章