实例分析+ 实践步骤,手把手教你编写以太坊、EOS智能合约!

来源 | 《人人都懂区块链》
面试

做者 | Carol
算法

出品 | 区块链大本营(blockchain_camp)编程

* 据说文末有福利!安全

今天,想和你们聊聊编写智能合约这事儿。ruby

不过,在讲编写智能合约以前,先说一个智能合约的故事。网络

绑匪、富豪和教父的故事app

一个绑匪绑架了富豪的儿子。编程语言


教父是黑白两道通吃的大佬。
ide


绑匪和富豪都相信教父。
函数

富豪收到绑匪的电话后,特别担忧给钱以后仍然救不了儿子的性命,而绑匪也担忧放了人拿不到赎金。

二者相持数小时,富豪的儿子提出一个解决办法,让富豪设立一个三方交易的比特币钱包地址,该交易只有在绑匪和教父都用私钥签名后才有效,而且协议被全网广播后,绑匪必须立刻放人。

做为一个自动担保帐户,当情景知足规定条件时,程序就会自动释放或转 移资金。整个过程能够描述为:

  • 富豪创建智能钱包;

  • 绑匪用本身的私钥解锁;

  • 仲裁者调用智能合约函数;

  • 函数触发,将资金转移到合约当中,等待回调发生。

在这个故事中,仲裁者成功调用智能合约函数解决了富豪与绑匪的困境。由此,富豪与绑匪之间的不信任博弈从技术层面被破解了。那么与智能合约相比,传统合约又是怎么运转的呢?

传统合约的订立

传统上,合同的订立是指缔约当事人相互为意思表示并达成合意而成立了合同。合同的订立由“ 订”和“ 立”两个阶段组成。

“ 订”强调缔约的行为和 过程是缔约各方接触、洽商过程,包括缔约各方的接触、洽商并最终达成协议前的整个讨价还价过程。

此阶段由要约邀请、要约、反要约诸制度加以规范和约束,产生先合同义务及缔约过失责任。而“ 立”强调缔约的结果 , 指的是双方合意的达成,即双方当事人就合同条款至少是合同的主要条款已经造成一致意见,各方当事人享有的权利和承担的义务得以肯定,简而言之,合同成立了。

实际而言,合约的“ 订”实际上是要约,要约指一方当事人向他人作出的以必定条件订立合同的意思表示。前者称为要约人,后者称为受要约人。而要约的形式——要约做为一种意思表示,能够书面形式作出,也能够对话形式作出。书面形式包括信函、电报、电传、传真、电子邮件等函件。

要约的有效条件有如下三点。

  1. 要约必须是特定人的意思表示。

  2. 要约必须是向相对人发出的意思表示。要约的相对人应为特定的人,但在特殊状况下也能够为不特定的人。

  3. 要约必须是可以反映所要订立合同主要内容的意思表示。

而合约“ 立”这一阶段就是承诺,承诺指受要约人赞成要约内容缔结合同的意思表示。承诺应以通知的方式作出,但根据交易习惯或要约代表能够经过行为作出的除外。缄默或不行为不能做为承诺的表示方式。

承诺的有效要件:承诺须由受要约人或其受权的代理人作出;承诺须在有效期内作出;承诺须与要约的内容一致;承诺须向要约人作出。因此,合同订立的通常程序应该以下。

  1. 当事人双方相互约定,双方当事人有合做意向后就合约的内容不断探讨交流,最后造成合做的一致意见。

  2. 合同起草。有了明确的合做意见后,就敲定合约的细节,由双方当事人或者第三方( 被双方所认可的)来着手合约的起草,完成合约的书面文本 后,由双方当事人确认合约细节,确认无误后方可。

  3. 专业人员评估。完成合约起草后,还须要合约有关专业人员( 如律师) 来确认合约自己的合法性,公证处对合同进行公证备案。

  4. 合同执行。合同执行主要靠当事人双方自觉执行,如出现违约等状况, 双方当事人应相互协商解决,协商后依旧没法解决的,可申请仲裁或上诉法 院,法院判决后强制执行。

