Go-ethereum 源码解析之 core/types/block.go
// Package types contains data types related to Ethereum consensus.
package types
import (
"encoding/binary"
"io"
"math/big"
"sort"
"sync/atomic"
"time"
"unsafe"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/crypto/sha3"
"github.com/ethereum/go-ethereum/rlp"
)
var (
EmptyRootHash = DeriveSha(Transactions{})
EmptyUncleHash = CalcUncleHash(nil)
)
// A BlockNonce is a 64-bit hash which proves (combined with the
// mix-hash) that a sufficient amount of computation has been carried
// out on a block.
type BlockNonce [8]byte
// EncodeNonce converts the given integer to a block nonce.
func EncodeNonce(i uint64) BlockNonce {
var n BlockNonce
binary.BigEndian.PutUint64(n[:], i)
return n
}
// Uint64 returns the integer value of a block nonce.
func (n BlockNonce) Uint64() uint64 {
return binary.BigEndian.Uint64(n[:])
}
// MarshalText encodes n as a hex string with 0x prefix.
func (n BlockNonce) MarshalText() ([]byte, error) {
return hexutil.Bytes(n[:]).MarshalText()
}
// UnmarshalText implements encoding.TextUnmarshaler.
func (n *BlockNonce) UnmarshalText(input []byte) error {
return hexutil.UnmarshalFixedText("BlockNonce", input, n[:])
}
//go:generate gencodec -type Header -field-override headerMarshaling -out gen_header_json.go
// 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 *big.Int `json:"timestamp" gencodec:"required"`
Extra []byte `json:"extraData" gencodec:"required"`
MixDigest common.Hash `json:"mixHash" gencodec:"required"`
Nonce BlockNonce `json:"nonce" gencodec:"required"`
}
// field type overrides for gencodec
type headerMarshaling struct {
Difficulty *hexutil.Big
Number *hexutil.Big
GasLimit hexutil.Uint64
GasUsed hexutil.Uint64
Time *hexutil.Big
Extra hexutil.Bytes
Hash common.Hash `json:"hash"` // adds call to Hash() in MarshalJSON
}
// Hash returns the block hash of the header, which is simply the keccak256 hash of its
// RLP encoding.
func (h *Header) Hash() common.Hash {
return rlpHash(h)
}
// Size returns the approximate memory used by all internal contents. It is used
// to approximate and limit the memory consumption of various caches.
func (h *Header) Size() common.StorageSize {
return common.StorageSize(unsafe.Sizeof(*h)) + common.StorageSize(len(h.Extra)+(h.Difficulty.BitLen()+h.Number.BitLen()+h.Time.BitLen())/8)
}
func rlpHash(x interface{}) (h common.Hash) {
hw := sha3.NewKeccak256()
rlp.Encode(hw, x)
hw.Sum(h[:0])
return h
}
// Body is a simple (mutable, non-safe) data container for storing and moving
// a block's data contents (transactions and uncles) together.
type Body struct {
Transactions []*Transaction
Uncles []*Header
}
// Block represents an entire block in the Ethereum blockchain.
type Block struct {
header *Header
uncles []*Header
transactions Transactions
// caches
hash atomic.Value
size atomic.Value
// Td is used by package core to store the total difficulty
// of the chain up to and including the block.
td *big.Int
// These fields are used by package eth to track
// inter-peer block relay.
ReceivedAt time.Time
ReceivedFrom interface{}
}
// [deprecated by eth/63]
// StorageBlock defines the RLP encoding of a Block stored in the
// state database. The StorageBlock encoding contains fields that
// would otherwise need to be recomputed.
type StorageBlock Block
// "external" block encoding. used for eth protocol, etc.
type extblock struct {
Header *Header
Txs []*Transaction
Uncles []*Header
}
// [deprecated by eth/63]
// "storage" block encoding. used for database.
type storageblock struct {
Header *Header
Txs []*Transaction
Uncles []*Header
TD *big.Int
}
// NewBlock creates a new block. The input data is copied,
// changes to header and to the field values will not affect the
// block.
//
// The values of TxHash, UncleHash, ReceiptHash and Bloom in header
// are ignored and set to values derived from the given txs, uncles
// and receipts.
func NewBlock(header *Header, txs []*Transaction, uncles []*Header, receipts []*Receipt) *Block {
b := &Block{header: CopyHeader(header), td: new(big.Int)}
// TODO: panic if len(txs) != len(receipts)
if len(txs) == 0 {
b.header.TxHash = EmptyRootHash
} else {
b.header.TxHash = DeriveSha(Transactions(txs))
b.transactions = make(Transactions, len(txs))
copy(b.transactions, txs)
}
if len(receipts) == 0 {
b.header.ReceiptHash = EmptyRootHash
} else {
b.header.ReceiptHash = DeriveSha(Receipts(receipts))
b.header.Bloom = CreateBloom(receipts)
}
if len(uncles) == 0 {
b.header.UncleHash = EmptyUncleHash
} else {
b.header.UncleHash = CalcUncleHash(uncles)
b.uncles = make([]*Header, len(uncles))
for i := range uncles {
b.uncles[i] = CopyHeader(uncles[i])
}
}
return b
}
// NewBlockWithHeader creates a block with the given header data. The
// header data is copied, changes to header and to the field values
// will not affect the block.
func NewBlockWithHeader(header *Header) *Block {
return &Block{header: CopyHeader(header)}
}
// CopyHeader creates a deep copy of a block header to prevent side effects from
// modifying a header variable.
func CopyHeader(h *Header) *Header {
cpy := *h
if cpy.Time = new(big.Int); h.Time != nil {
cpy.Time.Set(h.Time)
}
if cpy.Difficulty = new(big.Int); h.Difficulty != nil {
cpy.Difficulty.Set(h.Difficulty)
}
if cpy.Number = new(big.Int); h.Number != nil {
cpy.Number.Set(h.Number)
}
if len(h.Extra) > 0 {
cpy.Extra = make([]byte, len(h.Extra))
copy(cpy.Extra, h.Extra)
}
return &cpy
}
// DecodeRLP decodes the Ethereum
func (b *Block) DecodeRLP(s *rlp.Stream) error {
var eb extblock
_, size, _ := s.Kind()
if err := s.Decode(&eb); err != nil {
return err
}
b.header, b.uncles, b.transactions = eb.Header, eb.Uncles, eb.Txs
b.size.Store(common.StorageSize(rlp.ListSize(size)))
return nil
}
// EncodeRLP serializes b into the Ethereum RLP block format.
func (b *Block) EncodeRLP(w io.Writer) error {
return rlp.Encode(w, extblock{
Header: b.header,
Txs: b.transactions,
Uncles: b.uncles,
})
}
// [deprecated by eth/63]
func (b *StorageBlock) DecodeRLP(s *rlp.Stream) error {
var sb storageblock
if err := s.Decode(&sb); err != nil {
return err
}
b.header, b.uncles, b.transactions, b.td = sb.Header, sb.Uncles, sb.Txs, sb.TD
return nil
}
// TODO: copies
func (b *Block) Uncles() []*Header { return b.uncles }
func (b *Block) Transactions() Transactions { return b.transactions }
func (b *Block) Transaction(hash common.Hash) *Transaction {
for _, transaction := range b.transactions {
if transaction.Hash() == hash {
return transaction
}
}
return nil
}
func (b *Block) Number() *big.Int { return new(big.Int).Set(b.header.Number) }
func (b *Block) GasLimit() uint64 { return b.header.GasLimit }
func (b *Block) GasUsed() uint64 { return b.header.GasUsed }
func (b *Block) Difficulty() *big.Int { return new(big.Int).Set(b.header.Difficulty) }
func (b *Block) Time() *big.Int { return new(big.Int).Set(b.header.Time) }
func (b *Block) NumberU64() uint64 { return b.header.Number.Uint64() }
func (b *Block) MixDigest() common.Hash { return b.header.MixDigest }
func (b *Block) Nonce() uint64 { return binary.BigEndian.Uint64(b.header.Nonce[:]) }
func (b *Block) Bloom() Bloom { return b.header.Bloom }
func (b *Block) Coinbase() common.Address { return b.header.Coinbase }
func (b *Block) Root() common.Hash { return b.header.Root }
func (b *Block) ParentHash() common.Hash { return b.header.ParentHash }
func (b *Block) TxHash() common.Hash { return b.header.TxHash }
func (b *Block) ReceiptHash() common.Hash { return b.header.ReceiptHash }
func (b *Block) UncleHash() common.Hash { return b.header.UncleHash }
func (b *Block) Extra() []byte { return common.CopyBytes(b.header.Extra) }
func (b *Block) Header() *Header { return CopyHeader(b.header) }
// Body returns the non-header content of the block.
func (b *Block) Body() *Body { return &Body{b.transactions, b.uncles} }
// Size returns the true RLP encoded storage size of the block, either by encoding
// and returning it, or returning a previsouly cached value.
func (b *Block) Size() common.StorageSize {
if size := b.size.Load(); size != nil {
return size.(common.StorageSize)
}
c := writeCounter(0)
rlp.Encode(&c, b)
b.size.Store(common.StorageSize(c))
return common.StorageSize(c)
}
type writeCounter common.StorageSize
func (c *writeCounter) Write(b []byte) (int, error) {
*c += writeCounter(len(b))
return len(b), nil
}
func CalcUncleHash(uncles []*Header) common.Hash {
return rlpHash(uncles)
}
// WithSeal returns a new block with the data from b but the header replaced with
// the sealed one.
func (b *Block) WithSeal(header *Header) *Block {
cpy := *header
return &Block{
header: &cpy,
transactions: b.transactions,
uncles: b.uncles,
}
}
// WithBody returns a new block with the given transaction and uncle contents.
func (b *Block) WithBody(transactions []*Transaction, uncles []*Header) *Block {
block := &Block{
header: CopyHeader(b.header),
transactions: make([]*Transaction, len(transactions)),
uncles: make([]*Header, len(uncles)),
}
copy(block.transactions, transactions)
for i := range uncles {
block.uncles[i] = CopyHeader(uncles[i])
}
return block
}
// Hash returns the keccak256 hash of b's header.
// The hash is computed on the first call and cached thereafter.
func (b *Block) Hash() common.Hash {
if hash := b.hash.Load(); hash != nil {
return hash.(common.Hash)
}
v := b.header.Hash()
b.hash.Store(v)
return v
}
type Blocks []*Block
type BlockBy func(b1, b2 *Block) bool
func (self BlockBy) Sort(blocks Blocks) {
bs := blockSorter{
blocks: blocks,
by: self,
}
sort.Sort(bs)
}
type blockSorter struct {
blocks Blocks
by func(b1, b2 *Block) bool
}
func (self blockSorter) Len() int { return len(self.blocks) }
func (self blockSorter) Swap(i, j int) {
self.blocks[i], self.blocks[j] = self.blocks[j], self.blocks[i]
}
func (self blockSorter) Less(i, j int) bool { return self.by(self.blocks[i], self.blocks[j]) }
func Number(b1, b2 *Block) bool { return b1.header.Number.Cmp(b2.header.Number) < 0 }
Appendix A. 总体批注
文件 core/types/block.go 主要定义了区块相关的数据结构,如区块头 Header,区块 Block。
1. type BlockNonce [8]byte
Block 随机数的封装器。
- 通过函数 EncodeNonce() 将 uint64 类型的值转换为 BlockNonce 类型的值。
- 通过方法 Uint64() 将 BlockNonce 类型的值转换为 uint64 类型的值。
- 通过方法 MarshalText() 将 BlockNonce 类型的值编码为 16 进制的字符串,前面带 0x 前缀。
- 通过方法 UnmarshalText() 将已经编码后的 input 解码到 BlockNonce 类型的值中。
2. type Header struct
Header 用于描述以太坊区块链中的区块头。
ParentHash common.Hash: 父区块的哈希
UncleHash common.Hash: 叔区块列表的哈希
Coinbase common.Address: 矿工地址
Root common.Hash: 状态树的根哈希。
TxHash common.Has: 事务树的根哈希。
ReceiptHash common.Hash: 收据树的根哈希。
Bloom Bloom: 布隆过滤器。
Difficulty *big.Int: 目标哈希的难度值。
Number *big.Int: 区块编号。创始区块的编号为 0.
GasLimit uint64: 单个区块可消耗的 gas 上限。
GasUsed uint64: 当前区块消耗的 gas 总量。
Time *big.Int: 区块创建的时间戳。
Extra []byte: 额外数据。可提供一定程度的扩展能力。
MixDigest common.Hash: ???
Nonce BlockNonce: 使区块头哈希满足目标难度的随机数。
通过方法 Hash() 返回区块头的哈希,哈希只是简单地计算区块头 RLP 编码之后的 keccak256 哈希值。
方法 Size() 返回由所有内部内容使用的内存。被用于评估和限制各种缓存所需的内存消耗。
3. type Body struct
Body 对象是一起存储和移动一个区块的数据内容(事务列表、叔区块列表)的简单(可变地、不安全)容器。
- Transactions []*Transaction: 事务列表
- Uncles []*Header: 叔区块列表
4. type Block struct
Block 对象表示以太坊区块链中的整个区块。
- header *Header: 区块头
- uncles []*Header: 步区块头列表
- transactions Transactions: 事务列表
// caches
hash atomic.Value
size atomic.Value
td *big.Int: 被包 core 用于存储链到当前区块(包含)的总难度
// These fields are used by package eth to track inter-peer block relay.
ReceivedAt time.Time
ReceivedFrom interface{}
通过函数 NewBlock() 创建一个新区块。对输入数据进行深度拷贝,以避免新创建的区块受到参数的变化所影响。
通过函数 NewBlockWithHeader() 根据给定的区块头数据创建一个新的区块。对区块头数据进行了深度拷贝,以避免对区块头的修改会影响到新创建的区块。
通过方法 DecodeRLP() 从 RLP 流中解码出 Block。
通过方法 EncodeRLP() 将 Block 编码成 RLP 流。
通过方法 Uncles() 返回叔区块列表。
通过方法 Transactions() 返回事务列表。
通过方法 Transaction() 返回给定事务哈希对应的事务。
通过方法 Number() 返回区块编号。
通过方法 GasLimit() 返回区块的 header.GasLimit。
通过方法 GasUsed() 返回区块的 header.GasUsed。
通过方法 Difficulty() 返回区块的难度。
通过方法 Time() 返回区块的打包时间。
通过方法 NumberU64() 返回区块编号。
通过方法 MixDigest() 返回区块的 header.MixDigest
通过方法 Nonce() 返回区块的随机数,采用大端编码。
通过方法 Bloom() 返回区块的 header.Bloom。
通过方法 Coinbase() 返回区块的矿工地址。
通过方法 Root() 返回区块的状态树的根哈希。
通过方法 ParentHash() 返回父区块的哈希。
通过方法 TxHash() 返回区块的事务树的根哈希。
通过方法 ReceiptHash() 返回区块的收据树的根哈希。
通过方法 UncleHash() 返回区块的叔区块列表的哈希。
通过方法 Extra() 返回区块的 header.extraData 的深度拷贝。
通过方法 Header() 返回区块头的深度拷贝。
通过方法 Body() 返回区块的非区块头内容。
通过方法 Size() 返回区块采用 RLP 编码后的存储大小。
通过方法 WithSeal() 返回一个新区块,除了区块头用已经被验证的替换之外,其它的都用原来的。
通过方法 WithBody() 返回一个新区块,事务列表和叔区块列表用给定的参数替换,区块头用原区块的。
通过方法 Hash() 返回区块头的 keccak256 哈希。
5. type StorageBlock Block
StorageBlock 定义了存储于状态数据库中的 Block 的 RLP 编码。
- 通过方法 DecodeRLP() 从 RLP 流中解码出 StorageBlock。
6. type extblock struct
extblock 表示外部区块编码,用于 eth 协议等。
- Header *Header: 区块头
- Txs []*Transaction: 事务列表
- Uncles []*Header: 叔区块列表
7. type storageblock struct
storageblock 表示区块编码,用于 database。
- Header *Header: 区块头
- Txs []*Transaction: 事务列表
- Uncles []*Header: 叔区块列表
- TD *big.Int: 到当前区块的总难度
8. type writeCounter common.StorageSize
writeCounter 是 common.StorageSize 的包装器,并实现了 io.Writer 接口。而 common.StorageSize 又是 float64 的包装器,并实现了 Stringer 接口。
- 通过函数 Write() 实现了 io.Writer 接口,计算输入的字节数。
- 通过函数 CalcUncleHash() 返回叔区块列表的哈希。
9. type Blocks []*Block
Blocks 是 Block 列表的包装器。
10. type BlockBy func(b1, b2 *Block) bool
BlockBy 是函数 func(b1, b2 *Block) bool 的包装器。
- 通过方法 Sort() 对 Blocks 排序。
11. type blockSorter struct
blockSorter 是区块列表的排序器,封装了待排序对象 Blocks 和元素比较器。
blocks Blocks: 待排序对象
by func(b1, b2 *Block) bool: 比较两个元素的大小
通过方法 Len() 返回列表中的元素个数。
通过方法 Swap() 交换列表中的两个元素。
通过方法 Less() 返回第 i 个元素是否小于第 j 个元素。
12. 辅助函数
- 函数 rlpHash() 先对输入 x 进行 RLP 编码,再返回其 Keccak256 哈希。
- 函数 CalcUncleHash() 计算叔区块列表的哈希。
- 函数 CopyHeader() 创建了区块头的一个深度拷贝,以避免对区块头修改而产生的副作用。
- 函数 Number() 返回区块 b1 的编号是否比区块 b2 的编号小。
Appendix B. 详细批注
var
- EmptyRootHash:表示由空事务列表构成的 MPT 树的根哈希。
- EmptyUncleHash:表示空叔块列表的哈希。
type BlockNonce [8]byte
64 位(8 个字节)的哈希,与 mix-hash 组合用于证明已经对一个区块进行了足够的计算。
使区块头哈希满足目标难度的随机数。
func EncodeNonce(i uint64) BlockNonce
函数 EncodeNonce() 将 uint64 类型的值转换为 BlockNonce 类型的值。func (n BlockNonce) Uint64() uint64
方法 Uint64() 将 BlockNonce 类型的值转换为 uint64 类型的值。func (n BlockNonce) MarshalText() ([]byte, error)
方法 MarshalText() 将 BlockNonce 类型的值编码为 16 进制的字符串,前面带 0x 前缀。func (n *BlockNonce) UnmarshalText(input []byte) error
方法 UnmarshalText() 将已经编码后的 input 解码到 BlockNonce 类型的值中。
type Header struct
用于描述以太坊区块链中的区块头。
- ParentHash common.Hash: 父区块的哈希
- UncleHash common.Hash: 叔区块列表的哈希
- Coinbase common.Address: 矿工地址
- Root common.Hash: 状态树的根哈希。
- TxHash common.Has: 事务树的根哈希。
- ReceiptHash common.Hash: 收据树的根哈希。
- Bloom Bloom: 布隆过滤器。
- Difficulty *big.Int: 目标哈希的难度值。
- Number *big.Int: 区块编号。创始区块的编号为 0.
- GasLimit uint64: 单个区块可消耗的 gas 上限。
- GasUsed uint64: 当前区块消耗的 gas 总量。
- Time *big.Int: 区块创建的时间戳。
- Extra []byte: 额外数据。可提供一定程度的扩展能力。
- MixDigest common.Hash: ???
- Nonce BlockNonce: 使区块头哈希满足目标难度的随机数。
- func (h *Header) Hash() common.Hash
方法 Hash() 返回区块头的哈希,哈希只是简单地计算区块头 RLP 编码之后的 keccak256 哈希值。
- 哈希值的具体计算由 rlpHash() 函数实现。
- func (h *Header) Size() common.StorageSize
方法 Size() 返回由所有内部内容使用的内存。被用于评估和限制各种缓存所需的内存消耗。
func rlpHash(x interface{}) (h common.Hash)
函数 rlpHash() 先对输入 x 进行 RLP 编码,再返回其 Keccak256 哈希。
func CalcUncleHash()
函数 CalcUncleHash() 计算叔区块列表的哈希。
type Body struct
Body 对象是一起存储和移动一个区块的数据内容(事务列表、叔区块列表)的简单(可变地、不安全)容器。
- Transactions []*Transaction: 事务列表
- Uncles []*Header: 叔区块列表
type Block struct
Block 对象表示以太坊区块链中的整个区块。
- header *Header: 区块头
- uncles []*Header: 步区块头列表
- transactions Transactions: 事务列表
// caches
hash atomic.Value
size atomic.Value
td *big.Int: 被包 core 用于存储链到当前区块(包含)的总难度
// These fields are used by package eth to track inter-peer block relay.
- ReceivedAt time.Time
- ReceivedFrom interface{}
- func (b *Block) DeprecatedTd() *big.Int
此方法已被弃用。
方法 DeprecatedTd() 返回 b.td。
- func NewBlock(header Header, txs []Transaction, uncles []Header, receipts []Receipt) *Block
函数 NewBlock() 创建一个新区块。对输入数据进行深度拷贝,以避免新创建的区块受到参数的变化所影响。
参数 header 中的字段 TxHash, UncleHash, ReceiptHash, and Bloom 被忽略,并根据参数 txs, uncles, and receipts 重新进行计算。
主要实现的具体细节如下:
- 计算新区块头的事务列表的根哈希,并拷贝事务列表
- 计算新区块头的收据列表的根哈希,并根据收据列表创建布隆过滤器
- 计算新区块头的叔区块列表的根哈希,并拷贝叔区块。
func NewBlockWithHeader(header *Header) *Block
函数 NewBlockWithHeader() 根据给定的区块头数据创建一个新的区块。对区块头数据进行了深度拷贝,以避免对区块头的修改会影响到新创建的区块。func (b *Block) DecodeRLP(s *rlp.Stream) error
方法 DecodeRLP() 从 RLP 流中解码出 Block。
主要实现的具体细节如下:
- 使用 extblock 作为 Block 和其 RLP 编码之间的中间数据结构
- 将 Block 的 RLP 流解码到临时对象 extblock
- 从临时对象 extblock 恢复 Block 各字段
- func (b *Block) EncodeRLP(w io.Writer) error
方法 EncodeRLP() 将 Block 编码成 RLP 流。
主要实现的具体细节如下:
- 使用 extblock 作为 Block 和其 RLP 编码之间的中间数据结构
- 创建临时对象 extblock,并从 Block 中的拷贝同名字段
- 将临时对象 extblock 编码成 RLP 流
func (b Block) Uncles() []Header
方法 Uncles() 返回叔区块列表。func (b *Block) Transactions() Transactions
方法 Transactions() 返回事务列表。func (b *Block) Transaction(hash common.Hash) *Transaction
方法 Transaction() 返回给定事务哈希对应的事务。func (b *Block) Number() *big.Int
方法 Number() 返回区块编号。func (b *Block) GasLimit() uint64
方法 GasLimit() 返回区块的 header.GasLimit。func (b *Block) GasUsed() uint64
方法 GasUsed() 返回区块的 header.GasUsed。func (b *Block) Difficulty() *big.Int
方法 Difficulty() 返回区块的难度。func (b *Block) Time() *big.Int
方法 Time() 返回区块的打包时间。func (b *Block) NumberU64() uint64
方法 Number() 返回区块编号。func (b *Block) MixDigest() common.Hash
方法 MixDigest() 返回区块的 header.MixDigestfunc (b *Block) Nonce() uint64
方法 Nonce() 返回区块的随机数,采用大端编码。func (b *Block) Bloom() Bloom
方法 Bloom() 返回区块的 header.Bloom。func (b *Block) Coinbase() common.Address
方法 Coinbase() 返回区块的矿工地址。func (b *Block) Root() common.Hash
方法 Root() 返回区块的状态树的根哈希。func (b *Block) ParentHash() common.Hash
方法 ParentHash() 返回父区块的哈希。func (b *Block) TxHash() common.Hash
方法 TxHash() 返回区块的事务树的根哈希。func (b *Block) ReceiptHash() common.Hash
方法 ReceiptHash() 返回区块的收据树的根哈希。func (b *Block) UncleHash() common.Hash
方法 UncleHash() 返回区块的叔区块列表的哈希。func (b *Block) Extra() []byte
方法 Extra() 返回区块的 header.extraData 的深度拷贝。func (b *Block) Header() *Header
方法 Header() 返回区块头的深度拷贝。func (b *Block) Body() *Body
方法 Body() 返回区块的非区块头内容。func (b *Block) Size() common.StorageSize
方法 Size() 返回区块采用 RLP 编码后的存储大小。
主要实现的具体细节如下:
- 先查看缓存字段 size,如果有缓存则返回缓存的大小
- 采用 RLP 编码,并计算编码后的大小
- 更新缓存字段 size
- func (b *Block) WithSeal(header *Header) *Block
方法 WithSeal() 返回一个新区块,除了区块头用已经被验证的替换之外,其它的都用原来的。
主要实现的具体细节如下:
- 新区块的字段 header 用已被验证的区块头(参数 header)替换
- 新区块的字段 transactions 拷贝于原区块的字段 transactions
- 新区块的字段 uncles 拷贝于原区块的字段 uncles
- func (b Block) WithBody(transactions []Transaction, uncles []*Header) *Block
方法 WithBody() 返回一个新区块,事务列表和叔区块列表用给定的参数替换,区块头用原区块的。
主要实现的具体细节如下:
- 新区块的字段 header 由原区块的 header 填充,使用了函数 CopyHeader()
- 新区块的字段 transactions 由参数 transactions 填充,使用了函数 copy()
- 新区块的字段 uncles 由参数 uncles 填充,使用了函数 CopyHeader()
- func (b *Block) Hash() common.Hash
方法 Hash() 返回区块头的 keccak256 哈希。
主要实现的具体细节如下:
- 先尝试从缓存字段 hash 中恢复,如果成功直接返回
- 获取区块头的哈希并缓存
type StorageBlock Block
被 eth/63 弃用。
StorageBlock 定义了存储于状态数据库中的 Block 的 RLP 编码。
- func (b *StorageBlock) DecodeRLP(s *rlp.Stream) error
被 eth/63 弃用。
方法 DecodeRLP() 从 RLP 流中解码出 StorageBlock。
主要实现的具体细节如下:
- 使用 storageblock 作为 StorageBlock 和其 RLP 编码之间的中间数据结构
- 将 StorageBlock 的 RLP 流解码到临时对象 storageblock
- 从临时对象 storageblock 恢复 StorageBlock 各字段
type extblock struct
extblock 表示外部区块编码,用于 eth 协议等。
- Header *Header: 区块头
- Txs []*Transaction: 事务列表
- Uncles []*Header: 叔区块列表
type storageblock struct
被 eth/63 弃用。
storageblock 表示区块编码,用于 database。
- Header *Header: 区块头
- Txs []*Transaction: 事务列表
- Uncles []*Header: 叔区块列表
- TD *big.Int: 到当前区块的总难度
func CopyHeader(h *Header) *Header
函数 CopyHeader() 创建了区块头的一个深度拷贝,以避免对区块头修改而产生的副作用。
主要实现的具体细节如下:
- 拷贝字段 Time
- 拷贝字段 Difficulty
- 拷贝字段 Number
- 拷贝字段 Extra
type writeCounter common.StorageSize
writeCounter 是 common.StorageSize 的包装器,并实现了 io.Writer 接口。而 common.StorageSize 又是 float64 的包装器,并实现了 Stringer 接口。
- func (c *writeCounter) Write(b []byte)
函数 Write 实现了 io.Writer 接口。
主要实现的具体细节如下:
- 只是对输入 b 进行了计数
func CalcUncleHash(uncles []*Header) common.Hash
函数 CalcUncleHash() 返回叔区块列表的哈希。
主要实现的具体细节如下:
- 调用方法 rlpHash() 进行具体的哈希计算。
type Blocks []*Block
Blocks 是 Block 列表的包装器。
type BlockBy func(b1, b2 *Block) bool
BlockBy 是函数 func(b1, b2 *Block) bool 的包装器。
- func (self BlockBy) Sort(blocks Blocks)
方法 Sort() 对 Blocks 排序。
主要实现的具体细节如下:
- BlockBy 是具体的排序函数
- Blocks 是待排序的对象
- 调用函数 sort.Sort() 进行最终的排序
type blockSorter struct
blockSorter 是区块列表的排序器,封装了待排序对象 Blocks 和元素比较器。
- blocks Blocks: 待排序对象
- by func(b1, b2 *Block) bool: 比较两个元素的大小
func (self blockSorter) Len() int
方法 Len() 返回列表中的元素个数。func (self blockSorter) Swap(i, j int)
方法 Swap() 交换列表中的两个元素。func (self blockSorter) Less(i, j int) bool
方法 Less() 返回第 i 个元素是否小于第 j 个元素。
func Number(b1, b2 *Block) bool
函数 Number() 返回区块 b1 的编号是否比区块 b2 的编号小。
Reference
Contributor
- Windstamp, https://github.com/windstamp