搭建以太坊私有链-单机2节点

文章目录

  • 1. 下载和安装Geth
    • 1.1 下载Geth二进制版本
    • 1.2 安装
  • 2. 搭建私有链
    • 2.1 准备私有链数据存放目录
    • 2.2 准备创世区块
    • 2.3 准备第一个私有链节点
    • 2.4 准备第二个私有链节点
  • 3. 启动一个节点的私有链
    • 3.1 启动节点0
    • 3.2 节点0上创建两个账号
    • 3.3 节点0矿工挖矿
    • 3.4 同节点两账户之间转账
  • 4. 启动两个节点的私有链
    • 4.1 启动节点1
    • 4.2 节点1上创建两个账号
    • 4.3 关联两个节点
    • 4.4 跨节点两账户之间转账

本文使用二级制版本Geth在同一台机器上搭建两个节点的以太坊私有链。操作系统环境 :

  • Windows 10

1. 下载和安装Geth

这里参考官方文档 Installation instructions for Windows

1.1 下载Geth二进制版本

  • 下载来源 官方下载地址
  • 使用当前稳定版本 Geth 版本 : Geth – Elasa (v1.9.6)
  • 具体下载地址
    • Windows AMD64

1.2 安装

  1. 直接运行下载得到的安装程序 geth-windows-amd64-1.9.6-bd059680.exe,按照提示一步一步完成安装;
  2. 打开一个命令行窗口,运行 geth version,看到类似如下输出表明安装成功;:
Geth
Version: 1.9.6-stable
Git Commit: bd05968077f27f7eb083404dd8448157996a8788
Git Commit Date: 20191003
Architecture: amd64
Protocol Versions: [63]
Network Id: 1
Go Version: go1.13
Operating System: windows
GOPATH=
GOROOT=C:\go

2. 搭建私有链

这一节我们会在同一台机器上一步一步搭建一个以太坊私有链,包含两个节点 :

  • 节点0: 使用缺省端口 30303
    • 包含两个账户用于测试
  • 节点1: 使用指定端口 30305
    • 包含两个账户用于测试

2.1 准备私有链数据存放目录

在一个磁盘空间宽裕的位置创建一个目录用于保存我们的私有链数据,这里我使用的目录是 D:\ethereum\privatechain(你可以根据自己的实际情况自己命名目录)。

注意 : 下文中我们简称该目录为privatechain

2.2 准备创世区块

进入目录privatechain,创建json文件genesis.json内容如下 :

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

注意这里的 chainId我指定为20191101

2.3 准备第一个私有链节点

  1. 在目录privatechain下创建目录data0用于保存第一个私有链节点的数据。
  2. 初始化第一个私有链节点。
cd privatechain
geth --datadir data0 init genesis.json

控制台输出如下 :

D:\ethereum\privatechain>geth --datadir data0 init genesis.json
INFO [11-01|10:19:21.875] Maximum peer count                       ETH=50 LES=0 total=50
INFO [11-01|10:19:21.938] Allocated cache and file handles         database=D:\\ethereum\\privatechain\\data0\\geth\\chaindata cache=16.00MiB handles=16
INFO [11-01|10:19:22.009] Writing custom genesis block
INFO [11-01|10:19:22.012] Persisted trie from memory database      nodes=0 size=0.00B time=0s gcnodes=0 gcsize=0.00B gctime=0s livenodes=1 livesize=0.00B
INFO [11-01|10:19:22.019] Successfully wrote genesis state         database=chaindata hash=5e1fc7…d790e0
INFO [11-01|10:19:22.024] Allocated cache and file handles         database=D:\\ethereum\\privatechain\\data0\\geth\\lightchaindata cache=16.00MiB handles=16
INFO [11-01|10:19:22.101] Writing custom genesis block
INFO [11-01|10:19:22.106] Persisted trie from memory database      nodes=0 size=0.00B time=0s gcnodes=0 gcsize=0.00B gctime=0s livenodes=1 livesize=0.00B
INFO [11-01|10:19:22.118] Successfully wrote genesis state         database=lightchaindata hash=5e1fc7…d790e0

看到控制台输出中的Successfully wrote genesis state表明节点0初始化成功。

现在观察data0目录结构,会发现它已经不再是空目录了,现在它的结构看起来如下所示 :

