区块链开发之搭建以太坊私有链

(一)区块链开发之搭建以太坊私有链

本文链接:https://blog.csdn.net/rwdxll/article/details/82929417

1、安装ethereum/Go client(以太坊客户端)

https://github.com/ethereum/go-ethereum/wiki/Installation-Instructions-for-Mac

https://github.com/ethereum/homebrew-ethereum

 
  1. 一、命令行客户端

  2. 1、克隆仓库

  3. brew tap ethereum/ethereum

  4. 2、安装go 客户端

  5. brew install ethereum

  6. 3、运行

  7. geth

  8.  
  9. 二、图形化客户端

  10. https://github.com/ethereum/mist/releases/

  11.  

说明:

安装目录:/usr/local/Cellar/ethereum/1.8.14,将bin目录添加到环境变量里.

2、创建私有链

i.新建一个geth工作目录

mkdir geth

cd geth

touch gensis.json

ii.创世区块配置文件

创世(gensis)区块是区块链的起点,是区块链的第一块区块--------0号区块,唯一一个没有前任的区块。这个协议确保了没有其他节点会和你的节点的区块链版本一致,除非它们的创世区块和你的一模一样,通过这个方法可以创建多个私有区块链。

文件:gensis.json

{
  "config": {
        "chainId": 15,
        "homesteadBlock": 0,
        "eip155Block": 0,
        "eip158Block": 0
    },
  "alloc"      : {"0x6e1d19B1D713E39fD77Db95ff2929db78dB4ad34":{"balance":"100000"}

  },
  "coinbase"   : "0x0000000000000000000000000000000000000000",
  "difficulty" : "0x01",
  "extraData"  : "0x",
  "gasLimit"   : "0xfffffff",
  "nonce"      : "0x0000000000000001",
  "mixhash"    : "0x0000000000000000000000000000000000000000000000000000000000000000",
  "parentHash" : "0x0000000000000000000000000000000000000000000000000000000000000000",
  "timestamp"  : "0x00"
}

 

参数

描述

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

用来预置账号以及账号的以太币数量,因为私有链挖矿比较容易,所以我们不需要预置有币的账号,需要的时候自己创建即可以。可以使用MetaMask创建地址。

coinbase

矿工的账号,随便填

timestamp

设置创世块的时间戳

parentHash

上一个区块的hash值,因为是创世块,所以这个值是0

extraData

附加信息,随便填,可以填你的个性信息

gasLimit

该值设置对GAS的消耗总量限制,用来限制区块能包含的交易信息总和,因为我们是私有

iii.初始化

cd geth

mkdir db

geth --datadir "./db" init gensis.json

geth init 命令用来初始化区块链,命令可以带有选项和参数,其中--datadir选项后面跟一个文件夹名db,gensis.json是init命令行参数。初始成功后会在数据目录db下生产geth和keystore两个文件夹。此时目录结构如下:

区块链开发之搭建以太坊私有链_第1张图片

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

iv.启动节点

geth geth --datadir "./db" --rpc --rpcaddr=0.0.0.0 --rpcport 8545 --rpccorsdomain "*" --rpcapi "eth,net,web3,personal,admin,shh,txpool,debug,miner" --nodiscover --maxpeers 30 --networkid 1981 --port 30303 --mine --minerthreads 1 --etherbase "0x6e1d19B1D713E39fD77Db95ff2929db78dB4ad34" console

参数说明:

 

identity

区块链的标示,随便填写,用于标示目前网络的名字

 

init

指定创世块文件的位置,并创建初始块

 

datadir

设置当前区块链网络数据存放的位置

 

port

网络监听端口

 

rpc

启动rpc通信,可以进行智能合约的部署和调试

  rpcaddr 指定HTTP-RPC服务监听地址,默认为“localhost”
 

rpcapi

设置允许连接的rpc的客户端,一般为db,eth,net,web3

  rpcport 指定允许连接的rpc服务监听端口,默认为8545
 

networkid

设置当前区块链的网络ID,用于区分不同的网络,是一个数字

  etherbase 指定旷工账号,默认为keystore中的首个账号
 

mine

开启挖矿,默认为CPU挖矿

  minerthreads 挖矿占用CPU的线程数,默认为4
  nodiscover 关闭自动连接节点,但是可以手动添加节点,在搭建私有链时,为避免其他节点连入私有链,可以使用该命令
  maxpeers 设置允许最大连接节点数目,默认为25
  console 启动命令行模式,可以在Geth中执行命令 

log:

