Ethereum(以太坊)

290 阅读7分钟

Ethereum

世界状态 (world state)

Ether(以太币)记载在 世界状态(world state)

世界状态 = 每个人账户的状态的总集合

A535612C-7A82-4925-B6DB-67DB140FB644

余额变化

Ether(以太币)余额因交易而变化

以太坊既可以看作静态的区块的串联, 也可以看作一个状态机, 随着用户不断地发起交易,促成这个状态机进行状态转移

2101E30D-ED11-428F-BBDB-DAF09E23B0A8

24E6C1E9-869E-48F1-9BDA-1C90F8FA2BAC

账户状态

58E89057-1EEF-4B26-828A-8E92771106A6

已执行交易总数

该值会随着用户不断发送交易而递增,保障用户发出的交易是按照顺序被收纳入最终的区块链。 因为在同一个账户中,已执行交易总数不可以在区块链中再次出现。 当用户创建智能合约时,要指定合约地址,该地址是由用户账户的已执行交易总数和用户账户地址联合计算而得出的。

61A41C87-C5B2-437A-B93D-519C490282B8

代码区的哈希值

该值为 智能合约独有,外部账户不包含该值。 代码区即为智能合约代码本身。 在合约的生命周期中,该区域的内容是不可更改的 只读状态。 代码区存放于以太坊网络节点的硬盘中,当运行时被读入虚拟机执行。代码区的内容通过散列函数得出校验哈希值,该值即为代码区的哈希值。

EEA3E3B9-0F2F-4277-9CD6-32296AC118B1

公开地址从私钥派生逻辑

  • 32字节私钥生成的长度为65字节的公钥
  • 删除为首的一个字节0x04,还剩64字节
  • 将其放入keccak256哈希算法,生成一个256位的哈希值
  • 截取哈希值的最后20字节,既为所求的公开地址
  • (可选)辅以0x的开头装饰,表明这是一个16进制的书面记录形式

EIP-55格式的账户地址

为了解决转账地址填错的问题,该提议按照一定逻辑,将地址中的部分字母大写,与剩余的小写字母来形成校验和,让地址拥有自校验的能力,具体的代码参考下方

const createKeccakHash = require('keccak')
​
function toChecksumAddress (address) {
  address = address.toLowerCase().replace('0x''')
  var hash = createKeccakHash('keccak256').update(address).digest('hex')
  var ret = '0x'
​
  for (var i = 0; i < address.length; i++) {
    if (parseInt(hash[i], 16) >= 8) {
      ret += address[i].toUpperCase()
    } else {
      ret += address[i]
    }
  }
​
  return ret
}

交易(Transaction)

交易活动步骤:

  1. 用户签名打包一条或多条消息,组装成一笔交易,发送到以太坊网络上
  2. 该交易被矿工捕获,并收纳入某一个区块
  3. 区块形成后,被矿工广播到节点网络中,最终加入区块链

交易与消息的区别

消息在账户与账户之间传递数据(data)与价值(value),消息的具体表现形式如下:

  • 数据:一个账户向另一个账户请求函数调用
  • 价值:一个账户向另一个账户发送以太币

交易的特性

"原子性"

要么完全执行,要么完全不执行

"串行"执行

不会同时并行执行

"进入区块链的顺序不确定"

交易的结构

Web3.js代发的交易结构

{
  nonce: web3.toHex(10),
  GasPrice: web3.toHex(100000000000),
  Gas: web3.toHex(140000),
  from: '0x633296baebc20f33ac2e1c1b105d7cd1f6a0718b',
  to'0xD1E1cdbCE15f1009B5A7874053E09C728Df91d47',
  value: web3.toHex(0),
  data: '0xcc9ab24952616d6100000000000000000000000000000000000000000000000000000000'
}

字段解释:

  • nonce 该账户已发送交易数量,一个正整数
  • GasPrice 和 Gas 与现实生活中的汽油费类似,用以支付交易费(交易费 = Gas x GasPrice)

汽油数量 *Gas *由用户指定,汽油单价 *GasPrice *由市场价格决定。运行交易后多余的 *Gas *会退还给用户(惩罚性虚拟机指令assert例外,会扣除所有的剩余未花费的 *Gas *) 。 *Gas *的数值人工预测并不准确,可以让客户端软件在签发交易时代为预测,无须自己手动填写。

4D895A73-6DE9-4A2C-BCD5-7611B795F437

  • From 该笔交易的发送方
  • To 该笔交易的接收方

