2. ETH SPV¶
2.1. 什么是SPV¶
轻钱包(SPV)是“Simplified Payment Verification”(简单支付验证)的缩写。中本聪论文简要地提及了这一概念,指出:不运行完全节点也可验证支付,用户只需要保存所有的block header就可以了。用户虽然不能自己验证交易,但如果能够从区块链的某处找到相符的交易,他就可以知道网络已经认可了这笔交易,而且得到了网络的多少个确认。
2.1.1. ETH Hash 算法¶
DAG 分层级的有向无环图 ,每3万个块生成一次,
每个 epoch 的seed 是存在依赖的,
Seed Hash[0] = Kec(32 byte 0) Seed Hash[i] = Kec(32 byte i-1)
Seed 生成 cache, 初始值是 16MB,每个 epoch 增长 128K B, 每个 cache 的单位是 64B
cache 生成 Data,初始值 是 1GB,每个 epoch 增长 8M。
2.2. ETH 数据结构¶
2.2.1. Block¶
以太坊中的一个区块由区块头Header,以及交易列表 ,以及叔块的 header 集合三部分组成。
具体结构如下图

2.2.2. Block Header¶
// Header represents a block header in the Ethereum blockchain.
type Header struct {
ParentHash common.Hash `json:"parentHash" gencodec:"required"`
UncleHash common.Hash `json:"sha3Uncles" gencodec:"required"`
Coinbase common.Address `json:"miner" gencodec:"required"`
Root common.Hash `json:"stateRoot" gencodec:"required"`
TxHash common.Hash `json:"transactionsRoot" gencodec:"required"`
ReceiptHash common.Hash `json:"receiptsRoot" gencodec:"required"`
Bloom Bloom `json:"logsBloom" gencodec:"required"`
Difficulty *big.Int `json:"difficulty" gencodec:"required"`
Number *big.Int `json:"number" gencodec:"required"`
GasLimit uint64 `json:"gasLimit" gencodec:"required"`
GasUsed uint64 `json:"gasUsed" gencodec:"required"`
Time uint64 `json:"timestamp" gencodec:"required"`
Extra []byte `json:"extraData" gencodec:"required"`
MixDigest common.Hash `json:"mixHash"`
Nonce BlockNonce `json:"nonce"`
}
Header包括以下字段。
ParentHash用Hp表示。父节点的
hash值, 每个区块有且只有一个父区块, 但允许某个时候存在多个子块(分叉)。
UncleHash用Ho表示。Block结构体的成员uncles进行 RLP 编码后的 Hash 值,这块是跟GHOST相关的,
Coinbase用Hc表示。 矿工addressstateRoot用Hr表示。StateDB中的state Trie的根节点的RLP哈希值。Block中,每个账户以stateObject对象表示,账户以Address为唯一标示,其信息在相关交易Transaction的执行中被修改。所有账户对象可以逐个插入一个Merkle-PatricaTrie(MPT)结构里,形成state Trie。
transactionsRoot用Ht表示。Block中tx Trie的根节点的RLP哈希值。Block的成员变量transactions中所有的tx对象,被逐个插入一个MPT结构,形成tx Trie。
receiptsRoot用He表示。Block中的Receipt Trie的根节点的RLP哈希值。Block的所有Transaction执行完后会生成一个Receipt数组,这个数组中的所有Receipt被逐个插入一个MPT结构中,形成Receipt Trie。logsBloom用Hb表示。Bloom过滤器(Filter),用来快速判断一个参数Log对象是否存在于一组已知的Log集合中
difficulty用Hd表示。区块的难度。
Block的Difficulty由共识算法基于parentBlock的Time和Difficulty计算得出
number用Hi表示。 区块号gasLimit用Hl表示。区块的gas数量限制,即区块中交易使用掉的gas值不应该超过该值。gasUsed用Hg表示。区块使用掉的gas数量,timestamp用Hs表示。时间戳,extraData用Hx表示。额外的数据,合法的交易对长度有限制,mixHash用Hm表示。与nonce一起用作工作量证明,nonce用Hn表示。PoW中使用的随机数 与mixHash一起用作工作量证明,
2.2.3. 区块头校验¶
校验区块号和区块hash的符号化表示
难度计算的符号化表示
当区块编号为0的时候其难度值是固定好的,在这里用D0表示,其值为
131072.对于其他区块,其难度值需要根据其父区块难度值以及一些其他因素,出块的间隔时间,区块编号等有关进行调节的,若小于D0,则难度值调整为D0。
调节系数
the adjustment factorx 的定义。难度系数(
diculty parameter)ς2的定义。该系数主要与出块间隔时间有关,当间隔大的时候,系数变大,难度也会相应变大,当间隔小的时候,系数变小,难度也会变小。使得区块链在整体上出块时间是趋于稳定的。其中y值根据父节点的uncle节点是否为空而有所区别,可以看出当父节点的uncle不为空的时候,y值为2,说明当前的分叉程度较大,适当调大难度,一定程度上会减少分叉。
gasLimit限制的符号化表示

区块
gasLimit必须大于等于5000,和上个区块的gasLimit差值不超过上个块 gasLimit 除以 1024
时间戳的符号化表示
当前区块的时间戳必须大于父区块的时间戳
mixHash和nonce相关符号化表示
总体而言:区块头验证的符号化表示 如下

2.3. 为什么用SPV¶
以太坊区块的存储的信息主要包含两部分内容:Header和Body. Body主要由交易列表和Uncle Block构成;Header的内容更为丰富,主要有父区块的hash,时间戳,挖矿的难度等. 而Header中最重要的是以太坊的是"三棵树",对应于区块头中的StateRoot,TransactionRoot和ReceiptRoot三个哈希值
light client 只会同步 ETH 的 Block header data 。 由于没有具体的交易信息,只有 Block header data 无法验证某一个交易是否被确认,所以只能通过 Merkle 证明来判断一笔交易是否在现在的区块链交易列表中。
用户在验证一笔交易的时候就不需要知道其他交易的数据,只需要其他交易的交易哈希(Txhash),然后计算这笔交易的hash值,再逐步计算出Merkle Root并与接收到的Block Header的Merkel Root对比就可以验证交易是否存在了(需要用户提供交易的信息: 区块块高,交易的index)
lght client 无法识别最长链(规范链)
2.4. 如何维护一个 light client¶
计算 receiptsRoot 提供 tx 的校验
计算 header data 的校验