INFO [10-09|11:25:34.522] Maximum peer count                       ETH=30 LES=0 total=30
INFO [10-09|11:25:34.552] Starting peer-to-peer node               instance=Geth/v1.8.14-stable/darwin-amd64/go1.10.3
INFO [10-09|11:25:34.552] Allocated cache and file handles         database=/Users/xxx/Desktop/nasnano/ethereum/geth/db/geth/chaindata cache=768 handles=1024
INFO [10-09|11:25:34.662] Initialised chain configuration          config="{ChainID: 15 Homestead: 0 DAO: DAOSupport: false EIP150: EIP155: 0 EIP158: 0 Byzantium: Constantinople: Engine: unknown}"
INFO [10-09|11:25:34.663] Disk storage enabled for ethash caches   dir=/Users/xxx/Desktop/nasnano/ethereum/geth/db/geth/ethash count=3
INFO [10-09|11:25:34.663] Disk storage enabled for ethash DAGs     dir=/Users/xxx/.ethash                                      count=2
INFO [10-09|11:25:34.663] Initialising Ethereum protocol           versions="[63 62]" network=1981
INFO [10-09|11:25:34.664] Loaded most recent local header          number=0 hash=f62ece…c00ca7 td=1
INFO [10-09|11:25:34.664] Loaded most recent local full block      number=0 hash=f62ece…c00ca7 td=1
INFO [10-09|11:25:34.664] Loaded most recent local fast block      number=0 hash=f62ece…c00ca7 td=1
INFO [10-09|11:25:34.665] Regenerated local transaction journal    transactions=0 accounts=0
INFO [10-09|11:25:34.666] Starting P2P networking
INFO [10-09|11:25:34.667] RLPx listener up                         self="enode://576e857437aba95e59cfee3570a0fdd0d00dc9c4656ef9e48b47649cdc9b56f86bbf54081a5e38cec85fa150b4b088e22ccd93978e3de0c52aeed6b43471ee79@[::]:30303?discport=0"
INFO [10-09|11:25:34.669] IPC endpoint opened                      url=/Users/xxx/Desktop/nasnano/ethereum/geth/db/geth.ipc
INFO [10-09|11:25:34.697] HTTP endpoint opened                     url=http://0.0.0.0:8545                                      cors=* vhosts=localhost
INFO [10-09|11:25:34.697] Transaction pool price threshold updated price=18000000000
INFO [10-09|11:25:34.698] Commit new mining work                   number=1 uncles=0 txs=0 gas=0 fees=0 elapsed=514.993µs
Welcome to the Geth JavaScript console!

instance: Geth/v1.8.14-stable/darwin-amd64/go1.10.3
coinbase: 0x6e1d19b1d713e39fd77db95ff2929db78db4ad34
at block: 0 (Thu, 01 Jan 1970 08:00:00 CST)
 datadir: /Users/xxx/Desktop/nasnano/ethereum/geth/db
 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

> INFO [10-09|11:25:37.341] Generating DAG in progress               epoch=0 percentage=0 elapsed=1.492s
INFO [10-09|11:25:38.962] Generating DAG in progress               epoch=0 percentage=1 elapsed=3.113s

v.进入JavaScript控制台

通过attach命令,连接到iv启动的节点(会在db下生成geth.ipc),启动js命令环境

geth --datadir "./db" attach ipc:./db/geth.ipc

Welcome to the Geth JavaScript console!

instance: Geth/v1.8.14-stable/darwin-amd64/go1.10.3
coinbase: 0x6e1d19b1d713e39fd77db95ff2929db78db4ad34
at block: 0 (Thu, 01 Jan 1970 08:00:00 CST)
 datadir: /Users/liliang/Desktop/nasnano/ethereum/geth/db
 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

>

vi.以太坊JavaScript控制台命令

js控制台内置了一些对象,通过这些对象可以很方便的与以太坊交互,这些内置对象包括:

eth:提供操作区块链相关的方法

net:提供了查看p2p网络状态的的方法

admin:提供了管理节点相关的方法

miner:提供启动和停止挖矿的方法

personal:提供了管理账户的方法

txpool:提供了查看交易内存池的方法

web3:除了包含以上对象中有的方法,还包含一些单位换算的方法

1、新建账户

> personal.newAccount("123456")
"0x98d03a20eb02fc526534cabbda6dc2e6b43de214"

personal.newAccount("password"),传入的参数是账户的密码。执行成功后会返回账户的公钥,生成的账户文件在keystor目录下.

查看账户:

eth.accounts
["0x2dd6b2362d6351b18bd3af9519b8e5b2e44d0339", "0x98d03a20eb02fc526534cabbda6dc2e6b43de214"]

2、查看余额

> balance=web3.fromWei(eth.getBalance(eth.accounts[0]),"ether")
0
> balance=web3.fromWei(eth.getBalance(eth.accounts[1]),"ether")
0

eth.accouts[index]会按传入的索引返回已有的账户,eth.getBalance(address)会返回账户的余额,余额为wei为单位,传入的参数是账户的公钥。web3.fromWei单位转换,在这个例子中是将wei转换成ether。

创建的账户都是0,怎样获得以太币呢,答案是挖矿。

3、挖矿

为了获取以太币,我们需要开始挖矿,不过在开启挖矿之前,我们要先设置挖矿奖励的地址

> miner.setEtherbase(eth.accounts[0])
true

查看设置是否成功:

> eth.coinbase
"0x2dd6b2362d6351b18bd3af9519b8e5b2e44d0339"

开启挖矿:

miner.start(1),参数是线程数,表示可以开启几个线程来挖矿,本例中设置的是一个线程。当出现小锤子表示开始挖矿了。当挖矿时会有大量的输入填满终端,为了方便操作,你可以重现打开一个新的控制台,执行attach命令,进入一个新的JavaScript环境。

关闭挖矿,等需要的时候在开:

>miner.stop()

true

查看下余额:

>  balance=web3.fromWei(eth.getBalance(eth.accounts[0]),"ether")
6330

在以太坊上任何操作都需要借助交易来完成,如转账、部署合约、用用只能合约

