Skip to content

Latest commit

 

History

History
220 lines (172 loc) · 81 KB

File metadata and controls

220 lines (172 loc) · 81 KB
timezone Asia/Shanghai

Po

  1. 自我介绍:我是EthStorage的研究员, 主要研究ZK和Layer2欺诈证明等
  2. 你认为你会完成本次残酷学习吗?Yes

Notes

2025.02.06

Week 1: Protocol Intro

  • 以太坊升级主要通过EIP提案
  • 执行层和共识层规范,采用python版本更容易理解
  • The Merge升级之后包括执行层和共识层
    • 执行层:

      • EVM执行交易;采用Merkle Patricia Trie存储账户、合约代码等状态数据,;执行层节点之间通讯采用JSON-RPC,;应用层采用JSON-RPC API与执行层交互
      • 有多个客户端实现: go_ethereum, reth
    • 共识层:

      • LMD GHOST (Latest Message Driven - Greedy Heaviest Observed SubTree)作为fork choice rule, 它决定链的最新规范区块;共识层节点有另一个P2P网络来通讯;RANDAO
      • 有多个客户端: Prysm, lighthouse等
    • 执行层和共识层通过Engine API来通讯

  • 社区讨论:
  • Week 1相关资料

2025.02.07

Week 1的视频基本看完了, Week2的视频复习了一下。 比较感兴趣的地方在于Merkle tree的更高性能实现,看了下Layer0和MegaETH这方面的解读. 此外对于节点间如何进行P2P通讯也很感兴趣, 打算用python或者go实现一个最简单的版本。

2025.02.08

学习Randao 以太坊beacon chain公平选取proposer, committee等都需要随机数。以太坊采用RANDAO机制来产生随机数,它能够累加来自参与方的随机性,每次出块proposal都会给RANDAO值混入一部分随机性(randao_reveal)。

这个随机数需要足够的公平,不能让proposal任意选取,否则就会给他一定的优势用来作恶。以太坊采用BLS签名作为RANDAO贡献的随机数,BLS有几个特性非常适合作为随机数:

  • 签名值可以认为是均匀分布的
  • 签名值对于其他验证者而言是无法预测的(由于他们不知道proposal的私钥),但是验证者很容易根据proposal的公钥验证签名

RANDAO更新的算法如下图:

<title>Diagram illustrating updating the RANDAO.</title>

  • 关于RANDAO的安全性分析,可以详见Ben Edgington的文章。文中提到还可以结合VRF,让proposer在决定自己提交的值之前确定是否要提交randao_reveal,以消除RANDAO的机会主义偏差。 自己写了一个简单的[RANDAO python代码]
  • 还可以参考EthStorage很好的使用RANDAO作为随机源的例子,在链上采用blockhash+proof验证randao

2025.02.09

学习了以太坊的网络层相关内容,执行层的网络协议包括两部分:

  • 网络发现: 他基于UDP协议,底层基于Kademlia实现的分布式哈希表(DHT),具体的协议实现是discv5
  • 节点通讯: 基于TCP协议,具体使用的是DevP2P

共识层与执行层的网络协议类似,不过使用的是后来开发的libP2P

P2P节点采用Ethereum Node Records (ENR)来进行标记,他主要包括如下信息:

content   = [seq, key, value, ...]
signature = sign(content)
record    = [signature, seq, key, value, ...]

其中预定义的key包括:

id	name of identity scheme, e.g. “v4”
secp256k1	compressed secp256k1 public key, 33 bytes
ip	IPv4 address, 4 bytes
tcp	TCP port, big endian integer
udp	UDP port, big endian integer
ip6	IPv6 address, 16 bytes
tcp6	IPv6-specific TCP port, big endian integer
udp6	IPv6-specific UDP port, big endian integer

2025.02.10

学习了RLP编码,他是一种space-efficent的数据表示格式,用来序列化以太坊的交易、收据等数据。 写了一个编码简单数据和decode raw transaction的代码。 https://github.com/dajuguan/lab/blob/d10a269bf17ac14fbce8bfbadfd532b6d25c100a/eth/rlp_test.py

2025.02.11

学习了EL和CL的网络层相关内容,EL采用devP2P, 而CL则采用IPFS团队开发的libP2P,这是因为libP2P发展的较晚,以太坊出来的时候libP2P还没有成熟。 以太坊The merge也对libP2P提出了很多升级建议,比如加密算法采用Noise等等 References:

2025.02.12

学习了discv4节点网络发现的kademlia算法,该算法主要解决P2P网络中节点发现的问题。核心要解决:

  • 节点ID很多,160bits的hash表空间有2^160这么多节点,那么单级肯定没法存下来,每个节点存那些节点?
  • 如何获取到整个网络中的所有节点

