同步Ethereum全节点有感

>![](https://upload-images.jianshu.io/upload_images/47789-119525903c010574.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

**本人在18年的6月份用[Geth](https://github.com/ethereum/go-ethereum)同步过全节点**。当时想把区块链数据用异构的方式查询， 比如提供 Sql 、GraphQL访问，而不在通过rpc接口访问数据。
而首要工作是把全节点数据放入到数据仓库中，那就要先从同步全节点的任务开始。

> ![类似 ocap.arcblock.io](https://upload-images.jianshu.io/upload_images/47789-fdffd39e3b37f64d.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
 
### 服务器配置
当时云主机选择的是阿里云香港，操作系统是Ubuntu，8G内存，主流CPU，30G系统盘，外挂1T高效硬盘，带宽2M。 这是最低的基本硬件配置，再低，同步速度就太慢了。

### 获得Geth
https://ethereum.github.io/go-ethereum/downloads/，选择Stable Linux 64bit版本，**记得校验Checksum**，防止软件被篡改。

> ![Geth ](https://upload-images.jianshu.io/upload_images/47789-93e95faa38efddd5.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

```shell
# 下载
wget https://gethstore.blob.core.windows.net/builds/geth-linux-amd64-1.8.23-c9427004.tar.gz 
```

```
md5sum geth-linux-amd64-1.8.23-c9427004.tar.gz # 校验
# => a3b2dd950bc986036be4ff66efec36f9 
# 与上文提供的Checksum比较，如果一致说明文件没有被篡改

tar -xzf geth-linux-amd64-1.8.23-c9427004.tar.gz # 解压

mv geth-linux-amd64-1.8.23-c9427004/geth /usr/bin/ # 移动 放到全局环境变量中

which  geth # 查看位置
```

如果想通过手动编译的方式，请移步 https://www.jianshu.com/p/65ae648b97ae

### 同步方式

Geth 有3种同步方式：full，fast，light，默认是fast模式。

```
geth -h | grep sync
# --syncmode fast    Blockchain sync mode ("fast", "full", or "light")
```

>Full
同步完整的区块信息，获取所有历史区块的header、body数据，
从创始块开始校验每一个元素，并顺序执行其中的所有交易，验证区块头中的 stateRoot、transactionRoot 和 receiptRoot。

>Fast
获取所有历史区块的header、body数据，但不执行其中的任何交易，所以也无法验证区块头中的三个状态根。
在追上最新区块之后，会继续请求最新的完整 state trie 数据，并维护最新的 state trie 和 receipt trie 数据，但不保存它们的历史版本。
所以可以用 fast 模式同步的节点执行智能合约来获得最新的状态。使用此模式时可以设置 --cache，默认1024M

`--syncmode fast  --cache  2048`

>Light
只下载所有区块的header数据，本地仅做交易是否发生的验证，
也就是仅下载最新区块的所有数据并验证 transactionRoot 是否一致。无法进行任何状态验证。

设定datadir即储存数据的位置，使用full模式，并让这个进程在后台持续运行
`nohup geth --datadir /mnt/eth  --syncmode full &`

经过24小时不间断的同步，达到了500万块高度，硬盘空间大概用了683G，大概花了[10天左右时间](https://github.com/liushooter/etherscan/blob/master/block_time.txt)。

###  存档节点 gcmode

```
geth -h | grep gcmode
--gcmode full      Blockchain garbage collection mode ("full", "archive")

区块的垃圾回收模式，默认是full
```

**archive模式存储着智能合约中的所有值状态以及帐户余额的完整历史记录**
 
`syncmode=full`  验证每块的state trie、transaction trie 和 receipt trie数据，但并不保存所有的 state trie、transaction trie 和 receipt trie 的完整历史版本。

如果一个合约的字符串的值，在6000000高度的时候是xyz，在 6000001高度的时候变为ABC，**这只有在archive模式下才会记录**，其他的同步模式，会裁剪过去的状态，将只会保存最新的值。具体来说，`gcmode=full`模式，只有最近的128次状态被保存在内存中，再多的状态会被丢弃。比如说现在同步到了 7000000高度，只会记录7000000-128 到7000000高度的之间的合约的某个状态的值。

Parity甚至提供了一种同步模式，只记录一定数量的过去状态，从而减少了同步链数据的大小。

使用 `--syncmode=full --gcmode=archive` 模式，即**归档节点**，这种模式保存了最最最全的Ethereum节点数据，占用硬盘空间也会更大。

我当初就是用归档模式，同步到500w高度的时候，1T硬盘已经塞爆了...

也许本人使用的这种同步方式对达到工作目的来说并不是最有效的，最经济的，这个不是讨论的重点。

### 有感

我相信大部分人知道syncmode模式，而不知道 gcmode模式，更没有同步过存档模式。

Ethereum在 2015-07-30诞生，经过4年的发展到现在的740w高度，
从https://etherscan.io/chartsync/chainarchive 数据来看，**完完整整**的区块链数据已经膨胀到2231.5 GB，也就是2.2 TB，同步时间要花几个月时间，而且每天以 3～4 GB的速度在增长。在过几年5TB的硬盘可能也装不下了，这也是为什么ethereum技术社区对的分片呼声这么高的原因。

Bitcoin在2009-01-03诞生，经过10年的发展，完完整整的区块链数据基本也就200多GB，同步时间基本在24~36小时。

从保持去中心化，保有全量数据的角度来说，Bitcoin 在这两方面平衡的相当好。而Ethereum归档节点的机器成本已经很高了，个人没有太多动力去维护。

之前我曾抱怨Bitcoin技术推动太墨迹，丧失了很多机会，现在我感觉Ethereum面临的技术挑战相当严峻。从最近的君士坦丁堡硬分叉出现的问题来看，这2个最知名的区块链技术团队的行事风格差异也挺大的。

Bitcoin是伟大的创举，Ethereum是天才的设计，前者是从0到1跨时代的发明，后者带来了智能合约，深刻影响着传统的经济观念。总之，都祝好吧。

---

参考：

https://talk.nervos.org/t/topic/1515
https://blog.ethereum.org/2018/02/14/geth-1-8-iceberg%C2%B9/
https://ethereum.stackexchange.com/a/57712
https://ethfans.org/topics/29227
https://ethfans.org/topics/29242
https://www.8btc.com/article/373735
https://www.ccvalue.cn/show/2011
https://juejin.im/post/5b7050046fb9a00971405c73
https://zhuanlan.zhihu.com/p/29886689