4、解锁账户

在发送交易之前,要先解锁账户,否则会报错,执行以下命令解锁账户

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

> personal.unlockAccount(eth.accounts[0],"123456",300)
true

personal.unlockAccount(addr,passwd,duration)命令用来解锁账户,第一个参数解锁地址,第二个参数是密码,第三个参数传入解锁状态持续时间,其中duration单位为秒。

5、交易

> eth.sendTransaction({from: eth.accounts[0],to: eth.accounts[1],value:web3.toWei(1,"ether")})
"0x590f47c8d2aac75460c08cd761fa81559e2053ce608f9f4fb68c27a73cb86379"

查看交易池等待被打币的交易。

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

pending表示已提交,但未被处理的交易。

查看pending交易的详情。

> txpool.inspect.pending
{
  0x2dd6b2362D6351B18BD3af9519b8E5B2e44d0339: {
    0: "0x98D03a20EB02Fc526534CaBbdA6Dc2e6b43DE214: 1000000000000000000 wei + 90000 gas × 18000000000 wei"
  }
}

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

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

交易被打包,并且加入到区块链中了,查下余额

> balance=web3.fromWei(eth.getBalance(eth.accounts[1]),"ether")
1

vii.区块

查询发起转账交易的详情,参数为交易hash:

> eth.getTransaction("0x590f47c8d2aac75460c08cd761fa81559e2053ce608f9f4fb68c27a73cb86379")
{
  blockHash: "0x5e5cf36663b967ed1c1bb26018fbe5df8af645dc6d9abced0eb317697a220722",
  blockNumber: 1423,
  from: "0x2dd6b2362d6351b18bd3af9519b8e5b2e44d0339",
  gas: 90000,
  gasPrice: 18000000000,
  hash: "0x590f47c8d2aac75460c08cd761fa81559e2053ce608f9f4fb68c27a73cb86379",
  input: "0x",
  nonce: 0,
  r: "0x3a562af2294afae7116c0ae2f4ba09da53f9fab8ca74d7e6ace0d22562f93636",
  s: "0x5bf7b3df00558695dd315c049c238021b60b6d0fd05a06b2b9c5cf5a169c87c2",
  to: "0x98d03a20eb02fc526534cabbda6dc2e6b43de214",
  transactionIndex: 0,
  v: "0x42",
  value: 1000000000000000000
}

交易参数:

blockHash 交易所在区块的哈希值。当这个区块处于pending时将会返回null
blockNumber 交易所在区块号。当这个区块处于pending时将会返回null
from 交易发起者的地址
gas 交易发起者提供的gas数量
gasprice 交易发起者提供的gas数量
hash 交易的哈希值
input 交易附带的数据
nonce 交易的发起者在之前发起过的交易数量
transactionIndex 交易在区块中的序号。当这个区块处于pending时将会返回null
value 交易附带货币量,单位为Wei
to 交易接收者的地址

查看发起交易在区块中的详细信息:

> eth.getTransactionReceipt("0x590f47c8d2aac75460c08cd761fa81559e2053ce608f9f4fb68c27a73cb86379")
{
  blockHash: "0x5e5cf36663b967ed1c1bb26018fbe5df8af645dc6d9abced0eb317697a220722",
  blockNumber: 1423,
  contractAddress: null,
  cumulativeGasUsed: 21000,
  from: "0x2dd6b2362d6351b18bd3af9519b8e5b2e44d0339",
  gasUsed: 21000,
  logs: [],
  logsBloom: "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
  root: "0xf977149c1937aa24648e0225c7626a2e3b3a8446baa1e60fc9d210ea395f7861",
  to: "0x98d03a20eb02fc526534cabbda6dc2e6b43de214",
  transactionHash: "0x590f47c8d2aac75460c08cd761fa81559e2053ce608f9f4fb68c27a73cb86379",
  transactionIndex: 0
}

TransactionReceipt参数详解

blockHash 交易所在区块哈希
blockNumber 交易所在去考的块号
contractAddress 创建的合约地址。如果是一个合约创建交易,则返回合约地址,其他情况返回null
cumulativeGasUsed 当前交易执行后累计话费的gas总值
from 交易发送者的地址
gasUsed 执行当前这个交易单独花费的gas
logs logsBloom由logs中的address与topics共同决定,详细请查看以太坊黄皮书
root 交易执行后的stateroot
to 交易接受者的地址。如果是一个合约创建的交易,返回null
transactionHash 交易哈希值
transactionIndex 交易在区块里面的序号

常用的一些查询区块的命令:

查看当前区块总数:

> eth.blockNumber
1433

查询最新的区块(参数为区块数或Hash)
> eth.getBlock('latest')
{
  difficulty: 235650,
  extraData: "0xd98301080e846765746888676f312e31302e338664617277696e",
  gasLimit: 66190083,
  gasUsed: 0,
  hash: "0xd6a6e5da6ef0c5127363c468570c7f9a679b2d33dc14570ea751b916c0e17087",
  logsBloom: "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
  miner: "0x6e1d19b1d713e39fd77db95ff2929db78db4ad34",
  mixHash: "0xbf6a2bdde494f66921a763829a3d3d8ecc65bdbfbc4feba4ee9f99a599dec4a3",
  nonce: "0x0df18fb718d8ab3c",
  number: 1433,
  parentHash: "0xf631a736994fc3e9bd2772cbbcb092b2f8f58b49f0f7607deed83006d8500b61",
  receiptsRoot: "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
  sha3Uncles: "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",
  size: 540,
  stateRoot: "0xd604935e26d44991888489c6412a6f4cf04bbd25913a6eeda0b5920b8d0cef51",
  timestamp: 1539072197,
  totalDifficulty: 264521090,
  transactions: [],
  transactionsRoot: "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
  uncles: []
}

