工作,学习,生活,这里将会有一些记录. 备用域名:http://meisw.wdlinux.cn 注册 | 登陆
浏览模式: 标准 | 列表分类:区块链

Hyperledger fabric配置node.js

 一、配置Swagger-UI

1.你可以使用本地的node.js服务来运行rest-api,确保你本机已经安转node.js,如果没有安装,请安转一个
2.命令行下安转node.js
------npm install http-server -g
3.在你本机上启动http-server运行rest-api
------cd /opt/gopath/src/github.com/hyperledger/fabric/core/rest
-------http-server -a 0.0.0.0 -p 5554 --cors
4.浏览器中输入下面语句,确保能成功连接
------http://localhost:5554/rest_api.json
5.使用命令行下载 Swagger-UI包
------git clone https://github.com/swagger-api/swagger-ui.git
6.到 /swagger-ui/dist 下用浏览器打开index.html
7.启动没有连接到leader or validator的peer节点
----cd /opt/gopath/src/github.com/hyperledger/fabric
-----build/bin/peer node start
8.测试
----cd /opt/gopath/src/github.com/hyperledger/fabric/core/rest
----go test -v -run TestServerOpenchain_API_GetBlockCount

 

二、Node.Js应用程序
构建并且安装 fabric core.
    cd /opt/gopath/src/github.com/hyperledger/fabric
    make peer
在本地仅仅运行一个节点 (不是一个完整的网络) :
    build/bin/peer node start
配置一个测试区块链数据结构通过vagrant来运行测试接下来重启peer进程.
    cd /opt/gopath/src/github.com/hyperledger/fabric/core/rest
    go test -v -run TestServerOpenchain_API_GetBlockCount
在本地电脑上启动http-server来运行rest_api.json服务.
    npm install http-server -g
    cd /opt/gopath/src/github.com/hyperledger/fabric/core/rest
    http-server -a 0.0.0.0 -p 5554 --cors
下载和解压 Sample_1.zip
    unzip Sample_1.zip -d Sample_1
    cd Sample_1
如果没有默认的URL地址就在openchain.js文件中更新api_url变量以搭配合适的URL
    Update the api_url variable within openchain.js to the appropriate URL if it is not already the default
    var api_url = 'http://localhost:5554/rest_api.json';
运行Node.js app
    node ./openchain.js

ubuntu下搭建HyperLedger fabric开发环境

 一、安装docker
1、docker要求Linux内核版本不低于 3.10
>>检查Linux的内核版本,如果内核版本太低,升级内核
>>查看内核的版本命令uname -a
2、根据不同的Ubuntu版本安装docker
>>查看Ubuntu版本命令lsb_release -a
3、对于16.04的Ubuntu版本安装
>>sudo apt-get install docker-engine
4、启动
>>sudo systemctl enable docker
>>sudo systemctl start docker

二、从docker上拉取镜像
1、检验docker是否安装好
>>docker 
2、从docker上拉镜像
>>docker pull hyperledger/fabric-peer:latest
>>docker pull hyperledger/fabric-membersrvc:latest
3、校验镜像是否拉取完成
>>docker images

三、安装docker-compose项目
1、安装pip工具
>>pip工具会依赖Python,而Ubuntu下默认已经安转好Python2.7
>>apt-get install python_pip
2、安转docker compose项目
>>sudo pip install -U docker-compose
3、校验docker compose是否安装好
>> docker-compose -h

四、安装并配置nsenter工具
方法一、
 >>wget https://www.kernel.org/pub/linux/utils/util-linux/v2.29/util-linux-2.29.tar.xz; tar xJvf util-linux-2.29.tar.xz
>>cd util-linux-2.29
>> ./configure --without-ncurses && make nsenter
>>sudo cp nsenter /usr/local/bin
方法二、建议下载 .bashrc_docker,并将内容放到 .bashrc 中
>>wget -P ~ https://github.com/yeasy/docker_practice/raw/master/_local/.bashrc_docker;
>>echo "[ -f ~/.bashrc_docker ] && . ~/.bashrc_docker" >> ~/.bashrc; source ~/.bashrc

五、启动节点

1、在root的Home目录下创建Docker-compose.yml并写入一下内容

 

membersrvc:   image: hyperledger/fabric-membersrvc   ports:     - "7054:7054"   command: membersrvc vp0:   image: hyperledger/fabric-peer   ports:     - "7050:7050"     - "7051:7051"     - "7053:7053"   environment:     - CORE_PEER_ADDRESSAUTODETECT=true     - CORE_VM_ENDPOINT=unix:///var/run/docker.sock     - CORE_LOGGING_LEVEL=DEBUG     - CORE_PEER_ID=vp0     - CORE_PEER_PKI_ECA_PADDR=membersrvc:7054     - CORE_PEER_PKI_TCA_PADDR=membersrvc:7054     - CORE_PEER_PKI_TLSCA_PADDR=membersrvc:7054     - CORE_SECURITY_ENABLED=true     - CORE_SECURITY_ENROLLID=test_vp0     - CORE_SECURITY_ENROLLSECRET=MwYpmSRjupbT   links:     - membersrvc   command: sh -c "sleep 5; peer node start --peer-chaincodedev"  

2、通过docker-compose up运行已近配置好的节点

 

六、进入容器
1、docker -ps 找到要进入的容器的CONTAINER ID
2、用docker-pid指令获取需要进入容器的PID
>>echo PID=(docker-pid  b4378c920828)
3、借助PID进入容器
>>sudo nsenter --target 10981 --mount --uts --ipc --net --pid

七、测试环境是否搭建好
1、选择源码中的一个例子chaincode机型编译
>>cd$GOPATH/src/github.com/hyperledger/fabric/examples/chaincode/go/chaincode_example02
>>go build
2、注册和运行chaincode
>>CORE_CHAINCODE_ID_NAME=mycc CORE_PEER_ADDRESS=0.0.0.0:7051 ./chaincode_example02

3、另起一个终端,进入容器的方式和“六”一样,以WebAppAdmin的形式登录到节点上
>>peer network login WebAppAdmin -p DJY27pEnl16d
4、执行下面的代码,在另外一个终端里面会看到执行结果
安全模式
部署交易
>>CORE_SECURITY_ENABLED=true CORE_SECURITY_PRIVACY=true peer chaincode deploy -u WebAppAdmin -n mycc -c '{"Function":"init", "Args": ["a","100", "b", "200"]}'
调用交易
>>CORE_SECURITY_ENABLED=true CORE_SECURITY_PRIVACY=true peer chaincode invoke -u WebAppAdmin -l golang -n mycc -c '{"Function": "invoke", "Args": ["a", "b", "10"]}'
查询交易
>>CORE_SECURITY_ENABLED=true CORE_SECURITY_PRIVACY=true peer chaincode query -u WebAppAdmin -l golang -n mycc -c '{"Function": "query", "Args": ["b"]}'

dragonchain

 [root@localhost dragonchain-master]# python blockchain/transaction_svc.py transaction_svc.py --private-key sk.pem --public-key pk.pem

Traceback (most recent call last):
  File "blockchain/transaction_svc.py", line 39, in <module>
    import tornado
ImportError: No module named tornado
 
pip install tornado
 
 
---
http://www.cnblogs.com/mchina/archive/2012/06/06/2539003.html
https://yum.postgresql.org/repopackages.php#pg94
https://download.postgresql.org/pub/repos/yum/9.6/redhat/rhel-6-x86_64/pgdg-centos96-9.6-3.noarch.rpm
 
 1060  yum install postgresql96-server
 1061  yum install postgresql96-contrib
 1062  psql
 1063  /etc/rc.d/init.d/postgresql-9.6
 1064  /etc/rc.d/init.d/postgresql-9.6 start
 1065  /etc/rc.d/init.d/postgresql-9.6 initdb
 
 
