加载中 ...

以太坊竟然升级了,好在Go语言如何调用智能合约变化不大!

2019-10-23 13:26 编辑:btc268.com 来源:区块链资讯

2009年,比特币诞生,距离现在已经过去10年了。区块链技术也从一开始的不为人知,到如今的名扬天下。使用区块链技术,可以制造无须任何国家背书的金融产品,让区块链技术为世人所认知。作为继承和改造的产品以太坊,它推出的全球化编程技术又极大的推动了区块链技术的发展。

以太坊作为改进者,它增加了智能合约的功能,全球爱好者都可以编写自己的智能合约,在全球的以太坊网络中运行,它有一个美好的梦想就是让全球都实行契约化。那么到底什么是智能合约呢?

什么是智能合约?

具体什么是智能合约,我们还是先看一下以太坊智能合约的英文:smart contract,可以分为两部分,智能于合约。对于合约就很好理解了,合约就是合同,事先约定好的规则以及事情发生后双方要付出和接受的代价等。智能的含义就是这个合约(合同)是可以自动被触发和执行的,不用担心违约和赖账的问题,任何内容都写在合同中,一目了然。这样带来的好处就是双方即使没有彼此建立信任也可以完成交易。

智能合约该如何编写呢?

开发以太坊智能合约门槛并不高,目前互联网也有大量的学习资源,只不过自己筛选需要一些过程。那么如开发智能合约呢?从目前的区块链技术发展来看,可以用solidity,python,golang,c ,c#等语言开发智能合约,但从最初的智能合约产生来说,solidity还是更原汁原味一些,solidity其实就是一门语言,把它当成一门新的语言学习就好了。学习一门新的语言的过程无外乎是下面这样的步骤:

·环境安装,运行环境,IDE等

·基础语法

·小案例学习

·项目实战

对于solidity的学习也会包含这些内容,但毕竟区块链是特殊的技术,智能合约的学习也会比其他内容多一些特殊性,比如你要了解区块链的底层原理,你要了解智能合约的运行原理,还有由于智能合约离钱太近了,你还要学习如何编写安全的智能合约,最后就是要吃透一些智能合约讨论出来的标准,比如毁誉参半的ERC20,ERC721等等。

 

以太坊开发环境安装

 

智能合约编辑环境 -- remix

remix其实就是一个集成在网页中的在线编辑环境,不过对网络有一定的要求,相对来说更新的更及时一些,如果在线环境不能使用,可以使用本地环境安装,在后面的geth安装示例中有介绍,不过推荐使用在线环境,本地会经常有问题。remix在线环境:http://remix.ethereum.org

 

以太坊客户端安装 -- geth

在这里主要就是geth的安装,针对不同平台都可以安装,推荐用类unix系统。具体安装可以参考

也有一些人比较喜欢使用ganache作为以太坊客户端的学习工具,相对来说图形化比命令行好接受一些。

geth 私链搭建

geth是以太坊提供的客户端软件,用它你可以加入到以太坊主网中,也可以自己搭建私链,对于学习者来说,一般都是自己搭建私链。

·创世块配置- genesis.json

{ "config": { "chainId": 18, "homesteadBlock": 0, "eip155Block": 0, "eip158Block": 0 }, "alloc" : {}, "coinbase" : "0x0000000000000000000000000000000000000000", "difficulty" : "0x2", "extraData" : "", "gasLimit" : "0xffffffff", "nonce" : "0x0000000000000042", "mixhash" : "0x0000000000000000000000000000000000000000000000000000000000000000", "parentHash" : "0x0000000000000000000000000000000000000000000000000000000000000000", "timestamp" : "0x00"}

·创世块参数

  。chainId 私有网络ID

  。difficulty 挖矿难度,越低挖矿速度越快

  。coinbase 默认的挖矿账户,如果不设定,则使用默认第一个账户

  。gasLimit gas消耗限制,如果过小可能会影响合约发布和运行,建议设为:0xffffffff

·初始化

geth init genesis.json --datadir ./data

如果是首次启动,或者genesi.json文件发生变,那么必须初始化,data 是存放数据的目录,可以不存在,建议找一个独立目录。

·启动

geth --datadir ./data --networkid 18 --port 30303 --rpc --rpcport 8545 --rpcapi 'db,net,eth,web3,personal' --rpccorsdomain '*' --gasprice 0 console 2> 1.log