D:.
│  genesis.json
│
├─data0
│  ├─geth
│  │  ├─chaindata
│  │  │      000001.log
│  │  │      CURRENT
│  │  │      LOCK
│  │  │      LOG
│  │  │      MANIFEST-000000
│  │  │
│  │  └─lightchaindata
│  │          000001.log
│  │          CURRENT
│  │          LOCK
│  │          LOG
│  │          MANIFEST-000000
│  │
│  └─keystore

2.4 准备第二个私有链节点

  1. 在目录privatechain下创建目录data1用于保存第一个私有链节点的数据。
  2. 初始化第一个私有链节点。
cd privatechain
geth --datadir data1 init genesis.json

这里需要注意的是节点1和节点0数据的初始化使用了同一个创世区块,其目的是这样它们才能组成同一个私有链。

控制台输出如下 :

INFO [11-01|10:24:38.928] Maximum peer count                       ETH=50 LES=0 total=50
INFO [11-01|10:24:38.993] Allocated cache and file handles         database=D:\\ethereum\\privatechain\\data1\\geth\\chaindata cache=16.00MiB handles=16
INFO [11-01|10:24:39.084] Writing custom genesis block
INFO [11-01|10:24:39.088] Persisted trie from memory database      nodes=0 size=0.00B time=0s gcnodes=0 gcsize=0.00B gctime=0s livenodes=1 livesize=0.00B
INFO [11-01|10:24:39.101] Successfully wrote genesis state         database=chaindata hash=5e1fc7…d790e0
INFO [11-01|10:24:39.111] Allocated cache and file handles         database=D:\\ethereum\\privatechain\\data1\\geth\\lightchaindata cache=16.00MiB handles=16
INFO [11-01|10:24:39.194] Writing custom genesis block
INFO [11-01|10:24:39.204] Persisted trie from memory database      nodes=0 size=0.00B time=0s gcnodes=0 gcsize=0.00B gctime=0s livenodes=1 livesize=0.00B
INFO [11-01|10:24:39.242] Successfully wrote genesis state         database=lightchaindata hash=5e1fc7…d790e0

同样,看到控制台输出中的Successfully wrote genesis state表明节点1初始化成功。
现在data0目录和data1目录都不再是空目录了,现在其结构如下 :

├─data0
│  ├─geth
│  │  ├─chaindata
│  │  │      000001.log
│  │  │      CURRENT
│  │  │      LOCK
│  │  │      LOG
│  │  │      MANIFEST-000000
│  │  │
│  │  └─lightchaindata
│  │          000001.log
│  │          CURRENT
│  │          LOCK
│  │          LOG
│  │          MANIFEST-000000
│  │
│  └─keystore
└─data1
    ├─geth
    │  ├─chaindata
    │  │      000001.log
    │  │      CURRENT
    │  │      LOCK
    │  │      LOG
    │  │      MANIFEST-000000
    │  │
    │  └─lightchaindata
    │          000001.log
    │          CURRENT
    │          LOCK
    │          LOG
    │          MANIFEST-000000
    │
    └─keystore

现在同一台机器上的两个私有链节点的目录和数据我们已经初始化完成了,现在可以启动私有链了。不过接下来我们要做一些观察和验证,所以两个节点一个一个启动并顺带完成我们的任务 :

  1. 在同一个私有链节点上的两个账户之间转账
  2. 在两个位于不同的私有链节点上账户之间转账

3. 启动一个节点的私有链

本节我们将仅仅启动包含一个节点的私有链,创建两个账户,并在它们之间做转账。

3.1 启动节点0

cd privatechain
geth --datadir data0 --networkid 20191101 console

注意以上参数中:

  • console表明要进入交互式控制台;
  • --datadir data0 表明要启动是节点0;
  • --networkid 20191101表明这个私有网络的网络id是20191101;
    (网络 id 在连接其他节点时会用到,以太坊公网网络 id 为 1,为了避免与公有链网络冲突,私有链节点启动时要指定自己的网络 id)

控制台输出如下:

INFO [11-01|10:35:37.351] Maximum peer count                       ETH=50 LES=0 total=50
INFO [11-01|10:35:37.417] Starting peer-to-peer node               instance=Geth/v1.9.6-stable-bd059680/windows-amd64/go1.13
INFO [11-01|10:35:37.421] Allocated trie memory caches             clean=256.00MiB dirty=256.00MiB
INFO [11-01|10:35:37.425] Allocated cache and file handles         database=D:\\ethereum\\privatechain\\data0\\geth\\chaindata cache=512.00MiB handles=8192
INFO [11-01|10:35:37.743] Opened ancient database                  database=D:\\ethereum\\privatechain\\data0\\geth\\chaindata\\ancient
INFO [11-01|10:35:37.768] Initialised chain configuration          config="{ChainID: 20191101 Homestead: 0 DAO:  DAOSupport: false EIP150:  EIP155: 0 EIP158: 0 Byzantium:  Constantinople:  Petersburg:  Istanbul:  Engine: unknown}"
INFO [11-01|10:35:37.814] Disk storage enabled for ethash caches   dir=D:\\ethereum\\privatechain\\data0\\geth\\ethash count=3
INFO [11-01|10:35:37.839] Disk storage enabled for ethash DAGs     dir=C:\\Users\\andy_\\AppData\\Local\\Ethash count=2
INFO [11-01|10:35:37.862] Initialising Ethereum protocol           versions=[63] network=20191101 dbversion=<nil>
WARN [11-01|10:35:37.873] Upgrade blockchain database version      from=<nil> to=7
INFO [11-01|10:35:37.955] Loaded most recent local header          number=0 hash=5e1fc7…d790e0 td=131072 age=50y6mo3w
INFO [11-01|10:35:37.961] Loaded most recent local full block      number=0 hash=5e1fc7…d790e0 td=131072 age=50y6mo3w
INFO [11-01|10:35:37.967] Loaded most recent local fast block      number=0 hash=5e1fc7…d790e0 td=131072 age=50y6mo3w
INFO [11-01|10:35:37.973] Regenerated local transaction journal    transactions=0 accounts=0
INFO [11-01|10:35:38.016] Allocated fast sync bloom                size=512.00MiB
INFO [11-01|10:35:38.021] Initialized fast sync bloom              items=0 errorrate=0.000 elapsed=0s
INFO [11-01|10:35:38.078] New local node record                    seq=1 id=5f41aa2d19202b7a ip=127.0.0.1 udp=30303 tcp=30303
INFO [11-01|10:35:38.085] Started P2P networking                   self=enode://c05ffa7d768dce4c2b4e3c19ca297b3e567b1f52df2e70e84ba1ffe7dd9673345a88027f266a1277bcc7f30286436dd4f02476246b07cf166040e67b64f8a2ac@127.0.0.1:30303
INFO [11-01|10:35:38.087] IPC endpoint opened                      url=\\\\.\\pipe\\geth.ipc
WARN [11-01|10:35:38.178] Served eth_coinbase                      reqid=3 t=0s err="etherbase must be explicitly specified"
Welcome to the Geth JavaScript console!

instance: Geth/v1.9.6-stable-bd059680/windows-amd64/go1.13
at block: 0 (Thu, 01 Jan 1970 08:00:00 CST)
 datadir: D:\ethereum\privatechain\data0
 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

>

这里我们看到了字样Welcome to the Geth JavaScript console!,这说明节点0启动成功了。此时你可以认为一个以太坊私有链网络也已经启动了,只不过它只包含了一个节点,也就是我们所准备的节点0。

现在我们通过控制台在节点0上做一些观察和验证操作。

Geth JavaScript console控制台提供了如下几种管理对象 :
eth:区块链相关操作
net:查看 P2P 网络状态
admin:管理节点
miner:启动 & 停止挖矿
personal:管理账户
txpool:查看交易内存池
web3:单位换算等

