以太坊私有链搭建节点集群 到 简单helloworld智能合约编写 操作流程

1.选择一种以太坊客户端

Go-ethereum客户端通常被称为Geth,它是个命令行界面,执行在Go上实现的完整以太坊节点。Geth得益于Go语言的多平台特性,支持在多个平台上使用(比如Windows、Linux、Mac)。Geth是以太坊协议的具体落地实现,通过Geth,你可以实现以太坊的各种功能,如账户的新建编辑删除,开启挖矿,ether币的转移,智能合约的部署和执行等等。所以,我们选择 geth工具来进行开发。

Mac 中安装geth如下:

brew tap ethereum/ethereum
brew install ethereum

检查是否安装成功:

geth --help

如果输出一些帮助命令,则安装成功。

2.搭建私有链

以太坊支持自定义创世区块,要运行私有链,我们就需要定义自己的创世区块,创世区块信息写在一个json格式的配置文件中。

json文件内容如下:

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

2.1初始化:写入创世区块

准备好创世区块json配置文件后,需要初始化区块链,将上面的创世区块信息写入到区块链中。首先要新建一个目录data0用来存放区块链数据(其实,这个目录data0就相当于一个根节点。当我们基于genesis.json生成根节点后,其他人就可以来连接此根节点,从而能进行交易)。data0目录结构如图所示:

接下来进入privatechain目录中,执行初始化命令:

cd privatechain
geth --datadir data0 init genesis.json

上面的命令的主体是 geth init,表示初始化区块链,命令可以带有选项和参数,其中–datadir选项后面跟一个目录名,这里为 data0,表示指定数据存放目录为 data0, genesis.json是init命令的参数。

运行上面的命令,会读取genesis.json文件,根据其中的内容,将创世区块写入到区块链中。如果看到log信息中含有Successfully wrote genesis state字样,说明初始化成功。

初始化成功后的目录如下:

其中geth/chaindata中存放的是区块数据,keystore中存放的是账户数据。

2.2启动私有链节点

初始化完成后,就有了一条自己的私有链,之后就可以启动自己的私有链节点并做一些操作,在终端中输入以下命令即可启动节点:

geth --datadir data0 --networkid 1008 console

上面命令的主体是geth console,表示启动节点并进入交互式控制台,–datadir选项指定使用data0作为数据目录,–networkid选项后面跟一个数字,这里是1008,表示指定这个私有链的网络id为1008。网络id在连接到其他节点的时候会用到,以太坊公网的网络id是1,为了不与公有链网络冲突,运行私有链节点的时候要指定自己的网络id。

运行上面的命令后,就启动了区块链节点并进入了Javascript Console:

以太坊私有链搭建节点集群 到 简单helloworld智能合约编写 操作流程_第1张图片

这是一个交互式的Javascript执行环境,在这里面可以执行Javascript代码,其中>是命令提示符。在这个环境里也内置了一些用来操作以太坊的Javascript对象,可以直接使用这些对象。这些对象主要包括:

eth:包含一些跟操作区块链相关的方法 net:包含以下查看p2p网络状态的方法 admin:包含一些与管理节点相关的方法 miner:包含启动&停止挖矿的一些方法 personal:主要包含一些管理账户的方法 txpool:包含一些查看交易内存池的方法 web3:包含了以上对象,还包含一些单位换算的方法

2.3 Javascript Console

进入以太坊Javascript Console后,就可以使用里面的内置对象做一些操作,这些内置对象提供的功能很丰富,比如查看区块和交易、创建账户、挖矿、发送交易、部署智能合约等。接下来介绍几个常用功能,下面的操作中,前面带>的表示在Javascript Console中执行的命令。

创建账户

前面只是搭建了私有链,并没有自己的账户,可以在js console中输入eth.accounts来验证:

> eth.accounts
[]

此时没有账户,接下来使用personal对象来创建一个账户:

> personal.newAccount()
> Passphrase:
> Repeat passphrase:
"0x67346d5619ae5747eb69629c8b1c8cbae71111c3"

Passphrase其实就是密码的意思,输入两次密码后,就创建了一个账户。再次执行命令:

> personal.newAccount()
> Passphrase:
> Repeat passphrase:
"0xa48dba91281ee727c2424c85400f51f7a22716de"

这时候再去看账户,就有两个了。

> eth.accounts
["0x67346d5619ae5747eb69629c8b1c8cbae71111c3", "0xa48dba91281ee727c2424c85400f51f7a22716de"]

账户默认会保存在数据目录的keystore文件夹中。查看目录结构,发现data0/keystore中多了两个文件,这两个文件就对应刚才创建的两个账户,这是json格式的文本文件,可以打开查看,里面存的是私钥经过密码加密后的信息。