若该交易为普通以太币转账交易,则接收方为受益人账户地址;若该交易为调用智能合约的交易,则接收方为智能合约的地址;若该交易为创建智能合约,则接收方地址可空缺。

  • Value具体转移多少以太币到接收方

7744E408-B41A-48A1-B8B8-77D91CD72925

  • Data数据字段

当若进行以太币纯转账交易时,该字段可空缺;若进行为智能合约调用,则该值包含编码后的函数名和参数的字节码;若为进行合约创建,则该值包含初始化合约的字节码。

交易的生命周期

9E47CF7F-D1A8-41D9-9FA7-88756A3D93D1

  • 客户端软件在收集完交易信息,组织成相应的结构体,需要使用用户的私钥来签名该交易。
  • 交易后编码为一个公开消息,通过节点网络发出并逐渐扩散到网络中各个节点。
  • 挖矿节点和众多其他普通节点同时收到该消息,矿工将其暂时缓存起来。
  • 若矿工决定将该交易打包入某区块,则执行该消息内容并获得执行结果。
  • 矿工把打包好的区块(包含该交易)广播到网络中,参与共识算法挑选。
  • 区块进入最终的区块链被永久保存。

9A0CBA3C-75ED-4848-AD8E-6EB26CDE2EED

一笔交易在以太坊网络的节点间传播过程

67F24F14-7BE8-456F-A371-C6810983CD0C

以太坊上最常见的交易:

  • 以太币转账
  • 智能合约调用
  • 智能合约创建

这三种交易在交易发送时经历的步骤是 *一模一样 *的,区别仅在于填写交易时选择传递数据 data 还是传递价值 value 。 传递数据的即为合约相关操作,传递价值即为转账操作。

共识与工作量证明

分布式系统的问题就在于如何协调各个节点步调一致、共同进退。这称之为“拜占庭将军问题”。

F58617CF-891B-4255-A960-E91493A60E85

A5BE7A2B-2826-42DA-890C-B70B2AAA6EF8

中心化支付系统与中心化支付系统的拓扑结构

数据结构

Radix树

Merkle树和Merkle证明

62E564ED-5E8E-4E9E-9F86-A68FCC9D3252

Merkle树是一个在密码学中常使用的树形结构,适用于解决数据完整性问题。 它的结构功能异常简单,通常我们用二叉树的形式来表示一棵 Merkle树, 它存在的作用是数据分组并保证数据在存储中的完整性。 例如一棵包含了数字 1 到 8 的 Merkle二叉树

如果碰上基础数据集不是偶数个元素(例如仅有7个数据),则复制一个元素,让它与自己的双胞胎做哈希运算

94EC25C4-FA30-4B5E-9EB8-D9F085CDB6FB

Merkle Patricia树

以太坊团队开创性地融合了Radix树和Merkle树的结构,并进一步优化该结构的存储性能,形成了实用的Merkle Patricia树

Merkle Patiricia树 (以下简称MPT树) 是一个可以存储键值对 (key-value pair) 的高效数据结构,键、值分别可以是任意的序列化过的字符串。它具有Merkle树的密码学安全校验功能,提供树中的数据完整性与存在性的 Merkle 证明。它具有强大的互动能力,在log(N)级别的时间内完成插入、删除、查询等操作。我们来循序渐进地查看如何构建一棵 MPT树。

EC5A7CA1-D13B-42AB-B6B6-0D1376C807BF

0701E504-E6D5-497C-A97F-7221224AA236

状态树(以及存储树)

D7724404-B3A9-4E71-B486-7060DA827EEA

存储树,账户状态,世界状态的构成关系

根据以太坊黄皮书,账户若是一个智能合约账户,则必定包含了 *存储树 *(storageRoot)和 *代码存储 *(codeHash)

D2C0E1A4-CCF0-4B4B-8CB0-8B750D33EBFF

交易树

每个区块都有一棵独立的 交易树 (transactionsRoot)

BDAF1C6E-AAB5-4BC5-87D4-88A7B7D00BBF

单笔交易和交易树的构成

收据树

每个区块都有一棵独立的 收据树 (receiptsRoot)

8B22696F-F576-4427-A778-3D52CC132113

从左到右:日志、交易收据、收据树的构成

区块

*区块头 *较为轻量级,包含了一系列的数值、引用的数值以及哈希值, 总长度在 508Byte 左右;

*区块体 *较为重量级,包含了该区块收纳的交易列表和叔块列表,长度视包含的交易多寡而定,目前在 20KB 左右 。

EC7E92C9-A0B2-4028-BDDF-DC75D2F66091

6E415B49-3A3C-479F-8366-BB1633A9D3F2

一个以太坊区块的示意图