3.2 节点0上创建两个账号

  1. 首先,我们新建的私有链上应该是没有账户的;
    通过如下命令可以验证 :

    > eth.accounts
    []
    
  2. 接下来,我们创建第一个账户;

    > personal.newAccount()
    

    控制台交互输出如下 :

    Password:
    Repeat password:
    INFO [11-01|10:50:25.858] Your new key was generated               address=0x0C5Ae7c2520b1208d579bCF8b2bF624EdD7a025c
    WARN [11-01|10:50:25.862] Please backup your key file!             path=D:\\ethereum\\privatechain\\data0\\keystore\\UTC--2019-11-01T02-50-24.454154200Z--0c5ae7c2520b1208d579bcf8b2bf624edd7a025c
    WARN [11-01|10:50:25.870] Please remember your password!
    "0x0c5ae7c2520b1208d579bcf8b2bf624edd7a025c"
    

    从上面的输出可见,我们创建的账号是 : 0x0c5ae7c2520b1208d579bcf8b2bf624edd7a025c,密钥文件保存在文件D:\\ethereum\\privatechain\\data0\\keystore\\UTC--2019-11-01T02-50-24.454154200Z--0c5ae7c2520b1208d579bcf8b2bf624edd7a025c

    为了方便起见,本文中所创建的以太坊私有链账户的密码统一使用password

    此时再通过eth.accounts查看账户列表,结果输出如下 :

    > eth.accounts
    ["0x0c5ae7c2520b1208d579bcf8b2bf624edd7a025c"]
    
  3. 接下来,我们创建第二个账户;
    这里创建第二个账户,使用的方法跟创建第一个账户是相同的,使用personal.newAccount(),这里不再重复。第二个账号创建完成之后,我们再看账户列表,输出如下 :

    > eth.accounts
    ["0x0c5ae7c2520b1208d579bcf8b2bf624edd7a025c", "0xfb66cc211031fe8ae48acfed7a199d8d9038d978"]
    

这里所创建的第二个账号是0xfb66cc211031fe8ae48acfed7a199d8d9038d978

  1. 接下来,我们查看两个账户的余额;

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

    查询账户余额使用的方法是eth.getBalance()

    很显然,因为是新账户,所以其余额都是 0。要使账户有余额,可以从其他账户转账过来,或者通过挖矿来获取奖励。我们目前是只有一个节点的新建私有链,所有账户都没有余额,所以要想账户中有余额,只能通过挖矿获取奖励。

3.3 节点0矿工挖矿

通过 miner.start () 来启动挖矿:
js miner.start()

第一次启动挖矿会先生成挖矿所需的 DAG 文件,这个过程有点慢,等进度达到 100% 后,就会开始挖矿,此时控制台会不断输出挖矿信息。该命令控制台输出大致如下 :

> miner.start()
INFO [11-01|11:07:01.068] Updated mining threads                   threads=8
INFO [11-01|11:07:01.071] Transaction pool price threshold updated price=1000000000
INFO [11-01|11:07:01.074] Etherbase automatically configured       address=0x0C5Ae7c2520b1208d579bCF8b2bF624EdD7a025c
null
> INFO [11-01|11:07:01.093] Commit new mining work                   number=1 sealhash=a65bf2…04103e uncles=0 txs=0 gas=0 fees=0 elapsed=13.151ms
INFO [11-01|11:07:02.301] Generating DAG in progress               epoch=0 percentage=0 elapsed=656.222ms
INFO [11-01|11:07:03.041] Generating DAG in progress               epoch=0 percentage=1 elapsed=1.396s
// 这里为了便于阅读,删除了部分 DAG 生成过程的输出 ... 
INFO [11-01|11:08:11.552] Generating DAG in progress               epoch=0 percentage=99 elapsed=1m9.906s
INFO [11-01|11:08:11.559] Generated ethash verification cache      epoch=0 elapsed=1m9.913s
INFO [11-01|11:08:27.440] Successfully sealed new block            number=1 sealhash=a65bf2…04103e hash=d2cf12…d3024c elapsed=1m26.359s
INFO [11-01|11:08:27.463]  mined potential block                  number=1 hash=d2cf12…d3024c
INFO [11-01|11:08:27.473] Commit new mining work                   number=2 sealhash=4f491d…d28143 uncles=0 txs=0 gas=0 fees=0 elapsed=9.973ms
INFO [11-01|11:08:27.605] Successfully sealed new block            number=2 sealhash=4f491d…d28143 hash=3e79ae7edb93 elapsed=142.618ms
INFO [11-01|11:08:27.610]  mined potential block                  number=2 hash=3e79ae7edb93
INFO [11-01|11:08:27.624] Commit new mining work                   number=3 sealhash=3c173164c50f uncles=0 txs=0 gas=0 fees=0 elapsed=13.962ms
INFO [11-01|11:08:27.848] Successfully sealed new block            number=3 sealhash=3c173164c50f hash=22caae…fca7f8 elapsed=237.366ms
INFO [11-01|11:08:27.853]  mined potential block                  number=3 hash=22caae…fca7f8
INFO [11-01|11:08:27.853] Mining too far in the future             wait=2s
INFO [11-01|11:08:29.862] Commit new mining work                   number=4 sealhash=a5a106…024c01 uncles=0 txs=0 gas=0 fees=0 elapsed=2.009s
INFO [11-01|11:08:29.871] Successfully sealed new block            number=4 sealhash=a5a106…024c01 hash=0cc77b4a363b elapsed=8.956ms

