- A+
所属分类:学习笔记
介绍了以太坊的基本概念后, 我们将详细地讨论状态、交易和区块的含义。
状态
世界状态是在地址(160 位的标志符)和账户状态(序列化为 RLP 的数据结构,详见附录 B)的映射。
虽然世界状态没有直接储存在区块链上,但会假定在实施过程中会将这个映射维护在一个修改过的 Merkle Patricia树 (简称 trie, 字典树, 详见附录 D)。字典树需要一个简单的后端数据库去维护字节数组到字节数组的映射;我们称这个后端数据库为状态数据库。它有一系列的好处: 第一,这个结构的根节点是加密的且依赖于所有的内部数据,它的哈希可以作为整个系统状态的一个安全标志; 第二,作为
一个不变的数据结构,因此它允许任何一个之前状态(根部哈希已知的条件下)通过简单地改变根部哈希值而被召回。
因为我们在区块链中储存了所以这样的根部哈希值,所以我们能恢复到指定的历史状态。
账户状态包含以下四个字段:
nonce, 随机数: 这个值等于账户发出的交易数及这个账户创建的合约数量之和。
balance, 余额: [a]b, 表示这个账户拥有多少 Wei
storageRoot, 存储根节点: 保存账户内容的Merkle Patricia 树根节点的 256 位哈希编码到字典树中,
作为从256位整数键值哈希的Keccak 256 位哈希到256位整数的RLP-编码映射。
codeHash, 代码哈希: 这个账户的 EVM(Ethereum Virtual Machine, 以太坊虚拟机) 代码哈希值—代
码执行时, 这个地址会接收一个消息调用; 它和其它字段不同, 创建后不可更改。状态数据库中包含
所有像这样的代码片段哈希, 以便后续使用。
交易
交易(符号,T )是个单一的加密指令,通过以太坊中系统之外的操作者创建。
我们假设外部的操作者是人, 软件工具用于创建和传播。这里的交易类型有两种:一种是消息调用, 另一种通过代码创建新的账户(称为“合约创建”)。两种类型的交易都有的共同字段如下:
nonce, 随机数: Tn, 账户发出的交易数量。
gasPrice, 燃料价格: Tp, 为执行交易所需要的计算资源付的 gas 价格, 以 Wei 为单位。
gasLimit, 燃料上限: Tg , 用于执行交易的最大 gas数量。这个值须在交易前设置, 且设定后不能再修改
to, 接收者地址: 消息调用接收者的 160 位地址。对与合约创建交易, 无需接收者地址, 使用 ∅ 表示, ∅是 B0 的唯一成员。
value, 转账额度: Tv , 转到接收者账户的额度, 以 Wei为单位。对于合约创建, 表示捐赠到合约地址的额度。
此外, 合约创建还包含以下字段:init, 初始化: Ti , 一个不限制大小的字节数组, 表示账户初始化程序的 EVM 代码。
init 是 EVM 代码片段; 执行 init 后会返回另外一个代码片段, 每次合约接受消息调用 (通过交易或内部调用) 后都会执行这个代码片段。仅当合约账户创建时会执行一次init。
相比之下, 一个消息调用的交易包括:data, 数据: Td, 一个不限制大小的字节数组, 表示消息调用的输入数据。
区块
在以太坊中, 区块是相关信息的集合。与区块头H 想对应的交易信息为 T, 其它区块头数据的集合 U 表示它的父级区块中有和当前区块的爷爷辈区块是相同的。(这样的区块称为 ommers, 译者注: 不妨称之为叔链)。区块头包含的的信息如下:
parentHash, 父块哈希: Hp, 父 区 块 头 的 Keccak 256 位哈希。
ommersHash, 叔链哈希: Ho, 当前区块的叔链列表Keccak 256 位哈希。
beneficiary, 受益者地址: Hc, 成功挖到这个区块的160 位地址, 这个区块中的所有交易费用都会转到这个地址。
stateRoot, 状态字典树根节点哈希: 状态字典树根节点的 Keccak 256 位哈希, 交易打包到当前区
块且区块定稿后可以生成这个值
transactionsRoot, 交易字典树根节点哈希: 交 易字典树根节点的 Keccak 256 位哈希, 在交易字典树含有区块中的所有交易列表。
receiptsRoot, 接受者字典树根节点哈希: 接受者字典树根节点的 Keccak 256 位哈希, 在接受者字典树含有区块中的所有交易信息中的接受者。
logsBloom, 日志 Bloom: Hb, 日记 Bloom 过滤器由可索引信息(日志地址和日志主题)组成,这个信息包含在每个日志入口, 来自交易列表中的每个交易的接受者。
difficulty, 难度: Hd, 表示当前区块的难度水平, 这个值根据前一个区块的难度水平和时间戳计算得到。
number, 区块编号: Hi , 等于当前区块的直系前辈区块数量。创始区块的区块编号为 0。
gasLimit, 燃料限制: Hl , 目前每个区块的燃料消耗上限。
gasUsed, 燃料使用量: Hg , 当前区块的所有交易使用燃料之和。
timestamp, 时间戳: Hs, 当前区块初始化时的 Unix时间戳。
extraData, 附加数据: Hx, 32 字节以内的字节数组。
mixHash, 混合哈希: Hm, 与一个与随机数 (nonce)相关的 256 位哈希计算, 用于证明针对当前区块已经完成了足够的计算。
nonce, 随机数: Hn, 一个 64 位哈希, 和计算混合哈希相关, 用于证明针对当前区块已经完成了足够的计算。
此外, 当前区块还记录着这个区块的交易列表, 以及 2 个叔链 (ommer) 的区块头列表
交易收据. 为了让交易信息编码能有利于零知识证明、索引、搜索, 我们将每个包含一定信息的交易收据进行编码。以 BR[i] 表示第 i 个交易, 保存在一个索引字典树中,He 是这个字典树的根节点。交易收据是一个包含四个条目的元组:交易后的状态R;当前区块中交易累计燃料使用量 Ru, 交易发生后会立即更新这个值; 交易执行过程中创建的日志集合 Rl ;和日志 Bloom 过滤器 Rb。
整体有效性. 如果一个区块同时满足以下几个条件,我们才能认为这个区块是有效的:当从起始状态 (父块的最终状态) 按顺序执行完生成新的状态 Hr 后, 在内部要保持一致, 包括叔链、交易区块哈希、给定的交易 BT。
序列化. 函数 LB 和 LH 分别是区块和区块头的预备函数。
区块头验证,这就是区块链安全基础,这也是一个恶意节点不能用其新创建的区块中重写历史数据的重要原因。因为这个随机数必须满足这些条件,且因为条件依赖于这个区块的内容和相关交易, 创建新的合法的区块是困难且耗时的, 需要超过所有诚实矿工的算力总和。