部署以太坊智能合约-初级篇(1)

运行环境
win7

开发环境搭建Solidity安装
强烈建议新手使用Browser-Solidity来进行开发。(初次在浏览器打开需要一会加载时间)。
Browser-Solidity是一个基于浏览器的Solidity,就可以不用安装Solidity,本文的Hello World教程也将基于Browser-Solidity来进行。
如果你想自己安装请参考Solidity安装指引。

geth 安装
1、国内下载地址:http://ethfans.org/wikis/Ethereum-Geth-Mirror
2、选择windows系统版本进下载,下载完成后可直接进行安装。
3、程序安装目录默认是C盘,建议选择其它盘进行安装。
4、安装成功后,打开安装目录可看到geth.exe。
这里写图片描述
5、安装过程中已经默认配置了系统环境变量,所以可直接在cmd上执行geth命令。
这里写图片描述

启动环境(开发)
geth是一个以太坊客户端,现在利用geth启动一个以太坊(开发者)网络节点。

geth --datadir "D:\blockchain\geth\devchain" --dev console

执行命名后,会进入geth控制台,这时光标停在一个向右的箭头处,像这样:
这里写图片描述
命令参数说明:
dev 启用开发者网络(模式),开发者网络会使用POA共识,默认预分配一个开发者账户并且会再交易后自动开启挖矿。
datadir 后面的参数是区块数据及秘钥存放目录。
第一次输入命令后,它会在D:\blockchain\geth\devchain目录下存放数据。
console 进入控制台

准备账户
部署智能合约需要一个外部账户,我们先来看看分配的开发者账户,在控制台使用以下命令查看账户:

eth.accounts

回车后,返回一个账户数组,里面有一个默认账户,如:
这里写图片描述
也可以使用personal.listAccounts查看账户。

再来看一下账户里的余额,使用一下命令:

eth.getBalance(eth.accounts[0])

回车后,可以看到大量的余额,已wei为单位,如:
1.15792089237316195423570985008687907853269… e+77

开发者账户因余额太多,如果用这个账户来部署合约时会无法看到余额变化,为了更好的体验完整的过程,这里选择创建一个新的账户。

创建账户
使用以下命令创建账户:

personal.newAccount("123456")

123456为新账户的密码,回车后,返回一个新账户。
这里写图片描述
“0x55c8040eb4e4e4ef90a5de30e4301408413955e9”,为新账户的地址。

这时我们查看账户列表:
这里写图片描述
可以看到账户数组里包含两个账户,新账户在第二个(索引为1)位置。

现在看看新账户的余额:
这里写图片描述

给新账户转账
我们知道没有余额的账户是没法部署合约的,那我们就从默认账户转10以太币给新账户,使用以下命令。

eth.sendTransaction({from: '0x4ff53de60a3b7a3e358a3fe4904b106b3f8bc2d4', to: '0x55c8040eb4e4e4ef90a5de30e4301408413955e9', value: web3.toWei(10, "ether")})

from为输入,填默认账户的地址
to为输出,填新账户的地址
执行命令,进行交易
这里写图片描述
执行后信息提示生成新的区块,交易被确认了。
查看新账户的余额,以ehher为单位。

web3.fromWei(web3.eth.getBalance(eth.accounts[1]), 'ether')

这里写图片描述

解锁账户

在部署合约前需要先解锁账户(就像银行转账要输入密码一样),使用以下命令:

personal.unlockAccount(eth.accounts[1],"123456")

“123456” 是之前创建账户时的密码。
这里写图片描述
解锁成功后,账户就准备完毕啦,接下来就是编写合约代码。

编写合约代码
现在我们来开始编写第一个智能合约代码,solidity代码如下:

pragma solidity ^0.4.20;//当前solidity版本
contract hello {
    string greeting;

    //构造函数
    function hello(string _greeting) public {
        greeting = _greeting;
    }
    //获取greeting,无需gas
    function getGreeting() constant public returns (string) {
        return greeting;
    }
    //设置改变greeting,需要gas
    function setGreeting(string _greeting)  public payable{
        greeting = _greeting;
    }
}

简单解释下,我们定义了一个名为hello的智能合约,在智能合约初始化时保存了一个字符串(我们会传入hello world),每次调用getGreeting返回字符串,每次调用setGreeting改变字符串。

solidity发展非常快,solidity版本之间有可能不能兼容,这时你可以在Browser-Solidity的Settings里选择对应的编译器版本。
Browser-Solidity也不停的更新中,截图可能和你看到的界面不一样。

这里写图片描述

把这段代码写(拷贝)到Browser-Solidity,如果没有错误,点击Details获取部署代码,如:
这里写图片描述
在弹出的对话框中找到WEB3DEPLOY部分,点拷贝,粘贴到编辑器后,修改初始化字符串为hello world。
这里写图片描述
部署合约

Browser-Solidity生成的代码,拷贝到编辑器里修改后的代码如下:

1. var _greeting = "hello world";
2. var helloContract = web3.eth.contract([{"constant":false,"inputs":[{"name":"_greeting","type":"string"}],"name":"setGreeting","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":true,"inputs":[],"name":"getGreeting","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"inputs":[{"name":"_greeting","type":"string"}],"payable":false,"stateMutability":"nonpayable","type":"constructor"}]);
3. var hello = helloContract.new(
4.    _greeting,
5.    {
6.      from: web3.eth.accounts[1],
7.      data: '0x6060604052341561000f57600080fd5b6040516103d43803806103d4833981016040528080518201919050508060009080519060200190610041929190610048565b50506100ed565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f1061008957805160ff19168380011785556100b7565b828001600101855582156100b7579182015b828111156100b657825182559160200191906001019061009b565b5b5090506100c491906100c8565b5090565b6100ea91905b808211156100e65760008160009055506001016100ce565b5090565b90565b6102d8806100fc6000396000f30060606040526004361061004c576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff168063a413686214610051578063fe50cc72146100a3575b600080fd5b6100a1600480803590602001908201803590602001908080601f01602080910402602001604051908101604052809392919081815260200183838082843782019150505050505091905050610131565b005b34156100ae57600080fd5b6100b661014b565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156100f65780820151818401526020810190506100db565b50505050905090810190601f1680156101235780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b80600090805190602001906101479291906101f3565b5050565b610153610273565b60008054600181600116156101000203166002900480601f0160208091040260200160405190810160405280929190818152602001828054600181600116156101000203166002900480156101e95780601f106101be576101008083540402835291602001916101e9565b820191906000526020600020905b8154815290600101906020018083116101cc57829003601f168201915b5050505050905090565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f1061023457805160ff1916838001178555610262565b82800160010185558215610262579182015b82811115610261578251825591602001919060010190610246565b5b50905061026f9190610287565b5090565b602060405190810160405280600081525090565b6102a991905b808211156102a557600081600090555060010161028d565b5090565b905600a165627a7a72305820797c0495b8a7c3bc6f7ddff4bff5a8eb7566b3f803151cd12cf5220fad3bb0fa0029',
8.      gas: '4700000'
9.    }, function (e, contract){
10.     console.log(e, contract);
11.     if (typeof contract.address !== 'undefined') {
12.          console.log('Contract mined! address: ' + contract.address + ' transactionHash: ' + contract.transactionHash);
13.     }
14. })

这里解释下代码
第1行:修改过字符串为Hello World。
第2行:用eth.contract来定义一个合约类(ABI接口)。
第3行:部署创建合约实例,并修改合约实例名,之后可以直接用实例调用函数。
第4行:创建实例时的入参。
第6行:部署合约的账户,该账户需先解锁,不然会报错,这里用新账户部署。
第7行:data里为合约的编译后的二进制代码。
第8行:准备付的gas费用,IDE已经帮我们预估好了。
第9行:设置部署回调函数。

拷贝编辑好的代码到geth控制台里,回车后,看到输出如:
这里写图片描述
说明合约已经部署成功。
transactionHash: 0x2ba1c9ec9906550e7ca026e31b46eae0db921429c024df1f8a022c41bc507a32,为交易号(部署智能合约也是一笔交易)
address: 0x0bc4d7f46cfb79fb149c37a55f855c2f0e3dbb05,为智能合约的账户地址

现在我们查看下新账户的余额:
这里写图片描述
已经消耗掉一些gas了

运行合约

运行hello.getGreeting() ,输出Hello World,成功运行了,且没有消耗gas。
这里写图片描述

但是这样运行hello.setGreeting()就会报错。
这里写图片描述
因为运行setGreetin()有改变greeting值(也可理解为状态),则需要进行交易。

继续验证setGreetin()
查询eth.getBalance(eth.accounts[1])里写图片描述](https://img-blog.csdn.net/20180312170325164?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvdTAxMjExNzY1Ng==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)
新账户还剩:9999999999999585794 wei。

解锁账户。

personal.unlockAccount(eth.accounts[1],"123456")

这里写图片描述
执行setGreeting,进行交易

hello.setGreeting.sendTransaction('hey boy',{from:eth.accounts[1], gas:3000000})

执行setGreetin(),分配3000000wei的gas进行交易。
这里写图片描述
交易成功,得到交易号 0x87dc8f83594b28dc5e38fcf4cbf6f8c5a0908cbf005d274e489a8629c432cf63。
查询交易信息。

eth.getTransactionReceipt('0x87dc8f83594b28dc5e38fcf4cbf6f8c5a0908cbf005d274e489a8629c432cf63')

这里写图片描述
了解到实际消耗了33141wei的gas。
验证交易

eth.getBalance(eth.accounts[1])
hello.getGreeting()

这里写图片描述

验证成功。

总结下以上智能合约开发部署流程
1,启动geth客户端,进入console控制台
2,使用solidity语言实现智能合约代码
3,在Browser-Solidity上编译
4,复制编译好的代码粘贴到console控制台运行
5,部署完成

参考的资料
http://web3js.readthedocs.io/en/1.0/
http://blog.csdn.net/ddffr/article/details/76549320
http://remix.ethereum.org


版权声明:本文为u012117656原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。