一旦开始挖矿,可以通过在控制台输入miner.stop()停止挖矿。这里需要注意的是,因为该命令输入时,挖矿正在进行,所以该命令的显示会不断被挖矿输出打扰。不过不用担心,只要确保正确输入该命令并回车即可停止挖矿。

挖矿运行一段时间之后,我们停止挖矿,来看看挖矿的效果。

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

> eth.coinbase
"0x0c5ae7c2520b1208d579bcf8b2bf624edd7a025c" // 这里显示是我们上面所创建的第一个账户

矿工账户默认是本节点账户的第一个,但是也可以设置为其他的某个账户,相应命令miner.setEtherbase

现在我们看看矿工账户,也就是第一个账户的余额情况 :

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

由此可见,经过一段时间的挖矿,矿工账号的余额已经不再是0了,相应的挖矿奖励已经进入到了该账户中。不过eth.getBalance()方法返回的单位是wei,而不是以太币(ether),我们通过单位换算方法看看矿工到底获得了多少奖励:

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

注意 : wei/ether之间的换算关系 : 1 ether = 10的18次方 个 wei

3.4 同节点两账户之间转账

现在第一个账户作为矿工账户得到了以太币奖励,而第二个账户余额还是为0。现在我们观察一个从账户0到账户1的转账动作。
转账之前,我们需要解锁转出账户,在我们这里例子里面,就是解锁第一个账户(索引为0),否则转账会失败 :

> personal.unlockAccount(eth.accounts[0]) // 解锁账户命令行
Unlock account 0x0c5ae7c2520b1208d579bcf8b2bf624edd7a025c
Password:  // 这里输入该账户的密码
true // true 表示解锁成功
>

现在执行转账 : 账户0 转账到 账户1 10 个 ether

> amount = web3.toWei(10,'ether') // 定义一个变量 amount表示将要转账的金额:10 ether
"10000000000000000000"
> eth.sendTransaction({from:eth.accounts[0],to:eth.accounts[1],value:amount}) // 发起转账
INFO [11-01|11:32:35.037] Setting new local account                address=0x0C5Ae7c2520b1208d579bCF8b2bF624EdD7a025c
INFO [11-01|11:32:35.041] Submitted transaction                    fullhash=0x7a9c536af0c8cc28219d378396a66f4e420b690dac8d28c70513bb3168714f7d recipient=0xFb66cc211031fE8AE48AcfED7a199D8d9038D978
"0x7a9c536af0c8cc28219d378396a66f4e420b690dac8d28c70513bb3168714f7d"
>

现在我们看账户1里面的余额:

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

居然还是0。看起来上面的转账并未成功。确实是这样,因为此交易已经被提交到了区块链,但是因为没有矿工在工作,所以此交易并未被处理,所以转账尚未完成。现在,我们通过txpool验证一下这个情况:

> txpool.status
{
  pending: 1, // 一个交易处于悬挂状态
  queued: 0
}

接下来我们启动矿工挖矿,让这个交易被处理:

> miner.start(1);admin.sleepBlocks(1);miner.stop(); // 使用一个线程启动挖矿,在一个区块被挖到后停止挖矿
INFO [11-01|11:47:32.582] Updated mining threads                   threads=1
INFO [11-01|11:47:32.601] Transaction pool price threshold updated price=1000000000
INFO [11-01|11:47:32.616] Commit new mining work                   number=117 sealhash=b14634…97d03c uncles=0 txs=0 gas=0 fees=0 elapsed=0s
INFO [11-01|11:47:32.633] Commit new mining work                   number=117 sealhash=d3be56…a329d7 uncles=0 txs=1 gas=21000 fees=2.1e-05 elapsed=16.955ms
INFO [11-01|11:47:33.310] Successfully sealed new block            number=117 sealhash=d3be56…a329d7 hash=5f2525…c3ecc7 elapsed=677.208ms
INFO [11-01|11:47:33.317]  block reached canonical chain          number=110 hash=1ca8a958784c
INFO [11-01|11:47:33.323]  mined potential block                  number=117 hash=5f2525…c3ecc7
INFO [11-01|11:47:33.328] Commit new mining work                   number=118 sealhash=701c7e…d51321 uncles=0 txs=0 gas=0     fees=0       elapsed=10.953ms
null

