小白学习区块链以太坊区块链大学

以太坊源码研读0x07 Block

2018-10-25  本文已影响3人  WallisW

前面看了以太坊的交易模块,而交易都是要打包在区块上的。Block是Eth上存储价值信息的核心数据结构之一。

一个完整的Block大概包括以下几部分:

废话少说撸代码

Block结构

// 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.
    // totalDifficulty 区块总难度  当前区块难度值 = td - lastBlock.td
    td *big.Int

    // These fields are used by package eth to track
    // inter-peer block relay.
    // 出块时间
    ReceivedAt   time.Time
    // 区块体
    ReceivedFrom interface{}
}

一个Block的唯一标识符就是它的hash,这里的hash是指其Header内容的RLP哈希值。在第一次计算后会缓存到hash值里。

// 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
}
...
// 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)
}
..
func rlpHash(x interface{}) (h common.Hash) {
    hw := sha3.NewKeccak256()
    rlp.Encode(hw, x)
    hw.Sum(h[:0])
    return h
}

这里每一个Block都有一个BlockHeader,Header是Block的核心,它的成员变量全都是公共的,可以很方便的向调用者提供关于Block属性的操作。

// Header represents a block header in the Ethereum blockchain.
type Header struct {
    // 父区块hash,即链上上一个区块的Hash
    ParentHash  common.Hash    `json:"parentHash"       gencodec:"required"`
    // 叔块集合uncles的RLP哈希值
    UncleHash   common.Hash    `json:"sha3Uncles"       gencodec:"required"`
    // 挖出区块的矿工地址
    Coinbase    common.Address `json:"miner"            gencodec:"required"`
    // MPT状态树根哈希
    Root        common.Hash    `json:"stateRoot"        gencodec:"required"`
    // 交易树根节点RLP哈希值
    TxHash      common.Hash    `json:"transactionsRoot" gencodec:"required"`
    // 收据树根节点RLP哈希值
    ReceiptHash common.Hash    `json:"receiptsRoot"     gencodec:"required"`
    // Bloom过滤器(Filter),用来快速判断一个参数Log对象是否存在于一组已知的Log集合中
    Bloom       Bloom          `json:"logsBloom"        gencodec:"required"`
    // 区块难度
    Difficulty  *big.Int       `json:"difficulty"       gencodec:"required"`
    // 区块序号,相当于Bitcoin的Height
    Number      *big.Int       `json:"number"           gencodec:"required"`
    // 区块内所有Gas消耗的理论上限
    GasLimit    uint64         `json:"gasLimit"         gencodec:"required"`
    // 区块内所有Transaction执行时所实际消耗的Gas总和
    GasUsed     uint64         `json:"gasUsed"          gencodec:"required"`
    // 出块时间
    Time        *big.Int       `json:"timestamp"        gencodec:"required"`
    // 额外数据
    Extra       []byte         `json:"extraData"        gencodec:"required"`
    // 用于POW
    MixDigest   common.Hash    `json:"mixHash"          gencodec:"required"`
    // 用于POW 结合MixDigest生成区块哈希值
    Nonce       BlockNonce     `json:"nonce"            gencodec:"required"`
}

此外,以太坊将一个Block中的交易集合和叔块集合单独封装到一个Body结构中,因为他们相对于Header需要更多的内存空间,在传输和验证时为了节省时间可以和Header分开进行。

// Body is a simple (mutable, non-safe) data container for storing and moving
// a block's data contents (transactions and uncles) together.
// Body可以理解为Block里的数组成员集合,它相对于Header需要更多的内存空间,
// 所以在数据传输和验证时,往往与Header是分开进行的。
type Body struct {
    Transactions []*Transaction
    Uncles       []*Header
}

我们注意到,这里相比Bitcoin多了一个叔块(uncle)的概念。这里可以参考官方对叔块的解释。

叔块,顾名思义就是跟自己的父区块在一个高度上。我们知道相比Bitcoin,Eth将出块时间缩短到了15s左右。这样在庞大的P2P网络中就增大了同时出现同一高度区块的概率,这样就有可能使得大批矿工因为产生这样的区块而得不到奖励。因此,以太坊引入了叔块的概念,一个叔块该满足的条件为:

这样,以太坊的激励机制就有所改变。当一个矿工挖到一个普通区块B时,若该区块拥有叔块,该矿工将除固定区块奖励外额外再得到固定区块奖励/32*count(uncles)的奖励。
同时,曾经挖出叔块的矿工也将获得(Number(uncle)+8-Number(B))*固定区块奖励/8的叔块奖励。我们举个简单的小🌰:

A挖到一个Number为20的Block,该区块由两个叔块uncle1(B挖出Number=18)和uncle2(C挖出Number=13),此时的奖励分配为:

关于区块奖励的源码今天不是重点,这里只是稍微提一下。

Block基本操作

首先来看添加新Block的操作,代码逻辑清晰简单。

// 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)}
}

至此,关于Block数据结构的源码就看完了。

更多以太坊源码解析请移驾全球最大同性交友网,觉得有用记得给个小star哦😯😯😯

.
.
.
.

互联网颠覆世界,区块链颠覆互联网!

--------------------------------------------------20181010 22:58
上一篇下一篇

猜你喜欢

热点阅读