> eth.getBlock(0)
{
  difficulty: 1,
  extraData: "0x",
  gasLimit: 268435455,
  gasUsed: 0,
  hash: "0xf62ece4906c7cadd848274fc800e0d881f9d296db67c9641121ea5315ec00ca7",
  logsBloom: "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
  miner: "0x0000000000000000000000000000000000000000",
  mixHash: "0x0000000000000000000000000000000000000000000000000000000000000000",
  nonce: "0x0000000000000001",
  number: 0,
  parentHash: "0x0000000000000000000000000000000000000000000000000000000000000000",
  receiptsRoot: "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
  sha3Uncles: "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",
  size: 505,
  stateRoot: "0x19ef3cc3d7fdd74a91b4fcdcb8b18f6d151a74a6aa6dbab57ba0314152dadd2d",
  timestamp: 0,
  totalDifficulty: 1,
  transactions: [],
  transactionsRoot: "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
  uncles: []
}

区块参数详解

diffculty 挖矿难度,后面区块难度会随着区块高度升高而提高
extraData 当前区块附件信息,若创世区块该值为空,则在第二个区块中会保存创建该私有链时的geth、go,以及操作系统版本,保存的信息为第一个挖到该区块的矿工信息
gasLimit 该区块允许的最大gas数
gasUsed gas花费,在以太坊中交易和部署智能合约会消耗gas,暂时可理解为以太币
hash 当前区块hash值
logsBloom logsBloom由logs中的address与topics共同决定,详细请看以太坊黄皮书。作用是便于快速查找监听的事件是否在该交易中产生
miner 挖到该区块的矿工地址
mixHash 与nonce配合用于挖矿,由上一个区块的一部分生成的hash
nonce 工作量证明
number 当前的区块高度
parentHash 上一个区块hash值
receiptsRoot 区块receipt trie的根
sha3Uncles 对叔区块进行的hash运算的结果
size 区块大小,以字节为单位
stateRoot 块的状态树根结果
timestamp 时间戳
totalDifficulty 达到该区块的难度总数
transactions 以数组的形式保存交易的tx值
transactionsRoot 交易的默克尔树根
uncles 当前区块引用的叔父区块的哈希值

viii.远程节点管理

之前是单机上的操作,需要和其他节点醉成一个以太坊网络,需要获取其他节点的信息。

查看节点信息:

> admin.nodeInfo
{
  enode: "enode://576e857437aba95e59cfee3570a0fdd0d00dc9c4656ef9e48b47649cdc9b56f86bbf54081a5e38cec85fa150b4b088e22ccd93978e3de0c52aeed6b43471ee79@[::]:30303?discport=0",
  id: "576e857437aba95e59cfee3570a0fdd0d00dc9c4656ef9e48b47649cdc9b56f86bbf54081a5e38cec85fa150b4b088e22ccd93978e3de0c52aeed6b43471ee79",
  ip: "::",
  listenAddr: "[::]:30303",
  name: "Geth/v1.8.14-stable/darwin-amd64/go1.10.3",
  ports: {
    discovery: 0,
    listener: 30303
  },
  protocols: {
    eth: {
      config: {
        chainId: 15,
        eip150Hash: "0x0000000000000000000000000000000000000000000000000000000000000000",
        eip155Block: 0,
        eip158Block: 0,
        homesteadBlock: 0
      },
      difficulty: 264521090,
      genesis: "0xf62ece4906c7cadd848274fc800e0d881f9d296db67c9641121ea5315ec00ca7",
      head: "0xd6a6e5da6ef0c5127363c468570c7f9a679b2d33dc14570ea751b916c0e17087",
      network: 1981
    }
  }
}

添加其他节点:

获取另一个节点的encode的信息,将enode中的[::]替换成节点二的IP地址:

> admin.nodeInfo.enode
"enode://576e857437aba95e59cfee3570a0fdd0d00dc9c4656ef9e48b47649cdc9b56f86bbf54081a5e38cec85fa150b4b088e22ccd93978e3de0c52aeed6b43471ee79@[::]:30303?discport=0"

> admin.addpeer("enode://576e857437aba95e59cfee3570a0fdd0d00dc9c4656ef9e48b47649cdc9b56f86bbf54081a5e38cec85fa150b4b088e22ccd93978e3de0c52aeed6b43471ee79@172.16.15.145:30303")

true

查看远程节点:

> admin.peers

 

-------------------

使用最新版本geth客户,当执行personal.unlockAccount()或在程序中调用personal_unlockAccount接口时,会出现:account unlock with HTTP access is forbidden异常。

异常原因

新版本geth,出于安全考虑,默认禁止了HTTP通道解锁账户,相关issue:https://github.com/ethereum/go-ethereum/pull/17037

解决方案