智能合约的编写步骤

相比传统合约时效性受到诸多限制,智能合约则存在着诸多好处,签署效 率高,安全性强,且在违约执行时实现了不可抵赖和自动执行性。

那么,怎样编写一个智能合约来解决咱们的问题呢?

通常而言,一个运行智能合约的去中心化平台会提供一条公有区块链,并会制定面向智能合约的一套编程语言。智能合约的开发者能够在该智能合约平台上 使 用 官 方 提 供 的 工 具 , 来 开 发 支 持 该 平 台 区 块 链 协 议 的 应 用 ( 即 所 谓 的 D A P P )。

所以,能够在智能合约平台上进行编写,具体的逻辑步骤以下。

  • 第一步,启动一个区块链节点。

  • 第二步,使用编程语言编译智能合约,而后将源代码编译得到二进制代码。

  • 第三步,将编译好的合约部署到网络,得到合约的区块链地址和ABI 。(这一步可能会消耗费用,还须要使用节点的默认地址或者指定地址来给合约签名。)

  • 第四步,用JavaScript API来调用合约。(根据调用的类型有可能会消耗费用)

实例分析一:以太坊智能合约编写

1. 安装以太坊的准备工做

若是是首次接触 Ethereum( 以太坊),推荐使用下面的步骤安装部署。

第一步,安装 Ethereum。

sudo apt-get install software-properties-commonsudo add-apt-repository -y ppa:ethereum/ethereum sudo add-apt-repository -y ppa:ethereum/ethereum-dev sudo apt-get updatesudo apt-get install Ethereumsudo apt-get install software-properties-commonsudo add-apt-repository -y ppa:ethereum/ethereum sudo add-apt-repository -y ppa:ethereum/ethereum-dev sudo apt-get updatesudo apt-get install Ethereum

第二步,安装 solc 编译器。

sudo add-apt-repository ppa:ethereum/ethereum-qt sudo add-apt-repository ppa:ethereum/ethereum sudo apt-get updatesudo apt-get install cpp-ethereumsudo add-apt-repository ppa:ethereum/ethereum-qt sudo add-apt-repository ppa:ethereum/ethereum sudo apt-get updatesudo apt-get install cpp-ethereum

安装后可使用 geth 命令建立 Ethereum 帐户。

geth account newgeth account new

第三步,Solidity 语言支持。

Browser-solidity 提供了在线的 Solidity 语言测试。须要下载包括 Solidity 运行 环境的安装包。

第四步,安装客户端 Mist。

官方提供钱包客户端 Mist,支持进行交易,同时支持直接编写和部署智能合约。

所编写的代码编译发布后,能够部署到区块链上。使用者可经过 Mist 发送指令,调用相应交易合约,让以太坊虚拟机(EVM)在区块链上执行交易合约。

以太坊如今有多种语言实现的客户端,包括如下几种: 

  • ethereumjs-lib:JavaScript 语言实现;

  • Ethereum(J):Java 语言实现;

  • ethereumH:Haskell 语言实现;

  • go-ethereum:Go 语言实现;

  • Parity:Rust 语言实现;

  • pyethapp:Python 语言实现;

  • ruby-ethereum:Ruby 语言实现。

2. 在以太坊上编程时的注意事项

完成准备工做后,就能够着手编写属于本身的智能合约。在编写过程当中, 还有一些地方须要注意。

(1)查看验证节点可否正常运行 

在成功部署了一个智能合约后,输入数据时便可验证代码是否正常运行。

(2)部署在其余节点上 

为了使其余人能够运行你的智能合约,你须要两个信息。


① 智能合约地址Address。
② 智能合约ABI。ABI其实就是一个有序的用户手册,描述了全部方法的名字和如何调用它们。可使用如下代码得到其 ABI 和智能合约地址。

