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 factor
x 的定义。难度系数(
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 的校验