---
openssl
http://blog.csdn.net/as3luyuan123/article/details/14406429
http://www.docin.com/p-670347159.html
openssl
ecparam -list_curves
 
 
---
1.Linux环境下  
#su  postgres   
-bash-3.2$psql -U postgres   
postgres=#alter user postgres with password 'new password';  
postgres=#\q 
 
 
SELECT rolname FROM pg_roles;
 
创建用户  
grant all on all tables in schema schemaName to user; 给用户某个schema的所有权限  
----
cd <Dragonchain Home>/sql
createuser blocky
createdb -O blocky blockchain
psql -U blocky -d blockchain -a -f depl.sql
 
 
http://blog.csdn.net/suirosu/article/details/39718013
http://www.cyberciti.biz/faq/psql-fatal-ident-authentication-failed-for-user/

Hyperledger智能合约Hello World示例程序

 

简介

Hyperledger是Linux 基金会主导的一个开源的区块链(BlockChain)项目. 本文介绍了一个简单的Hyperledger智能合约的开发过程.

开发环境

本文使用Docker作为Hyperledger智能合约的本地开发环境.

第一步

从Docker官网http://www.docker.com/下载其安装包,并安装Docker.

第二步

启动Docker QuickStarter Terminal并运行如下命令在Docker中安装Hyperledger Fabric.

docker pull hyperledger/fabric-peer:latest docker pull hyperledger/fabric-membersrvc:latest

第三步

在工作目录下创建如下的docker-compose.yml

membersrvc:   image: hyperledger/fabric-membersrvc   ports:     - "7054:7054"   command: membersrvc vp0:   image: hyperledger/fabric-peer   ports:     - "7050:7050"     - "7051:7051"     - "7053:7053"   environment:     - CORE_PEER_ADDRESSAUTODETECT=true     - CORE_VM_ENDPOINT=unix:///var/run/docker.sock     - CORE_LOGGING_LEVEL=DEBUG     - CORE_PEER_ID=vp0     - CORE_PEER_PKI_ECA_PADDR=membersrvc:7054     - CORE_PEER_PKI_TCA_PADDR=membersrvc:7054     - CORE_PEER_PKI_TLSCA_PADDR=membersrvc:7054     - CORE_SECURITY_ENABLED=true     - CORE_SECURITY_ENROLLID=test_vp0     - CORE_SECURITY_ENROLLSECRET=MwYpmSRjupbT   links:     - membersrvc   command: sh -c "sleep 5; peer node start --peer-chaincodedev"

然后在Docker QuickStarter Terminal中运行以下命令以启动Hyperledger Fabric

docker-compose up

第四步

安装并运行SSH客户端,例如putty或mRemoteNG, 使用以下信息连接Docker

host : 192.168.99.100 user name : docker password : tcuser

第五步

运行如下命令以确认Hyperledger Fabric的进程

docker ps

运行如下命令以进入Hyperledger Fabric环境

docker exec -it hyperledger_vp0_1 bash

第六步

运行如下命令从git下载Hyperledger Fabric源代码

mkdir -p $GOPATH/src/github.com/hyperledger cd $GOPATH/src/github.com/hyperledger git clone http://gerrit.hyperledger.org/r/fabric

第七步

运行如下命令创建HelloWorld目录

mkdir -p $GOPATH/src/github.com/HelloWorld/ cd $GOPATH/src/github.com/HelloWorld/

创建如下HelloWorld.go文件

package main  import (     "errors"     "fmt"     "strconv"      "github.com/hyperledger/fabric/core/chaincode/shim" )   type HelloWorldChaincode struct { }  func (t *HelloWorldChaincode) Init(stub shim.ChaincodeStubInterface, function string, args []string) ([]byte, error) {     fmt.Printf("HelloWorld - Init called with function %s!\n", function)      return nil, nil }  func (t *HelloWorldChaincode) Invoke(stub shim.ChaincodeStubInterface, function string, args []string) ([]byte, error) {     fmt.Printf("HelloWorld - Invoke called with function %s!\n", function)      return nil, nil     }  func (t *HelloWorldChaincode) Query(stub shim.ChaincodeStubInterface, function string, args []string) ([]byte, error) {     fmt.Printf("HelloWorld - Query called with function %s!\n", function)      message := "Hello World"     return []byte(message), nil; }  func main() {     err := shim.Start(new(HelloWorldChaincode))     if err != nil {         fmt.Printf("Error starting Hello World chaincode: %s", err)     } }

使用如下命令编译代码

go build ./ 

第八步

使用如下命令运行HelloWorld

export CORE_CHAINCODE_ID_NAME=mycc export CORE_PEER_ADDRESS=0.0.0.0:7051 ./HelloWorld &

第九步

向Hyperledger服务接口http://192.168.99.100:7050/registrar 发送如下REST请求,使用内置的jim用户登录系统

{     "enrollId": "jim",     "enrollSecret": "6avZQLwcUe9b" }

第十步

向Hyperledger服务接口http://192.168.99.100:7050/chaincode 发送如下初始化HelloWorld的REST请求

{    "jsonrpc": "2.0",    "method": "deploy",    "params": {     "type": 1,     "chaincodeID":{         "name": "mycc"     },     "ctorMsg": {          "function":"init",          "args":[]      },     "secureContext": "jim"   },    "id": 1  }

调用HelloWorld的REST请求

{    "jsonrpc": "2.0",    "method": "invoke",    "params": {        "type": 1,        "chaincodeID":{            "name":"mycc"        },        "ctorMsg": {           "function":"invoke",           "args":[]        },        "secureContext": "jim"    },    "id": 3  }  

以及查询HelloWorld的REST请求

{    "jsonrpc": "2.0",    "method": "query",    "params": {        "type": 1,        "chaincodeID":{            "name":"mycc"        },        "ctorMsg": {           "function":"query",           "args":[]        },        "secureContext": "jim"    },    "id": 5  }

总结

本文介绍了一个简单的Hyperledger智能合约在本地Docker环境下的开发过程.

http://www.cnblogs.com/huyouhengbc/p/5934683.html#3545114

以太坊智能合约编程之菜鸟教程

 译注:原文首发于ConsenSys开发者博客,原作者为Eva以及ConsenSys的开发团队。如果您想要获取更多及时信息,可以访问ConsenSys首页点击左下角Newsletter订阅邮件。本文的翻译获得了ConsenSys创始人Lubin先生的授权。

有些人说以太坊太难对付,于是我们(译注:指Consensys, 下同)写了这篇文章来帮助大家学习如何利用以太坊编写智能合约和应用。这里所用到的工具,钱包,应用程序以及整个生态系统仍处于开发状态,它们将来会更好用!

  • 第一部分概述,讨论了关键概念,几大以太坊客户端以及写智能合约用到的编程语言。
  • 第二部分讨论了总体的工作流程,以及目前流行的一些DApp框架和工具。
  • 第三部分主要关于编程,我们将学习如何使用Truffle来为智能合约编写测试和构建DApp。

第一部分. 概述