如果已经了解打开此功能的风险,可通启动命令中添加参数:

--allow-insecure-unlock

来进行打开操作。

示例:

geth --rpc --rpcapi eth,web3,personal --allow-insecure-unlock

 

以太坊测试区块链环境搭建

比特币吸金之道系列文章,由计算机黑客发明的网络货币,无国界,无政府,无中心。没有政府滥发货币,没有通货膨胀。在全球计算机网络中,自由的实现货币兑换和流通。

本系列文章只讲程序和策略,不谈挖矿…

关于作者:

  • 张丹(Conan), 程序员/Quant: Java,R,Nodejs
  • blog: http://blog.fens.me
  • email: [email protected]

转载请注明出处:
http://blog.fens.me/bitcoin-geth-testnet

区块链开发之搭建以太坊私有链_第2张图片

前言

以太坊(ETH)的出现开启了区块链的2.0时代,要进行ETH的开发和测试,我们先要搭建起来ETH的测试区块链网络。在测试环境中,我们可以直接通过参数配置,生成创世区块,设置挖矿难度,设置gas消耗,执行转账交易,定义智能合约等的操作。

目录

  1. 搭建测试区块链
  2. 开发挖矿
  3. 第一笔转账
  4. 多节点网络

1. 搭建测试区块链

由于在以太坊公链上做任何操作,都需要消耗以太币(eth),对于开发者来说,很有必要在本地自行搭建一个测试区块链网络,进行智能合约的开发,最后再将开发好的合约部署到公链上。私有区块链不同于以太坊公链,给我们很多的自由度,直接可能通过参数配置,生成创世区块,设置挖矿难度,设置gas消耗,执行转账交易,定义智能合约等的操作,这些都需要我们手动进行设置。

私有区块链的搭建,也是基于geth客户端来完成的,geth的安装过程,请参考文章 geth以太坊节点安装。

下面,我们就用geth客户端,开始搭建测试区块链。创建测试节点的文件存储目录。


> mkdir /data0/eth-test/
> cd /data0/eth-test/

新建配置文件genesis.json


> vi genesis.json
{
 "nonce": "0x0000000000000042",
 "timestamp": "0x0",
 "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
 "mixhash": "0x0000000000000000000000000000000000000000000000000000000000000000",
 "extraData": "0x",
 "gasLimit": "0x80000000",
 "difficulty": "0x3",
 "coinbase": "0x3333333333333333333333333333333333333333",
 "config":{
    "chainId": 55,
    "homesteadBlock": 0,
    "eip155Block": 0
 },
 "alloc": {}
}

参数设置:

  • nonce:64位随机数,用于挖矿
  • timestamp:创世块的时间戳
  • parentHash:上一个区块的hash值,因为是创世块,所以这个值是0
  • mixhash:与 nonce 配合用于挖矿,由上一个区块的一部分生成的 hash。
  • extraData:附加信息,任意填写
  • gasLimit :对GAS的消耗总量限制,用来限制区块能包含的交易信息总和,因为我们就测试链,所以随意填写。
  • difficulty:难度值,越大越难
  • coinbase:矿工账号,第一个区块挖出后将给这个矿工账号发送奖励的以太币。
  • alloc: 预设账号以及账号的以太币数量,测试链挖矿比较容易可以不配置
  • chainId 指定了独立的区块链网络 ID,不同 ID 网络的节点无法互相连接。

初始化区块链,生成创世区块和初始状态。


> geth --datadir=/data0/eth-test init /data0/eth-test/genesis.json
INFO [06-26|08:10:32.943749] Maximum peer count                       ETH=25 LES=0 total=25
INFO [06-26|08:10:32.944172] Allocated cache and file handles         database=/data0/eth-test/geth/chaindata cache=16 handles=16
INFO [06-26|08:10:32.989586] Persisted trie from memory database      nodes=0 size=0.00B time=3.877µs gcnodes=0 gcsize=0.00B gctime=0s livenodes=1 livesize=0.00B
INFO [06-26|08:10:32.989983] Successfully wrote genesis state         database=chaindata                      hash=4a306e…543a63
INFO [06-26|08:10:32.990028] Allocated cache and file handles         database=/data0/eth-test/geth/lightchaindata cache=16 handles=16
INFO [06-26|08:10:33.036685] Persisted trie from memory database      nodes=0 size=0.00B time=3.258µs gcnodes=0 gcsize=0.00B gctime=0s livenodes=1 livesize=0.00B
INFO [06-26|08:10:33.037027] Successfully wrote genesis state         database=lightchaindata                      hash=4a306e…543a63

运行日志,包括了允许最大点对点连接当前节点数为total=25,普通节点连接数ETH=25,LES轻节点连接数0。数据库存储的目录在 /data0/eth-test/geth/chaindata ,当前存活的节点 livenodes=1。

参数说明

  • datadir, 设置当前区块链网络数据存放的位置
  • init,初始化,生成创世区块

接下来,启动测试节点,并进入 geth 命令行界面。


