文档章节

以太坊智能合约开发第四篇:实现Hello World智能合约

Marser_cn
 Marser_cn
发布于 04/15 22:12
字数 1865
阅读 417
收藏 3
点赞 0
评论 0

原文发表于:以太坊智能合约开发第四篇:实现Hello World智能合约

绝大部分开发者学习一门语言的时候,都是从输出一个 Hello World 开始。我们也从实现一个 Hello World 合约为切入点,开始进入智能合约的世界吧。

环境准备

安装好 nodenpm。这里对node和npm的安装过程,不做详细介绍。本篇依赖的环境版本:

Node : v8.9.0 Npm: 5.5.1

在你的代码目录里,创建名为 smartcontract 的文件夹,并创建如下两个文件 package.jsonHello.sol

smartcontract ├── Hello.sol └── package.json

package.json 文件里,添加如下依赖包配置:

{
  "name": "smartcontract",
  "version": "0.0.1",
  "dependencies": {
    "fs": "0.0.1-security",
    "solc": "^0.4.21",
    "web3": "^0.20.0"
  }
}

fs模块用于文件的相关操作 solc模块是编译器 web3模块是以太坊提供的工具包,主要用于与合约的通信

接下来执行 npm install 下载相关的依赖包。

编写合约代码

环境准备好后,就可以开始编写合约代码了。 打开 Hello.sol 文件,编写代码如下:

//pragma关键字:版本申明。
//用来指示编译器将代码编译成特定版本,以免引起兼容性问题
//此处不支持0.4.0之前的编译器,也不支持0.5.0之后的编译器(条件为 ^)
pragma solidity ^0.4.0;

//contract关键字:合约申明
//和Java、PHP中的class类似
//此处是申明一个名为Hello的合约
contract Hello {

    //public: 函数访问属性(后续文章为详细阐述)
    //returns (string): 定义返回值类型为string
    function say(string name) public returns (string) {
        return name;
    }
}

代码很简单。就实现了用户输入什么字符串,合约就原样返回的操作。

接下来,我们需要编写 合约部署 脚本。

编写合约部署脚本

smartcontract 目录下,新建名为 deploy.js 的文件。代码如下:

//设置web3连接
var Web3 = require('web3');
//http://localhost:7545 为Ganache提供的节点链接
var web3 = new Web3(new Web3.providers.HttpProvider('http://localhost:7545'));
//读取合约
var fs = require('fs');
var contractCode = fs.readFileSync('Hello.sol').toString();
//编译合约代码
var solc = require('solc');
var compileCode = solc.compile(contractCode);

console.log(compileCode);

//获取合约abi和字节码
var abi = JSON.parse(compileCode.contracts[':Hello'].interface);
var byteCode = compileCode.contracts[':Hello'].bytecode;
//创建合约对象
var VotingContract = web3.eth.contract(abi);
//部署合约,并返回部署对象
var deployedContract = VotingContract.new({
    data:byteCode,
    from:web3.eth.accounts[0],  //部署合约的外部账户地址
    gas:750000        //部署合约的矿工费
});
console.log(deployedContract);

代码里我加上了简单的注释。这里解释一下 abi 这个概念。

abi全称是 Application Binary Interface,即应用程序二进制接口。简单的说,就是合约对外的接口描述

需要注意的是,矿工费gas为750000。以太坊上每笔交易的执行(被矿工打包)都会被收取一定数量的gas。gas的目的是限制执行交易所需的工作量,同时为执行支付费用。当EVM执行交易时,gas将按照特定规则被逐渐消耗,无论执行到什么位置,一旦gas被耗尽,将会触发一个 out of gas 异常。当前调用帧所做的所有状态修改都将被回滚。如果执行结束,还有gas剩余,这些gas将会返还给发送账户。因此,如果部署时抛出 out of gas 的异常,我们可适当的提高gas值。

部署

在当前目录下,执行 node deploy.js 命令。我们在部署脚本里将 compileCode 变量打印出来了,粗略看看就行:

{ contracts:
   { ':Hello':
      { assembly: [Object],
        bytecode: '6060604052341561000f57600080fd5b61016c8061001e6000396000f300606060405260043610610041576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff168063d5c6130114610046575b600080fd5b341561005157600080fd5b6100a1600480803590602001908201803590602001908080601f0160208091040260200160405190810160405280939291908181526020018383808284378201915050505050509190505061011c565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156100e15780820151818401526020810190506100c6565b50505050905090810190601f16801561010e5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b61012461012c565b819050919050565b6020604051908101604052806000815250905600a165627a7a72305820ff14cafd1df21e1edf19eff7598bc82a98940cc0fe045d6107d04bb224014f990029',
        functionHashes: [Object],
        gasEstimates: [Object],
        interface: '[{"constant":false,"inputs":[{"name":"name","type":"string"}],"name":"say","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"nonpayable","type":"function"}]',
        metadata: '{"compiler":{"version":"0.4.21+commit.dfe3193c"},"language":"Solidity","output":{"abi":[{"constant":false,"inputs":[{"name":"name","type":"string"}],"name":"say","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"nonpayable","type":"function"}],"devdoc":{"methods":{}},"userdoc":{"methods":{}}},"settings":{"compilationTarget":{"":"Hello"},"evmVersion":"byzantium","libraries":{},"optimizer":{"enabled":false,"runs":200},"remappings":[]},"sources":{"":{"keccak256":"0x2e3dd18fbfbd17bb4f866b1bfbb38082172a0bb58d9396b63bab04e67d9d8e08","urls":["bzzr://d1aae746dfab03e712d8a3cb76b7d4b5bf60f48fafbffa04dfa8a2d53ad5d0ca"]}},"version":1}',
        opcodes: 'PUSH1 0x60 PUSH1 0x40 MSTORE CALLVALUE ISZERO PUSH2 0xF JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH2 0x16C DUP1 PUSH2 0x1E PUSH1 0x0 CODECOPY PUSH1 0x0 RETURN STOP PUSH1 0x60 PUSH1 0x40 MSTORE PUSH1 0x4 CALLDATASIZE LT PUSH2 0x41 JUMPI PUSH1 0x0 CALLDATALOAD PUSH29 0x100000000000000000000000000000000000000000000000000000000 SWAP1 DIV PUSH4 0xFFFFFFFF AND DUP1 PUSH4 0xD5C61301 EQ PUSH2 0x46 JUMPI JUMPDEST PUSH1 0x0 DUP1 REVERT JUMPDEST CALLVALUE ISZERO PUSH2 0x51 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH2 0xA1 PUSH1 0x4 DUP1 DUP1 CALLDATALOAD SWAP1 PUSH1 0x20 ADD SWAP1 DUP3 ADD DUP1 CALLDATALOAD SWAP1 PUSH1 0x20 ADD SWAP1 DUP1 DUP1 PUSH1 0x1F ADD PUSH1 0x20 DUP1 SWAP2 DIV MUL PUSH1 0x20 ADD PUSH1 0x40 MLOAD SWAP1 DUP2 ADD PUSH1 0x40 MSTORE DUP1 SWAP4 SWAP3 SWAP2 SWAP1 DUP2 DUP2 MSTORE PUSH1 0x20 ADD DUP4 DUP4 DUP1 DUP3 DUP5 CALLDATACOPY DUP3 ADD SWAP2 POP POP POP POP POP POP SWAP2 SWAP1 POP POP PUSH2 0x11C JUMP JUMPDEST PUSH1 0x40 MLOAD DUP1 DUP1 PUSH1 0x20 ADD DUP3 DUP2 SUB DUP3 MSTORE DUP4 DUP2 DUP2 MLOAD DUP2 MSTORE PUSH1 0x20 ADD SWAP2 POP DUP1 MLOAD SWAP1 PUSH1 0x20 ADD SWAP1 DUP1 DUP4 DUP4 PUSH1 0x0 JUMPDEST DUP4 DUP2 LT ISZERO PUSH2 0xE1 JUMPI DUP1 DUP3 ADD MLOAD DUP2 DUP5 ADD MSTORE PUSH1 0x20 DUP2 ADD SWAP1 POP PUSH2 0xC6 JUMP JUMPDEST POP POP POP POP SWAP1 POP SWAP1 DUP2 ADD SWAP1 PUSH1 0x1F AND DUP1 ISZERO PUSH2 0x10E JUMPI DUP1 DUP3 SUB DUP1 MLOAD PUSH1 0x1 DUP4 PUSH1 0x20 SUB PUSH2 0x100 EXP SUB NOT AND DUP2 MSTORE PUSH1 0x20 ADD SWAP2 POP JUMPDEST POP SWAP3 POP POP POP PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 RETURN JUMPDEST PUSH2 0x124 PUSH2 0x12C JUMP JUMPDEST DUP2 SWAP1 POP SWAP2 SWAP1 POP JUMP JUMPDEST PUSH1 0x20 PUSH1 0x40 MLOAD SWAP1 DUP2 ADD PUSH1 0x40 MSTORE DUP1 PUSH1 0x0 DUP2 MSTORE POP SWAP1 JUMP STOP LOG1 PUSH6 0x627A7A723058 KECCAK256 SELFDESTRUCT EQ 0xca REVERT SAR CALLCODE 0x1e 0x1e 0xdf NOT 0xef 0xf7 MSIZE DUP12 0xc8 0x2a SWAP9 SWAP5 0xc 0xc0 INVALID DIV 0x5d PUSH2 0x7D0 0x4b 0xb2 0x24 ADD 0x4f SWAP10 STOP 0x29 ',
        runtimeBytecode: '606060405260043610610041576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff168063d5c6130114610046575b600080fd5b341561005157600080fd5b6100a1600480803590602001908201803590602001908080601f0160208091040260200160405190810160405280939291908181526020018383808284378201915050505050509190505061011c565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156100e15780820151818401526020810190506100c6565b50505050905090810190601f16801561010e5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b61012461012c565b819050919050565b6020604051908101604052806000815250905600a165627a7a72305820ff14cafd1df21e1edf19eff7598bc82a98940cc0fe045d6107d04bb224014f990029',
        srcmap: '25:102:0:-;;;;;;;;;;;;;;;;;',
        srcmapRuntime: '25:102:0:-;;;;;;;;;;;;;;;;;;;;;;;;47:78;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;23:1:-1;8:100;33:3;30:1;27:10;8:100;;;99:1;94:3;90:11;84:18;80:1;75:3;71:11;64:39;52:2;49:1;45:10;40:15;;8:100;;;12:14;47:78:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;89:6;;:::i;:::-;114:4;107:11;;47:78;;;:::o;25:102::-;;;;;;;;;;;;;;;:::o' } },
  errors:
   [ ':5:5: Warning: Function state mutability can be restricted to pure\n    function say(string name) public returns (string) {\n    ^ (Relevant source part starts here and spans across multiple lines).\n' ],
  sourceList: [ '' ],
  sources: { '': { AST: [Object] } } }

