ETH數(shù)據(jù)結(jié)構(gòu)
// block塊數(shù)據(jù)
type Block struct {
header *Header
uncles []*Header
transactions Transactions
// caches
hash atomic.Value
size atomic.Value
// Td is used by package core to store the total difficulty
// of the chain up to and including the block.
td *big.Int
// These fields are used by package eth to track
// inter-peer block relay.
ReceivedAt time.Time
ReceivedFrom interface{}
}
// header數(shù)據(jù)
type Header struct {
ParentHash common.Hash `json:"parentHash" gencodec:"required"` // 指向父區(qū)塊的指針踱蛀。
UncleHash common.Hash `json:"sha3Uncles" gencodec:"required"` // Block結(jié)構(gòu)體的成員uncles的RLP哈希值。
Coinbase common.Address `json:"miner" gencodec:"required"` // 挖掘出這個(gè)區(qū)塊的作者地址。
Root common.Hash `json:"stateRoot" gencodec:"required"` // StateDB中的“state Trie”的根節(jié)點(diǎn)的RLP哈希值。
TxHash common.Hash `json:"transactionsRoot" gencodec:"required"` // Block中 “tx Trie”的根節(jié)點(diǎn)的RLP哈希值盔憨。
ReceiptHash common.Hash `json:"receiptsRoot" gencodec:"required"` // Block中的 "Receipt Trie”的根節(jié)點(diǎn)的RLP哈希值浙宜。
Bloom Bloom `json:"logsBloom" gencodec:"required"` // Bloom過濾器(Filter)平夜,用來快速判斷一個(gè)參數(shù)Log對(duì)象是否存在于一組已知的Log集合中线脚。
Difficulty *big.Int `json:"difficulty" gencodec:"required"` // 區(qū)塊的難度。
Number *big.Int `json:"number" gencodec:"required"` // 區(qū)塊的序號(hào)板甘。
GasLimit uint64 `json:"gasLimit" gencodec:"required"` // 區(qū)塊內(nèi)所有Gas消耗的理論上限党瓮。
GasUsed uint64 `json:"gasUsed" gencodec:"required"` // 區(qū)塊內(nèi)所有Transaction執(zhí)行時(shí)所實(shí)際消耗的Gas總和。
Time *big.Int `json:"timestamp" gencodec:"required"` // 區(qū)塊時(shí)間戳盐类,要么等于parentBlock.Time + 10s寞奸,要么等于當(dāng)前系統(tǒng)時(shí)間。
Extra []byte `json:"extraData" gencodec:"required"` // ?
MixDigest common.Hash `json:"mixHash" gencodec:"required"` // ?
Nonce BlockNonce `json:"nonce" gencodec:"required"` // 挖礦隨機(jī)數(shù)在跳,一個(gè)64bit的哈希數(shù)蝇闭。
}
// Transaction數(shù)據(jù)
type Transaction struct {
data txdata //交易明細(xì)
// caches
hash atomic.Value // 交易hash
size atomic.Value // ?
from atomic.Value // from地址
}
type txdata struct {
AccountNonce uint64 `json:"nonce" gencodec:"required"`
Price *big.Int `json:"gasPrice" gencodec:"required"`
GasLimit uint64 `json:"gas" gencodec:"required"`
Recipient *common.Address `json:"to" rlp:"nil"` // nil means contract creation
Amount *big.Int `json:"value" gencodec:"required"`
Payload []byte `json:"input" gencodec:"required"`
// Signature values
V *big.Int `json:"v" gencodec:"required"`
R *big.Int `json:"r" gencodec:"required"`
S *big.Int `json:"s" gencodec:"required"`
// This is only used when marshaling to JSON.
Hash *common.Hash `json:"hash" rlp:"-"`
}
// 塊數(shù)據(jù)示例
{
"jsonrpc": "2.0",
"id": 1,
"result": {
"difficulty": "0x7b56814e8e0",
"extraData": "0xd783010203844765746887676f312e342e32856c696e7578",
"gasLimit": "0x2fefd8",
"gasUsed": "0x37c5e",
"hash": "0x3d3ebb11286a91fdc00cfb6ffa4f4a73e3e528ce13467bb2203532dc9cb42a8f",
"logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000400000000000000000000040000000000000",
"miner": "0x52bc44d5378309ee2abf1539bf71de1b7d7be3b5",
"mixHash": "0x40384589c970bff24a4d5d87692cfd948c89cb7e5381ad28d31071e85c7f22b6",
"nonce": "0xda9cbaa29db514a5",
"number": "0xaae61",
"parentHash": "0x6c621dc6d89cecd48004bd6bd6f3098a18f61aa140b912f0db583198cb69558e",
"receiptsRoot": "0x852ede9b7d114119ecf6f6221f9f6ed059bb25e098ffc6ae89f451186d44c056",
"sha3Uncles": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",
"size": "0x572",
"stateRoot": "0x3b65505100e6fdfa2649764e63a7a980aebfd93726690fe0239e384ede4e3980",
"timestamp": "0x567137a7",
"totalDifficulty": "0x3b49b0afd6d0597c",
"transactionsRoot": "0xb42c31f189406cc77674b5e6f7a7b7d63dd895f875befb3351fb117f37580d38",
"uncles": [],
"transactions": [
{
"blockHash": "0x3d3ebb11286a91fdc00cfb6ffa4f4a73e3e528ce13467bb2203532dc9cb42a8f",
"blockNumber": "0xaae61",
"from": "0xcba4c3cc041b09d3cbf416b73633cb6bd21c88f8",
"gas": "0x3d090",
"gasPrice": "0xc1b710800",
"hash": "0x8c1dd51958fc97a95a24acce4cafba517337138545b57a84cdef3e970bbdf919",
"input": "0x651e723c000000000000000000000000f0b019bb52f59680845b670453ffd875ae3a59e400000000000000000000000000000000000000000000000000000000567137b900000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000001600000000000000000000000000000000000000000000000000000000000000002961caac0fcae0a7f51e4131ef6a243df537d11696bb1a27bac34e37a7c198b9b7ca5c71e62ed55fbca1516ad12305849bfb7421cc199d40dd08f8bb8bd0b57dc0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000001b0000000000000000000000000000000000000000000000000000000000000004000000000000000000000000f0b019bb52f59680845b670453ffd875ae3a59e400000000000000000000000059cc8539f5515335f1340662ce569fa988b40938000000000000000000000000761566074a8e0f7063044abfb8c80ca4cd8c5fd3000000000000000000000000d4fcbd984baebcc12f70f9a151c5c5708d825a7f",
"nonce": "0x35",
"to": "0x7de5aba7de728950c92c57d08e20d4077161f12f",
"transactionIndex": "0x0",
"value": "0x1",
"v": "0x1b",
"r": "0x378066c58af812dc57dc3d090cd6717338d1e51bc1d6fbc308e293ebb69089b",
"s": "0x6208bfb9f67145ce1ac7fadb65682f3a2ea43380e80d07f6d0eab8e5fc5df926"
},
{
"blockHash": "0x3d3ebb11286a91fdc00cfb6ffa4f4a73e3e528ce13467bb2203532dc9cb42a8f",
"blockNumber": "0xaae61",
"from": "0xf8b483dba2c3b7176a3da549ad41a48bb3121069",
"gas": "0x15f90",
"gasPrice": "0xba43b7400",
"hash": "0x5408d12bde03366c4a4b9ad484341bd1c69f86c58ef27a792d1fff1ceda6a6be",
"input": "0x",
"nonce": "0x7e55",
"to": "0xec33b995e319527958760affd24f61fee029e4f9",
"transactionIndex": "0x1",
"value": "0x15c98d913a1bc00",
"v": "0x1c",
"r": "0xd308fb2c73d6f72545d0f7f5b9ac393f28834bb1f4c64c625cfb71f6ff0fd9f4",
"s": "0x20ca14e9481c8c8a97ed2d761f3692e05fb3d7dc262176203670be6d6f934573"
},
{
"blockHash": "0x3d3ebb11286a91fdc00cfb6ffa4f4a73e3e528ce13467bb2203532dc9cb42a8f",
"blockNumber": "0xaae61",
"from": "0x2a65aca4d5fc5b5c859090a6c34d164135398226",
"gas": "0x15f90",
"gasPrice": "0xba43b7400",
"hash": "0x5d8cb5dfd613171daf733f65baefe727060bef89e705a4a7ac46cda1ffb53744",
"input": "0x",
"nonce": "0xf4ae",
"to": "0x7fdf07a0f977e4032c1f082df831423abf58d13d",
"transactionIndex": "0x2",
"value": "0xf6ceba93384a000",
"v": "0x1b",
"r": "0xa24aefa55e9e47915a0b67bbac1b4cc0a823574077cb60a0b2f75f05eec758e8",
"s": "0x1b2b89d5a963003283b81c5da14e58b52a611827db1066f0992d36b2fd88a4d"
}
]
}
}
database_util.go 說明
// 初始化前綴信息
headHeaderKey = []byte("LastHeader") // 最新區(qū)塊頭 Headchain中使用
headBlockKey = []byte("LastBlock") // 最新區(qū)塊 BlockChain中使用
headFastKey = []byte("LastFast") // 最新快速同步的區(qū)塊頭 這里“LastFast”所存儲(chǔ)的是在一種特別的同步方式FastSync下,最新Block的canonical hash硬毕。FastSync相比于FullSync,可以僅僅同步Header而不考慮Body礼仗,故此得名Fast吐咳。
// Data item prefixes (use single byte to avoid mixing data types, avoid `i`). ETH定義好的區(qū)塊頭前綴標(biāo)識(shí),key的前綴可以區(qū)分leveldb中存儲(chǔ)的是什么類型的數(shù)據(jù)。
headerPrefix = []byte("h") // headerPrefix + num (uint64 big endian) + hash -> header 區(qū)塊頭key前綴
tdSuffix = []byte("t") // headerPrefix + num (uint64 big endian) + hash + tdSuffix -> td 區(qū)塊難度
numSuffix = []byte("n") // headerPrefix + num (uint64 big endian) + numSuffix -> hash 區(qū)塊高度
blockHashPrefix = []byte("H") // blockHashPrefix + hash -> num (uint64 big endian) 區(qū)塊hash前綴
bodyPrefix = []byte("b") // bodyPrefix + num (uint64 big endian) + hash -> block body 區(qū)塊體前綴
blockReceiptsPrefix = []byte("r") // blockReceiptsPrefix + num (uint64 big endian) + hash -> block receipts 區(qū)塊交易收據(jù)
lookupPrefix = []byte("l") // lookupPrefix + hash -> transaction/receipt lookup metadata
bloomBitsPrefix = []byte("B") // bloomBitsPrefix + bit (uint16 big endian) + section (uint64 big endian) + hash -> bloom bits
preimagePrefix = "secure-key-" // preimagePrefix + hash -> preimage
configPrefix = []byte("ethereum-config-") // config prefix for the db
// Chain index prefixes (use `i` + single byte to avoid mixing data types).
BloomBitsIndexPrefix = []byte("iB") // BloomBitsIndexPrefix is the data table of a chain indexer to track its progress
// used by old db, now only used for conversion
oldReceiptsPrefix = []byte("receipts-")
oldTxMetaSuffix = []byte{0x01}
ErrChainConfigNotFound = errors.New("ChainConfig not found") // general config not found error
preimageCounter = metrics.NewCounter("db/preimage/total")
preimageHitCounter = metrics.NewCounter("db/preimage/hits")
- 方法歸類整理
數(shù)據(jù)庫操作封裝
1.塊hash -> 塊頭
headerPrefix = []byte("h") // headerPrefix + num (uint64 big endian) + hash -> header
a.WriteHeader()
b.GetHeaderRLP()
c.GetHeader()
d.DeleteHeader()
2.塊hash -> 總難度
tdSuffix = []byte("t") // headerPrefix + num (uint64 big endian) + hash + tdSuffix -> td
a.WriteTd()
b.GetTd()
c.DeleteTd()
3.塊高 -> 塊hash
numSuffix = []byte("n") // headerPrefix + num (uint64 big endian) + numSuffix -> hash
canonical hash:區(qū)塊hash元践,Block(或Header)對(duì)象的RLP哈希值韭脊。
num(Number)和hash是Block最為重要的兩個(gè)屬性:num用來確定Block在整個(gè)區(qū)塊鏈中所處的位置,hash用來辨識(shí)惟一的Block/Header對(duì)象单旁。
a.encodeBlockNumber(number uint64) //將區(qū)塊高度轉(zhuǎn)化為ig endian uint64類型,大端格式
b.GetCanonicalHash()
c.WriteCanonicalHash()
d.DeleteCanonicalHash()
4.塊hash -> 塊高
blockHashPrefix = []byte("H") // blockHashPrefix + hash -> num (uint64 big endian)
5.塊hash -> body數(shù)據(jù)
bodyPrefix = []byte("b") // bodyPrefix + num (uint64 big endian) + hash -> block body
a.WriteBodyRLP()
b.GetBodyRLP()
c.WriteBody()
d.GetBody()
e.DeleteBody()
6.塊hash -> 交易收據(jù)
blockReceiptsPrefix = []byte("r") // blockReceiptsPrefix + num (uint64 big endian) + hash -> block receipts
a.WriteBlockReceipts()
b.GetBlockReceipts()
c.DeleteBlockReceipts()
7.塊hash -> 交易收據(jù)lookup metadata
lookupPrefix = []byte("l") // lookupPrefix + hash -> transaction/receipt lookup metadata
a.WriteTxLookupEntries()
b.GetTxLookupEntry()
c.DeleteTxLookupEntry()
8.塊高 -> bloom bits
bloomBitsPrefix = []byte("B") // bloomBitsPrefix + bit(uint16 big endian) + section(uint64 big endian) + hash -> bloom bits
a.WriteBloomBits()
b.GetBloomBits()
9.沒看懂
preimagePrefix = "secure-key-" // preimagePrefix + hash -> preimage(原像)
WritePreimages()
10.eth配置數(shù)據(jù)庫信息
configPrefix = []byte("ethereum-config-") // config prefix for the db
a.WriteChainConfig()
b.GetChainConfig()
11.沒看懂
BloomBitsIndexPrefix = []byte("iB") // BloomBitsIndexPrefix is the data table of a chain indexer to track its progress 索引進(jìn)度跟蹤
12.//used by old db, now only used for conversion 轉(zhuǎn)換
oldReceiptsPrefix = []byte("receipts-")
oldTxMetaSuffix = []byte{0x01}
對(duì)外封裝方法:
1.初始化數(shù)據(jù)
missingNumber // 如果數(shù)據(jù)庫中沒有獲取到塊高數(shù)據(jù)沪羔,則使用該缺省塊高。
TxLookupEntry //Lookup實(shí)體
2.塊高
GetBlockNumber() //返回missingNumber/塊高
3.塊hash
WriteHeadHeaderHash()
GetHeadHeaderHash() //返回當(dāng)前塊頭的hash
WriteHeadBlockHash()
GetHeadBlockHash() //返回當(dāng)前塊頭的hash
WriteHeadFastBlockHash()
GetHeadFastBlockHash() //返回當(dāng)前塊頭的hash
4.區(qū)塊操作
WriteBlock()
GetBlock()
DeleteBlock()
5.區(qū)塊頭操作
FindCommonAncestor() // 獲取兩個(gè)區(qū)塊頭的共同父類區(qū)塊頭信息?
6.交易信息
GetTransaction()
7.交易收據(jù)信息
GetReceipt()
8.區(qū)塊鏈操作
WriteBlockChainVersion()
GetBlockChainVersion()
9.公用方法
headerKey() //公用headerKey生成
blockBodyKey() //公用bodyKey生成
數(shù)據(jù)庫體系
LDBDatabase
屬于Ethereum代碼范圍內(nèi)的最底層數(shù)據(jù)庫是ethdb.LDBDatabase,它通過持有一個(gè)levelDB的對(duì)象蔫饰,最終為Ethereum世界里所有需要存儲(chǔ)/讀取[k,b]的需求提供服務(wù)琅豆。
- interface.go
統(tǒng)一接口封裝,包含數(shù)據(jù)庫的單/批操作方法(putter,get,has,delete,close,batch) - database.go
a.NewLDBDatabase()--初始化LevelDB實(shí)例,初始化數(shù)據(jù)庫數(shù)據(jù)篓吁,文件緩存容量+塊緩存容量+寫緩存等
b.Put()--保存數(shù)據(jù)茫因,將數(shù)據(jù)放入levelDB存儲(chǔ)隊(duì)列
c.Has()--校驗(yàn)key值在LevelDB中是否存在
d.Get()--查詢key對(duì)應(yīng)的value值
e.Delete()--刪除key對(duì)應(yīng)的數(shù)據(jù)
f.NewIterator()--創(chuàng)建LevelDB數(shù)據(jù)遍歷器
g.Close()--數(shù)據(jù)庫關(guān)閉操作
h.Meter()--初始化特殊請(qǐng)求前綴,并啟動(dòng)監(jiān)聽程序
i.NewBatch()--初始化批處理實(shí)例杖剪,后續(xù)提供了相關(guān)Put/ValueSize/Write等方法
j.table/tableBatch--按照前綴操作單/批量數(shù)據(jù)的實(shí)例冻押,后續(xù)提供了相關(guān)Put/Has/Get/Delete/Close等方法 - database_test.go
基于database.go對(duì)外提供的測(cè)試接口 - memory_database.go
使用內(nèi)存變量模擬數(shù)據(jù)庫單/批的并行操作
Trie
圖中多次出現(xiàn)一種類似的設(shè)計(jì)模式,比如trie.Trie持有一個(gè)本地接口trie.<<Database>>盛嘿,而后者的具體實(shí)現(xiàn)是ethdb.LDBDatabase洛巢。這種設(shè)計(jì)模式其實(shí)是golang的語法帶來的。在golang中次兆,一個(gè)結(jié)構(gòu)體(類)要實(shí)現(xiàn)另一個(gè)接口的所有方法稿茉,不必在結(jié)構(gòu)體聲明時(shí)顯式繼承那個(gè)接口,只要完全實(shí)現(xiàn)那些方法类垦。這樣狈邑,當(dāng)一個(gè)結(jié)構(gòu)體想調(diào)用另一個(gè)包路徑下結(jié)構(gòu)體的多個(gè)方法時(shí),可以聲明一個(gè)本地接口蚤认,帶有幾個(gè)同想要調(diào)用方法完全一樣的方法米苹,就可以了,這種方式的優(yōu)點(diǎn)是不同包之間的代碼更充分的解耦合砰琢。所以在上圖中蘸嘶,這些輔助性的本地接口全都被標(biāo)為灰色,只需要關(guān)注實(shí)際調(diào)用的實(shí)現(xiàn)類就好了陪汽。
- 源碼整理
a.Trie-LevelDB
實(shí)例:
Database:DatabaseReader/DatabaseWriter
方法:
DatabaseReader:Get/Has
DatabaseWriter:Put
b.Trie
實(shí)例:
Trie
-- root node 始終作為整個(gè)MPT的根節(jié)點(diǎn)
-- db Database Trie-LevelDB中數(shù)據(jù)庫操作實(shí)例
-- originalRoot common.Hash 創(chuàng)建Trie對(duì)象時(shí)承接入?yún)ashNode
-- cachegen, cachelimit uint16 cacheGen是cache次數(shù)的計(jì)數(shù)器训唱,每次Trie的變動(dòng)提交后(寫入的對(duì)象可由外部參數(shù)傳入),cacheGen自增1
方法:
New 根據(jù)數(shù)據(jù)庫數(shù)據(jù)創(chuàng)建根節(jié)點(diǎn)數(shù)據(jù)挚冤,
NodeIterator 創(chuàng)建節(jié)點(diǎn)迭代器
Get 根據(jù)key值返回Trie中的value况增,不報(bào)錯(cuò)
TryGet 根據(jù)key值返回Trie中的value,報(bào)錯(cuò)(MissingNodeError)
Update/TryUpdate 根據(jù)key更新(insert)value训挡,如果value長度為0澳骤,則從Trie中刪除并返回nil。
Delete/TryDelete
Commit/CommitTo 將trie記錄提交至數(shù)據(jù)庫
State
系統(tǒng)設(shè)計(jì)中澜薄,在底層數(shù)據(jù)庫模塊和業(yè)務(wù)模型之間为肮,往往需要設(shè)置本地存儲(chǔ)模塊,它面向業(yè)務(wù)模型肤京,可以根據(jù)業(yè)務(wù)需求靈活的設(shè)計(jì)各種存儲(chǔ)格式和單元颊艳,同時(shí)又連接底層數(shù)據(jù)庫,如果底層數(shù)據(jù)庫(或者第三方API)有變動(dòng),可以大大減少對(duì)業(yè)務(wù)模塊的影響棋枕。在Ethereum世界里白修,StateDB就擔(dān)任這個(gè)角色,它通過大量的stateObject對(duì)象集合戒悠,管理所有“賬戶”信息熬荆。
面向業(yè)務(wù)的存儲(chǔ)模塊 - StateDB
StateDB有一個(gè)trie.Trie類型成員trie,它又被稱為storage trie或stte trie绸狐,這個(gè)MPT結(jié)構(gòu)中存儲(chǔ)的都是stateObject對(duì)象卤恳,每個(gè)stateObject對(duì)象以其地址(20 bytes)作為插入節(jié)點(diǎn)的Key;每次在一個(gè)區(qū)塊的交易開始執(zhí)行前寒矿,trie由一個(gè)哈希值(hashNode)恢復(fù)出來突琳。另外還有一個(gè)map結(jié)構(gòu),也是存放stateObject符相,每個(gè)stateObject的地址作為map的key拆融。那么問題來了,這些數(shù)據(jù)結(jié)構(gòu)之間是怎樣的關(guān)系呢啊终?
如上圖所示镜豹,每當(dāng)一個(gè)stateObject有改動(dòng),亦即“賬戶”信息有變動(dòng)時(shí)蓝牲,這個(gè)stateObject對(duì)象會(huì)更新趟脂,并且這個(gè)stateObject會(huì)標(biāo)為dirty,此時(shí)所有的數(shù)據(jù)改動(dòng)還僅僅存儲(chǔ)在map里例衍。當(dāng)IntermediateRoot()調(diào)用時(shí)昔期,所有標(biāo)為dirty的stateObject才會(huì)被一起寫入trie。而整個(gè)trie中的內(nèi)容只有在CommitTo()調(diào)用時(shí)被一起提交到底層數(shù)據(jù)庫佛玄∨鹨唬可見,這個(gè)map被用作本地的一級(jí)緩存梦抢,trie是二級(jí)緩存般贼,底層數(shù)據(jù)庫是第三級(jí),各級(jí)數(shù)據(jù)結(jié)構(gòu)的界限非常清晰奥吩,這樣逐級(jí)緩存數(shù)據(jù)具伍,每一級(jí)數(shù)據(jù)向上一級(jí)提交的時(shí)機(jī)也根據(jù)業(yè)務(wù)需求做了合理的選擇。
StateDB中賬戶狀態(tài)的版本管理
StateDB還可以管理賬戶狀態(tài)的版本圈驼。這個(gè)功能用到了幾個(gè)結(jié)構(gòu)體:journal,revision望几,先來看看UML關(guān)系圖:
其中journal對(duì)象是journalEntry的散列绩脆,長度不固定,可任意添加元素。接口journalEntry存在若干種實(shí)現(xiàn)體靴迫,描述了從單個(gè)賬戶操作(賬戶余額惕味,發(fā)起合約次數(shù)等),到account trie變化(創(chuàng)建新賬戶對(duì)象玉锌,賬戶消亡)等各種最小事件名挥。revision結(jié)構(gòu)體,用來描述一個(gè)‘版本’主守,它的兩個(gè)整型成員jd和journalIndex禀倔,都是基于journal散列進(jìn)行操作的。
上圖簡述了StateDB中賬戶狀態(tài)的版本是如何管理的参淫。首先journal散列會(huì)隨著系統(tǒng)運(yùn)行不斷的增長啤贩,記錄所有發(fā)生過的單位事件弛车;當(dāng)某個(gè)時(shí)刻需要產(chǎn)生一個(gè)賬戶狀態(tài)版本時(shí),代碼中相應(yīng)的是Snapshop()調(diào)用,會(huì)產(chǎn)生一個(gè)新revision對(duì)象培廓,記錄下當(dāng)前journal散列的長度,和一個(gè)自增1的版本號(hào)越妈。
基于以上的設(shè)計(jì)泪勒,當(dāng)發(fā)生回退要求時(shí),只要根據(jù)相應(yīng)的revision中的journalIndex棕兼,在journal散列上陡舅,根據(jù)所記錄的所有journalEntry,即可使所有賬戶回退到那個(gè)狀態(tài)程储。
Ethereum里的賬戶 - stateObject
每個(gè)stateObject對(duì)象管理著Ethereum世界里的一個(gè)“賬戶”蹭沛。stateObject有一個(gè)成員變量data,類型是Accunt結(jié)構(gòu)體章鲤,里面存有賬戶Ether余額摊灭,合約發(fā)起次數(shù),最新發(fā)起合約指令集的哈希值败徊,以及一個(gè)MPT結(jié)構(gòu)的頂點(diǎn)哈希值帚呼。
stateObject內(nèi)部也有一個(gè)Trie類型的成員trie,被稱為storage trie皱蹦,它里面存放的是一種被稱為State的數(shù)據(jù)煤杀。State跟每個(gè)賬戶相關(guān),格式是[Hash, Hash]鍵值對(duì)沪哺。有意思的是沈自,stateObject內(nèi)部也有類似StateDB一樣的二級(jí)數(shù)據(jù)緩存機(jī)制,用來緩存和更新這些State辜妓。
stateObject定義了一種類型名為storage的map結(jié)構(gòu)枯途,用來存放[]Hash,Hash]類型的數(shù)據(jù)對(duì)忌怎,也就是State數(shù)據(jù)。當(dāng)SetState()調(diào)用發(fā)生時(shí)酪夷,storage內(nèi)部State數(shù)據(jù)被更新榴啸,相應(yīng)標(biāo)示為"dirty"。之后晚岭,待有需要時(shí)(比如updateRoot()調(diào)用)鸥印,那些標(biāo)為"dirty"的State數(shù)據(jù)被一起寫入storage trie,而storage trie中的所有內(nèi)容在CommitTo()調(diào)用時(shí)再一起提交到底層數(shù)據(jù)庫坦报。
cachingDB
看代碼封裝了一些對(duì)合約進(jìn)行操作的方法库说,如ContractCode/ContractCodeSize,具體需要后續(xù)研究燎竖。