参数介绍

  。--datadir 指定数据路径

  。--networkid 指定私链ID,与配置文件chainId一样

  。--port p2p端口,节点之间通信采用的端口

  。--rpc 所有rpc相关都是代表远程调用的参数设计,可以设定ip,端口(此端口为对外提供http服务端口),api等

  。--gasprice 设定gas的价格,如果gas为0则不消耗以太币

简易教程

可以下载本人github工程,直接用脚本启动即可,三步就够了


$git clone https://github.com/yekai1003/rungeth
$cd rungeth
$geth init genesis.json --datadir ./data
$./rungeth.sh

  geth启动后,我们会进入到一个管理台当中,在其中可以创建账户,解锁账户,挖矿,查询余额等等操作。


geth命令行客户端操作

  geth启动后,进入管理台,会看到如下的信息:

ykdeMac-mini:eth yekai$ ./rungeth.sh localhost:rungeth yekai$ ./rungeth.sh Welcome to the Geth JavaScript console!
instance: Geth/v1.9.6-stable/darwin-amd64/go1.13.1at block: 0 (Thu, 01 Jan 1970 08:00:00 CST) datadir: /Users/yekai/eth/rungeth/data modules: admin:1.0 debug:1.0 eth:1.0 ethash:1.0 miner:1.0 net:1.0 personal:1.0 rpc:1.0 txpool:1.0 web3:1.0
>

·创建账户

注意123是密码,返回的字符串才是以太坊的账户地址> eth.accounts[]> personal.newAccount("123")"0xdc78ec60eba4eb3bf8a497d94223615d43352c7e"> eth.accounts["0xdc78ec60eba4eb3bf8a497d94223615d43352c7e"]

  eth.accounts 是查看当前有哪些账户。

余额查看

> acc0=eth.accounts[0]"0xdc78ec60eba4eb3bf8a497d94223615d43352c7e"> eth.getBalance(acc0)0

挖矿

  一开始账户肯定没有钱,需要挖一挖,才能有钱。

> miner.start(1)null> eth.getBalance(acc0)0> eth.getBalance(acc0)0> eth.getBalance(acc0)0> eth.getBalance(acc0)0> eth.getBalance(acc0)20000000000000000000> miner.stop()null

  miner.start(1) 启动挖矿,其中的1可以不写,代表的是实际挖矿的线程数量。

解锁账户

  账户有钱后就可以挥霍了,但是在remix环境使用之时,必须先要解锁。

> personal.unlockAccount(acc0,"123")true

如果解锁命令失败,则需要在geth启动的时候添加参数,这也是以太坊新版客户端的一个更新。

--allow-insecure-unlock
智能合约开发

  先来看一个简单的例子,编写一个最简单的智能合约:

pragma solidity^0.5.11;
contract Person { string public name ; function setName(string memory _name) public { name = _name; }}

  第一句是交代编译器版本,要使用大于等于0.5.11的编译器对本合约进行编译,编译器版本不能超过0.5.的范围。

contract Person是定义合约的名字

setName是一个公共函数,任何人可以调用,目的是修改内部成员name

name与_name是内部成员和形参的区别,在以太坊中却非常重要,内部成员name是要存储在全球计算机上,需要消耗gas,_name是临时存储,不会消耗gas,当然任何指令的执行都需要消耗gas。

  在remix部署可以看到如下效果:

  

  我们看到一个黄颜色的setName函数和一个蓝颜色的name函数,黄颜色的每次调用都要收取gas,蓝颜色的则不需要提供gas。可能也有人奇怪name函数是怎么出来的,只要我们把变量声明为public,它就会自动生成。

  我们可以先调用一下name看看效果,结果什么都没有。

  

  我们用setName来修改一下名字:

  

  之后我们再来点击name,就可以看到效果了。

  

  以上就是一个最简单的智能合约运行,怎么样,感觉操作复杂吗?


合约案例:每人一个去中心化IDpragma solidity^0.5.11;pragma experimental ABIEncoderV2; //支持结构体变量