现在我们再来看当前的各种状态 :

> txpool.status
{
  pending: 0, // 这里表明上面提交的交易已经完成
  queued: 0
}
> web3.fromWei(eth.getBalance(eth.accounts[1]),'ether')
10 // 这里表明提交的转账交易已经完成,收款方已经收到10个ether
> web3.fromWei(eth.getBalance(eth.accounts[0]),'ether')
575 // 转出方10个ether已经扣除,不过作为矿工,又被刚才的挖矿动作奖励了5个ether
> eth.blockNumber
117 // 每个区块奖励5ether,117对应585个either,账户0575个,账户110

到此为止,我们在同一个私有链节点内转账有关的观察任务就算是完成了。接下来,我们看两个节点的私有链的情况。

4. 启动两个节点的私有链

目前我们已经有了一个私有链,包含一个启动的节点,也就是上面使用的节点:节点0。
现在我们打开一个新的命令行来启动我们最开始所准备的第二个节点:节点1。

4.1 启动节点1

因为节点0已经使用了默认端口30303,所以第二个节点我们使用了一个不一样的端口30305

geth --datadir data1 --networkid 20191101 console --port 30305 --ipcdisable

4.2 节点1上创建两个账号

类似地,我们在节点1上创建两个账号,如下 :

> eth.accounts
["0x717f9c974a3fe520cd6c258fa87b14eccb07a74c", "0xf91a6b107291a4271a2196562dd31dcb33c30119"]

到目前为止,我们有了一个如下的一个私有链 :

  • 两个节点
    • 第一个节点 : 节点0 => data0
    • 第二个节点 : 节点1 => data1
    • 两个节点目前尚未协同
  • 四个账号
    • 节点0上两个账号
      • 第一个账号 : 账号 0 => 0x0c5ae7c2520b1208d579bcf8b2bf624edd7a025c (矿工账号)
        • 当前余额 : 575 ether
      • 第二个账号 : 账号 1 => 0xfb66cc211031fe8ae48acfed7a199d8d9038d978
        • 当前余额 : 10 ether
    • 节点1上两个账号
      • 第一个账号 : 账号 0 => 0x717f9c974a3fe520cd6c258fa87b14eccb07a74c (矿工账号)
        • 当前余额 : 0 ether
      • 第二个账号 : 账号 1 => 0xf91a6b107291a4271a2196562dd31dcb33c30119
        • 当前余额 : 0 ether

4.3 关联两个节点

在第一个节点中查看自己的节点信息 :

> admin.nodeInfo.enode
"enode://c05ffa7d768dce4c2b4e3c19ca297b3e567b1f52df2e70e84ba1ffe7dd9673345a88027f266a1277bcc7f30286436dd4f02476246b07cf166040e67b64f8a2ac@127.0.0.1:30303"

在第二个节点上将第一个节点添加为自己的对等节点:

> admin.addPeer("enode://c05ffa7d768dce4c2b4e3c19ca297b3e567b1f52df2e70e84ba1ffe7dd9673345a88027f266a1277bcc7f30286436dd4f02476246b07cf166040e67b64f8a2ac@127.0.0.1:30303")
true
> admin.peers
[{
    caps: ["eth/63"],
    enode: "enode://c05ffa7d768dce4c2b4e3c19ca297b3e567b1f52df2e70e84ba1ffe7dd9673345a88027f266a1277bcc7f30286436dd4f02476246b07cf166040e67b64f8a2ac@127.0.0.1:30303",
    id: "5f41aa2d19202b7a296edcaa2e20df52c9713bbabf58149461d44817e635e32a",
    name: "Geth/v1.9.6-stable-bd059680/windows-amd64/go1.13",
    network: {
      inbound: false,
      localAddress: "127.0.0.1:61622",
      remoteAddress: "127.0.0.1:30303",
      static: true,
      trusted: false
    },
    protocols: {
      eth: {
        difficulty: 15891698,
        head: "0x5f2525d836d9a5a7f37c9815cbae8906f1604b573d25742d81e41067c4c3ecc7",
        version: 63
      }
    }
}]
>

通过上面输出我们可以看到,两个节点已经同一个私有链上互通了。

4.4 跨节点两账户之间转账