打开Ganache的 LOGS 面板,可以看到部署产生的交易(transaction)日志:

transaction

箭头所指就是部署成功后的合约地址:0xbf474d24ba8b19811db5deb51137ddccbe3ff288(每个人部署后的地址可能都不相同)。 我们记录下来,后面的合约调用代码里需要用到。同时,也可以打开 ACCOUNTS 面板,观察账户余额的变化。

合约调用

合约部署成功之后,我们写一段代码来调用合约里的 say() 方法,检测一下效果。在 smartcontract 目录下,新建名为 run.js 的文件,代码如下:

//设置web3连接
var Web3 = require('web3');
//http://localhost:7545 为Ganache提供的节点链接
var web3 = new Web3(new Web3.providers.HttpProvider('http://localhost:7545'));
//读取合约
var fs = require('fs');
var contractCode = fs.readFileSync('Hello.sol').toString();
//编译合约代码
var solc = require('solc');
var compileCode = solc.compile(contractCode);
//获取合约abi和字节码
var abi = JSON.parse(compileCode.contracts[':Hello'].interface);
var byteCode = compileCode.contracts[':Hello'].bytecode;
//创建合约对象
var VotingContract = web3.eth.contract(abi);
//0xbf474d24ba8b19811db5deb51137ddccbe3ff288为合约部署地址
var contractInstance = VotingContract.at("0xbf474d24ba8b19811db5deb51137ddccbe3ff288");

