以太坊黄皮书精简解读

Posted by 姚飞亮 on 2020-07-14

以太坊黄皮书精简解读

两个基础编码算法

HP编码

十六进制前缀 Hex-Prefix 编码

主要树节点结构 Merkle Patricia tree (Trie)

RLP编码

递归长度前缀编码 Recursive Length Prefix Encoding

数据保存与传输,将任意格式的数据编码串型

以太坊数据结构

accountSate帐户

accountSate 描述说明
nonce 交易计数;合约账户初始化1
balance 余额
storageRoot
codeHash 如果有关联代码就是合约账户

transaction交易

transaction 描述说明
nonce 发出交易的账户的nonce
gasPrice 余额
gasLimit transaction里最多能用费用
to 接受者地址
value 转账金额、合约创建初始充值
data 附加数据
v,r,s 交易签名

receipt收据log

receipt 描述说明
medState 交易之前有其他交易,初始执行完到当前交易的状态 、中间状态
gasUsed 余额
logBloom 日志过滤器 数据去重算法 合约地址index日志
logs 如果有关联代码就是合约账户

block区块

block 描述说明
parentHash 交易计数,合约账户初始化1
ommersHash
beneficiary 挖矿奖励获取人地址
stateRoot mpt根节点Hash
transactionsRoot mpt根节点Hash
receiptsRoot mpt根节点Hash
logsBloom 区块内所有日志项组成的日志过滤器
difficulty 难度值 12秒-16秒自动调整 难度炸弹-300万
number 区块号
gasLimit 区块内能用的gas 允许矿工可以有5%的上下浮动
gasUsed 区块内所有交易实际使用的gas
timeStamp 时间戳
extraData 32字节数组 用途矿工标示 谁挖的
mixHash 挖矿算法输出
nonce 挖矿算法输出

State Trie全局状态树

State Trie value 描述说明
nonce RLP(accountState) 关联block的stateRoot

Transactions Trie区块级交易树

value Trie value 描述说明
RLP(transactionIndex) RLP(transaction) 关联block的transactionsRoot

Receipts Trie区块级数据树

value value 描述说明
RLP(transactionIndex) RLP(transactionReceipt) 关联block的receiptsRoot

Storage Trie全局存储数

key value 描述说明
F(address, storage position,blockNumber) Storage Data 关联acountState的storageRoot

四个Trie 都不在网络传输 ,网络中只传输交易数据

交易执行

交易数据 tx =(nonce,gasPrice,gasLimit,to,value,data)

三种情况

数据逻辑条件 a
tx.to 为有效地址,且 tx.data为空 普通转账交易
tx.to 为空,且 tx.data不为空 合约创建
tx.to 为有效地址,且 tx.data不为空 消息调用

执行步骤

逻辑步骤 D
1 有效性检查 ECRecover(hash(tx),v,r,s)=sender.address 签名恢复成公钥 公钥160位就是地址 tx.nonce=sender.nonce 交易者交易计数 tx.gas0<=tx.gasLimit sender.balance>=tx.gas0*tx.gasPrice block.gasUsed+tx.gas0<=block.gasLimit
2 不可撤销的状态修改 sender.nonce+=1 sender.balance-=tx.gas0*tx.gasPrice
3 转移tx.value (普通转账) sender.balance-=tx.balue tx.to.balance+=tx.value
3 执行合约创建(合约创建交易) 将tx.data作为EVM字节码进行执行
3 执行消息调用(消息调用交易) 将tx.data作为ABI编码进行执行

执行模型-以太坊虚拟机

存储设计

存储结构 A A
ROM 用来保存所有EVM程序代码的“只读”存储,由以太坊客户端独立维护 -
Stack 即所谓的“运行栈”,用来保存EVM指令的输入和输出数据 最大深度为1024,其中每个单元是个”字(word)256位 32字节“
Momory 内存,一个简单的字节数组,用于临时存储EVM代码运行中需要的存取的各种数据 基于“字”进行寻址和扩展
Storage 存储,由以太坊客户端独立维护的持久化数据区域 每个账户的存储区域被以“字”为单位划分为若干”槽(slot)“,合约中的“状态变量”会根据其具体类型分别保存到这些“槽”中