> geth --identity "TestNode" --rpc --rpcport "8545" --datadir=/data0/eth-test --port "30303" --nodiscover console
INFO [06-26|08:14:00.916738] Maximum peer count                       ETH=25 LES=0 total=25
INFO [06-26|08:14:00.918148] Starting peer-to-peer node               instance=Geth/TestNode/v1.8.12-unstable-f1986f86/linux-amd64/go1.10.3
INFO [06-26|08:14:00.918235] Allocated cache and file handles         database=/data0/eth-test/geth/chaindata cache=768 handles=512
INFO [06-26|08:14:00.979836] Initialised chain configuration          config="{ChainID: 55 Homestead: 0 DAO:  DAOSupport: false EIP150:  EIP155: 0 EIP158:  Byzantium:  Constantinople:  Engine: unknown}"
INFO [06-26|08:14:00.979915] Disk storage enabled for ethash caches   dir=/data0/eth-test/geth/ethash count=3
INFO [06-26|08:14:00.979943] Disk storage enabled for ethash DAGs     dir=/root/.ethash               count=2
INFO [06-26|08:14:00.980023] Initialising Ethereum protocol           versions="[63 62]" network=1
INFO [06-26|08:14:00.980566] Loaded most recent local header          number=0 hash=4a306e…543a63 td=3
INFO [06-26|08:14:00.980634] Loaded most recent local full block      number=0 hash=4a306e…543a63 td=3
INFO [06-26|08:14:00.980662] Loaded most recent local fast block      number=0 hash=4a306e…543a63 td=3
INFO [06-26|08:14:00.980842] Regenerated local transaction journal    transactions=0 accounts=0
INFO [06-26|08:14:00.981818] Starting P2P networking 
INFO [06-26|08:14:00.982303] RLPx listener up                         self="enode://15653a443e91b04040fe2731e0a0fa556a1d050580fa587110b17460cf471a8c3b42ac08dbc3d84a404f8c102ae35b28d9e2c1b9f2eae4c828a0dfa21c1f2117@[::]:30303?discport=0"
INFO [06-26|08:14:00.985029] IPC endpoint opened                      url=/data0/eth-test/geth.ipc
INFO [06-26|08:14:00.985503] HTTP endpoint opened                     url=http://127.0.0.1:8545    cors= vhosts=localhost
Welcome to the Geth JavaScript console!

instance: Geth/TestNode/v1.8.12-unstable-f1986f86/linux-amd64/go1.10.3
 modules: admin:1.0 debug:1.0 eth:1.0 miner:1.0 net:1.0 personal:1.0 rpc:1.0 txpool:1.0 web3:1.0

> 
  • identity, 自定义的节点名字
  • rpc , 允许 HTTP-RPC 访问
  • rpcport , HTTP_RPC的访问端口,默认为8545
  • port , 网络监听端口,默认为30303
  • datadir, 设置当前区块链网络数据存放的位置
  • console, 启动命令行模式,可以在Geth中执行命令
  • nodiscover, 私有链地址,不会被网上看到

这样我们就把一个测试网络启动起来了,由于是单节点,网络没有其他的节点,所以并没有直接的数据输出。

2. 开始挖矿

接下来,我们在自己搭建的私有网络中,开始做常规ETH的操作。

2.1 创建账号

创建一个新账号,密码为123456,账号的地址为:0x9cac40f650e2cbe459dcb32c7c23103497134467。


> personal.newAccount("123456")
"0x9cac40f650e2cbe459dcb32c7c23103497134467"

另一种方式,生成一个新账号。


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

查看所有账号


> eth.accounts
["0x9cac40f650e2cbe459dcb32c7c23103497134467", "0x762a2e28c5dbab9cd31369db5f3cbb48f421c0e3"]

2.2 挖矿

接下来,我们开始挖矿。挖矿,就是产生以太币的过程。之前在genesis.json文件中,设置的difficulty=3,挖矿难比较低,很快就是挖出以太币来。


# 开始挖矿
> miner.start(1)
INFO [06-26|08:19:58.086688] Updated mining threads                   threads=1
INFO [06-26|08:19:58.086828] Transaction pool price threshold updated price=18000000000

# 矿工账号:如果有多个账户的情况下,挖矿获得的eth,会自动计入第一账户中。
INFO [06-26|08:19:58.086887] Etherbase automatically configured       address=0x9cac40F650E2CBE459dcb32c7c23103497134467   
INFO [06-26|08:19:58.087015] Starting mining operation 

# 开始探索新区块,没有交易内容
INFO [06-26|08:19:58.087793] Commit new mining work                   number=1 txs=0 uncles=0 elapsed=659.441µs            

# 成功发现新区块
INFO [06-26|08:19:58.451612] Successfully sealed new block            number=1 hash=c120d3…23dad2                          

#  确认挖到新区块
INFO [06-26|08:19:58.452182]  mined potential block                  number=1 hash=c120d3…23dad2                      
INFO [06-26|08:19:58.45237] Commit new mining work                   number=2 txs=0 uncles=0 elapsed=165.519µs
INFO [06-26|08:20:00.683558] Successfully sealed new block            number=2 hash=011b1c…100594
INFO [06-26|08:20:00.68399]  mined potential block                  number=2 hash=011b1c…100594
INFO [06-26|08:20:00.684181] Commit new mining work                   number=3 txs=0 uncles=0 elapsed=111.601µs
INFO [06-26|08:20:09.965339] Successfully sealed new block            number=3 hash=173ea5…c059ef
INFO [06-26|08:20:09.965789]  mined potential block                  number=3 hash=173ea5…c059ef
INFO [06-26|08:20:09.966091] Commit new mining work                   number=4 txs=0 uncles=0 elapsed=246.371µs
INFO [06-26|08:20:11.622999] Successfully sealed new block            number=4 hash=56240d…0910a3