contract PersonDID {
address owner; struct Person { bytes32 DID; string name; string sex; uint256 age; bool isExists; } //内部一个自动增长的ID uint256 autoID; //地址==>人,每个地址一个人 mapping(address=>Person) persons; //构造函数,constructor是关键字 constructor() public { autoID = 1; owner = msg.sender; } //将个人与ID绑定 function bindID(string memory _name, string memory _sex, uint256 _age) public { //验证该人员是否已经绑定过了 require(!persons[msg.sender].isExists,"caller must not exists"); //assert(!persons[msg.sender].isExists,"caller must not exists"); //利用hash函数计算一个DID的值 bytes32 DID = keccak256(abi.encode(now, autoID)); Person memory p = Person(DID, _name, _sex, _age, true); persons[msg.sender] = p; autoID ; } //验证该DID是否属于调用者 function verifyPeron(bytes32 _DID) public view returns (Person memory) { Person storage p = persons[msg.sender]; require(_DID == p.DID );//调用者的DID与传入的DID相等 return p; } //获取DID function getDID() public view returns (bytes32) { return persons[msg.sender].DID; }
}
智能合约如何调用

  首先要明确,智能合约是运行在以太坊上的智能合同,所以要调用智能合约必然要和以太坊打交道。至于调用的方式,可以采用两种:rpc和ipc。

ipc 本地套接字调用

rpc 远程调用

  

  我们都知道以太坊是存储数据的,当然就很容易联想到数据库也是存储数据的,数据库对外提供了多种语言的访问机制,以太坊同样如此。对于以太坊智能合约以及相关api的调用,可以使用java,js,python,golang等多种语言,只要相应研究对应的sdk即可。

  接下来我们主要介绍Go语言如何调用智能合约。

  首先需要下载go版本的以太坊源码

$ cd $GOPATH/src$ mkdir -p github.com/ethereum$ cd github.com/ethereum/$ git clone https://github.com/ethereum/go-ethereum.git

引用源码的rpc库

import "github.com/ethereum/go-ethereum/rpc"

创建一个账户

func NewAcct(pass string) { //获得与geth的连接 cli, err := rpc.Dial("http://localhost:8545") if err != nil { log.Fatal("connet to geth error:", err) } //函数结束自动关闭连接 defer cli.Close() var account string //调用call方法,call可以调用personal.newAccount err = cli.Call(&account, "personal_newAccount", pass) if err != nil { log.Fatal("call personal_newAccount error:", err) } fmt.Println("account=", account)
}Go语言调用合约的步骤

  

  将源码文件获得abi,之后用abi编译成对应的Go代码,然后其实也就没有然后了,Go代码都给你了,调用就可以了,不过有些细节我们还是要注意的。

  如果使用命令行安装的方式abigen程序会伴随安装,如果没有则需要借助源码安装的方式,下面的步骤可以作为参考。

yekaideMBP:~ yk$ cd $GOPATH/src/github.com/ethereum/go-ethereum/cmd/abigen/yekaideMBP:abigen yk$ lsmain.goyekaideMBP:abigen yk$ pwd/Users/yk/src/gowork/src/github.com/ethereum/go-ethereum/cmd/abigenyekaideMBP:abigen yk$ go build -iyekaideMBP:abigen yk$ ls -ltotal 20904-rwxr-xr-x 1 yk staff 10694032 7 29 00:02 abigen-rw-r--r-- 1 yk staff 5006 7 21 20:45 main.go

使用abigen将abi翻译成go(最好先将abigen拷贝到$PATH的某个路径下)

abigen --abi xx.abi --pkg pkgname --type apiname --out xx.go

  abigen参数说明:

abi 文件在 remix 部署时可以得到

Pkg 指定的是编译成的 go 文件对应的 package 名称

type指定的是go文件的入口函数,可以认为是类名

out 指定输出go文件名称

  接下来,我们我们之前编写的合约代码来转换为Go代码,然后加以调用。首先先要得到abi文件,这个可以在remix环境直接拷贝得到,其实如果安装了solc编译器,在本地编译也可,只不过需要随时关注版本更新的情况,不如在线方便。具体拷贝位置,如下图所示:

  

  将abi文件拷贝到我们的代码目录,然后保存为person.abi文件,执行下面的命令:

abigen -abi person.abi -out person.go -type person -pkg main

  这样就可以得到person.go的Go源码文件,注意此文件为自动生成,不要修改!

  接下来就是调用的问题了,该文件会给我们提供一个入口函数,叫NewPerson。

// NewPerson creates a new instance of Person, bound to a specific deployed contract.func NewPerson(address common.Address, backend bind.ContractBackend) (*Person, error) { contract, err := bindPerson(address, backend, backend, backend) if err != nil { return nil, err } return &Person{PersonCaller: PersonCaller{contract: contract}, PersonTransactor: PersonTransactor{contract: contract}, PersonFilterer: PersonFilterer{contract: contract}}, nil}

  这个函数的返回结果就是我们合约实例对象,通过合约实例对象,就可以调用合约内的方法了,关键是传递参数。