费用设计

value instruction
Gzero 0 stop, return,revert
Gbase 2 address, origin,caller,callvalue,calldatasize,codesize,gasprice,coinbase,timestamp, number,difficulty,gaslimit,returndatasize,pop,pc,msize,gas
Gverylow 3 add, sub,not,lt,gt,slt,sgt,eq,iszero,and,or,xor,byte,calldataload,mload,store,mstore8,push,dup,swap*
Glow 5 mul,div,sdiv,mod,smod,signextend
Gmid 8 added,mulmod,jump
Ghigh 10 jumpier
Gextcode 700 extcodesize

EVM代码的执行环境

环境要素 A
Account State 当前执行中会接触到所有账户的状态数据,包括nonce、balance等
Storage State 当前执行中会接触到的所有账户的存储数据,即有以太坊客户端独立维护的“仓储树(storage trie)”中给定账户地址对应的存储数据
Block Information 即引发当前执行的原始交易所在的区块信息,包括blockhash、coinbase(beneficiary)、timestamp、number、difficulty和gaslimit等
Runtime Environment 当前执行的一些运行时的参数,包括gasPrice、调用者(直接发起这次调用的地址)和原始调用者(触发这次执行的原始交易发送者地址)等

EVM细节

  • EVM 代码执行的实际gas消耗与其对内存memory的使用有关,并不是固定的。
  • 鼓励最小化使用存储storage,用sstore操作将非0值存储区域重置为0值,会获得实时的gas返还。
  • 交易执行的最后会删除执行过程中接触过的所有“空账户”和自毁列表中的账户,这也会返还一定量的gas。
  • EVM代码的执行必定会持续到一个正常终止或一个异常终止,但无法用代码直接触发一个异常终止。
  • EVM代码执行的异常终止会撤销当前交易中所有对状态的更改,但执行过程中所有消耗的gas不会返还。

合约创建

创建空账户

  • nonce=1
  • balance=endowment
  • storageRoot=()
  • codeHash=sha3(())

执行合约创建代码

一次性的bytecode

  • 更改账户存储
  • 创建其他合约
  • 执行消息调用

正常终止

  • 保存生成的最终代码 runtime bytecode
  • 执行转账

异常终止

  • 回退所有状态变动
  • 不执行转账

消息调用

设recipient为消息调用的目标地址,sender为消息调用的发起者地址,code address 为消息调用实际执行的代码所属的地址,我们有4种发起消息调用的方法

操作码 A
call 向某个接受者地址发起消息调用,recipient(=code address)与sender可以相同,也可以不同,且会根据recipient地址切换执行环境(包含账户状态,存储状态等程序执行所以来的上下文)
callcode 与call基本等价,但recipient与sender相同且与code address 相同(所以不需要切换执行环境)
delegatecall 与call基本等价,但recipient与sender相同、与code address 不同,不允许进行转账,且执行环境保持不变
staticcall 与call基本等价,但不允许进行转账,且不允许对状态state进行任何修改

GHOST 算法

Greedy Heaviest-Observed Sub-Tree

分支选举协议

比特币是最长量分支 10分钟 ,

以太坊是16秒所以不能最长量

image-20200714143312256

区块定稿

矿工节点

一个区块里可以关联两个ommer,向上找6次

ommer 验证->从交易池中选取交易并顺序执行->激励发放->状态验证 生成区块头->工作量证明 计算

非矿工节点

ommer 验证->顺序执行区块中包含的所有交易->激励发放->状态验证 验证区块头->工作量证明 验证

完整的区块链范式

  • 世界状态->

    • 区块1:{交易:{正常交易,

      ​ 虚拟机:{交易、合约创建/消息调用、异常终止、正常终止}

      ​ },

    ​ 奖励发放}

  • 区块2

以太坊是一个状态机,最终区块交易的状态就是区块链的状态



Ω