var result = contractInstance.say.call('Hello world');
console.log(result);

我们来执行 node run.js 命令,可以看到在终端里输出了 Hello world

至此,第一个智能合约的代码编写 -> 编译 -> 部署 -> 调用的过程就完成了。建议大家动手执行一遍,加深理解。

抛砖引玉

如果我们事先在合约里定义好 Hello 字符串,如何与 name 变量进行字符串拼接?

敬请期待下一篇的讲解。

智能合约开发QQ群:753778670

智能合约开发QQ群


目前有几套区块链实践的视频课程(视频+源码),需要的可加我微信(kuangwenjie)私信我(付费):

  • 『区块链』从零构建以太坊(Ethereum)智能合约到项目实战
  • 基于Ethereum & IPFS的去中心化Ebay区块链项目开发实战
  • HyperLedger(超级账本)Fabric

© 著作权归作者所有

共有 人打赏支持
Marser_cn

Marser_cn

粉丝 55
博文 28
码字总数 20349
作品 0
广州
项目经理
用Solidity语言通过以太坊钱包开发hello world示例

使用以太坊钱包开发实现经典的HelloWord智能合约类。本文中,我们将看到如何编写简单的合约并将其部署到区块链上。我们还将通过发送和读取数据来了解如何与我们的智能合约进行交互。 Solidi...

笔阁
06/21
0
0
智能合约开发环境搭建及Hello World合约

如果你对于以太坊智能合约开发还没有概念(本文会假设你已经知道这些概念),建议先阅读入门篇。 就先学习任何编程语言一样,入门的第一个程序都是Hello World。今天我们来一步一步从搭建以太...

熊丽兵
2017/11/26
0
0
区块链技术术语表 - 以太坊篇

区块链技术相关表包含了常见的区块链术语(概念)及其解释,及进一步阅读参考文章,以加深理解。方便大家阅读博客或网络上其他文章时做快速索引,比特币相关术语参考比特币篇 以太坊 一个基于...

Tiny熊
2017/11/30
0
0
不同的区块链技术,涉及那些编程语言?

区块链技术入门,涉及那些编程语言?在本文中,将介绍比特币、超级账本Fabric和以太坊这三种区块链中,分别使用什么开发语言来进行智能合约编程,并提供你进一步学习的资源链接。 小调查:你...

笔阁
05/05
0
0
不同区块链智能合约开发语言的选择

在本文中,将介绍比特币、超级账本Fabric和以太坊这三种区块链中,分别使用什么开发语言来进行智能合约的编程,并提供你进一步学习的资源链接。 比特币 比特币是第一个真正意义上的区块链,不...

以太坊教程
05/08
0
0
以太坊是什么 - 以太坊开发入门指南