// 省略

INFO [06-26|08:20:16.264066] Commit new mining work                   number=10 txs=0 uncles=0 elapsed=155.89µs
INFO [06-26|08:20:16.466436] Successfully sealed new block            number=10 hash=819037…fbcd88
INFO [06-26|08:20:16.466774]  block reached canonical chain          number=5  hash=7f1015…f53c57
INFO [06-26|08:20:16.466794]  mined potential block                  number=10 hash=819037…fbcd88
INFO [06-26|08:20:16.466965] Commit new mining work                   number=11 txs=0 uncles=0 elapsed=92.726µs

# 停止挖矿
> miner.stop()
true

开始挖了几秒,就产生了10个区块。查看账户资金为50000000000000000000 wei。第一个账户为矿工账号,第二个账户是一个普通账号。


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

由于Wei是最小的单位,我们把Wei转换为ether为单位,比较好看,就是为 50 ether = 50000000000000000000/10^18


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

转换单位

  • Wei = 10^0 Wei
  • Ada = 10^3 Wei
  • Babbage = 10^6 Wei
  • Shannon = 10^9 Weiv
  • Szabo = 10^12 Wei
  • Finney = 10^15 Wei
  • Ether = 10^18 Wei
  • Einstein = 10^21 Wei
  • Douglas = 10^42 Wei

2.3 查看区块高度

下一步,我们查看一下区块高度,并分析一下区块的细节。


# 查看区块高度
> eth.blockNumber
10

# 查看第10个区块的细节
> eth.getBlock(10)
{
  difficulty: 131648,
  extraData: "0xd88301080c846765746888676f312e31302e33856c696e7578",
  gasLimit: 2126604064,
  gasUsed: 0,
  hash: "0x819037bcc65eb789eca82fcc3d6c686852ab8297df6396cffa6cfffeaffbcd88",
  logsBloom: "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
  miner: "0x9cac40f650e2cbe459dcb32c7c23103497134467",
  mixHash: "0x311cd5ef45d9295d8c1b1b8778fb05b0e49dc6cae5971763c2e2d7e3d20bd895",
  nonce: "0x0b1aae8070cdff77",
  number: 10,
  parentHash: "0x1c5609a70d36a460234b95116fcc391e49890c5082af41d8cba3b5b366aa0028",
  receiptsRoot: "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
  sha3Uncles: "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",
  size: 537,
  stateRoot: "0x0917e990c98b3daf316d0d38a4a2eefd0ad30436bab8ae61adb1ca24723eea81",
  timestamp: 1529972416,
  totalDifficulty: 1313603,
  transactions: [],
  transactionsRoot: "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
  uncles: []
}

第10个区块为当前的最后一个区块,挖矿难度difficulty=131648,没有交易gasUsed=0,当前块的hash值hash: “0x819037bcc65eb789eca82fcc3d6c686852ab8297df6396cffa6cfffeaffbcd88”,,上一个块的地址parentHash: “0x819037bcc65eb789eca82fcc3d6c686852ab8297df6396cffa6cfffeaffbcd88”,矿工账号miner: “0x9cac40f650e2cbe459dcb32c7c23103497134467”,区块高度number=10。

3. 第一笔转账

接下来,让我完成第一笔转账。从矿工账号转账30ether到第二个账号。


> eth.sendTransaction({from:eth.accounts[0],to:eth.accounts[1],value:web3.toWei(30,"ether")})
Error: authentication needed: password or unlock
    at web3.js:3143:20
    at web3.js:6347:15
    at web3.js:5081:36
    at :1:1

第一次,执行转账操作时,出现错误。需要把转输eth的账号进行解锁,才能转账。


# 解锁账号
> personal.unlockAccount(eth.accounts[0])
Unlock account 0x9cac40f650e2cbe459dcb32c7c23103497134467
Passphrase: 
true

# 再次转账
> eth.sendTransaction({from:eth.accounts[0],to:eth.accounts[1],value:web3.toWei(30,"ether")})
INFO [06-26|08:26:44.060461] Submitted transaction                    fullhash=0x8d6d1eb3c1c82be1f419d8f772048644361c41362fd8de27f8252470f975d6bb recipient=0x762A2e28C5DbaB9cD31369DB5f3CBB48f421C0E3
"0x8d6d1eb3c1c82be1f419d8f772048644361c41362fd8de27f8252470f975d6bb"

交易日志,交易的hash值fullhash=0x8d6d1eb3c1c82be1f419d8f772048644361c41362fd8de27f8252470f975d6bb,收款账号recipient=0x762A2e28C5DbaB9cD31369DB5f3CBB48f421C0E3。

我们提交了第一笔的转账,查看2个账户的余额。


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

账户的余额并没有发生变化,这是因为基于区块链的转账操作需要矿工确认才能完成,矿工确认的过程是要经过挖矿的。我们的转账的操作的任务已经提交,但是交易并未完成,还需要矿工挖矿提交新的区块,在区块中加入这次转账交易,提交新的区块全网的节点(按百分比算,具体还没细看源代码)确认完成后,交易才正式生效。

