当前位置:主页 > 查看内容

【区块链基础】6——ETH区块结构

发布时间:2021-05-07 00:00| 位朋友查看

简介:账户 与BTC不同ETH使用的是基于账户的账本account-based ledger账本中记录了各个用户的的余额交易时不必追溯币的来源。 基于账户的账本对 双花攻击 duoble spending attack有着天然的防御作用账户余额是系统中全节点维护的一个状态称为balance交易发生时余额……

账户

与BTC不同,ETH使用的是基于账户的账本(account-based ledger),账本中记录了各个用户的的余额,交易时不必追溯币的来源。

基于账户的账本对双花攻击(duoble spending attack)有着天然的防御作用,账户余额是系统中全节点维护的一个状态,称为balance,交易发生时余额随机改变,但与之而来的问题便是重放攻击(reply attack):若将已发布的交易再一次进行广播发布,造成支付者多次支付,接收者将因此获利。

ETH中使用nonce解决这一问题,nonce作为账户状态中的一个字段,有着计数器的功能,记录了账户有史以来交易的次数,转账时,nonce成为交易内容的一部分,受支付者的签名保护。

ETH有两类账户:

  1. 外部账户(externally owned account)
    也称普通账户,由公私钥对进行控制,包含之前所述的balance和nonce;另外一类账户为合约账户;
  2. 合约账户(smart contract account)
    合约账户不是通过公私钥对进行控制。在创建合约时,合约将返回一个地址,由此地址可调用合约,但合约账户不能主动发起一次交易,所有的交易只能由外部账户发起,之后可能会引起合约间的相互调用。另外,除了balance和nonce,合约账户还有代码code和存储storage。

由于ETH支持智能合约,要求参与者有比较稳定的身份,这与BTC的设计有所不同。

状态树

ETH的账户地址是160bits,共20个字节,账户地址到账户状态为一对映射,账户状态为前述的包括balance,nonce,code,storage等。所有的账户组织成一个改进的Merkle Patricia Tree。

存储账户状态的结构为状态树,其基本数据结构为Merkle Patricia Tree。MPT是一种融合了merkle tree和patricia tree两种树结构优点的数据结构,用路径压缩提高效率,可计算出一个账户状态的根哈希值, 保存于block header中。

MPT丰富了节点类型,共有如下4个类型的节点:

  • 扩展节点 extension Node: [key, value],只能有一个子节点。这里的value值存储的是孩子节点的哈希值;
  • 分支节点 branch Node [0,1,…,16,value],可以有多个节点。因为MPT树中的key被编码成一种特殊的16进制的表示,再加上最后的value,所以分支节点是一个长度为17的list,前16个元素对应着key中的16个可能的十六进制字符,如果有一个[key, value]对在这个分支节点终止,最后一个元素为value值,存储的是刚好在分支节点结束时的值,若没有节点在分支节点中结束时,value值没有存储数据,即分支节点既可以搜索路径的终止也可以是路径的中间节点。分支节点的父亲必然是extension node;
  • 叶子节点 leaf Node : [key, value],这里的key都是16编码出来的字符串,每个字符只有0-f 16种,value是RLP编码的数据;
  • 空白节点 NULL

ETH对MPT做了略微的改进:

  1. Extension Node 和 Branch Node 与原生的MPT不同;
  2. prefix 分奇偶数个nibbles(16进制数);

具体以官方的下图为例:
在这里插入图片描述
MPT作用如下:

  1. 防止篡改
    只要根哈希值不变,整个树的任何部分都无法被篡改,每个账户的状态不会被篡改。
  2. 证明账户余额
    账户所在的分支自下而上作为merkle proof发给轻节点,轻节点进行验证。

交易树

用于记录交易的数据信息,其结构也为MPT,其键值为交易在发布的区块中交易的序号。

收据树

每笔交易完成后形成一个收据,用于记录交易的相关信息与执行结果,其数据结构也为MPT,其键值为交易在发布的区块中交易的序号,与交易树中的节点一一对应,。由于ETH智能合约执行过程比较复杂,增加收据树有利于快速查询执行结果。

布隆过滤器 bloom filter

bloom filter可以比较高效的查找某个元素是否包含在比较大的集合之内。直观的说,bloom算法类似一个hash set,用来判断某个元素(key)是否在某个集合中。和一般的hash set不同的是,这个算法无需存储key的值,对于每个key,只需要k个比特位,每个存储一个标志,用来判断key是否在集合中。

算法:

  1. 首先需要k个hash函数,每个函数可以把key散列成为1个整数
  2. 初始化时,需要一个长度为n比特的数组,每个比特位初始化为0
  3. 某个key加入集合时,用k个hash函数计算出k个散列值,并把数组中对应的比特位置为1
  4. 判断某个key是否在集合时,用k个hash函数计算出k个散列值,并查询数组中对应的比特位,如果所有的比特位都是1,认为在集合中。

在查找某一交易时可快速过滤掉大量无关的区块

区块

header

// Header represents a block header in thr 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"`
}
  • ParentHash:前一个区块header的哈希
  • UncleHash:叔块的哈希,可能比Parent大好几辈
  • Coinbase:挖出区块的矿工地址
  • Root:状态树的根哈希
  • TxHash:交易树的根哈希,类似于比特币中的merkle root
  • ReceiptHash:收据树的根哈希
  • Bloom:布隆过滤器,和收据树相关,提供高效的查询符合某种条件的交易的执行结果
  • Difficulty:挖矿难度
  • GasLimit,GasUsed:和汽油费相关,智能合约消耗汽油费,类似于比特币中的交易费
  • Time:区块产生时间
  • MixDigest:nonce经过计算得到的哈希
  • Nonce:符合难度要求的随机数

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.
    td *big.Int  //总难度值

    // These fields are used by package eth to track
    // inter-peer block relay.
    ReceivedAt   time.Time
    ReceivedFrom interface{}
}
  • header:指向header的指针
  • uncles:指向叔块的header的指针数组
  • transactions:交易列表

extblock

// "external" block encoding. used for eth protocol, etc.
type extblock struct {
    Header *Header
    Txs    []*Transaction
    Uncles []*Header
}

extblock为真正发布的区块信息,即为block结构的前三项。

新区块发布
多个区块的状态树共享节点,每次发布新区块,MPT树中部分节点状态会改变,但改变并非在原地修改,而是新建一些分支,保留原本状态。当仅仅有新发生改变的节点才需要修改,其他未修改节点直接指向前一个区块中的对应节点。而交易树与收据树只将当前区块内发布的交易组织起来,如图所示:
在这里插入图片描述
由于以太坊中出块时间15s左右,会产生很多的分叉,保持历史记录的一个好处是,当某些分叉需要回滚时可以更好的查看历史记录。

交易驱动的状态机 transaction-drived state machine

ETH为一个交易驱动的状态机,其状态为状态树中账户的状态,通过执行交易树的交易,可驱动系统由当前状态转移到下一个状态,其状态转移时确定性的,即通过给定的当前状态和交易,能确定性的转移到下一个状态。

;原文链接:https://blog.csdn.net/sinat_27066063/article/details/115441731
本站部分内容转载于网络,版权归原作者所有,转载之目的在于传播更多优秀技术内容,如有侵权请联系QQ/微信:153890879删除,谢谢!

推荐图文


随机推荐