很多同学已经跃跃欲试投入到区块链开发队伍当中来,可是又感觉无从下手,本文将基于以太坊平台,以通俗的方式介绍以太坊开发中涉及的各晦涩的概念,轻松带大家入门。 以太坊是什么 以太坊(E...

熊丽兵
2017/11/22
0
0
php程序员如何开发区块链、以太坊、智能合约的教程

以太坊是备受关注的区块链,它基于密码学技术和P2P通信技术 构建了一个去中心化的平台,所有的交易同步保存在每个节点中, 通过将区块单向级联成链,以太坊有效的保证了交易的不可篡改: 智能...

笔阁
07/02
0
0
以太坊智能合约开发第七篇:智能合约与网页交互

原文发表于:以太坊智能合约开发第七篇:智能合约与网页交互 上一篇中,我们通过truffle开发框架快速编译部署了合约。本篇,我们将来介绍网页如何与智能合约进行交互。 编写网页 首先我们需要...

Marser_cn
04/25
0
0
以太坊开发--truffle和testrpc使用介绍

truffle是本地的用来编译、部署智能合约的工具,而testrpc不同于geth,geth是真正的以太坊环境,testrpc是在本地使用内存模拟的一个以太坊环境,对于开发调试来说,更为方便快捷,当你的合约...

chenyufeng1991
2016/12/04
0
0
嘿,程序员!手把手教你写出智能合约"Hello, World"

区块链大本营出品 参与 | Arvin、波波 由于Dapp(去中心化应用)涉及到智能合约概念、以太坊区块链机制等更为基础的知识点,仅从编程角度来讲解Dapp开发的入门,不免给人以空中楼阁、镜花水月...

雪花又一年
04/19
0
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

DevExpress v18.1最新版帮助文档下载大全

DevExpress v18.1.4帮助文档下载列表大全来啦!包含.NET、VCL、HTML/JS系列所有帮助文档,提供CHM和PDF两个版本。除已停止更新的Silverlight、Windows 8外,其余均为最新版本。 文章底部扫描...

Miss_Hello_World
8分钟前
0
0
Unity Shader中各种空间及变换方法

前几天尝试写一个传送门的shader,发现自己对坐标之间的变换掌握的不够熟练,趁着这阵子想整理shader相关的知识点,先把各种空间及之间转换整理一下。 1 模型空间-世界空间-观察空间-裁剪空间...

爽歪歪ES
14分钟前
0
0

定义和应用 栈(stack)是一种特殊的线性表,其插入(也称入栈或压栈)和删除(也称出栈或弹栈)操作都在表的同一端进行。这一端被称为栈顶(top)另一端称为栈底端(bottom)。 我们生活中其实...

Frost729
15分钟前
0
0
数据分析挖掘学习干货:大数据处理技术的总结与分析

一 数据分析处理需求分类 1 事务型处理 在我们实际生活中,事务型数据处理需求非常常见,例如:淘宝网站交易系统、12306网站火车票交易系统、超市POS系统等都属于事务型数据处理系统。 这类系...

加米谷大数据
20分钟前
0
0
关于看到的从页面调取html或者接口

你看到的可能是路由或者进行的接口拦截的跳转而不是前端页面进行的跳转

凡人修仙者
24分钟前
0
0
Ubuntu 安装 Redis (非源码Build方式)

安装redis : apt-get install redis-server # 安装完会自动自动 使用命令 ps -aux|grep redis 查看是否启动 ---------------------------------- redis 服务操作方式 /etc/init.d/redis-serv......

Alex142857
29分钟前
0
0
mysql字段中去掉括号

eg: select * from (select *,substring_index(substring_index(remarks,"[",1),']',-1) as carCard from test ) as t where carCard LIKE '%C999%'...

writeademo
32分钟前
0
0
web3.py简介

与web3.py库交互的共同入口是web3对象。web3对象提供API,用于python开发的应用与以太坊区块链进行交互,通常是通过连接JSON-RPC服务器进行。 Providers提供者 Providers使web3连接到区块链上...

笔阁
33分钟前
0
0
jquery 获取父页面某一个input框值得写法

//login_name 为父页面的input框的ID var login_name= $('#login_name', window.parent.document).val();//当前用户登录名...

gulf
34分钟前
0
0
mybatis高级查询

说实话不怎么想写这些,可能是我昨天太累了,妹的那个错误一直找不到。醉了,写一下把,分别是多表联合查询以及汇总 <resultMap id="mdxlResult" type="java.util.Map"> <id column="id" ...

木九天
36分钟前
0
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部