由于链上只有我们自己,我们要重新开起挖矿程序。


# 开始挖矿
> miner.start(1)
INFO [06-26|08:27:24.712255] Updated mining threads                   threads=1
INFO [06-26|08:27:24.712434] Transaction pool price threshold updated price=18000000000
INFO [06-26|08:27:24.712617] Starting mining operation 

# 探索新的区块,包含一个操作信息txs=1
INFO [06-26|08:27:24.713512] Commit new mining work                   number=11 txs=1 uncles=0 elapsed=808.72µs
INFO [06-26|08:27:27.638518] Successfully sealed new block            number=11 hash=68495b…35d4fe
INFO [06-26|08:27:27.638986]  block reached canonical chain          number=6  hash=3617e8…0dd7f5
INFO [06-26|08:27:27.639006]  mined potential block                  number=11 hash=68495b…35d4fe
INFO [06-26|08:27:27.639245] Commit new mining work                   number=12 txs=0 uncles=0 elapsed=227.705µs
INFO [06-26|08:27:28.199602] Successfully sealed new block            number=12 hash=96fd37…37c016
INFO [06-26|08:27:28.199963]  block reached canonical chain          number=7  hash=a8d6d5…e6036d
INFO [06-26|08:27:28.19998]  mined potential block                  number=12 hash=96fd37…37c016
INFO [06-26|08:27:28.200427] Commit new mining work                   number=13 txs=0 uncles=0 elapsed=276.033µs
INFO [06-26|08:27:29.766971] Successfully sealed new block            number=13 hash=a13201…c051c8
INFO [06-26|08:27:29.767429]  block reached canonical chain          number=8  hash=16222d…7a9445
INFO [06-26|08:27:29.767447]  mined potential block                  number=13 hash=a13201…c051c8
INFO [06-26|08:27:29.767572] Commit new mining work                   number=14 txs=0 uncles=0 elapsed=110.439µs
INFO [06-26|08:27:30.302882] Successfully sealed new block            number=14 hash=e1ab15…e44665
INFO [06-26|08:27:30.303213]  block reached canonical chain          number=9  hash=1c5609…aa0028
INFO [06-26|08:27:30.303243]  mined potential block                  number=14 hash=e1ab15…e44665
INFO [06-26|08:27:30.303471] Commit new mining work                   number=15 txs=0 uncles=0 elapsed=114.85µs
INFO [06-26|08:27:35.685475] Successfully sealed new block            number=15 hash=e1b5a4…1bab9e
INFO [06-26|08:27:35.686032]  block reached canonical chain          number=10 hash=819037…fbcd88
INFO [06-26|08:27:35.686146]  mined potential block                  number=15 hash=e1b5a4…1bab9e
INFO [06-26|08:27:35.686523] Commit new mining work                   number=16 txs=0 uncles=0 elapsed=294.263µs

# 停止挖矿
> miner.stop()
true

在高度number=11的区块上,我们发现了有一笔转账信息。再次,查看账户余额,发现账户余额发生了变化。


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

第一个账户变成了 45 ether,第二个账号变成了30 ether。第二个账户余额,正是我们之前设定的转账金额。


# 查看当前块的高度
> eth.blockNumber
15

# 第11个区块的细节
> eth.getBlock(11)
  difficulty: 131072,
  extraData: "0xd88301080c846765746888676f312e31302e33856c696e7578",
  gasLimit: 2124527304,
  gasUsed: 21000,
  hash: "0x68495bf329e886a8043d1af74d145a870ae6aa2d4e42134499b3730e5c35d4fe",
  logsBloom: "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
  miner: "0x9cac40f650e2cbe459dcb32c7c23103497134467",
  mixHash: "0xbbf5053e0409cded11f0c8f1059cad389d366723cb2f6c077d6c71c36d31a254",
  nonce: "0x3cc35610dc92f143",
  number: 11,
  parentHash: "0x819037bcc65eb789eca82fcc3d6c686852ab8297df6396cffa6cfffeaffbcd88",
  receiptsRoot: "0x170861bbc9f17f29b4c8ef046f44fa7435c3ad3a54e752591c87050345c29d31",
  sha3Uncles: "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",
  size: 653,
  stateRoot: "0x6e44fbe836ebf62523a37bbbb1beaad0c0802be9ff5c4e7b19c16a1eb4c50112",
  timestamp: 1529972844,
  totalDifficulty: 1444675,
  transactions: ["0x8d6d1eb3c1c82be1f419d8f772048644361c41362fd8de27f8252470f975d6bb"],
  transactionsRoot: "0x98881bb99ed82df9a69726705fb2ac2d1371e9ba992c52ed3b4cd3ee50762d38",
  uncles: []
}

第11个区块发生了交易,消耗的gas手续费为gasUsed=21000 Wei,交易一共发生1笔transactions=0x8d6d1eb3c1c82be1f419d8f772048644361c41362fd8de27f8252470f975d6bb,矿工账号miner: “0x9cac40f650e2cbe459dcb32c7c23103497134467″。

总结一下,本文介绍了如何搭建以太坊的私有节点,实现了挖矿的过程,并完了2个账户的第一笔转账操作。下一篇文章,找我了解智能合约的编写。

 

 

你可能感兴趣的:(区块链)