现在我们尝试从节点0上的账号1向节点1上的账号1转账8 ether,并且该任务让节点1上的矿工完成 。

首先,从节点0上发起转账 :

> amount8 = web3.toWei(8,'ether')
"8000000000000000000"
> eth.getBalance("0xfb66cc211031fe8ae48acfed7a199d8d9038d978") // 节点0账号1转帐前余额
10000000000000000000
> eth.getBalance("0xf91a6b107291a4271a2196562dd31dcb33c30119")  // 节点1账号1转帐前余额
0
> eth.sendTransaction({from:"0xfb66cc211031fe8ae48acfed7a199d8d9038d978",to:"0xf91a6b107291a4271a2196562dd31dcb33c30119",value:amount8}) // 发起转账
INFO [11-01|15:04:50.782] Setting new local account                address=0xFb66cc211031fE8AE48AcfED7a199D8d9038D978
INFO [11-01|15:04:50.786] Submitted transaction                    fullhash=0x140784348c1baeb00d4c7b622d17884e21a56c2b4337d2bc1a93140e2e13fe44 recipient=0xF91A6B107291a4271a2196562DD31Dcb33C30119
"0x140784348c1baeb00d4c7b622d17884e21a56c2b4337d2bc1a93140e2e13fe44"
> txpool.status
{
  pending: 1,
  queued: 0
}

接下来,我们从节点1上开启挖矿 :

> miner.start(1);admin.sleepBlocks(1);miner.stop(); // 使用一个线程启动挖矿,在一个区块被挖到后停止挖矿
INFO [11-01|15:06:17.236] Updated mining threads                   threads=1
INFO [11-01|15:06:17.239] Transaction pool price threshold updated price=1000000000
INFO [11-01|15:06:17.242]  block lost                             number=1   hash=988aff3518ae
INFO [11-01|15:06:17.247] Commit new mining work                   number=118 sealhash=147484…a20630 uncles=0 txs=0 gas=0 fees=0 elapsed=4.985ms
INFO [11-01|15:06:17.254] Commit new mining work                   number=118 sealhash=46f768…ef2f47 uncles=0 txs=1 gas=21000 fees=2.1e-05 elapsed=11.967ms
INFO [11-01|15:06:25.744] Successfully sealed new block            number=118 sealhash=46f768…ef2f47 hash=1176cd765bd8 elapsed=8.490s
INFO [11-01|15:06:25.751]  mined potential block                  number=118 hash=1176cd765bd8
INFO [11-01|15:06:25.756] Commit new mining work                   number=119 sealhash=b50c09…2e3e35 uncles=0 txs=0 gas=0     fees=0       elapsed=4.987ms
null
>

然后,我们再从节点1控制台上观察相关账号的余额:

> web3.fromWei(eth.getBalance("0xfb66cc211031fe8ae48acfed7a199d8d9038d978"),'ether') // 节点0账号1转帐后余额
1.999979
> web3.fromWei(eth.getBalance("0xf91a6b107291a4271a2196562dd31dcb33c30119"),'ether')  // 节点1账号1转帐后余额
8
>web3.fromWei(eth.getBalance("0x717f9c974a3fe520cd6c258fa87b14eccb07a74c"),'ether')  // 节点1账号0挖矿后余额
5.000021

这里,我们梳理一下转账过程中的要点信息 :

  1. 节点0账号1发起对节点1账号1的转账,金额是8个以太币;
  2. 节点1充当矿工执行了这笔转账交易形成了一个区块;
    1. 交易对矿工的奖励费用是0.000021个以太币;
    2. 矿工挖矿产生一个区块得到网络奖励5个以太币;
  3. 节点1使用账号0作为矿工账户;

然后基于此,转账成功后,最终结果是 :

  1. 节点0账号1余额为 : 1.999979 以太币 = 转帐前余额 10 以太币 - 转账金额 8 以太币 - 转账费用 0.000021 以太币;
  2. 节点1账号1余额为 : 8以太币 = 外部转入金额;
  3. 节点1账号0余额为 : 5.000021 以太币 = 网络奖励金额 5 以太币 + 转账费用 0.000021 以太币;

从上面节点0上的账号1向节点1上的账号1之间的转账命令来看,和同一节点上两个账户直接的转账并无不同。以上内容将同节点账户转账和跨节点账户之间转账分开的目的只是为了逐步深入熟悉以太坊私有链的工作模式。

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