身份问题

  因为合约函数在调用的时候需要确认身份,接下来,我们介绍如何签名,这个需要对钱包技术有一些了解,简单来说就是借助keystore 密码一起来构建身份。

//设置签名func MakeAuth(addr, pass string) (*bind.TransactOpts, error) { keystorePath := "/Users/yekai/eth/rungeth/data/keystore" fileName, err := GetFileName(string([]rune(addr)[2:]), keystorePath) if err != nil { fmt.Println("failed to GetFileName", err) return nil, err }
file, err := os.Open(keystorePath "/" fileName) if err != nil { fmt.Println("failed to open file ", err) return nil, err } auth, err := bind.NewTransactor(file, pass) if err != nil { fmt.Println("failed to NewTransactor ", err) return nil, err } auth.GasLimit = 300000 return auth, err}

  核心思路就是找到geth运行后产生的keystore文件,读取后用密码进行解析得到私钥,此后就可以创作成数字身份,进行签名交易。

  签名搞定后,就可以考虑调用合约函数的问题了。步骤如下:

连接到geth节点

通过合约地址构造合约实例

设置数字身份

通过身份,合约实例调用合约具体函数,注意各个参数传递

  代码如下:

//1. 连接到节点 cli, err := ethclient.Dial("http://localhost:8545") if err != nil { fmt.Println("Failed to Dial ", err) return } //2. 构造合约实例,注意传入合约地址 ins, err := NewPerson(common.HexToAddress("0x5ff2D46A84c4ABB525beF98DFd71C1Dc1060Fb8c"), cli) if err != nil { fmt.Println("Failed to NewPerson", err) } //3. 用账户地址构建签名,传入密码 auth, err := MakeAuth("0xbd72018032e5f0b1a19943f5e7d6225e0ab99fbd", "123") if err != nil { fmt.Println("failed to MakeAuth") return } //4. 调用合约函数 tx, err := ins.BindID(auth, "wangyuyan", "woman", big.NewInt(35)) if err != nil { fmt.Println("Failed to BindID", err) return } //打印交易hash结果,注意此交易需要矿工确认后才会生效,所以不会立即在网络中体现 fmt.Println(tx.Hash().Hex())

如果不需要消耗gas,但还需要账户的情况下,这个时候就需要构造CallOpts

type CallOpts struct { Pending bool From common.Address BlockNumber *big.Int Context context.Context }

此时不需要密码和keystore文件了,这样构造即可。

opt := &bind.CallOpts{ false, common.HexToAddress("0xbd72018032e5f0b1a19943f5e7d6225e0ab99fbd"), nil, context.Background(), }

之后仍然是调用合约函数,示例如下:

//4. 调用合约函数 hash, err := ins.GetDID(opt) if err != nil { fmt.Println("Failed to GetDID", err) return } data, err := ins.VerifyPeron(opt, hash) fmt.Printf("%s , %s, %s, %d\n", common.ToHex(data.DID[:]), data.Name, data.Sex, data.Age)

  总结一下,本文主要介绍了以太坊节点的搭建,命令行操作账户,包括创建,解锁,挖矿等等,之后又介绍了智能合约如何编写,如何部署,如何测试,以及如何通过Go语言调用智能合约,如何构造签名等知识点,希望对学习者有所帮助。

  吐槽一下:以太坊升级对于开发者影响还是挺大的,比如这次升级就让编写本文的我有些无力吐槽,首先remix环境出现一些问题,调用智能合约会失败,当然Go语言调用时也出现了问题,好在经过摸索,发现变化并不大,还好还好!

结尾福利:想学习Go语言或区块链的小伙伴可以联系张老师开通免费课程!



     



看回放可以关注公众号,并点击“公开课”,即可前往柏链官网观看回放!



  


关键词:比特币新闻 币牛牛

转载自比特币新闻网(www.btc268.com),提供比特币行情走势分析与数字货币投资炒币最新消息。

原文标题:以太坊竟然升级了,好在Go语言如何调用智能合约变化不大!

原文地址:http://www.btc268.com/ytf/xw/16381.html

本文来源:区块链资讯编辑:btc268.com

本文仅代表作者个人观点,与本网站立场无关。

本网站转载信息目的在于传递更多信息。请读者仅作参考,投资有风险,入市须谨慎!

'); })();