前言:本文的目的是打算深入淺出講講以太坊的整體結構以及儲存相關的內容,會聚焦在儲存上,同時會結合原始碼講解,整個過程也可以體會到作者的設計思想之精妙。
block是最重要的資料結構之一,主要由header和body兩部分組成
1, block原始碼(部分重要字段)
type block struct
}
1.1,headertype header struct
1.2,bodytype body struct
看原始碼總是最好的方式,我們先看看trie的結構體的字段
1,trie
type trie struct
從上面我們可以看到節點型別是node,那麼接下來看看node的各個實現類
2,node的各個實現類
type (
fullnode struct
shortnode struct
hashnode byte
valuenode byte
)
(1) fullnode
可以擁有多個子節點,長度為17的node陣列,前16位對應16進製制,子節點根據key的第一位,插入到相應的位置。第17位,還不清除具體作用是什麼。
(2) shortnode
僅有乙個子節點的節點。它的成員變數val指向乙個子節點
(3) valuenode
葉子節點,攜帶資料部分的rlp雜湊值,資料的rlp編碼值作為valuenode的匹配項儲存在資料庫裡
(4) hashnode
是fullnode或者shortnode物件的rlp雜湊值,以nodeflag結構體的成員(nodeflag.hash)的形式,被fullnode和shortnode間接持有
接下來看看在mpt樹中,是如何對key進行編碼的,在encoding.go中,我們可以看到,有三種編碼方式
(1) keybytes:
就是真正的key(乙個byte),沒什麼特殊的含義
(2) hex:
先看一幅圖,結合圖來說明:
將乙個byte的高4位和低4位分別存到兩個byte中(每4位即乙個nibble),然後在尾部加上乙個標記來標識這是屬於hex編碼方式。通過這種方式,每個byte都可以表示為乙個16進製制,從而加入到上面提到的fullnode的children陣列中
(3) compact:
同樣,看乙個圖:
然後來看看hex是如何轉換到compact的
func hextocompact(hex byte) byte
buf := make(byte, len(hex)/2+1)
buf[0] = terminator << 5 // the flag byte
if len(hex)&1 == 1
decodenibbles(hex, buf[1:])
return buf
}
前面只是簡單的乙個介紹,這裡才是本文的乙個重點,接下來將學習是各種資料如何進行儲存的。以太坊中使用的資料庫是leveldb
(1) header和block儲存
headerprefix = byte("h") // headerprefix + num (uint64 big endian) + hash -> header
tdsuffix = byte("t") // headerprefix + num (uint64 big endian) + hash + tdsuffix -> td
numsuffix = byte("n") // headerprefix + num (uint64 big endian) + numsuffix -> hash
blockhashprefix = byte("h") // blockhashprefix + hash -> num (uint64 big endian)
bodyprefix = byte("b") // bodyprefix + num (uint64 big endian) + hash -> block body
blockreceiptsprefix = byte("r") // blockreceiptsprefix + num (uint64 big endian) + hash -> block receipts
lookupprefix = byte("l") // lookupprefix + hash -> transaction/receipt lookup metadata
bloombitsprefix = byte("b") // bloombitsprefix + bit (uint16 big endian) + section (uint64 big endian) + hash -> bloom bits
從上面**我們可以看出儲存的對應規則,接下來對幾個字段解釋一下。 num:區塊號(uint64大端格式); hash:區塊雜湊值;
這裡有乙個需要特別注意的地方:因為header的前向指標是不能修改的,那麼當把header寫入資料庫時候,我們必須要先保證parent和parent的parent等,已經寫入資料庫
(2) 交易儲存
這裡我們看一下**
func writetxlookupentries(db ethdb.putter, block *types.block) error
data, err := rlp.encodetobytes(entry)
if err != nil
return err
} }return nil
}
(3) statedb模組
在以太坊中,賬戶的呈現形式是乙個stateobject,所有賬戶首statedb管理。statedb中有乙個成員叫trie,儲存stateobject,每個stateobject有20bytes的位址,可以將其作為key;每次在乙個區塊的交易開始執行前,trie由乙個雜湊值(hashnode)恢復出來。另外還有乙個map結構,也是存放stateobject,每個stateobject的位址作為map的key
可見,這個map被用作本地的一級快取,trie是二級快取,底層資料庫是第**
(4) 儲存賬戶(stateobject)
每個stateobject對應了乙個賬戶(account包含了餘額,合約發起次數等資料),同時它也包含了乙個trie(storage trie),用來儲存state資料。相關資訊如下圖
以太坊的資料儲存結構
區塊分為兩部分,即區塊頭和區塊體。區塊頭就是以太坊中的區塊鏈部分。它儲存了前乙個區塊 也可稱為父區塊 的雜湊值,通過區塊頭的連線形成了一條由密碼學背書的鏈。區塊體包含了此區塊中記錄的一系列交易,以及叔塊 ommer 區塊頭列表。區塊頭的結構如下圖所示 其中交易樹和收據樹是merkle樹,狀態樹是me...
以太坊技術知識講解
鏈客,專為開發者而生,有問必答!以太坊 ethereum 是2013年底由乙個叫作 vitalik buterin 的90後小夥子提出來的技術。以太坊和位元幣相似,是乙個開源的,基於區塊鏈技術的分布式計算平台,它強調自己是乙個智慧型合約系統 通常只要有一套金鑰系統,也就是加密系統,讓交易可跟蹤,這種...
深入以太坊智慧型合約 ABI
編譯智慧型合約的 變成可在 evm 上執行的 bytecode binary code 同時可以通過編譯取得智慧型合約的 abi 部署智慧型合約,實際上是把 bytecode 儲存在鏈上 通過乙個transaction 並取得乙個專屬於這個合約的位址 如果要寫個程式呼叫這個智慧型合約,就要把資訊傳送...