geiverCompiled.griver.info.abiDefinition; greeter.address;geiverCompiled.griver.info.abiDefinition; greeter.address;

而后能够实例化一个 JavaScript 对象,该对象能够用来在任意联网机器上 调用该合约,此处 ABI 和 Address 是上述代码返回值。

var griver= eth.contract(ABI).at(Address);var griver= eth.contract(ABI).at(Address);

(3)自毁程序 

一个交易被发送到网络须要支付费用,自毁程序是对网络的补充,花费的费用远小于一次经常使用交易。

能够经过如下代码来检验是否成功,若是自毁程序运行成功,如下代码会返回 0。

giver.kill.sendTransaction({from:eth.accounts[0]})giver.kill.sendTransaction({from:eth.accounts[0]})

3. 实际操做

根据以太坊白皮书上所说的对冲合约,即一种金融衍生品,咱们能够进行代码编写。如下是白皮书上所举的一个例子:

等待 A 输入 1000 以太币;等待 B 输入 1000 以太币;经过查询数据提供合 约,将价值 1000 以太币的等值美圆,如 x 美圆,记录至存储器。

30 天后,容许 A 或 B“ 从新激活”合约以发送价值 x 美圆的以太币( 从新查 询数据提供合约,以获取新价格并计算)给 A,并将剩余的以太币发送给 B。

实现步骤以下。

第一步,肯定进行交易的双方,包含双方地址、是否投票( 默认为否)、 金额等数据。代码以下。