如果你对诸如比特币以及其工作原理等密码学货币的概念完全陌生,我们建议你先看看Andreas Antonopoulos所著的Bitcoin Book的头几章,然后读一下以太坊白皮书。(译注:以太坊白皮书中文版请看 http://ethfans.org/posts/ethereum-whitepaper)

如果你觉得白皮书中的章节太晦涩,也可以直接动手来熟悉以太坊。在以太坊上做开发并不要求你理解所有那些“密码经济计算机科学”(crypto economic computer science),而白皮书的大部分是关于以太坊想对于比特币架构上的改进。

新手教程

ethereum.org提供了官方的新手入门教程,以及一个代币合约和众筹合约的教程。合约语言Solidity也有官方文档。学习智能合约的另一份不错的资料(也是我的入门资料)是dappsForBeginners,不过现在可能有些过时了。

这篇文章的目的是成为上述资料的补充,同时介绍一些基本的开发者工具,使入门以太坊,智能合约以及构建DApps(decentralized apps, 分布式应用)更加容易。我会试图按照我自己(依然是新手)的理解来解释工作流程中的每一步是在做什么,我也得到了ConsenSys酷酷的开发者们的许多帮助。

基本概念

了解这些名词是一个不错的开始:

公钥加密系统。 Alice有一把公钥和一把私钥。她可以用她的私钥创建数字签名,而Bob可以用她的公钥来验证这个签名确实是用Alice的私钥创建的,也就是说,确实是Alice的签名。当你创建一个以太坊或者比特币钱包的时候,那长长的0xdf...5f地址实质上是个公钥,对应的私钥保存某处。类似于Coinbase的在线钱包可以帮你保管私钥,你也可以自己保管。如果你弄丢了存有资金的钱包的私钥,你就等于永远失去了那笔资金,因此你最好对私钥做好备份。过来人表示:通过踩坑学习到这一点是非常痛苦的...

点对点网络。 就像BitTorrent, 以太坊分布式网络中的所有节点都地位平等,没有中心服务器。(未来会有半中心化的混合型服务出现为用户和开发者提供方便,这我们后面会讲到。)

区块链。 区块链就像是一个全球唯一的帐簿,或者说是数据库,记录了网络中所有交易历史。

以太坊虚拟机(EVM)。 它让你能在以太坊上写出更强大的程序(比特币上也可以写脚本程序)。它有时也用来指以太坊区块链,负责执行智能合约以及一切。

节点。 你可以运行节点,通过它读写以太坊区块链,也即使用以太坊虚拟机。完全节点需要下载整个区块链。轻节点仍在开发中。

矿工。 挖矿,也就是处理区块链上的区块的节点。这个网页可以看到当前活跃的一部分以太坊矿工:stats.ethdev.com

工作量证明。 矿工们总是在竞争解决一些数学问题。第一个解出答案的(算出下一个区块)将获得以太币作为奖励。然后所有节点都更新自己的区块链。所有想要算出下一个区块的矿工都有与其他节点保持同步,并且维护同一个区块链的动力,因此整个网络总是能达成共识。(注意:以太坊正计划转向没有矿工的权益证明系统(POS),不过那不在本文讨论范围之内。)

以太币。 缩写ETH。一种你可以购买和使用的真正的数字货币。这里是可以交易以太币的其中一家交易所的走势图。在写这篇文章的时候,1个以太币价值65美分。

Gas. (汽油) 在以太坊上执行程序以及保存数据都要消耗一定量的以太币,Gas是以太币转换而成。这个机制用来保证效率。

DApp. 以太坊社区把基于智能合约的应用称为去中心化的应用程序(Decentralized App)。DApp的目标是(或者应该是)让你的智能合约有一个友好的界面,外加一些额外的东西,例如IPFS(可以存储和读取数据的去中心化网络,不是出自以太坊团队但有类似的精神)。DApp可以跑在一台能与以太坊节点交互的中心化服务器上,也可以跑在任意一个以太坊平等节点上。(花一分钟思考一下:与一般的网站不同,DApp不能跑在普通的服务器上。他们需要提交交易到区块链并且从区块链而不是中心化数据库读取重要数据。相对于典型的用户登录系统,用户有可能被表示成一个钱包地址而其它用户数据保存在本地。许多事情都会与目前的web应用有不同架构。)

如果想看看从另一个新手视角怎么理解这些概念,请读Just Enough Bitcoin for Ethereum

以太坊客户端,智能合约语言

编写和部署智能合约并不要求你运行一个以太坊节点。下面有列出基于浏览器的IDE和API。但如果是为了学习的话,还是应该运行一个以太坊节点,以便理解其中的基本组件,何况运行节点也不难。

运行以太坊节点可用的客户端

以太坊有许多不同语言的客户端实现(即多种与以太坊网络交互的方法),包括C++, Go, Python, Java, Haskell等等。为什么需要这么多实现?不同的实现能满足不同的需求(例如Haskell实现的目标是可以被数学验证),能使以太坊更加安全,能丰富整个生态系统。

在写作本文时,我使用的是Go语言实现的客户端geth (go-ethereum),其他时候还会使用一个叫testrpc的工具, 它使用了Python客户端pyethereum。后面的例子会用到这些工具。

注: 我曾经使用过C++的客户端,现在仍然在用其中的ethminer组件和geth配合挖矿,因此这些不同的组件是可以一起工作的。
关于挖矿:挖矿很有趣,有点像精心照料你的室内盆栽,同时又是一种了解整个系统的方法。虽然以太币现在的价格可能连电费都补不齐,但以后谁知道呢。人们正在创造许多酷酷的DApp, 可能会让以太坊越来越流行。

交互式控制台。 客户端运行起来后,你就可以同步区块链,建立钱包,收发以太币了。使用geth的一种方式是通过Javascript控制台(JavaScript console, 类似你在chrome浏览器里面按F12出来的那个,只不过是跑在终端里)。此外还可以使用类似cURL的命令通过JSON RPC来与客户端交互。本文的目标是带大家过一边DApp开发的流程,因此这块就不多说了。但是我们应该记住这些命令行工具是调试,配置节点,以及使用钱包的利器。

在测试网络运行节点。 如果你在正式网络运行geth客户端,下载整个区块链与网络同步会需要相当时间。(你可以通过比较节点日志中打印的最后一个块号和stats.ethdev.com上列出的最新块来确定是否已经同步。) 另一个问题是在正式网络上跑智能合约需要实实在在的以太币。在测试网络上运行节点的话就没有这个问题。此时也不需要同步整个区块链,创建一个自己的私有链就勾了,对于开发来说更省时间。

testrpc. 用geth可以创建一个测试网络,另一种更快的创建测试网络的方法是使用testrpc. Testrpc可以在启动时帮你创建一堆存有资金的测试账户。它的运行速度也更快因此更适合开发和测试。你可以从testrpc起步,然后随着合约慢慢成型,转移到geth创建的测试网络上 - 启动方法很简单,只需要指定一个networkid:geth --networkid "12345"。这里是testrpc的代码仓库,下文我们还会再讲到它。

接下来我们来谈谈可用的编程语言,之后就可以开始真正的编程了。

写智能合约用的编程语言

用Solidity就好。 要写智能合约有好几种语言可选:有点类似Javascript的Solidity, 文件扩展名是.sol. 和Python接近的Serpent, 文件名以.se结尾。还有类似Lisp的LLL。Serpent曾经流行过一段时间,但现在最流行而且最稳定的要算是Solidity了,因此用Solidity就好。听说你喜欢Python? 用Solidity。

solc编译器。 用Solidity写好智能合约之后,需要用solc来编译。它是一个来自C++客户端实现的组件(又一次,不同的实现产生互补),这里是安装方法。如果你不想安装solc也可以直接使用基于浏览器的编译器,例如Solidity real-time compiler或者Cosmo。后文有关编程的部分会假设你安装了solc。

注意:以太坊正处于积极的开发中,有时候新的版本之间会有不同步。确认你使用的是最新的dev版本,或者稳定版本。如果遇到问题可以去以太坊项目对应的Gitter聊天室或者forums.ethereum.org上问问其他人在用什么版本。

web3.js API. 当Solidity合约编译好并且发送到网络上之后,你可以使用以太坊的web3.js JavaScript API来调用它,构建能与之交互的web应用。

以上就是在以太坊上编写智能合约和构建与之交互的DApp所需的基本工具。

第二部分. DApp框架,工具以及工作流程

DApp开发框架

虽然有上文提到的工具就可以进行开发了,但是使用社区大神们创造的框架会让开发更容易。

Truffle and Embark. 是Truffle把我领进了门。在Truffle出现之前的那个夏天,我目睹了一帮有天分的学生是如何不眠不休的参加一个hackathon(编程马拉松)活动的,虽然结果相当不错,但我还是吓到了。然后Truffle出现了,帮你处理掉大量无关紧要的小事情,让你可以迅速进入写代码-编译-部署-测试-打包DApp这个流程。另外一个相似的DApp构建与测试框架是Embark。我只用过Truffle, 但是两个阵营都拥有不少DApp大神。

Meteor. 许多DApp开发者使用的另一套开发栈由web3.js和Meteor组成,Meteor是一套通用webapp开发框架(ethereum-meteor-wallet项目提供了一个很棒的入门实例,而SilentCiero正在构建大量Meteor与web3.js和DApp集成的模板)。我下载并运行过一些不错的DApp是以这种方式构造的。在11月9日至13日的以太坊开发者大会ÐΞVCON1上将有一些有趣的讨论,是关于使用这些工具构建DApp以及相关最佳实践的(会议将会在YouTube上直播)。

APIs. BlockApps.net打算提供一套RESTful API给DApp使用以免去开发者运行本地节点的麻烦,这个中心化服务是基于以太坊Haskell实现的。这与DApp的去中心化模型背道而驰,但是在本地无法运行以太坊节点的场合非常有用,比如在你希望只有浏览器或者使用移动设备的用户也能使用你的DApp的时候。BlockApps提供了一个命令行工具bloc,注册一个开发者帐号之后就可以使用。

许多人担心需要运行以太坊节点才能使用DApp的话会把用户吓跑,其实包括BlockApps在内的许多工具都能解决这个问题。Metamask允许你在浏览器里面使用以太坊的功能而无需节点,以太坊官方提供的AlethZero或者AlethOne是正在开发中有易用界面的客户端,ConsenSys正在打造一个轻钱包LightWallet,这些工具都会让DApp的使用变得更容易。轻客户端和水平分片(sharding)也在计划和开发之中。这是一个能进化出混合架构的P2P生态系统。

智能合约集成开发环境 (IDE)

IDE. 以太坊官方出品了用来编写智能合约的Mix IDE,我还没用过但会尽快一试。

基于浏览器的IDE. Solidity real-time compilerCosmo都可以让你快速开始在浏览器中编写智能合约。你甚至可以让这些工具使用你的本地节点,只要让本地节点开一个端口(注意安全!这些工具站点必须可信,而且千万不要把你的全部身家放在这样一个本地节点里面!Cosmo UI上有如何使用geth做到这一点的指引)。在你的智能合约调试通过之后,可以用开发框架来给它添加用户界面和打包成DApp,这正是Truffle的工作,后面的编程章节会有详细讲解。

Ether.Camp正在开发另一个强大的企业级浏览器IDE。他们的IDE将支持沙盒测试网络,自动生成用于测试的用户界面(取代后文将展示的手动编写测试),以及一个测试交易浏览器test.ether.camp。当你的合约准备正式上线之前,使用他们的测试网络会是确保你的智能合约在一个接近真实的环境工作正常的好方法。他们也为正式网络提供了一个交易浏览器frontier.ether.camp,上面可以看到每一笔交易的细节。在本文写作时Ether.Camp的IDE还只能通过邀请注册,预计很快会正式发布。

合约和Dapp示例。 在Github上搜索DApp仓库和.sol文件可以看到进行中的有趣东西。这里有一个DApp大列表:dapps.ethercasts.com,不过其中一些项目已经过时。Ether.fund/contracts上有一些Solidity和Serpent写的合约示例,但是不清楚这些例子有没有经过测试或者正确性验证。11月12日的开发者大会ÐΞVCON1将会有一整天的DApp主题演讲。

部署智能合约的流程

流程如下:

  1. 启动一个以太坊节点 (例如geth或者testrpc)。
  2. 使用solc*编译*智能合约。 => 获得二进制代码。
  3. 将编译好的合约部署到网络。(这一步会消耗以太币,还需要使用你的节点的默认地址或者指定地址来给合约签名。) => 获得合约的区块链地址和ABI(合约接口的JSON表示,包括变量,事件和可以调用的方法)。(译注:作者在这里把ABI与合约接口弄混了。ABI是合约接口的二进制表示。)
  4. 用web3.js提供的JavaScript API来调用合约。(根据调用的类型有可能会消耗以太币。)

下图详细描绘了这个流程:

你的DApp可以给用户提供一个界面先部署所需合约再使用之(如图1到4步),也可以假设合约已经部署了(常见方法),直接从使用合约(如图第6步)的界面开始。

第三部分. 编程

在Truffle中进行测试

Truffle用来做智能合约的测试驱动开发(TDD)非常棒,我强烈推荐你在学习中使用它。它也是学习使用JavaScript Promise的一个好途径,例如deferred和异步调用。Promise机制有点像是说“做这件事,如果结果是这样,做甲,如果结果是那样,做乙... 与此同时不要在那儿干等着结果返回,行不?”。Truffle使用了包装web3.js的一个JS Promise框架Pudding(因此它为为你安装web3.js)。(译注:Promise是流行于JavaScript社区中的一种异步调用模式。它很好的封装了异步调用,使其能够灵活组合,而不会陷入callback hell.)

Transaction times. Promise对于DApp非常有用,因为交易写入以太坊区块链需要大约12-15秒的时间。即使在测试网络上看起来没有那么慢,在正式网络上却可能会要更长的时间(例如你的交易可能用光了Gas,或者被写入了一个孤儿块)。

下面让我们给一个简单的智能合约写测试用例吧。

使用Truffle

首先确保你 1.安装好了solc以及 2.testrpc。(testrpc需要Pythonpip。如果你是Python新手,你可能需要用virtualenv来安装,这可以将Python程序库安装在一个独立的环境中。)

接下来安装 3.Truffle(你可以使用NodeJS's npm来安装:npm install -g truffle-g开关可能会需要sudo)。安装好之后,在命令行中输入truffle list来验证安装成功。然后创建一个新的项目目录(我把它命名为'conference'),进入这个目录,运行truffle init。该命令会建立如下的目录结构:

现在让我们在另一个终端里通过执行testrpc来启动一个节点(你也可以用geth):

回到之前的终端中,输入truffle deploy。这条命令会部署之前truffle init产生的模板合约到网络上。任何你可能遇到的错误信息都会在testrpc的终端或者执行truffle的终端中输出。

在开发过程中你随时可以使用truffle compile命令来确认你的合约可以正常编译(或者使用solc YourContract.sol),truffle deploy来编译和部署合约,最后是truffle test来运行智能合约的测试用例。

第一个合约

下面是一个针对会议的智能合约,通过它参会者可以买票,组织者可以设置参会人数上限,以及退款策略。本文涉及的所有代码都可以在这个代码仓库找到。

contract Conference {   address public organizer;   mapping (address => uint) public registrantsPaid;   uint public numRegistrants;   uint public quota;    event Deposit(address _from, uint _amount);  // so you can log these events   event Refund(address _to, uint _amount);     function Conference() { // Constructor     organizer = msg.sender;     quota = 500;     numRegistrants = 0;   }   function buyTicket() public returns (bool success) {     if (numRegistrants >= quota) { return false; }     registrantsPaid[msg.sender] = msg.value;     numRegistrants++;     Deposit(msg.sender, msg.value);     return true;   }   function changeQuota(uint newquota) public {     if (msg.sender != organizer) { return; }     quota = newquota;   }   function refundTicket(address recipient, uint amount) public {     if (msg.sender != organizer) { return; }     if (registrantsPaid[recipient] == amount) {        address myAddress = this;       if (myAddress.balance >= amount) {          recipient.send(amount);         registrantsPaid[recipient] = 0;         numRegistrants--;         Refund(recipient, amount);       }     }   }   function destroy() { // so funds not locked in contract forever     if (msg.sender == organizer) {        suicide(organizer); // send funds to organizer     }   } }

接下来让我们部署这个合约。(注意:本文写作时我使用的是Mac OS X 10.10.5, solc 0.1.3+ (通过brew安装),Truffle v0.2.3, testrpc v0.1.18 (使用venv))

部署合约

(译注:图中步骤翻译如下:)

使用truffle部署智能合约的步骤:
1. truffle init (在新目录中) => 创建truffle项目目录结构
2. 编写合约代码,保存到contracts/YourContractName.sol文件。
3. 把合约名字加到config/app.json的'contracts'部分。
4. 启动以太坊节点(例如在另一个终端里面运行testrpc)。
5. truffle deploy(在truffle项目目录中)

添加一个智能合约。 在truffle init执行后或是一个现有的项目目录中,复制粘帖上面的会议合约到contracts/Conference.sol文件中。然后打开config/app.json文件,把'Conference'加入'deploy'数组中。

启动testrpc。 在另一个终端中启动testrpc

编译或部署。 执行truffle compile看一下合约是否能成功编译,或者直接truffle deploy一步完成编译和部署。这条命令会把部署好的合约的地址和ABI(应用接口)加入到配置文件中,这样之后的truffle testtruffle build步骤可以使用这些信息。

出错了? 编译是否成功了?记住,错误信息即可能出现在testrpc终端也可能出现在truffle终端。

重启节点后记得重新部署! 如果你停止了testrpc节点,下一次使用任何合约之前切记使用truffle deploy重新部署。testrpc在每一次重启之后都会回到完全空白的状态。

合约代码解读

让我们从智能合约头部的变量声明开始:

address public organizer; mapping (address => uint) public registrantsPaid; uint public numRegistrants; uint public quota;

address. 地址类型。第一个变量是会议组织者的钱包地址。这个地址会在合约的构造函数function Conference()中被赋值。很多时候也称呼这种地址为'owner'(所有人)。

uint. 无符号整型。区块链上的存储空间很紧张,保持数据尽可能的小。

public. 这个关键字表明变量可以被合约之外的对象使用。private修饰符则表示变量只能被本合约(或者衍生合约)内的对象使用。如果你想要在测试中通过web3.js使用合约中的某个变量,记得把它声明为public

Mapping或数组。(译注:Mapping类似Hash, Directory等数据类型,不做翻译。)在Solidity加入数组类型之前,大家都使用类似mapping (address => uint)的Mapping类型。这个声明也可以写作address registrantsPaid[],不过Mapping的存储占用更小(smaller footprint)。这个Mapping变量会用来保存参加者(用他们的钱包地址表示)的付款数量以便在退款时使用。

关于地址。 你的客户端(比如testrpc或者geth)可以生成一个或多个账户/地址。testrpc启动时会显示10个可用地址:

第一个地址, accounts[0],是发起调用的默认地址,如果没有特别指定的话。

组织者地址 vs. 合约地址。 部署好的合约会在区块链上拥有自己的地址(与组织者拥有的是不同的地址)。在Solidity合约中可以使用this来访问这个合约地址,正如refundTicket函数所展示的:address myAddress = this;

Suicide, Solidity的好东西。(译注:suicide意为'自杀', 为Solidity提供的关键字,不做翻译。)转给合约的资金会保存于合约(地址)中。最终这些资金通过destroy函数被释放给了构造函数中设置的组织者地址。这是通过suicide(orgnizer);这行代码实现的。没有这个,资金可能被永远锁定在合约之中(reddit上有些人就遇到过),因此如果你的合约会接受资金一定要记得在合约中使用这个方法!

如果想要模拟另一个用户或者对手方(例如你是卖家想要模拟一个买家),你可以使用可用地址数组中另外的地址。假设你要以另一个用户,accounts[1], 的身份来买票,可以通过from参数设置:

conference.buyTicket({ from: accounts[1], value: some_ticket_price_integer });

函数调用可以是交易。 改变合约状态(修改变量值,添加记录,等等)的函数调用本身也是转账交易,隐式的包含了发送人和交易价值。因此web3.js的函数调用可以通过指定{ from: __, value: __ }参数来发送以太币。在Solidity合约中,你可以通过msg.sendermsg.value来获取这些信息:

function buyTicket() public {     ...     registrantsPaid[msg.sender] = msg.value;     ... }

事件(Event)。 可选的功能。合约中的Deposit(充值)和Send(发送)事件是会被记录在以太坊虚拟机日志中的数据。它们实际上没有任何作用,但是用事件(Event)把交易记录进日志是好的做法。

好了,现在让我们给这个智能合约写一个测试,来确保它能工作。

写测试

把项目目录test/中的example.js文件重命名为conference.js,文件中所有的'Example'替换为'Conference'。

contract('Conference', function(accounts) {   it("should assert true", function(done) {     var conference = Conference.at(Conference.deployed_address);     assert.isTrue(true);     done();   // stops tests at this point   }); });

在项目根目录下运行truffle test,你应该看到测试通过。在上面的测试中truffle通过Conference.deployed_address获得合约部署在区块链上的地址。

让我们写一个测试来初始化一个新的Conference,然后检查变量都正确赋值了。将conference.js中的测试代码替换为:

contract('Conference', function(accounts) {   it("Initial conference settings should match", function(done) {     var conference = Conference.at(Conference.deployed_address);       // same as previous example up to here     Conference.new({ from: accounts[0]  })     .then(function(conference) {       conference.quota.call().then(           function(quota) {             assert.equal(quota, 500, "Quota doesn't match!");            }).then( function() {             return conference.numRegistrants.call();           }).then( function(num) {             assert.equal(num, 0, "Registrants should be zero!");             return conference.organizer.call();           }).then( function(organizer) {             assert.equal(organizer, accounts[0], "Owner doesn't match!");             done();   // to stop these tests earlier, move this up         }).catch(done);       }).catch(done);     });   });

构造函数。 Conference.new({ from: accounts[0] })通过调用合约构造函数创造了一个新的Conference实例。由于不指定from时会默认使用accounts[0],它其实可以被省略掉:

Conference.new({ from: accounts[0] }); // 和Conference.new()效果相同

Promise. 代码中的那些thenreturn就是Promise。它们的作用写成一个深深的嵌套调用链的话会是这样:

conference.numRegistrants.call().then(   function(num) {     assert.equal(num, 0, "Registrants should be zero!");     conference.organizer.call().then(      function(organizer) {         assert.equal(organizer, accounts[0], "Owner doesn't match!");         }).then(           function(...))             }).then(               function(...))             // Because this would get hairy...

Promise减少嵌套,使代码变得扁平,允许调用异步返回,并且简化了表达“成功时做这个”和“失败时做那个”的语法。Web3.js通过回调函数实现异步调用,因此你不需要等到交易完成就可以继续执行前端代码。Truffle借助了用Promise封装web3.js的一个框架,叫做Pudding,这个框架本身又是基于Bluebird的,它支持Promise的高级特性。

call. 我们使用call来检查变量的值,例如conference.quota.call().then(...,还可以通过传参数,例如call(0), 来获取mapping在index 0处的元素。Solidity的文档说这是一种特殊的“消息调用”因为 1.不会为矿工记录和 2.不需要从钱包账户/地址发起(因此它没有被账户持有者私钥做签名)。另一方面,交易/事务(Transaction)会被矿工记录,必须来自于一个账户(也就是有签名),会被记录到区块链上。对合约中数据做的任何修改都是交易。仅仅是检查一个变量的值则不是。因此在读取变量时不要忘记加上call()!否则会发生奇怪的事情。(此外如果在读取变量是遇到问题别忘记检查它是否是public。)call()也能用于调用不是交易的函数。如果一个函数本来是交易,但你却用call()来调用,则不会在区块链上产生交易。

断言。 标准JS测试中的断言(如果你不小心拼成了复数形式'asserts',truffle会报错,让你一头雾水),assert.equal是最常用的,其他类型的断言可以在Chai的文档中找到。

再一次运行truffle test确保一切工作正常。

测试合约函数调用

现在我们测试一下改变quote变量的函数能工作。在tests/conference.js文件的contract('Conference', function(accounts) {...};)的函数体中添加如下测试用例:

it("Should update quota", function(done) {   var c = Conference.at(Conference.deployed_address);    Conference.new({from: accounts[0] }).then(     function(conference) {       conference.quota.call().then(          function(quota) {            assert.equal(quota, 500, "Quota doesn't match!");          }).then( function() {            return conference.changeQuota(300);         }).then( function(result) {  // result here is a transaction hash           console.log(result);  // if you were to print this out it’d be long hex - the transaction hash           return conference.quota.call()         }).then( function(quota) {            assert.equal(quota, 300, "New quota is not correct!");           done();         }).catch(done);     }).catch(done); });

这里的新东西是调用changeQuota函数的那一行。console.log对于调试很有用,用它能在运行truffle的终端中输出信息。在关键点插入console.log可以查看执行到了哪一步。记得把Solidity合约中changeQuota函数被声明为public,否则你不能调用它:

  function changeQuota(uint newquota) public {  }

测试交易

现在让我们调用一个需要发起人发送资金的函数。

Wei. 以太币有很多种单位(这里有个很有用的转换器),在合约中通常用的是Wei,最小的单位。Web3.js提供了在各单位与Wei之间互相转换的便利方法,形如web3.toWei(.05, 'ether')。JavaScript在处理很大的数字时有问题,因此web3.js使用了程序库BigNumber,并建议在代码各处都以Wei做单位,直到要给用户看的时候(文档

账户余额。 Web3.js提供了许多提供方便的方法,其中另一个会在下面测试用到的是web3.eth.getBalance(some_address)。记住发送给合约的资金会由合约自己持有直到调用suicide

contract(Conference, function(accounts) {...};)的函数体中插入下面的测试用例。在高亮显示的方法中,测试用例让另一个用户(accounts[1])以ticketPrice的价格买了一张门票。然后它检查合约的账户余额增加了ticketPrice,以及购票用户被加入了参会者列表。

这个测试中的buyTicket是一个交易函数:

it("Should let you buy a ticket", function(done) {   var c = Conference.at(Conference.deployed_address);    Conference.new({ from: accounts[0] }).then(     function(conference) {       var ticketPrice = web3.toWei(.05, 'ether');       var initialBalance = web3.eth.getBalance(conference.address).toNumber();        conference.buyTicket({ from: accounts[1], value: ticketPrice }).then(         function() {           var newBalance = web3.eth.getBalance(conference.address).toNumber();           var difference = newBalance - initialBalance;           assert.equal(difference, ticketPrice, "Difference should be what was sent");           return conference.numRegistrants.call();       }).then(function(num) {           assert.equal(num, 1, "there should be 1 registrant");           return conference.registrantsPaid.call(accounts[1]);       }).then(function(amount) {           assert.equal(amount.toNumber(), ticketPrice, "Sender's paid but is not listed");           done();       }).catch(done);   }).catch(done); });

交易需要签名。 和之前的函数调用不同,这个调用是一个会发送资金的交易,在这种情况下购票用户(accounts[1])会用他的私钥对buyTicket()调用做签名。(在geth中用户需要在发送资金之前通过输入密码来批准这个交易或是解锁钱包的账户。)

toNumber(). 有时我们需要把Solidity返回的十六进制结果转码。如果结果可能是个很大的数字可以用web3.toBigNumber(numberOrHexString)来处理因为JavaScript直接对付大数要糟。

测试包含转账的合约

最后,为了完整性,我们确认一下refundTicket方法能正常工作,而且只有会议组织者能调用。下面是测试用例:

it("Should issue a refund by owner only", function(done) {   var c = Conference.at(Conference.deployed_address);    Conference.new({ from: accounts[0] }).then(     function(conference) {       var ticketPrice = web3.toWei(.05, 'ether');       var initialBalance = web3.eth.getBalance(conference.address).toNumber();         conference.buyTicket({ from: accounts[1], value: ticketPrice }).then(         function() {           var newBalance = web3.eth.getBalance(conference.address).toNumber();           var difference = newBalance - initialBalance;           assert.equal(difference, ticketPrice, "Difference should be what was sent");  // same as before up to here           // Now try to issue refund as second user - should fail           return conference.refundTicket(accounts[1], ticketPrice, {from: accounts[1]});           }).then(           function() {             var balance = web3.eth.getBalance(conference.address).toNumber();             assert.equal(web3.toBigNumber(balance), ticketPrice, "Balance should be unchanged");             // Now try to issue refund as organizer/owner - should work             return conference.refundTicket(accounts[1], ticketPrice, {from: accounts[0]});           }).then(           function() {             var postRefundBalance = web3.eth.getBalance(conference.address).toNumber();             assert.equal(postRefundBalance, initialBalance, "Balance should be initial balance");             done();         }).catch(done);     }).catch(done);  });

这个测试用例覆盖的Solidity函数如下:

function refundTicket(address recipient, uint amount) public returns (bool success) {   if (msg.sender != organizer) { return false; }   if (registrantsPaid[recipient] == amount) {      address myAddress = this;     if (myAddress.balance >= amount) {        recipient.send(amount);       Refund(recipient, amount);       registrantsPaid[recipient] = 0;       numRegistrants--;       return true;     }   }   return false; }

合约中发送以太币。 address myAddress = this展示了如何获取该会议合约实例的地址,以变接下来检查这个地址的余额(或者直接使用this.balance)。合约通过recipient.send(amount)方法把资金发回了购票人。

交易无法返回结果给web3.js. 注意这一点!refundTicket函数会返回一个布尔值,但是这在测试中无法检查。因为这个方法是一个交易函数(会改变合约内数据或是发送以太币的调用),而web3.js得到的交易运行结果是一个交易哈希(如果打印出来是一个长长的十六进制/怪怪的字符串)。既然如此为什么还要让refundTicket返回一个值?因为在Solidity合约内可以读到这个返回值,例如当另一个合约调用refundTicket()的时候。也就是说Solidity合约可以读取交易运行的返回值,而web3.js不行。另一方面,在web3.js中你可以用事件机制(Event, 下文会解释)来监控交易运行,而合约不行。合约也无法通过call()来检查交易是否修改了合约内变量的值。

关于sendTransaction(). 当你通过web3.js调用类似buyTicket()或者refundTicket()的交易函数时(使用web3.eth.sendTransaction),交易并不会立即执行。事实上交易会被提交到矿工网络中,交易代码直到其中一位矿工产生一个新区块把交易记录进区块链之后才执行。因此你必须等交易进入区块链并且同步回本地节点之后才能验证交易执行的结果。用testrpc的时候可能看上去是实时的,因为测试环境很快,但是正式网络会比较慢。

事件/Event. 在web3.js中你应该监听事件而不是返回值。我们的智能合约示例定义了这些事件:

event Deposit(address _from, uint _amount); event Refund(address _to, uint _amount);

它们在buyTicket()refundTicket()中被触发。触发时你可以在testrpc的输出中看到日志。要监听事件,你可以使用web.js监听器(listener)。在写本文时我还不能在truffle测试中记录事件,但是在应用中没问题:

Conference.new({ from: accounts[0] }).then(   function(conference) {     var event = conference.allEvents().watch({}, ''); // or use conference.Deposit() or .Refund()     event.watch(function (error, result) {       if (error) {         console.log("Error: " + error);       } else {         console.log("Event: " + result.event);       }     });     // ...

过滤器/Filter. 监听所有事件可能会产生大量的轮询,作为替代可以使用过滤器。它们可以更灵活的开始或是停止对事件的监听。更多过滤器的信息可查看Solidity文档

总的来说,使用事件和过滤器的组合比检查变量消耗的Gas更少,因而在验证正式网络的交易运行结果时非常有用。

Gas. (译注:以太坊上的燃料,因为代码的执行必须消耗Gas。直译为汽油比较突兀,故保留原文做专有名词。)直到现在我们都没有涉及Gas的概念,因为在使用testrpc时通常不需要显式的设置。当你转向geth和正式网络时会需要。在交易函数调用中可以在{from: __, value: __, gas: __}对象内设置Gas参数。Web3.js提供了web3.eth.gasPrice调用来获取当前Gas的价格,Solidity编译器也提供了一个参数让你可以从命令行获取合约的Gas开销概要:solc --gas YouContract.sol。下面是Conference.sol的结果:

为合约创建DApp界面

下面的段落会假设你没有网页开发经验。

上面编写的测试用例用到的都是在前端界面中也可以用的方法。你可以把前端代码放到app/目录中,运行truffle build之后它们会和合约配置信息一起编译输出到build/目录。在开发时可以使用truffle watch命令在app/有任何变动时自动编译输出到build/目录。然后在浏览器中刷新页面即可看到build/目录中的最新内容。(truffle serve可以启动一个基于build/目录的网页服务器。)

app/目录中有一些样板文件帮助你开始:

index.html会加载app.js

因此我们只需要添加代码到app.js就可以了。

默认的app.js会在浏览器的console(控制台)中输出一条"Hello from Truffle!"的日志。在项目根目录中运行truffle watch,然后在浏览器中打开build/index.html文件,再打开浏览器的console就可以看到。(大部分浏览器例如Chrome中,单击右键 -> 选择Inspect Element然后切换到Console即可。)

app.js中,添加一个在页面加载时会运行的window.onload调用。下面的代码会确认web3.js已经正常载入并显示所有可用的账户。(注意:你的testrpc节点应该保持运行。)

window.onload = function() {   var accounts = web3.eth.accounts;   console.log(accounts); }

看看你的浏览器console中看看是否打印出了一组账户地址。

现在你可以从tests/conference.js中复制一些代码过来(去掉只和测试有关的断言),将调用返回的结果输出到console中以确认代码能工作。下面是个例子:

window.onload = function() {   var accounts = web3.eth.accounts;   var c = Conference.at(Conference.deployed_address);    Conference.new({ from: accounts[0] }).then(     function(conference) {      var ticketPrice = web3.toWei(.05, 'ether');     var initialBalance = web3.eth.getBalance(conference.address).toNumber();      console.log("The conference's initial balance is: " + initialBalance);      conference.buyTicket({ from: accounts[1], value: ticketPrice }).then(       function() {         var newBalance = web3.eth.getBalance(conference.address).toNumber();         console.log("After someone bought a ticket it's: " + newBalance);         return conference.refundTicket(accounts[1], ticketPrice, {from: accounts[0]});       }).then(         function() {             var balance = web3.eth.getBalance(conference.address).toNumber();           console.log("After a refund it's: " + balance);       });   }); };

上面的代码应该输出如下:

(console输出的warning信息可忽略。)

现在起你就可以使用你喜欢的任何前端工具,jQuery, ReactJS, Meteor, Ember, AngularJS,等等等等,在app/目录中构建可以与以太坊智能合约互动的DApp界面了!接下来我们给出一个极其简单基于jQuery的界面作为示例。

这里是index.html的代码,这里是app.js的代码

通过界面测试了智能合约之后我意识到最好加入检查以保证相同的用户不能注册两次。另外由于现在是运行在testrpc节点上,速度很快,最好是切换到geth节点并确认交易过程依然能及时响应。否则的话界面上就应该显示提示信息并且在处理交易时禁用相关的按钮。

尝试geth. 如果你使用geth, 可以尝试以下面的命令启动 - 在我这儿(geth v1.2.3)工作的很好:

build/bin/geth --rpc --rpcaddr="0.0.0.0" --rpccorsdomain="*" --mine --unlock='0 1' --verbosity=5 --maxpeers=0 --minerthreads='4'  --networkid '12345' --genesis test-genesis.json

这条命令解锁了两个账户, 01。1. 在geth控制台启动后你可能需要输入这两个账户的密码。2. 你需要在test-genesis.json文件里面的'alloc'配置中加入你的这两个账户,并且给它们充足的资金。3. 最后,在创建合约实例时加上gas参数:

Conference.new({from: accounts[0], gas: 3141592})

然后把整个truffle deploytruffle build流程重来一遍。

教程中的代码。 在这篇基础教程中用到的所有代码都可以在这个代码仓库中找到。

自动为合约生成界面。 SilentCicero制作了一个叫做DApp Builder的工具,可以用Solidity合约自动生成HTML, jQuery和web.js的代码。这种模式也正在被越来越多的正在开发中的开发者工具采用。

教程到此结束! 最后一章我们仅仅学习了一套工具集,主要是Truffle和testrpc. 要知道即使在ConsenSys内部,不同的开发者使用的工具和框架也不尽相同。你可能会发现更适合你的工具,这里所说的工具可能很快也会有改进。但是本文介绍的工作流程帮助我走上了DApp开发之路。

(⊙ω⊙) wonk wonk

感谢Joseph Chow的校阅和建议,Christian Lundkvist, Daniel Novy, Jim Berry, Peter Borah和Tim Coulter帮我修改文字和debug,以及Tim Coulter, Nchinda Nchinda和Mike Goldin对DApp前端步骤图提供的帮助。

http://ethfans.org/posts/101-noob-intro

区块链开发(一)搭建基于以太坊go-ethereum的私有链环境

 通过各方资料了解学习之后,决定自己开始搭建基于以太坊Go-ethereum的私有链环境。由于本人的电脑系统为win8,为避免window环境出现过多莫名其妙的问题,特意通过vm搭建了一台ubuntu16.04版本的虚拟系统。以下内容均基于ubuntu16.04系统。

 
go-ethereum客户端
下载地址&参考手册
首先,可以查看一下go-ethereum项目在Git上的地址:
https://github.com/ethereum/Go-ethereum
可以在点击项目上的wiki标签,也可以通过一下地址访问wiki:
https://github.com/ethereum/Go-ethereum/wiki/Building-Ethereum
在wiki页面选择ubuntu系统的安装说明,也可以直接访问下面链接:
https://github.com/ethereum/go-ethereum/wiki/Installation-Instructions-for-Ubuntu
 
ubuntu下安装命令
打开命令行窗口,或通过快捷键CTL+ALT+T,依次输入以下命令,即可安装成功:
sudo apt-get install software-properties-common
sudo add-apt-repository -y ppa:ethereum/ethereum
sudo add-apt-repository -y ppa:ethereum/ethereum-dev
sudo apt-get update
sudo apt-get install ethereum
PS:如果安装过程中需要依赖其他组件,则先安装其他组件。另外,在ubuntu16.04版本,sudo apt-get install命令可精简为sudo apt install。
 
安装测试
安装完成之后在命令行输入:
geth --help
如果现实出命令行各种参数提示信息,则说明安装成功。
 
创世块
在以上安装成功之后,直接启动,即可连接公有链。现在通过配置创世块来创建私有链。同一个网络中,创世块必须是一样的,否则无法联通。
创建一个eth的根目录,在根目录下新建创世块json文件piccgenesis.json。内容如下:
{
"nonce":"0x0000000000000042",
"mixhash":"0x0000000000000000000000000000000000000000000000000000000000000000",
"difficulty": "0x4000",
"alloc": {},
"coinbase":"0x0000000000000000000000000000000000000000",
"timestamp": "0x00",
"parentHash":"0x0000000000000000000000000000000000000000000000000000000000000000",
"extraData": "SecBroBlock",
"gasLimit":"0x0000ffff"
}
参数解释:
参数名称 参数描述
mixhash 与nonce配合用于挖矿,由上一个区块的一部分生成的hash。注意他和nonce的设置需要满足以太坊的Yellow paper, 4.3.4. Block Header Validity, (44)章节所描述的条件。
nonce nonce就是一个64位随机数,用于挖矿,注意他和mixhash的设置需要满足以太坊的Yellow paper, 4.3.4. Block Header Validity, (44)章节所描述的条件。
difficulty 设置当前区块的难度,如果难度过大,cpu挖矿就很难,这里设置较小难度
alloc 用来预置账号以及账号的以太币数量,因为私有链挖矿比较容易,所以我们不需要预置有币的账号,需要的时候自己创建即可以。
coinbase 矿工的账号,随便填
timestamp 设置创世块的时间戳
parentHash 上一个区块的hash值,因为是创世块,所以这个值是0
extraData 附加信息,随便填,可以填你的个性信息
gasLimit 该值设置对GAS的消耗总量限制,用来限制区块能包含的交易信息总和,因为我们是私有链,所以填最大。
 
启动私有链节点
启动私有节点所需参数
参数名称 参数描述
identity 区块链的标示,随便填写,用于标示目前网络的名字
init 指定创世块文件的位置,并创建初始块
datadir 设置当前区块链网络数据存放的位置
port 网络监听端口
rpc 启动rpc通信,可以进行智能合约的部署和调试
rpcapi 设置允许连接的rpc的客户端,一般为db,eth,net,web3
networkid 设置当前区块链的网络ID,用于区分不同的网络,是一个数字
console 启动命令行模式,可以在Geth中执行命令
 
启动
本人启动eth所在目录为:
/home/zhuzs/eth
此目录下放置刚才配置好的创世块json文件:piccgenesis.json
因此直接执行如下命令:
geth --identity "secbro etherum" --rpc --rpccorsdomain "*" --datadir "/home/zhuzs/eth/chain" --port "30303" --rpcapi "db,eth,net,web3" -- networkid 95518 console --dev 
PS:根据自己的环境进行对应的替换。注意,最后添加了–dev,以开发模式启动。
看到一下输出说明启动成功,并且是使用的私有链:
 
随后就是相关的命令操作,在下一篇文章中进一步说明。

区块链开发(二)以太坊客户端操作命令

 启动命令

重复上篇文章步骤,先将区块链客户端启动,命令如下:
geth --identity "secbro etherum" --rpc --rpccorsdomain "*" --datadir "/home/zhuzs/eth/chain" --port "30303" --rpcapi "db,eth,net,web3" -- networkid 95518 console --dev
看到启动页面之后,新开启一个终端,并执行一下命令,并把日志输出到文本文件当中:
geth --dev console 2>> file_to_log_output
这些需要注意的是,在启动客户端时添加了参数–dev,开发模式,这里直接使用dev参数来调用使用启动的服务,显示结果如下:
在这里可以执行具体的操作命令。
 
查看账户
eth.accounts
 
创建用户:
personal.newAccount("111111")
其中参数为此账户的密码。
也可以先创建账户,然后输入密码:
personal.newAccount()
 
查看区块数据
eth.blockNumber
 
启动挖矿
miner.start()
返回结果为true则启动成功,具体执行情况可查看日志。
 
停止挖矿
miner.stop()
当在执行挖矿时日志会不停刷屏,不用管,只要命令输入全,执行即可停止挖矿。
 
查看账户余额
其中参数为区块链地址
eth.getBalance("0x7d1f7be4112ce63b9de04a0bf95c1e87e430bd1b")
 
转账
从账户0x7d1f7be4112ce63b9de04a0bf95c1e87e430bd1b转账3个以太币到0x587e57a516730381958f86703b1f8e970ff445d9
eth.sendTransaction({from:"0x7d1f7be4112ce63b9de04a0bf95c1e87e430bd1b", to:"0x587e57a516730381958f86703b1f8e970ff445d9",value:web3.toWei(3,"ether")})
当直接执行此方法时会抛出异常:
account is locked
at web3.js:3119:20
at web3.js:6023:15
at web3.js:4995:36
at <anonymous>:1:1
很明显,账户被锁。
 
解锁转出账户
其中第一个参数为转出账户,第二个参数为密码。也可以直填写第一个参数,然后通过命令行提示再输入密码。
personal.unlockAccount("0x7d1f7be4112ce63b9de04a0bf95c1e87e430bd1b","111111")
解锁完成之后,即可执行转账操作。但此时查看时会发现接收账户依旧为原来数值。此时需要执行挖矿命令,才会把转账真正完成。

以太坊不同客户端的定义和用途

 以太坊发布以后,有多个客户端,同时也支持多个平台,初学者往往被各种各样的客户端弄迷糊,本文进行了详细的总结。

 
以太坊客户端以语言进行分类,在github上分成了不同项目,源代码地址:https://github.com/ethereum/,虽然以太坊客户端众多,但是有两个共同特点:
 
1、同一语言的客户端在不同平台上的使用是完全相同的
 
2、不同语言的客户端(mist、geth、eth等等)之间在同一个平台(linux、windows或OSX)上共用一样的应用配置,同时其命令行可使用的参数也是一致。
 
下面就以github上的项目为分类说明各个客户端的用途和特点:
 
一、go-ethereum项目
 
开发语言:go语言
客户端文件:Geth
界面:命令行
适用平台:windows、linux和OSX
功能和特点:该项目是使用最广泛的以太坊客户端,大部分节点都是运行的该客户端,教程和例子也最多,推荐使用,可用于挖矿,组建私有链,管理账号,部署智能合约等常用功能,不可以编译智能合约。
 
二、webthree-umbrella项目
 
此项目包含3个客户端
开发语言:c++
客户端文件:AlethZero、Mix和Eth
使用平台:windows、linux和OSX
界面:图形化界面
功能和特点:该项目严格来说是cpp-ethereum 项目的一个shell,是以太坊基金会的前CTO,Gavin Wood主持编写的,所以人气也很高,易用性也很好。AlethZero是图形化的钱包客户端,对应的是Geth的功能,不过是全图形化的。但是随着后续以太坊基金会主推的图形化钱包Mist的推出,渐渐没落。Mix 是智能合约(以太坊称为DAPP)的开发IDE,可以支持智能合约(DAPP)的编写、调试,部署,全图形化界面,目前最主流的以太坊智能合约开发平台,非常方便,强烈推荐。Eth是C++编写的命令行客户端功能和Geth一样。
 
三、Mist项目
 
开发语言:JavaScript
客户端文件:Mist(目前使用Ethereum-Wallet的名称)
使用平台:windows、linux和OSX
界面:图形化界面
功能和特点:该项目是以太坊基金会主推的项目,Mist定位不只是一个钱包,而是将来DAPP(智能合约的应用APP)市场,类似于苹果市场,在这里可以有你的账号,可以浏览、发布和买卖以太坊的DAPP应用。目前因为开发还不够全面,名称暂时显示为Ethereum-Wallet,作用也很简单,就是一个钱包的功能。强烈推荐,未来的主流客户端。
 
四、solidity项目
 
开发语言:C++
客户端文件:solc
使用平台:windows、linux和OSX
界面:命令行界面
功能和特点:该项目是以太坊智能合约(DAPP)的编程语言,使用solc作为编译程序,该项目主要用于编译,严格来说是一个基本的编译平台,一般开发可用MIX替代。
 
五、browser-solidity项目
 
开发语言:C++
客户端文件:浏览器中显示
使用平台:windows、linux和OSX
界面:浏览器界面
功能和特点:该项目是智能合约浏览器版本的开发环境,可以支持在浏览器中直接开发、调试和编译,对于初学者来说,可以快速上手,不需要安装,非常方便,直接访问地址使用:https://ethereum.github.io/browser-solidity/
 
六、pyethereum项目和ethereumj项目
 
pyethereum项目是用python语言编写的以太坊客户端,ethereumj项目是用JAVA语言编写的以太坊客户端,只是语言不同,和前面GO语言编写的客户端Geth的功能完全相同。
 
七、etheminer项目
 
开发语言:C++
客户端文件:ethminer
使用平台:windows、linux和OSX
界面:命令行
功能和特点:该项目是cpp-ethereum项目的一部分,用于和Geth配合进行GPU挖矿,比CPU挖矿效率高100多倍,也可以用于矿池挖矿。
Records:271234