查看账户余额

> eth.getBalance(eth.accounts[0])
0
> eth.getBalance(eth.accounts[1])
0

启动、停止挖矿

> miner.start(10)

其中start的参数表示挖矿使用的线程数。第一次启动挖矿会先生成挖矿所需的DAG文件,这个过程有点慢,等进度达到100%后,就会开始挖矿,此时屏幕会被挖矿信息刷屏。

如果想停止挖矿,并且进度已经达到100%之后,可以在js console中输入

> miner.stop()

挖到一个区块会奖励5个以太币,挖矿所得的奖励会进入矿工的账户,这个账户叫做coinbase,默认情况下coinbase是本地账户中的第一个账户:

> eth.coinbase
"0x67346d5619ae5747eb69629c8b1c8cbae71111c3"

getBalance()返回值的单位是wei,wei是以太币的最小单位,1个以太币=10的18次方个wei。要查看有多少个以太币,可以用web3.fromWei()将返回值换算成以太币:

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

发送一笔交易

> eth.sendTransaction({from:eth.accounts[0],to:eth.accounts[1],value:amount})

这里报错了,原因是账户每隔一段时间就会被锁住,要发送交易,必须先解锁账户,由于我们要从账户0发送交易,所以要解锁账户0:

> personal.unlockAccount(eth.accounts[0])

输入创建账户时设置的密码,就可以成功解锁账户。然后再发送交易。

我们去查看账户1中的余额,发现还没转过去,此时交易已经提交到区块链,但还未被处理,这可以通过查看txpool来验证:

> txpool.status
{
  pending: 1,
  queued: 0
}

其中有一条pending的交易,pending表示已提交但还未被处理的交易。

要使交易被处理,必须要挖矿。这里我们启动挖矿,然后等待挖到一个区块之后就停止挖矿:

> miner.start(1);admin.sleepBlocks(1);miner.stop();

当miner.stop()返回true后,txpool中pending的交易数量应该为0了,说明交易已经被处理了,而账户1应该收到币了:

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

查看交易

eth对象封装了查看交易和区块信息的方法。

查看当前区块总数:

> eth.blockNumber

3.建立节点集群

在私有网络中建立多个节点组成的集群,并互相发现,产生交易。

如果是为了在本地网络运行多个以太坊节点的实例,必须确保一下几点:
1. 每个实例都有独立的数据目录(--datadir)
2. 每个实例运行都有独立的端口.(eth和rpc两者都是)(--port 和 --rpcprot)
3. 在集群的情况下, 实例之间都必须要知道彼此.

4. 唯一的ipc通信端点,或者禁用ipc.

在这里,我们选择在不同的电脑上分别建立节点组成集群,互相发现,产生交易。

在第一台电脑上启动节点

geth --datadir data0 --networkid 1008 console

在第二台电脑上初始化并启动节点,注意网络ID要相同,确保节点都在一个私有网络中。

geth --datadir ./data/01 init ./genesis.json  初始化 注意和第一个节点使用相同的创始快json文件

geth --datadir data0 --networkid 1008 --bootnodes "enode://b86d51f0737672b80c9000caa706955b2a94286f8593774aab40c86cbb4fc871ce6853172871eef24bced4e6fa4576fb9d8fadfd0893b3f0873eddb9eb2072f2@192.168.6.150:30303" console

bootnodes后边的参数是第一台电脑上节点的enode url 可以在第一台电脑上通过

>admin.nodeInfo.enode

来获取。

@192.168.6.150:30303  是第一台电脑的IP地址:192.168.150 以及ports:30303

本节点的ports可以通过

admin.nodeInfo

来获取。

至此两个节点应该就链接成功了。

3.1节点间发送以太币

> eth.sendTransaction({from: "0x5fba50fce50baf0b8a7314200ba46336958ac97e", to: "0x0a8c35653d8b229c16f0c9ce6f63cffb877cfdcf", value: web3.toWei(1, "ether")})

from中填当前节点的账号地址,to中填要发送给的节点的账号地址。

执行以上命令发送一个以太币。注意发送交易操作前要先解锁账号:

> personal.unlockAccount(eth.accounts[0], "passwoed")

然后执行挖矿太能让交易生效。

> miner.start()

4.编写helloworld智能合约

   让我们开始你的第一个严肃的合约。前沿是一个很大的开放领土,有时候你可能会感到孤独,所以我们的第一步就是创造一个自动伴侣,在你感到孤独时迎接你。我们会称他为“Greeter”。

   Greeter是一个智能数字化实体,它存在于区块链中,并能够根据其输入与任何与之交互的人进行对话。它可能不是一个说话者,但它是一个很好的倾听者。这是它的代码:

contract Mortal {
    /* Define variable owner of the type address */
    address owner;

    /* This function is executed at initialization and sets the owner of the contract */
    function Mortal() { owner = msg.sender; }

    /* Function to recover the funds on the contract */
    function kill() { if (msg.sender == owner) selfdestruct(owner); }
}

contract Greeter is Mortal {
    /* Define variable greeting of the type string */
    string greeting;

    /* This runs when the contract is executed */
    function Greeter(string _greeting) public {
        greeting = _greeting;
    }

    /* Main function */
    function greet() constant returns (string) {
        return greeting;
    }
}
   你会注意到这个代码中有两个不同的合约:“Mortal”和“Greeter”。这是因为Solidity(我们使用的高级合同语言)具有继承性,这意味着一个合约可以继承另一个合约的特征。这对简化编码非常有用,因为合约的通用特征不需要每次重写,并且所有合约都可以用更小,更易读的块编写。所以通过只声明Greeter是Mortal的,你就继承了来自“Mortal”合约的所有特征,并使Greeter代码简单易读。

  继承特征的“Mortal”仅仅意味着Greeter合同可以被其所有者杀死,以清理区块链并在不再需要合同时收回锁定在其中的资金。以太坊中的契约默认为不朽,并且没有所有者,这意味着一旦部署,作者就没有特殊的特权了。部署前请考虑这一点。

  在部署合同前,需要准备两样东西:

1.编译后的代码。

2.应用程序二进制接口(ABI),它是一个定义如何与合约进行交互的JavaScript对象

  我们可以通过使用Solidity编译器来获得这两者。(在线编译器remix的地址:点击打开链接)

4.1获得编译后的代码

   将源代码(位于本页顶部)复制到Remix,它应该自动编译您的代码。 您可以放心地忽略右侧任何黄色警告框。

以太坊私有链搭建节点集群 到 简单helloworld智能合约编写 操作流程_第2张图片

  要访问已编译的代码,请确保右窗格中的下拉菜单已选中Greeter。 然后直接点击下拉菜单右边的details按钮。 在弹出窗口中,向下滚动并复制WEB3DEPLOY文本框中的所有代码。

以太坊私有链搭建节点集群 到 简单helloworld智能合约编写 操作流程_第3张图片


  在计算机上创建一个临时文本文件并粘贴该代码。 确保将第一行更改为如下所示:

var _greeting = "Hello World!"

  现在,可以将结果文本粘贴到geth窗口中,或者使用loadScript(“yourFilename.js”)导入文件。

 然后执行挖矿。  

 等待一会终端中会看到类似这样的消息:


您可能必须先使用您在开始时选择的密码来“解锁”发送交易的帐户,因为您需要支付部署合同的GAS费用。 

personal.unlockAccount(web3.eth.accounts [0],“yourPassword”)

您可以使用以下命令来验证已部署的代码(将被编译):

eth.getCode(greeter.address)

如果它返回“0x”以外的任何内容,那么恭喜! 你的小家伙活着! 如果再次创建合同(通过执行另一个eth.sendTransaction),它将发布到新地址。

4.2 执行Greeter

为了召唤你的机器人,只需在终端上输入以下命令:

greeter.greet();

由于这个调用没引起在区块链上的任何变化,因此它会立即返回并且无需任何燃气费用。 你应该看到它返回你的问候语:

'Hello World!'

4.3 让其他人与您的代码交互

为了让其他人来执行你的合同,他们需要两个东西:
1.合同所在地址
2. ABI(应用程序二进制接口),这是一种用户手册,描述合同功能的名称以及如何将它们调用到您的JavaScript控制台
    想要获取地址,请运行以下命令:
greeter.address;

    得到类似下图的一个合约地址:


   为了得到ABI,您需要直接从Remix复制ABI,类似于复制WEB3DEPLOY编译代码的方式。 在右侧窗格中,单击详细信息按钮并向下滚动到ABI文本框。 点击复制按钮复制整个ABI,然后将其粘贴到临时文本文档中。

以太坊私有链搭建节点集群 到 简单helloworld智能合约编写 操作流程_第4张图片



然后,您可以实例化一个可用于在连接到网络的任何计算机上调用合同的JavaScript对象。 在以下行中,替换ABI(一个数组)和Address(一个字符串)以在JavaScript中创建合同对象:

var greeter = eth.contract(ABI).at(Address);
这样别的节点就也可以通过
greeter.greet();

调用你的机器人了。结果显示:

'Hello World!'

  







你可能感兴趣的:(blockchain)