以太坊的主要数据对象以前,我想先向各位简要介绍一下默尔克树究竟是什么,以使得它得以发挥做用的属性特征数据库
假设由定制的默克尔-帕特里夏树维护世界状态和交易。编程
在默克尔树中,由叶子节点保存区块数据的哈希,而由非叶子节点保存其子节点的哈希。数组
-默克尔树示意图(包括节点以及他们之间的关系)网络
默克尔树所指向数据的任何改动都会引发节点哈希的变化。因为每个父节点中所保存的哈希值都取决于子节点所包含的数据,因此子节点中数据的变动都会引发父节点哈希的变化。而且这样的影响是连锁反应,从叶子节点直达根节点的。所以对叶子节点所指向数据的改动会引发根节点所保存哈希的变化。由上述结构特征,咱们能够引伸出两条重要的属性:分布式
在判断两棵默克尔树所指向数据是否彻底相同时,咱们不须要比较每一个叶子节点,而只需比较根节点所保存的哈希。学习
在判断特定数据是否被树所指向时,咱们可使用 默克尔证实 技术。此处不对该技术做过多介绍,只需知道这是证实数据存在于默克尔树中的一种简单、高效的方法。区块链
第一种属性的重要之处在于,咱们可以仅利用根节点的哈希值,就标示某一时刻整棵树所指向的数据。这意味着仅经过保存根节点的哈希值就能标示区块(无需储存区块链中全部的数据),且维护数据的不可篡改。spa
至此咱们理清了默克尔树中根节点哈希的做用,下面来介绍以太坊中的主要对象。设计
世界状态是地址(帐户)到帐户状态的映射。虽然世界状态不保存在区块链上,但在黄皮书的描述中,世界状态也由树来保存数据(此树也被称为状态数据库或者状态树)。世界状态能够被视做为随着交易的执行而持续更新的全局状态。以太坊就像一个去中心化的计算机,世界状态则是这台电脑的硬盘。日志
以太坊中全部的帐户信息都体如今世界状态之中,并由世界状态树保存。若是你想知道某一帐户的余额,或者某智能合约当前的状态,就须要经过查询世界状态树来获取该帐户的具体状态信息。下文中我也会简要介绍这些信息是如何存储的。
-世界状态树与帐户存储-
以太坊中有两种帐户类型:外部全部帐户(Externally Owned Accounts 简称 EOA)以及合约帐户。咱们用来互相收发以太币、部署智能合约的帐户就是 EOA 帐户,而部署智能合约时自动生成的帐户则是合约帐户。每个智能合约都有其独一无二的以太坊帐户。
帐户状态反映了一个以太坊帐户的各项信息。例如,它存储了当前帐户以太币的余额信息、当前帐户发送过的交易数量...每个帐户都有帐户状态。
下面就来看看帐户状态中都包括什么:
nonce
今后地址发送出去的交易数量(若是当前为 EOA 帐户)或者此帐号产生的合约建立操做(如今先别管合约建立操做是什么)。
balance
此帐号所拥有的以太币数量(以 Wei 计量)。
storageRoot
帐户存储树的根节点哈希值(稍后介绍帐户存储是什么)。
codeHash
对于合约帐户,就是此帐户存储 EVM 代码的哈希值。对于 EOA 帐户,此处留空。
帐户状态中不容忽视的一个细节是,上述对象在内的全部对象均可变(除了 codeHash)。举例来讲,当一个帐户向其余帐户发送以太币时,除了 nonce 会增长,帐户的余额也会相应改变。
而 codeHash 的不可变性使得,若是部署了有漏洞的智能合约,也没法修复更新此合约。对应的,只能部署一个新合约(而有漏洞的版本会一直存在于区块链上)。这也是为何使用 Truffle 进行智能合约的开发和部署十分必要,而且用 Solidity 编程时要遵循 最佳实践 的要求。
帐户存储树是保存与帐户相关联数据的结构。该项只有合约帐户才有,而在 EOA 中, storageRoot 留空、 codeHash 则是一串空字符串的哈希值。全部智能合约的数据都以 32 字节映射的形式保存在帐户存储树中。此处再也不赘述帐户状态树如何维持合约数据。若是读者对其内部实现感兴趣,强烈建议阅读这篇文章。帐户状态中的 storageRoot 区域负责维持帐户存储树根节点哈希值。
-帐户状态与帐户存储树-
交易推进当前状态到下一状态的转变。在以太坊中有三种交易:
EOA 之间传输值的交易(例如,改变发送方和接收方余额大小)。
发送消息来调用合约的交易(例如,经过发送消息调用来触发 setter 方法,以设置合约中的值)。
用于部署合约的交易(由此建立了合约帐户)。
(从技术角度来说,前两种交易是同样的...它们都是经过消息调用来改变帐户状态的交易,只不过一个是 EOA 帐户,一个是合约帐户。此处将交易分为三种是为了方便读者的理解。)
交易由如下部分组成:
nonce
此帐户发出的交易序号数(校对注:能够粗略理解为“这是该帐户的第几笔交易”)。
gasPrice
执行此交易、进行计算时为每单位 gas 所支付的费用(以 Wei 计量)。
gasLimit
执行此交易时可使用的最大 gas 数量。
to
若是此交易用于传送以太币,此处为接收以太币的 EOA 地址。
若是此交易用于向合约发送消息(例如,调用智能合约中的方法),此处为合约的地址。
若是此交易用于建立合约,此处值为空。
value
若是此交易用于收发以太币,此处为接收帐户以 Wei 计量的代币数量。
若是此交易用于发送对合约的消息调用,此处为向接收此消息智能合约所给付的 Wei 数量。
若是此交易用于建立合约,此处为合约初始化时帐户存放的以 Wei 计量的以太币数量。
v, r, s
在交易的密码学签名中用到的值,能够用于肯定交易的发送方。
data(只用于价值传输以及向智能合约发送消息调用)
发送消息调用时附带的输入数据(例如,假设你想要执行智能合约中的 setter 方法,数据区就应该包括 setter 方法的标识符,以及你想要设定的参数值)。
init(只用于合约建立)
用于初始化合约的 EVM 代码。
别想着一会儿就把这些概念消化完... 必须对以太坊的内部机理有更深的认识才真正理解、使用像 data 区、init 区这样的概念。
相信不出你的意料,区块中全部的交易也是存储在默克尔树中的。而且这棵树的根节点哈希值由区块头保存!下面咱们就来剖析一下以太坊区块结构。
区块分为两部分,即区块头和区块体。
区块头就是以太坊中的区块链部分。它保存了前一个区块(也可称为父区块)的哈希值,经过区块头的链接造成了一条由密码学背书的链。
区块体包含了此区块中记录的一系列交易,以及叔块(ommer)区块头列表。若是想要进一步了解叔块,我推荐阅读这篇文章。
-以太坊区块的抽象示意图-
下面就来介绍区块头包括哪些部分。
parentHash
前一个区块的区块头哈希值。每一个区块都包含前序区块的哈希值,一路可回溯至链上的创世块。这也就是维护数据不会被篡改的结构设计(任何对前序区块的篡改都会影响后续全部区块的哈希值)。
ommersHash
叔块头以及部分区块体的哈希值。
beneficiary
由于挖到此区块而得到收益的以太坊帐户。
stateRoot
世界状态树的根节点哈希值(在全部交易被执行后)。
transactionsRoot
交易树根节点的哈希值。这棵树包含了区块体的全部交易。
receiptsRoot
每当交易执行时,以太坊都会生成对应结果的交易收据。此处就是这个交易收据树的根节点哈希。
logsBloom
布隆过滤器,用于判断某区块的交易是否产生了某日志(若是对这方面感兴趣,能够查阅 Stack Overflow 的这个答案)。这避免了在区块中存储日志信息(节省了大量空间)。
difficulty
此区块的难度值。这是当前区块挖矿难度的度量值(此处不对此概念的细节和计算做介绍)。
number
前序区块的总数。这标示了区块链的高度(即区块链上有多少区块)。创世区块的 number 为 0 。
gasLimit
每个交易都须要消耗 gas 。gas limit 标示了该区块所记录的全部交易可使用的 gas 总量。这是限制区块内交易数量的一种手段。
gasUsed
区块中各条交易所实际消耗的 gas 总量。
timestamp
区块建立时的 Unix 时间戳。谨记因为以太坊网络去中心化的特性,咱们不能信任这个值,特别是撰写智能合约、涉及到时间相关的商业逻辑时不能依靠这个值。
extraData
能输入任何东西的不定长字节数组。当矿工建立区块时,能够在这个区域添加任何东西。
mixHash
用于验证一个区块是否被真正记录到链上的哈希值(若是想要真正理解这个概念,建议阅读这篇文章 Ethash proof-of-work function )。
nonce
和 mixHash 同样,用于验证区块是否被真正记录到链上的值。
哎呀...真是讲到我嘴都酸了...建议你别着急,慢慢吸取!不过我要再次强调,阅读本文不该以记住每个名词及其做用为目标(在谷歌上这些都能搜到)。个人写做初衷是想用一种简单的方式(至少比黄皮书简单)介绍以太坊对象的方方面面,来帮助新手理解那些专业名词表明什么。把这篇文章看成“笨方法学以太坊对象”就行了!🙂
让咱们简要回顾一下学到了什么!整体而言,以太坊有四种前缀树:
世界状态树包括了从地址到帐户状态之间的映射。 世界状态树的根节点哈希值由区块保存(在 stateRoot 字段),它标示了区块建立时的当前状态。整个网络中只有一个世界状态树。
帐户存储树保存了与某一智能合约相关的数据信息。由帐户状态保存帐户存储树的根节点哈希值(在 storageRoot 字段)。每一个帐户都有一个帐户存储树。
交易树包含了一个区块中的全部交易信息。由区块头(在 transactionsRoot 区域)保存交易树的根节点哈希值。每一个区块都有一棵交易树。
交易收据树包含了一个区块中全部交易的收据信息。一样由区块头(在 receiptsRoot 区域)保存交易收据树的根节点哈希值;每一个区块都有对应的交易收据树。
咱们今天讨论的对象有:
世界状态: 以太坊这台分布式计算机的硬盘。它是从地址到帐户状态的映射。
帐户状态: 保存着每一个以太坊帐户的状态信息。帐户状态一样保存着帐户状态树的 storageRoot,后者包含了该帐户的存储数据。
交易: 标示了系统中的状态转移。它能够是资金的转移、消息调用或是合约的部署。
区块: 包括对前序区块(parentHash)的连接,而且保存了当执行时会在系统中产生新状态的交易。区块同时保存了 stateRoot 、transactionRoot 、 receiptsRoot 、 世界状态树的根节点哈希、交易树以及对应的交易收据树。
我想用一张图来表示文中说起的各类概念信息。
-区块、交易、帐户状态对象以及以太坊的默克尔树-
根据个人经验,直接从黄皮书中学习以太坊并不方便,且须要巨大的耐心。如前所述,本文的主要目标就是用区块链初学者能听得懂的语言描述以太坊的主要对象。衷心但愿这篇文章能指引你的学习之路!