核心思想还是用到局部性思想,通过XOR来定义节点之间的距离,每个节点只存储最多k个与自己log距离为i(1≤i≤MAX_BITS)的节点,这样存储空间只需要k*MAX_BITS。距离函数满足几个特性:

  • distance(x,x) == 0
  • distance(x,y) > 0
  • distance(x, y) + distance(y, z) ≥ distance(x, z)
  • distance(x, y) == distance(y, z) 距离可互换 为了保证查找节点收敛,每次向自己已知的节点查询与目标节点最近的k个节点,根据返回值再递归地查询,这样保证每次log距离减小1或者不变,用O(log(MAX_BITS))查询就能找到网络中的任意目标节点。非常高效而简单的算法!

需要注意的是,每个节点在所有log距离为[1,2,MAX_BITS]的各个buckets中至少要存储一个节点,否则有可能导致距离不会减小,没法迅速收敛。

References

2025.02.13

用python实现了kademlia算法

2025.02.14

学习EVM状态转换这一节,发现除了正常的用户交易外,在处理用户交易之前或者之后有几个特殊的系统合约调用,具体顺序如下: 1.调用EIP4788系统合约生成beacon root的context 2.调用EIP2935生成历史blockhash 3.处理所有正常交易 4.分别调用EIP-6110, EIP-7002,EIP-7251这三个系统合约

几个系统合约在write的时候会使用特殊的SYTEM_ADDRESS=0xffffFFFfFFffffffffffffffFfFFFfffFFFfFFfE作为caller来设置相应的合约storage,读取的时候则是任何用户可以读取合约的状态。具体可见geth相应的处理代码

Ref:

2025.02.15

玩了下EIP4788测试代码: https://github.com/dajuguan/lab/blob/main/eth/contracts/test/EIP4788.t.sol

2025.02.16

阅读了EL优化相关内容,尤其是Georgios的推文reth perf,主要有几个方面优化:

2025.02.17

学习了下EIP2930 access list相关内容,它定义了一种新的交易类型,可以在交易中定义需要访问的address和storage slots, 从而对相应数据进行预取,以节约gas开销。gas主要分为两部分:

  • prewarm的冷数据读取gas消耗相比于直接SLOAD或者CALL更低
  • warm数据读取gas只需要100 以前(EIP2929):
  • COLD_SLOAD_COST 2100
  • COLD_ACCOUNT_ACCESS_COST 2600
  • WARM_STORAGE_READ_COST 100 现在(EIP2930):
  • ACCESS_LIST_STORAGE_KEY_COST 1900
  • ACCESS_LIST_ADDRESS_COST 2400 总体下来一个slot数据读取会节约200gas。

同时写了相应的forge合约来测试

Refs:

2025.02.18

  • 学习merkle patricia tree这种压缩前缀树的实现机制

2025.02.19

  • 学习merkle patricia tree这种压缩前缀树的实现机制,并写了个简单的demo

2025.02.20

学习以太坊的数据结构,主要包括5种DB:

  • ethdb: 定义了持久层的接口和leveldb/pebbledb/memorydb/remotedb对其接口的具体实现
  • triedb: 介于trie和持久成之间,包括两种后端
    • hashdb: key为node的hash,value为node的值
    • pathdb: key为节点的path
  • statedb: 在执行一个区块交易的时候需要从ethdb或triedb中读取contract和storage trie,他提供了一个thin layer来读取这些数据
    • 生命周期为一个区块
    • L2魔改EVM主要就是要修改statedb
  • rawdb: 可以看做KV数据的schema,他定义了实际的数据在DB中的key具体是如何定义的
var CodePrefix = []byte("c") // CodePrefix + code hash -> account code

// codeKey = CodePrefix + hash
func codeKey(hash common.Hash) []byte {
 return append(CodePrefix, hash.Bytes()...)
}

// ReadCodeWithPrefix retrieves the contract code of the provided code hash.
func ReadCodeWithPrefix(db ethdb.KeyValueReader, hash common.Hash) []byte {
 data, _ := db.Get(codeKey(hash))
 return data
}

2025.02.21

2025.02.22

  • 继续深入学习pathdbhashdb的相关代码
    • hashdb实际上存的是hash=> value,所以实际上不同合约地址如果存储相同的storage,那么他们有可能会引用相同的key及相应的数据(即使他们的contract地址不一样!,因为不是按照前缀地址存储数据的),这样导致不好删除数据,即使一个合约destroy了,他内部的hash对应的数据可能被其他合约引用,导致没法直接删除,所以即使是full node也可能会保存不需要的过期数据(比如hash对应的parent root已经被gc了)
    • pathdb则在具体的合约上加了contract address前缀,这样不同的合约确保不会引用相同的hash对应的数据,更容易prune,所以在内存和实际数据库中(fullnode)只需要维护一个trie即可
    • 因此pathdb没法做archive node,因为他需要维护所有的增量数据,这个成本很高

2025.02.23