在以太坊完成上海升級后,以太坊已成功從 PoW 過渡到了 PoS 協(xié)議。以太坊路線圖中的另一個大的升級是 EIP-4844,也被稱之為 Ptoto-Danksharding,這次升級旨在提高基于以太坊 rollup 的可擴展性,將于 2024 年 1 月 17 日開始在測試環(huán)境升級。這次升級也為以太坊的完整擴容方案 Danksharding 做好了準(zhǔn)備工作。本文將介紹坎昆升級的內(nèi)容,并對其中關(guān)鍵升級 EIP-4844 進行深入分析,同時也分析了 EIP-4844 升級所帶來的影響。
本文中代碼使用 geth(執(zhí)行層)和 prysm(共識層)的實現(xiàn)。
# 01坎昆升級簡介
坎昆升級最近有了新的進展,確定會在 2024 升級,測試環(huán)境將在 1 月 17 日進行,主網(wǎng)升級預(yù)計會在 2024 年的 3-4 月。作為以太坊生態(tài)的下一個主要敘事,這次升級肯定會得到很大的關(guān)注。
坎昆(Cancun)是墨西哥的一個城市,也是 Devcon3 的舉辦地,作為以太坊升級的傳統(tǒng),這次執(zhí)行層的升級代號就是 Cancun。這次升級還會涉及到共識層的升級,共識層的升級代號是 Deneb,完整的升級代號是這兩個代號的結(jié)合:Dencun = Deneb + Cancun。
這次升級包含的內(nèi)容很多,執(zhí)行層和共識層分別需要實施的 EIP 如下:
- 執(zhí)行層
- EIP-1153
- EIP-4788
- EIP-4844
- EIP-5656
- EIP-6780
- EIP-7516
- 共識層
- EIP-4788
- EIP-4844
- EIP-7044
- EIP-7045
- EIP-7514
這次升級的主角就是 EIP-4844,其他的升級要么是為它服務(wù),要么是一些小修小補。在本文中,我們重點來研究 EIP-4844 升級的細(xì)節(jié),以及升級之后帶來的影響。
EIP-4844 也被稱之為 Proto-Danksharding,這個名字來源于 Protolambda 和 Dankrad Feist 兩位研究員。以太坊最終的數(shù)據(jù)擴展方案是 Danksharding,EIP-4844 是 DankSharding 的前置升級。這次升級主要的目的是提升 rollup 層的可擴展性,并且為后續(xù)的 DankSharding 升級做好準(zhǔn)備。
# 02
理解坎昆升級,你需要知道
2.1 數(shù)據(jù)可用性(DA)
在區(qū)塊鏈中,不要信任,要驗證是一個基本的原則。每個區(qū)塊鏈節(jié)點都可以保存完整的數(shù)據(jù),可以通過重新執(zhí)行交易來確定所有數(shù)據(jù)的真實性,通過獨立地驗證這些數(shù)據(jù),就不用管其他的節(jié)點是否在*。
數(shù)據(jù)可用性是指在驗證區(qū)塊是否正確時,所需要的數(shù)據(jù)能夠公開可獲取。對于當(dāng)前的以太坊架構(gòu)來說,這很容易做到,因為每個節(jié)點都可以保存所有的數(shù)據(jù),缺少數(shù)據(jù)的區(qū)塊會被丟棄,對于所有的節(jié)點來說,數(shù)據(jù)是可用的,這是區(qū)塊鏈的一個特性,數(shù)據(jù)可用性是區(qū)塊鏈的安全保障。
對于 Layer2 rollup,能證明區(qū)塊合法有效的數(shù)據(jù)都會上傳到以太坊,它們的數(shù)據(jù)可用性需要依靠以太坊來保證。
這樣就帶來了兩個問題:
- 所有的 Layer2 都向以太坊提交數(shù)據(jù),會讓 gas fee 持續(xù)保持在高位
- 以太坊本身的存儲能力有限,制約了 Layer2 的發(fā)展
以太坊需要一種不犧牲數(shù)據(jù)可用性,同時又能讓 Layer2 向以太坊用更低的成本提交更多交易的方案,讓 Layer2 的潛力發(fā)揮出來。
EIP-4844 是這個方案的前半部分,通過增加一種新的 blob 交易,blob 交易中的數(shù)據(jù)存儲成本更低,Layer2 可以將交易打包,通過 blob 交易提交到以太坊,從而增加并發(fā)、降低成本。但 EIP-4844 帶來的提升是有限的,因為 blob 數(shù)據(jù)依然會傳播到所有的節(jié)點,會給節(jié)點帶來很大的存儲和網(wǎng)絡(luò)成本,所以這次升級中,每個區(qū)塊只能支持 6 個 blob。
Dankshrding 是這個方案的后半部分,在完成 DankSharding 之后,每個區(qū)塊鏈支持的 blob 可能會到 64 個,這樣 Layer2 基本就沒有什么限制了。但在這個升級之后,大多以太坊節(jié)點就不可能獨立的存儲這些數(shù)據(jù)了,大多數(shù)人承擔(dān)不了網(wǎng)絡(luò)和存儲成本。如果節(jié)點不能完整的存儲數(shù)據(jù),那么數(shù)據(jù) DA 要怎么來保證呢?
檢查數(shù)據(jù)可用性的方式有很多種,但 DAS(Data availability sampling)是最去中心化的一種,DankSharding 中使用的也是這種。通過 DAS,完整的數(shù)據(jù)不用在節(jié)點之間傳播,只需要隨機檢查部分?jǐn)?shù)據(jù)的 KZG 證明就可以保證數(shù)據(jù)的可用性。
基于同樣的原因,只有區(qū)塊鏈的 Builder 需要獲取所有的數(shù)據(jù),創(chuàng)建好區(qū)塊之后,其他的 Proposer 不用下載全部的數(shù)據(jù),只需要通過 DAS 來驗證區(qū)塊是否有效,這個功能升級就是 PBS(Proposer-builder separation)。除了提高數(shù)據(jù)的處理效率,其他的 Proposer 也看不到交易的內(nèi)容,這在一定程度還增加了抗審查能力。
2.2 KZG
KZG(Kate Zaverucha Goldberg)是一種零知識證明系統(tǒng),EIP-4844 中引入了 KZG,作為 blob 驗證和證明生成的一部分。每一個 blob 都會生成一個對應(yīng)的 KZG commitment,為后續(xù)的 DankSharding 升級做準(zhǔn)備。
在 EIP-4844 升級后,blob 數(shù)據(jù)還是會在各個節(jié)點之間傳播。但是在完全的 DankSharding 升級之后,blob 的數(shù)據(jù)量大量增加,節(jié)點之間不能再全量地同步 blob 數(shù)據(jù)。節(jié)點之間會通過 KZG 和 DAS 來檢查數(shù)據(jù)的 DA,這是 DankSharding 實現(xiàn)的基礎(chǔ)。
# 03
Blast 與 L2
EIP-4844 升級中已經(jīng)完成的工作:
- 實現(xiàn) blob 交易以及 blob 數(shù)據(jù)的 KZG 處理
- 實現(xiàn)執(zhí)行層&共識層邏輯,以及執(zhí)行層和共識層交互接口的修改
- blob 交易自動調(diào)整 gas 的機制
在完全實施 DankSharding 之前,還需要完成的工作:
- DAS 實施
- PBS 實施
EIP-4844 完成了后續(xù) DankSharding 升級中的大部分基礎(chǔ)工作。剩下的升級,只需要通過升級共識層來完成,不需要執(zhí)行層和 rollup 的參與,用戶和開發(fā)者對后續(xù)的升級無感。
3.1 blob 交易詳解
在 blob 交易出現(xiàn)之前,Layer2 的交易數(shù)據(jù)通過 calldata 來存儲,calldata 是合約調(diào)用中傳入的函數(shù)參數(shù),是只讀的,并且會被永久存儲到鏈上,blob 交易中的數(shù)據(jù)存儲在額外的空間中,并且在一段時間后被刪除。
blob 存儲和 calldata 的區(qū)別:
EIP- 4844 在執(zhí)行層增加了 blob 的交易類型:
const ( LegacyTxType = 0x00 AccessListTxType = 0x01 DynamicFeeTxType = 0x02 BlobTxType = 0x03 // 新增的 blob 交易)
blob 的交易結(jié)構(gòu)如下:
//geth core/types/tx_blob.go type BlobTx struct { //...
BlobHashes [][]byte // 相比于 EIP-1559 的交易,多了一個 Sidecar 參數(shù) Sidecar *BlobTxSidecar `rlp:"-"`
//...}
// Sidecar 結(jié)構(gòu)type BlobTxSidecar struct { Blobs []kzg4844.Blob // Blobs needed by the blob pool Commitments []kzg4844.Commitment // Commitments needed by the blob pool Proofs []kzg4844.Proof // Proofs needed by the blob pool}
// 每個 blob 原始數(shù)據(jù)最大 128 kbtype Blob [131072]byte
// 生成的 KZG commitment,占 48 字節(jié)type Commitment [48]byte
type Proof [48]byte
相比于 EIP-1559 交易,多了一個 Sidecar 參數(shù),其中存放的就是就是 blob 數(shù)據(jù),這些 blob 不會被打包進入執(zhí)行層的區(qū)塊。其中每個 blob sidecar 包含三部分?jǐn)?shù)據(jù),包括 blob 的原始數(shù)據(jù)和經(jīng)過 KZG 處理之后的數(shù)據(jù),BlobHashes 中存儲 Sidesar 中 Commitments 的 hash 值。
blob 交易中,blob 數(shù)據(jù)存儲部分的價格是單獨計算的,而且會隨之前區(qū)塊 blob 的使用情況而變動,如果上一個區(qū)塊中 blob 的使用超過了 blob 最大限制的 50%,那么費用就會上調(diào),如果低于 50%,那么費用就會降低:
//geth core/types/transaction.go func CalcBlobFee(excessBlobGas uint64) *big.Int { return fakeExponential(minBlobGasPrice, new(big.Int).SetUint64(excessBlobGas), blobGaspriceUpdateFraction)}
// fakeExponential approximates factor * e ** (numerator / denominator) using// Taylor expansion.func fakeExponential(factor, numerator, denominator *big.Int) *big.Int { var ( output = new(big.Int) accum = new(big.Int).Mul(factor, denominator) ) for i := 1; accum.Sign() > 0; i++ { output.Add(output, accum)
accum.Mul(accum, numerator) accum.Div(accum, denominator) accum.Div(accum, big.NewInt(int64(i))) } return output.Div(output, denominator)}
計算一筆交易中 blob gas 的最大限制:
//geth core/types/transaction.gofunc (tx *BlobTx) blobGas() uint64 { return params.BlobTxBlobGasPerBlob * uint64(len(tx.BlobHashes)) }
計算最終交易的花費:
//geth core/types/transaction.gofunc (tx *Transaction) Cost() *big.Int { total := new(big.Int).Mul(tx.GasPrice(), new(big.Int).SetUint64(tx.Gas())) if tx.Type() == BlobTxType { total.Add(total, new(big.Int).Mul(tx.BlobGasFeeCap(), new(big.Int).SetUint64(tx.BlobGas()))) } total.Add(total, tx.Value()) return total}
最終一筆 blob 交易的開銷由三部分組成:交易 gas fee + 發(fā)送的 value + blob fee。
在 EIP-4844 的升級中,每個區(qū)塊中攜帶的 blob 數(shù)量不超過 6 個。后續(xù)完成 DankSharding 升級之后,每個區(qū)塊上 blob 的數(shù)量可以擴展到 64 個。
執(zhí)行層并不會存儲這些 blob 數(shù)據(jù),會在構(gòu)建區(qū)塊的時候,通過 API 將 Blob 數(shù)據(jù)傳輸?shù)焦沧R層:
// geth beacon/engine/types.gotype ExecutionPayloadEnvelope struct { ExecutionPayload *ExecutableData `json:"executionPayload" gencodec:"required"` BlockValue *big.Int `json:"blockValue" gencodec:"required"` BlobsBundle *BlobsBundleV1 `json:"blobsBundle"` Override bool `json:"shouldOverrideBuilder"`}
type BlobsBundleV1 struct { Commitments []hexutil.Bytes `json:"commitments"` Proofs []hexutil.Bytes `json:"proofs"` Blobs []hexutil.Bytes `json:"blobs"`}
共識層收到這些交易之后,會將 blob 的 KZG commitment 打包到鏈上,而將 blob 原始數(shù)據(jù)分開存儲:
// prysm type BeaconBlockBody struct { //... blobKzgCommitments [][]byte // blob 的 Kzg 數(shù)據(jù)}
共識層會負(fù)責(zé)驗證 Blob 數(shù)據(jù)的可用性,驗證的邏輯都被封裝在 isDataAvailable 方法中。目前的實現(xiàn)是先驗證本地數(shù)據(jù)庫中是否可以找到完整的 blob 數(shù)據(jù),如果找不到,那就通過特定的渠道去獲取,直到獲取成功或者報錯。后續(xù) Danksharding 升級完成后,那么通過也會通過這個方法來實現(xiàn) DAS 驗證,減少對其他模塊的影響。
// prysm/beacon-chain/blockchainfunc (s *Service) isDataAvailable(ctx context.Context, root [32]byte, signed interfaces.ReadOnlySignedBeaconBlock) error { //...}
在 EIP-4844 的升級后,blob 數(shù)據(jù)還是會通過 gossip 協(xié)議廣播到所有的節(jié)點,在完全升級到 Danksharding 之后,會通過 DAS 來驗證數(shù)據(jù)的完整性,而不用下載完整的數(shù)據(jù)。
總結(jié)一下,新增的 blob 交易允許用戶將一些數(shù)據(jù)放到 blob 中,blob 數(shù)據(jù)不會在執(zhí)行層存儲, EVM 也無法讀取到這些數(shù)據(jù),這些數(shù)據(jù)會被直接放到共識層存儲,然后廣播給其他的共識層節(jié)點。
3.2 blob 如何影響 gas fee
理論上來說,EIP-4844 升級肯定會降低 Layer2 的 gas fee。因為 blob 的存儲費用會比 calldata 更低,而且一個 blob 中可以容納更多的交易,但實際的情況卻會更復(fù)雜。
EIP-4844 升級中,每個區(qū)塊的中最多可以掛 6 個 blob。但 blob 的費用是動態(tài)調(diào)整的,如果前一個區(qū)塊中的 blob 數(shù)量超過了最大值的 50%,也就是 3 個,那么當(dāng)前這個區(qū)塊的 blob fee 就會上漲 12.5%,如果低于 50%,這個區(qū)塊的 blob fee 就會下降 12.5%,所以最后每個區(qū)塊中的 blob 數(shù)量會維持在最大容量的 50% 左右。
對于 Layer2 來說,理論上 gas fee 會降低到十分之一甚至更低,但是如果鏈上交易繁忙,多個 rollup 同時向以太坊提交數(shù)據(jù),那么 blob fee 也會暴漲,很難準(zhǔn)確地估計升級之后的 gas fee,這樣取決于當(dāng)時的網(wǎng)絡(luò)情況。只有等到 DankSharding 完全升級,每個以太坊區(qū)塊可以支持到 64 個 blob 時才能解決。
另外,一個 blob 的大小是 128kb,大小不能改變,對于交易的提交方來說,即使沒有這么多數(shù)據(jù),也需要付出一個完整 blob 的成本。如果一個 Layer2 上的交易量沒有這么大,有可能使用 calldata 的成本會更低。當(dāng)然也有可能多個交易量不大的 Layer2 會將數(shù)據(jù)合并后再使用 blob 交易提交。
EIP-4844 升級肯定會降低 Layer2 的 gas fee,但是也會因為網(wǎng)絡(luò)和 blob 交易的使用情況讓 gas fee 有比較大的波動。
3.3 blob 數(shù)據(jù)如何存儲
EIP-4844 的升級某種程度上與比特幣的隔離見證(Segwit)升級有點類似,通過額外存儲提升區(qū)塊鏈的容量,而不用大區(qū)塊的升級方案。這些額外多出來的數(shù)據(jù)也需要合適的存儲方式,否則會增加節(jié)點的存儲成本,降低以太坊網(wǎng)絡(luò)的去中心化程度。
在 EIP-4844 升級之后,每個區(qū)塊中可以有 6 個 blob,如果按照 50% 利用率,每天最多可以有 21600 個 blob,每天會新增 2.7G 的數(shù)據(jù),這樣會給節(jié)點帶來很大的存儲成本。所以這些數(shù)據(jù)在一定周期之后會從節(jié)點上刪除,轉(zhuǎn)而使用鏈下存儲,包括 Layer2 rollup 自身、BitTorrent、區(qū)塊鏈瀏覽器、Ethereum portal network、The Graph、個人等等。
特別是在 DankSharding 完全實現(xiàn)之后,每年可能會增加 40TB 的數(shù)據(jù),單個節(jié)點上想要存儲這些數(shù)據(jù)基本是不可能的,所以會采用定期刪除,但是能按需找回的方案。
# 04
坎昆升級的影響
以太坊的坎昆升級和后續(xù)的 DankSharding 升級本質(zhì)上是在給以太坊擴容,在完成擴容的同時,又沒有采用大區(qū)塊的方式,以太坊的區(qū)塊還是會在 1M 以內(nèi),這有利于以太坊的長期發(fā)展,可以讓以太坊在長時間內(nèi)保持較高的去中心化程度。
坎昆升級可以提升 Layer2 交易的吞吐量以及降低 gas fee,甚至有望將 Layer2 的 gas fe 降低到當(dāng)前十分之一的水平,各種大規(guī)模的應(yīng)用就有可能開始爆發(fā),可以將更多的 Web2 用戶帶入 Web3,當(dāng)然這個情況更可能在 DankSharding 完全升級之后出現(xiàn)。
同時 EIP-4844 的升級,也是對模塊化區(qū)塊鏈的肯定,這也會繼續(xù)利好模塊化區(qū)塊鏈的發(fā)展。完成這次升級之后,以太坊的職能將會加速轉(zhuǎn)變,越來越多的 DAPP 會在 Layer2 層開發(fā),用戶也會直接使用 Layer2,以太坊將會成為所有 Layer2 的 DA 層,成為整個 EVM 生態(tài)安全的守護者。
# 05總結(jié)
EIP-4844 本身并不是一個顛覆性的升級,對以太坊的用戶來說改變并不多,以太坊還是很慢而且很貴。而各種 rollup 方案則會從從中受益,可以說這次升級就是為 rollup 所準(zhǔn)備的。EIP-4844 的升級會讓以太坊走向模塊化區(qū)塊鏈的方向,等到 Danksharding 升級完成之后,以太坊主網(wǎng)就成了 Layer2 的 DA 層,Layer2 就成了執(zhí)行層,負(fù)責(zé)性能的提升,后續(xù)模塊化的方案應(yīng)該會不斷出現(xiàn)。