EOS · 2018年8月29日 1

EOS智能合约-概述

简介

EOSIO区块链使用Webassembly(WASM)来执行用户编写的智能合约。WASM是一种新兴的Web标准,得到了Google、Microsoft、Apple和其他公司的广泛支持。对编写WASM标准的智能合约来说使用clang/llvm和它的C/C++编译器是目前最为成熟的编译工具链。建议您使用EOSIO工具链。

其他的第三方工具链在开发中,包括:Rust,Python和Solidity。虽然这些语言可能看起来更简单,但它们的性能可能会影响构建的应用程序的规模。对于开发高性能和安全的智能合约,C++是最好的语言,将来eos的智能合约也还会继续支持C++。

EOSIO中一个用户只能管理发布一个智能合约。

本文内容从官方:智能合约概述等相关内容翻译修改所得。

智能合约的通信模式

客户端通过向nodeos发送(推送)消息来调用合约中的动作。这可以使用cleos命令完成。它也可以使用一种EOSIO发送方法(例如,eosio::action::send)来完成。nodeos将操作请求分派给实现合同的WASM代码。该代码完整运行,然后继续处理下一个操作。

在合约中可以定义两种通信模式,InlineDeferred。在当前交易中执行操作是属于Inline;触发一个未来的交易属于Deferred

EOSIO智能合约之间的通信应视为异步的。异步通信模型可能导致垃圾信息,使用资源限制算法可以解决这个问题。(原文:Communication among contracts should be considered as occurring asynchronously. The asynchronous communication model can result in spam, which the resource limiting algorithm will resolve.)

  • Inline
    这种模式下可以理解为同步模式,即请求的其他外部Action要作为原始Action的一部分来执行,并且Inline模式中将使用与原始交易相同的作用域和权限来请求其他Action。如果一个交易的任何部分失败,则Inline调用操作将与当前交易的其余部分一起释放(unwind)。无论成功与否,Inline操作都不会在交易范围之外生成任何通知。

  • Deferred.
    Deferred模式的概念是,将需要执行的动作命令推送到一个节点上。根据节点的判断,该Deferred操作可以在稍后运行,或者一个最佳的时间,但是无法保证一定会执行该Deferred操作。
    如上所述,Deferred模式将由节点自行决定执行与否。从使用Deferred的角度来看,只能确定创建Deferred的请求是否成功提交。Deferred会携带原始合约的权限。可以取消Deferred操作。

Action 与 Transaction

Action表示一个智能合约内的单个操作,而transaction是一个或多个Action的集合。合约和账户之间通过调用Action进行通信。Action可以单独执行,或者组合组合起来作为一个整体执行。

包含多个action的transaction, 这些action要么全部成功要么全部失败。

Action名称约束

Action的类型是 base32被编码为64-bit整数. 这意味着它的字符集长度是12,并且只能包含a-z,1-5,和'.'。如果长度超过12个,他会自动截取前12个符合规则的字符作为action的名字。
合约内Table Names, Structs, Functions, Classes等最大都只能为12个字符。

Action Handlers 与 Action "Apply" Context

智能合约会提供Action句柄来执行所请求的内容。当每一个Action执行的时候,EOS都会为其创建一个独立且隔离的空间,让Action在这个空间内执行。但是一个transaction可能会有多个Action,那么就必然会涉及Action互通的问题,唯一方法是将其持久存储并从EOSIO数据库中检索。这涉及到Multi-Index DB相关的内容。

  • Multi-Index DB是一种在RAM中缓存状态或数据以便快速访问的方法。它支持创建,读取,更新和删除操作,特点就和它的名字一样——多索引。EOSIO Multi-Index API提供了C++接口,它的原型实际是Boost Multi-index Containers;简单讲我们可以使用EOSIO Multi-Index API执行创建表、索引、查询等等的操作,后续会详细介绍它的使用。

如下图所示:

From a global view of an EOSIO blockchain, every node in the EOSIO network gets a copy of and runs every action in every contract. Some of the nodes are doing the actual work of the contract, while others are processing in order to prove the validity of the transaction blocks. It is, therefore, important that contracts be able to determine "who they are", or basically, under which context are they running. Context identification information is provided in the action context, as illustrated in the above diagram by receiver, code, action. receiver is the account that is currently processing the action. code is the account that authorized the contract. action is the ID of the currently running action.

As discussed above, actions operate within transactions; if a transaction fails, the results of all actions in the transaction must be rolled back. A key part of the action context is the Current Transaction Data. This contains a transaction header, an ordered vector of all of the original actions in the transaction, a vector of the context free actions in the transaction, a prunable set of context free data (provided as a vector of blobs) defined by the code that implements the contract, and a full index to the vector of blobs.

Before processing an action, EOSIO sets up a clean working memory for the action. This is where the working variables for the action are held. An action's working memory is available only to that action, even for actions in the same transaction. Variables that might have been set when another action executed are not available within another action's context. The only way to pass state among actions is to persist it to and retrieve it from the EOSIO database. See Persistence API for details on how to use the EOSIO persistence services.

An action can have many side effects. Among these are:
- Change state persisted in the EOSIO persistent storage
- Notify the recipient of the current transaction
- Send inline action requests to a new receiver
- Generate new (deferred) transactions
- Cancel existing (in-flight) deferred transactions (i.e., cancel already-- submitted deferred transaction requests)

以上为官方原文对此的描述。

Transaction确认

收到一个transaction并不意味着这个transaction已经被确认,它仅仅说明这个transaction被一个BP节点接受并且没有错误,当然也意味着很有可能这个transaction被其他bp接受了。

当一个transaction被包含在一个block当中的时候,它才是可以被确认执行的。

Transaction限制

每个transaction必须在30ms或更短时间内执行。如果transaction包含多个Action,并且执行这些Action的总和大于30毫秒,则整个transaction将失败。解决办法就是将多个Action拆分出来,分为不同的transaction执行。

智能合约的文件构成

官方提供了一个工具eosiocpp,它可以按照固定的模板创建一个新的智能合约。eosiocpp可以创建2个合约文件(曾经是三个文件),它们仅仅包含了合约的框架。

$ cd /data/eos/build/tools
$ ./eosiocpp -n testcc
created testcc from skeleton

$ cd testcc
$ tree
.
├── testcc.cpp
└── testcc.hpp

testcc.hpp:

/**
 *  @file
 *  @copyright defined in eos/LICENSE.txt
 */
#include <eosiolib/eosio.hpp>

testcc.cpp:

#include <eosiolib/eosio.hpp>

using namespace eosio;

class hello : public eosio::contract {
  public:
      using contract::contract;

      /// @abi action 
      void hi( account_name user ) {
         print( "Hello, ", name{user} );
      }
};

EOSIO_ABI( hello, (hi) )

.cpp与.hpp

.hpp是合约的头文件,可以包含一些变量,常量和函数的声明。

.cpp是合约的源码文件,包含合约的具体实现。

.wasm与.wast

.wasm与.wast都是WebAssembly技术对应的文件。简单讲WebAssembly可以把编译型语言(C/C++、golang等)编译成wasm字节码的程序,再藉虚拟机引擎在浏览器内运行,。

任何合约程序想要部署到EOSIO的区块链网络中都必须编译成WASM格式。这是EOS的支持唯一个的格式。.wast是可读的文件(记事本等打开可以很清楚的看到内容),.wasm是.wast对应的二进制文件,两者可以互相转化。

一旦你的CPP文件写好了,就可以用eosiocpp把它编译成WASM文件了,就如在EOS智能合约-HELLO WORLD中所做的那样,以下命令会同时生成${contract}.wasm${contract}.wast两个文件。

$ eosiocpp -o ${contract}.wast ${contract}.cpp

.abi