struct giver{address gaddr;//A方人地址bool yn;//是否投票 uint}amount;//金额struct reciever{address raddr;//B方人地址 bool yn;//是否投票uint amount;//金额 }struct giver{address gaddr;//A方人地址bool yn;//是否投票 uint}amount;//金额struct reciever{address raddr;//B方人地址 bool yn;//是否投票uint amount;//金额 }

第二步,对双方进行初始化,首先每一个帐户内打入 1000 以太币;确认交易后,将 bool 从新设定为 true;接着用一个 storage 保存相关地址以方便后面调用( 若是没有 amount 而使用 balance,将会使得 storage 没法调用);最后两个帐户之间的转帐能够只用 msg.sender( 准备下次实现),目前只有将 amount 数值设定为 0,来表示将 1000 以太币转入对冲基金,在现实生活中则有很高的风险,是明显不可取的。代码以下。

function initializeA(address giverA){ // A方人初始化givers[giverA].amount = 1000 ether; givers[giverA].yn = true;p1 = giverA;givers[giverA].amount = 0 ether;}function initializeB(address recieverB){ // B方人初始化recievers[recieverB].amount = 1000 ether; recievers[recieverB].yn = true;p2 = recieverB; recievers[recieverB].amount = 0 ether; }function initializeA(address giverA){ // A方人初始化givers[giverA].amount = 1000 ether; givers[giverA].yn = true;p1 = giverA;givers[giverA].amount = 0 ether;}function initializeB(address recieverB){ // B方人初始化recievers[recieverB].amount = 1000 ether; recievers[recieverB].yn = true;p2 = recieverB; recievers[recieverB].amount = 0 ether; }

第三步,实现对冲的第一步,将 1000 以太币根据汇率转换成其余货币。

inthedgevalue;function hedging1(uintexchangerate) returns (uint){ hedgevalue = 1000 ether /exchangerate ;return hedgevalue;}inthedgevalue;function hedging1(uintexchangerate) returns (uint){ hedgevalue = 1000 ether /exchangerate ;return hedgevalue;}

第四步,实现对冲的第二步,30 天后再次转化回以太币。值得注意的是, 使用了 bool 以防交易失败。

bool success;function hedging2(uintexchangerate ,uint time) returns(bool success){if(time != 30) return false ;if(givers[p1].yn == false) return false; if(recievers[p2].yn == false) return false; givers[p1].amount = hedgevalue * exchangerate;recievers[p2].amount = 2000 ether - hedgevalue * exchangerate; return true ;}bool success;function hedging2(uintexchangerate ,uint time) returns(bool success){if(time != 30) return false ;if(givers[p1].yn == false) return false; if(recievers[p2].yn == false) return false; givers[p1].amount = hedgevalue * exchangerate;recievers[p2].amount = 2000 ether - hedgevalue * exchangerate; return true ;}

第五步,肯定双方交易后的金额。

经过这五步,一个简单的智能合约就创建起来了。注意,这个智能合约在转换汇率的时候用的是整型,这是一种理想状态,程序能够在 Remix 上完成调试。

全部代码组合起来以下。


以上代码能够简单构成一个智能合约——对冲合约,但这个对冲合约还不够完善,须要更加详细地引入函数和变量来优化它。

实例分析二:EOS 智能合约编写

1. 前期准备

(1)编程语言选择

基于EOS.IO的区块链,使用Web Assembly(WASM)执行开发者提供的应用代码。WASM 是一个已崭露头角的 Web 标准,受到 Google、Microsoft、Apple 及 其余大公司的普遍支持。到目前为止,用于构建应用及 WASM 代码编译的最成 熟的工具链是 clang/llvm 及其 C/C++ 编译器。

其余由第三方开发中的工具链包括 Rust、Python 和 Solidity。尽管用其余语言更简单,可是它们的性能极可能制约所构建的应用规模。EOS 官方推荐的是 C++ 为开发高性能及安全智能合约的最佳语言。

(2)开发环境准备


EOS.IO 软件仅官方支持以下环境:

Ubuntu 16.10 或更高;
MacOS Sierra 或更高。

(3)命令行工具


EOS.IO 提供了一系列工具,须要基本的命令行知识来操做它们。

(4)message 与transaction设定

一个message表明单个操做, 一个transaction是一个或多个messages的集合。合约和帐户经过 messages 通讯。messages 能够单个发送,若是但愿一次执行批 处理也能够集合起来发送。

① 单个message的transaction。

{ "ref_block_num": "100", "ref_block_prefix": "14070148", "expiration": "2018-04-09T06:28:49", "scope": ["initb","initc"], "messages": [{ "code": "eos", "type": "transfer", "authorization": [{ "account": "initb","permission": "active" }],"data": "fbbc85598ab319612aa7f5c904b20701897722968a577a1229873aeb6293192b"} ],"signatures": [],"authorizations": [] }{ "ref_block_num": "100", "ref_block_prefix": "14070148", "expiration": "2018-04-09T06:28:49", "scope": ["initb","initc"], "messages": [{ "code": "eos", "type": "transfer", "authorization": [{ "account": "initb","permission": "active" }],"data": "fbbc85598ab319612aa7f5c904b20701897722968a577a1229873aeb6293192b"} ],"signatures": [],"authorizations": [] }

② 多个messages的transaction,这些messages将所有成功或所有失败。

{ "ref_block_num": "100", "ref_block_prefix": "14070148", "expiration": "2018-04-09T06:28:49", "scope": [...],"messages": [{ "code": "...","type": "...", "authorization": [...], "data": "..."}, {"code": "...","type": "...", "authorization": [...], "data": "..."}, ... ],"signatures": [],"authorizations": [] }{ "ref_block_num": "100", "ref_block_prefix": "14070148", "expiration": "2018-04-09T06:28:49", "scope": [...],"messages": [{ "code": "...","type": "...", "authorization": [...], "data": "..."}, {"code": "...","type": "...", "authorization": [...], "data": "..."}, ... ],"signatures": [],"authorizations": [] }

③ message名的限定。

message的类型其实是base32编码的64位整数。因此message名的前12 个字符需限制在字母a~z, 数字1~5, 以及“.”。第13个之后的字符限制在前16个字符(“.”,a~p)。

④ transaction确认。


得到一个 transaction 哈希并不等于 transaction 完成,它只表示该节点无报错
地接受了,而其余区块生产者极可能也会接受它。但要确认该 transaction,你 须要在 transaction 历史中查看含有该 transaction 的区块数。

2. 技术限制

(1)无浮点数
合约不接受浮点小数计算,由于这在 CPU 层级上是一个不肯定的行为,可能会致使意想不到的分叉。

(2)输出执行时间

transaction 须要在 1 秒内执行,transaction 的执行时间须要 * 小于或等于 1 秒,不然 transaction 将会失败。

(3)tps 限制
最大 30 tps。根据测试公网设置,每一个帐户最多每秒可发布 30 个 transactions.

3. 编写第一个 EOS 智能合约“Hello World”

第一步,使用 eoscpp 来生成智能合约的骨架。这将在 hello 文件夹里产生一 个空白工程,里面有 abi、hpp 和 cpp 文件。

$ eoscpp -n hello$ eoscpp -n hello


① 从.cpp文件含有一个“当收到message后打印 Hello World: ${account}-
>${action}”的样例代码。代码以下。

oid apply( uint64_t code, uint64_t action ) { eosio::print( "Hello World: ", eosio::name(code), "->", eosio::name(action), "\n" );}oid apply( uint64_t code, uint64_t action ) { eosio::print( "Hello World: ", eosio::name(code), "->", eosio::name(action), "\n" );}

② 从.cpp文件生成.wast文件。

$ eoscpp -o hello.wast hello.cpp$ eoscpp -o hello.wast hello.cpp

③ 得到.wast 和 .abi 文件后,就能够将合约部署到区块链上了。

第二步,假设你的钱包已经解锁,而且有 ${account} 的 keys,你就能够上传,用下面的命令将合约上传到 EOS 区块链上。

$ eosc set contract ${account} hello.wasthello.abi Reading WAST...Assembling WASM...Publishing contract...{ "transaction_id": "1abb46f1b69feb9a88dbff881ea421fd4f399 14df769ae09f66bd684436443d5","processed": {"ref_block_num": 144, "ref_block_prefix": 2192682225, "expiration": "2017-09-14T05:39:15", "scope": ["eos","${account}" ],"signatures": [ "2064610856c773423d239a388d22cd30b7ba98f6a9fbabfa621e42cec 5dd03c3b87afdcbd68a3a82df020b78126366227674dfbdd33de7d488f 2d010ada914b438"],"messages": [{"code": "eos", "type": "setcode", "authorization": [{"account": "${account}","permission": "active" }],"data": "0000000080c758410000f1010061736d0100000001110460017f0060017e0060000060027e7e00021b0203656e76067072696e746e000103656e76067072696e7473000003030202030404017000000503010001071903066d656d6f7279020004696e69740002056170706c7900030a20020600411010010b17004120100120001000413010012001100041c00010010b0b3f050041040b04504000000041100b0d496e697420576f726c64210a000041200b0e48656c6c6f20576f726c643a20000041300b032d3e000041c0000b020a000029046e616d6504067072696e746e0100067072696e7473010004696e697400056170706c79020130013 1010b4163636f756e744e616d65044e616d6502087472616e736665720 0030466726f6d0b4163636f756e744e616d6502746f0b4163636f756e7 44e616d6506616d6f756e740655496e743634076163636f756e7400020 76163636f756e74044e616d650762616c616e63650655496e743634010 00000b298e982a4087472616e736665720100000080bafac6080369363 401076163636f756e7400076163636f756e74"} ],"output": [{ "notify": [],"deferred_transactions": [] }}]}$ eosc set contract ${account} hello.wasthello.abi Reading WAST...Assembling WASM...Publishing contract...{ "transaction_id": "1abb46f1b69feb9a88dbff881ea421fd4f399 14df769ae09f66bd684436443d5","processed": {"ref_block_num": 144, "ref_block_prefix": 2192682225, "expiration": "2017-09-14T05:39:15", "scope": ["eos","${account}" ],"signatures": [ "2064610856c773423d239a388d22cd30b7ba98f6a9fbabfa621e42cec 5dd03c3b87afdcbd68a3a82df020b78126366227674dfbdd33de7d488f 2d010ada914b438"],"messages": [{"code": "eos", "type": "setcode", "authorization": [{"account": "${account}","permission": "active" }],"data": "0000000080c758410000f1010061736d0100000001110460017f0060017e0060000060027e7e00021b0203656e76067072696e746e000103656e76067072696e7473000003030202030404017000000503010001071903066d656d6f7279020004696e69740002056170706c7900030a20020600411010010b17004120100120001000413010012001100041c00010010b0b3f050041040b04504000000041100b0d496e697420576f726c64210a000041200b0e48656c6c6f20576f726c643a20000041300b032d3e000041c0000b020a000029046e616d6504067072696e746e0100067072696e7473010004696e697400056170706c79020130013 1010b4163636f756e744e616d65044e616d6502087472616e736665720 0030466726f6d0b4163636f756e744e616d6502746f0b4163636f756e7 44e616d6506616d6f756e740655496e743634076163636f756e7400020 76163636f756e74044e616d650762616c616e63650655496e743634010 00000b298e982a4087472616e736665720100000080bafac6080369363 401076163636f756e7400076163636f756e74"} ],"output": [{ "notify": [],"deferred_transactions": [] }}]}

第三步,若是查看 eosd 进程的输出,你会看到:

...] initt generated block #188249 @ 2018-04-13T22:00:24 with 0 trxs 0 pendingInit World!Init World!Init World!...] initt generated block #188249 @ 2018-04-13T22:00:24 with 0 trxs 0 pendingInit World!Init World!Init World!

能够看到“Init World!”被执行了三次,这其实并非个bug。区块链处理 transactions 的流程以下。

① eosd收到一个新transaction(正在验证的transaction);

建立一个新的临时会话;
尝试应用此 transaction;
成功并打印出“Init World!”; 失败则回滚所作的变化(也有可能打印“Init World!”后失败)。

② eosd开始产出区块;

撤销全部 pending 状态; 

推进全部交易输出记录在该区块; 

第二次打印“Init World!”; 

完成区块;

撤销全部创造区块时的临时变化。

③ eosd如同从网络上得到区块同样将区块追加到链上;

第三次打印“Init World!”。

此时,合约就能够开始接收 messages 了。由于默认 message 处理器接收所有 messages,咱们能够发送任何咱们想发的东西。

第四步,咱们试试发一个空的 message:

此命令将“hello”message 及十六进制字符串“abcd”所表明的二进制文件传出。注意,后面将展现如何用一个好看易读的 JSON 对象替换十六进制字符串的 ABI。以上,咱们只是想证实“hello”类型的 message 是如何发送到帐户的。

结果以下。

第五步,继续查看 eosd 的输出,将在屏幕上看到:

Hello World: ${account}->hello Hello World: ${account}->hello Hello World: ${account}->helloHello World: ${account}->hello Hello World: ${account}->hello Hello World: ${account}->hello

再一次,你的合约在 transaction 被第三次应用并成为产出的区块以前被执行和撤销了两次。

第六步,若是查看ABI文件,将会注意到这个ABI 定义了一个叫transfer 的 action,它的类型也是 transfer。这就告诉 EOS.IO,当 ${account}->transfer 的 message 发生时,它的 payload 是 transfer 类型的。transfer 类型是在 structs 的列表 中定义的,其中有个对象,name 属性是 transfer。

第七步,在弄清骨架 ABI 后,能够构造一个 transfer 类型的 message。

第八步,继续观察 eosd 的输出,将看到:

根据ABI,transfer message应该是以下格式:

account_name -> uint64表示这个message的二进制,表示以下:

第九步,修改 hello.cpp,打印出消息内容:

第十步,重编译并部署:

① 重部署将再次调用init( ):

② 执行transfer:

③ 将看到eosd有以下输出:

④ 使用 C++ API来读取 messages,代码以下。

目前咱们使用的是C API,由于这是EOS.IO直接暴露给WASM虚拟机的最底层的 API。幸运的是,eoslib 提供了一个更高级的 API,移除了不少没必要要的代码。

第十一步,能够像下面同样更新 hello.cpp,把它变得更简洁。

这里能够注意到,咱们更新了transfer的struct,直接使用eosio::name 类型, 并将 read_message 先后的类型检查压缩为一个单个的 current-Message 调用。

在编译和上传后,还能够看到和 C 语言版本一样的结果。到此为止,已经完成了第一个智能合约“Hello World”的编写。

4. 部署和升级智能合约

如上所述,将合约部署到区块链上能够经过set contract命令简单地完成。而且若是有权限的话,set contract命令还可更新现有合约。

使用下面的命令来部署一个新合约,更新现存合约。

5. 调试智能合约

为调试智能合约,须要安装本地的 eosd 节点。本地的 eosd 节点能够以单独的调试私网来运行,也能够做为调试公网( 或官方的调试网络)的延伸来运行。

在第一次建立智能合约时,最好先在测试私网中测试调试完毕智能合约, 由于这样能够彻底掌握整个区块链。这使你有无限的 eos,并且能够随时重置 区块链的状态。当合约能够上生产环境时,能够经过将本地 eosd 和测试公网( 或官方的调试网络)链接起来以完成公网的调试,这样就能够在本地的 eosd 上看到测试网络的数据了。

若是尚未安装本地 eosd,请根据安装指南安装。默认状况下,本地 eosd 将只在测试私网中运行,除非修改config.ini 文件,将其与测试公网(或官方的 调试网络)节点链接,就像该指南中提到的同样。

(1)方法
用于调试智能合约的主要方法是 Caveman调试法,咱们使用打印的方法来

监控一个变量并检查合约的流程。在智能合约中打印信息能够经过打印 API(C 和 C++)来完成。C++ API 是 C API的封装,所以,大多数状况下咱们用的是 C++ API。

(2)打印
C API 支持打印以下数据类型:
prints - a null terminated char array (string);
prints_l - any char array (string) with given size;
printi - 64-bit unsigned integer;
printi128 - 128-bit unsigned integer;
printd - double encoded as 64-bit unsigned integer; 

printn - base32 string encoded as 64-bit unsigned integer;

printhex - hex given binary of data and its size。

打印时,C++ API 经过重写print( )方法封装了一些上面的C API,使用户 不须要关心须要调用哪一个打印函数。C++ 打印 API支持如下数据类型:

a null terminated char array (string);
integer (128-bit unsigned, 64-bit unsigned, 32-bit unsigned, signed, unsigned); base32 string encoded as 64-bit unsigned integer;
struct that has print( ) method。

结语 : 智能合约的漏洞隐患

智能合约的编写其实并不困难,但对于编写智能合约代码的逻辑和正确性须要认真对待。The DAO事件中,黑客就是利用了智能合约的漏洞攻击了该智 能合约,使合约内源源不断地有以太币转帐到黑客的帐户,给以太坊和众筹投资者形成了大量损失。

因此在编写智能合约方面,若是只是想学习一下,那么请随意尝试,但若是是要实际应用智能合约,必定要注意其安全性和正确性。

恋人之间“永不分离”的海誓山盟也能够经过智能合约来实现。如婚前双方拿出部分资产写入智能合约,而后将智能合约的触发条件绑定在婚姻登记链上,一旦双方离婚,智能合约内的财产将直接转入第三方公益组 织,双方都将没法拿回财产,这样就使男女双方难以离开对方。

若是让你编写一个恋人之间海誓山盟的智能合约,你会怎么写呢?欢迎留言告诉咱们,咱们将在 12 月 16 日抽出 2 个优质留言,赠送《人人都懂区块链》纸质书一本!快拉到文末留言吧!

如今报名,立享200元优惠,赶忙报名吧!???????? 

推荐阅读


猛戳 “阅读财经 ”当即报名

老铁在看了吗?????