ABI( Application Binary Interface)文件是一个JSON格式的描述文件,一个ABI定义了机器码如何访问数据结构与对应的方法。一旦你用了ABI描述了你的合约,开发人员就可以通过此ABI和合约进行交互。

ABI与API有相似之处也有差异,API定义了源代码和库之间的接口,因此同样的代码可以在支持这个API的任何系统中编译,然而ABI允许编译好的目标代码在使用兼容ABI的系统中无需改动就能运行。

可以通过eosiocpp工具给指定的.hpp文件生成.abi文件。在EOS智能合约-HELLO WORLD中也有涉及。

$ eosiocpp -g ${contract}.abi ${contract}.hpp

一个.abi示例:

{
  "types": [{
      "new_type_name": "account_name",
      "type": "name"
    }
  ],
  "structs": [{
      "name": "transfer",
      "base": "",
      "fields": {
        "from": "account_name",
        "to": "account_name",
        "quantity": "uint64"
      }
    },{
      "name": "account",
      "base": "",
      "fields": {
        "account": "name",
        "balance": "uint64"
      }
    }
  ],
  "actions": [{
      "action": "transfer",
      "type": "transfer"
    }
  ],
  "tables": [{
      "table": "account",
      "type": "account",
      "index_type": "i64",
      "key_names" : ["account"],
      "key_types" : ["name"]
    }
  ]
}

基础的智能合约

在EOS中,有几个基础的或官方提供的智能合约,分别是eosio.bios、eosio.token、exchange、eosio.msig、eosio.system、eosio.sudo,理论上讲在一个完整的EOS区块链系统中这几种合约都需要部署。下面分别简单介绍一下。

eosio.bios

这个合约用于管理链上的堆栈和非堆栈资源,通过确认用户持有的token控制资源分配,包括带宽、CPU以及内存资源。

在官方的教程中,使用的是eosio账户部署的eosio.bios,我在本地尝试使用其他自建账号部署此合约,发现可以部署但是调用的时候会提示权限错误(缺少密钥),后来直接部署在eosio上解决问题,尚不清楚此合约是否只能部署到eosio

eosio.system

系统智能合约,通过这个智能合约,可以进行很多系统级别的操作,比如用户投票、将用户注册成为生产者、抵押token等等,区块链中的基本操作都会使用到。

一旦部署了eosio.system那么在注册账号等操作的时候会需要RAM、NET、CPU三种资源,而且只能注册12字符长度的账号;会将竞价注册的相关机制加入,就无法注册类似asd、qwe,此种短账号,此类账号的注册需要经过竞价拍卖系统,每天只会成功全网最高价的账号名称。还有最重要的一点:Dawn 4.2版本下发布eosio.system合约之前必须创建eosio.ramfeeeosio.rameosio.stakeeosio.nameseosio.savingeosio.bpayeosio.vpay等7个系统账号,否则某些功能讲无法使用(但有办法弥补)。

此合约我在本地也尝试的使用非eosio账户部署,但是部署成功后不生效,得出的结论就是eosio.bioseosio.system都只能部署到eosio特权账号上,而且两个合约只能生效一个。

EOSIO Dawn 4.2版本官方说明

eosio.token

就是用来发行自定义token,并包含了交易转账等操作。是EOSIO的基石,此合约应当作第一个合约发布。

exchange

目前看来是用于token与token之间相关兑换使用的。

eosio.msig

这个合约用于多重签名(multisig)和用户权限管理用的。每一笔Transaction都会被相应的用户用其密钥签名发布,多重签名即Transaction被多个人签名后才可以发布成功。

eosio.sudo

这是在最新的版本中新增的合约。作用是绕过常规授权检查执行Transaction,前提是需要一个特权账户eosio.sudo。GitHub官方介绍

.
.
.
.
.
.
.
【本文章出自NM1024.com,转载请注明作者出处。】






>>转载请注明原文链接地址:EOS智能合约-概述