以太坊geth结构解析和源码分析
原文地址: http://blog.csdn.net/DDFFR/article/details/74389051
第一部分 看看geth客戶端的整體結(jié)構(gòu)?
創(chuàng)建私鏈的時候已經(jīng)指定所有的信息都放在private-geth目錄下,現(xiàn)在是已經(jīng)有過挖礦的目錄。
當(dāng)時我們把創(chuàng)世文件genesis.json放在該目錄下了、
root@i-5tthrr8u:/home/ubuntu/private-geth# ll total 16 drwxr-xr-x 3 root root 4096 Jul 2 17:02 ./ drwxr-xr-x 6 ubuntu ubuntu 4096 Jul 4 14:07 ../ drwx------ 5 root root 4096 Jul 2 17:41 data/ -rw-r--r-- 1 root root 529 Jul 2 16:29 genesis.json- 1
- 2
- 3
- 4
- 5
- 6
進入真正的存放數(shù)據(jù)的目錄private-geth/data/00?
geth中保存的是區(qū)塊鏈的相關(guān)數(shù)據(jù)?
keystore中保存的是該鏈條中的用戶信息
- 1
- 2
- 3
- 4
- 5
- 6
- 7
之前我們這個節(jié)點已經(jīng)創(chuàng)建了兩個賬戶,現(xiàn)在我們可以看到keystore里面有兩個賬戶信息的文件
root@i-5tthrr8u:/home/ubuntu/private-geth/data/00/keystore# ll total 16 drwx------ 2 root root 4096 Jul 2 17:10 ./ drwx------ 4 root root 4096 Jul 2 17:23 ../ -rw------- 1 root root 491 Jul 2 17:02 UTC--2017-07-02T09-02-56.470592674Z--28b769b3b9109afd1e9e50a9312c5a3bfae8a699 -rw------- 1 root root 491 Jul 2 17:10 UTC--2017-07-02T09-10-28.087401309Z--b4e2e2514eae3684157bf34a0cee2c07c431cf92- 1
- 2
- 3
- 4
- 5
- 6
每個賬戶都由一對鑰匙定義,一個私鑰和一個公鑰。 賬戶以地址為索引,地址由公鑰衍生而來,取公鑰的最后 20個字節(jié)。每對私鑰 /地址都編碼在一個鑰匙文件里。鑰匙文件是JSON文本文件,可以用任何文本編輯器打開和瀏覽。鑰匙文件的關(guān)鍵部分,賬戶私鑰,通常用你創(chuàng)建帳戶時設(shè)置的密碼進行加密。鑰匙文件的文件名格式為UTC。賬號列出時是按字母順序排列,但是由于時間戳格式,實際上它是按創(chuàng)建順序排列。如果把秘鑰丟了鑰匙文件可以在以太坊節(jié)點數(shù)據(jù)目錄的keystore子目錄下找到,接下來我們進入一個keystore目錄文件看看他的信息:
root@i-5tthrr8u:/home/ubuntu/private-geth/data/00/keystore# vim UTC--2017-07-02T09-02-56.470592674Z--28b769b3b9109afd1e9e50a9312c5a3bfae8a699 {"address":"28b769b3b9109afd1e9e50a9312c5a3bfae8a699", "crypto":{ "cipher":"aes-128-ctr", "ciphertext":"89ce1513b4b5a325735891b559c361ce696bb2c173a7a1b290549e79dad8f847", "cipherparams":{"iv":"982c86418fae2dd39e04d1e51528cffa"}, "kdf":"scrypt", "kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"4227384ea0e3d15af1bac190f7e01d392543d0a5ca1ec931c1d340f87845f771"}, "mac":"46cffc6e4f57fa27b69e53dc4ae43a03ce1b93f24c132aa4655f53ddf215f112"}, "id":"e516b9d4-2161-4648-b3db-fc2ef1c3739c", "version":3 }- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
警告:記住密碼并”備份鑰匙文件”。為了從賬號發(fā)送交易,包括發(fā)送以太幣,你必須同時有鑰匙文件和密碼。確保鑰匙文件有個備份并牢記密碼,盡可能安全地存儲它們。這里沒有逃亡路徑,如果鑰匙文件丟失或忘記密碼,就會丟失所有的以太幣。沒有密碼不可能進入賬號,也沒有忘記密碼選項。所以一定不要忘記密碼。
接下來進入geth可以看到chaindata,lightchaindata,nodes目錄
root@i-5tthrr8u:/home/ubuntu/private-geth/data/00/geth# ll total 24 drwxr-xr-x 5 root root 4096 Jul 2 17:02 ./ drwx------ 4 root root 4096 Jul 2 17:23 ../ drwxr-xr-x 2 root root 4096 Jul 4 14:12 chaindata/ drwxr-xr-x 2 root root 4096 Jul 2 17:02 lightchaindata/ -rw-r--r-- 1 root root 0 Jul 2 17:02 LOCK -rw------- 1 root root 64 Jul 2 17:02 nodekey drwxr-xr-x 2 root root 4096 Jul 4 15:55 nodes/- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
進入nodes(我們這條私鏈有三個節(jié)點,所以這里有三個ldb文件)
root@i-5tthrr8u:/home/ubuntu/private-geth/data/00/geth/nodes# ll total 5316 drwxr-xr-x 2 root root 4096 Jul 4 15:55 ./ drwxr-xr-x 5 root root 4096 Jul 2 17:02 ../ -rw-r--r-- 1 root root 405250 Jul 4 15:57 000033.log -rw-r--r-- 1 root root 2132979 Jul 4 15:55 000035.ldb -rw-r--r-- 1 root root 2131238 Jul 4 15:55 000036.ldb -rw-r--r-- 1 root root 739354 Jul 4 15:55 000037.ldb -rw-r--r-- 1 root root 16 Jul 4 14:12 CURRENT -rw-r--r-- 1 root root 0 Jul 2 17:02 LOCK -rw-r--r-- 1 root root 8187 Jul 4 15:55 LOG -rw-r--r-- 1 root root 4557 Jul 4 15:55 MANIFEST-000013- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
進入chaindata,區(qū)塊鏈最后的本地存儲都是以ldb文件的形勢(但這里是不是應(yīng)該每個區(qū)塊一個ldb文件呢?)
root@i-5tthrr8u:/home/ubuntu/private-geth/data/00/geth/chaindata# ll total 52 drwxr-xr-x 2 root root 4096 Jul 5 09:51 ./ drwxr-xr-x 5 root root 4096 Jul 2 17:02 ../ -rw-r--r-- 1 root root 5288 Jul 2 17:56 000008.ldb -rw-r--r-- 1 root root 11681 Jul 4 14:12 000009.ldb -rw-r--r-- 1 root root 8921 Jul 4 14:13 000010.log -rw-r--r-- 1 root root 16 Jul 4 14:12 CURRENT -rw-r--r-- 1 root root 0 Jul 2 17:02 LOCK -rw-r--r-- 1 root root 2807 Jul 4 14:12 LOG -rw-r--r-- 1 root root 346 Jul 4 14:12 MANIFEST-000011- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
進入Lightchaindata
root@i-5tthrr8u:/home/ubuntu/private-geth/data/00/geth/lightchaindata# ll total 24 drwxr-xr-x 2 root root 4096 Jul 2 17:02 ./ drwxr-xr-x 5 root root 4096 Jul 2 17:02 ../ -rw-r--r-- 1 root root 1237 Jul 2 17:02 000001.log -rw-r--r-- 1 root root 16 Jul 2 17:02 CURRENT -rw-r--r-- 1 root root 0 Jul 2 17:02 LOCK -rw-r--r-- 1 root root 358 Jul 2 17:02 LOG -rw-r--r-- 1 root root 54 Jul 2 17:02 MANIFEST-000000- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
第二部分 看看源碼的結(jié)構(gòu)
1 Core/types/block.go?
首先看到的是一個區(qū)塊的結(jié)構(gòu)
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
2 這是一個交易的結(jié)構(gòu)體?
Core/types/transaction.go
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
3 Receiptroot我們剛剛在區(qū)塊頭有看到,那他具體包含的是什么呢?它是一個交易的結(jié)果,主要包括了poststate,交易所花費的gas,bloom和logs
// Receipt represents the results of a transaction. type Receipt struct {// Consensus fields PostState []byte `json:"root" gencodec:"required"` CumulativeGasUsed *big.Int `json:"cumulativeGasUsed" gencodec:"required"` Bloom Bloom `json:"logsBloom" gencodec:"required"` Logs []*Log `json:"logs" gencodec:"required"` // Implementation fields (don't reorder!) TxHash common.Hash `json:"transactionHash" gencodec:"required"` ContractAddress common.Address `json:"contractAddress"` GasUsed *big.Int `json:"gasUsed" gencodec:"required"` }- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
4 一個個交易被打包到區(qū)塊上面,那區(qū)塊又是怎么變成去快鏈的呢??
Core/blockchain.go
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
注意:1. BlockChain無結(jié)構(gòu)化查詢需求,僅Hash查詢, Key/Value數(shù)據(jù)庫最方便; 2. 低層用LevelDB存儲,性能好
5 stateDB用來存儲世界狀態(tài)?
Core/state/statedb.go
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
注意:1. StateDB完整記錄Transaction的執(zhí)行情況; 2. StateDB的重點是StateObjects; 3. StateDB中的 stateObjects,Account的Address為 key,記錄其Balance、nonce、code、codeHash ,以及tire中的 {string:Hash}等信息;
那我們接下來看看stateObject結(jié)構(gòu)體?
Core/state/state_object.go
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
再看看state的一個接口,可以查看賬戶的余額,nonce,代碼和storage
// ChainStateReader wraps access to the state trie of the canonical blockchain. Note that implementations of the interface may be unable to return state values for old blocks. // In many cases, using CallContract can be preferable to reading raw contract storage.type ChainStateReader interface {BalanceAt(ctx context.Context, account common.Address, blockNumber *big.Int) (*big.Int, error)StorageAt(ctx context.Context, account common.Address, key common.Hash, blockNumber *big.Int) ([]byte, error)CodeAt(ctx context.Context, account common.Address, blockNumber *big.Int) ([]byte, error)NonceAt(ctx context.Context, account common.Address, blockNumber *big.Int) (uint64, error) }- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
所有的結(jié)構(gòu)湊明朗了,那具體的驗證過程是怎么樣的呢?
Core/state_processor.go?
Core/state_transition.go?
Core/block_validator.go
StateProcessor 1. 調(diào)用StateTransition,驗證(執(zhí)行)Transaction; 2. 計算Gas、Recipt、Uncle Reward
// StateProcessor is a basic Processor, which takes care of transitioning // state from one point to another. // // StateProcessor implements Processor. type StateProcessor struct {config *params.ChainConfig // Chain configuration optionsbc *BlockChain // Canonical block chainengine consensus.Engine // Consensus engine used for block rewards }- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
StateTransition?
1. 驗證(執(zhí)行)Transaction;?
3. 扣除transaction.data.payload計算數(shù)據(jù)所需要消耗的gas;?
4. 在vm中執(zhí)行code(生成contract or 執(zhí)行contract);vm執(zhí) 行過程中,其gas會被自動消耗。如果gas不足,vm會自 選退出;?
5. 將多余的gas退回到sender.balance中;?
6. 將消耗的gas換成balance加到當(dāng)前env.Coinbase()中;
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
BlockValidator?
1. 驗證UsedGas?
2. 驗證Bloom?
3. 驗證receiptSha?
4. 驗證stateDB.IntermediateRoot
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
可以注意到剛才的state和block都是寫進db數(shù)據(jù)庫的,那我們看一下leveldb數(shù)據(jù)庫結(jié)構(gòu)
type LDBDatabase struct {fn string // filename for reportingdb *leveldb.DB // LevelDB instancegetTimer gometrics.Timer // Timer for measuring the database get request counts and latenciesputTimer gometrics.Timer // Timer for measuring the database put request counts and latenciesdelTimer gometrics.Timer // Timer for measuring the database delete request counts and latenciesmissMeter gometrics.Meter // Meter for measuring the missed database get requestsreadMeter gometrics.Meter // Meter for measuring the database get request data usagewriteMeter gometrics.Meter // Meter for measuring the database put request data usagecompTimeMeter gometrics.Meter // Meter for measuring the total time spent in database compactioncompReadMeter gometrics.Meter // Meter for measuring the data read during compactioncompWriteMeter gometrics.Meter // Meter for measuring the data written during compactionquitLock sync.Mutex // Mutex protecting the quit channel accessquitChan chan chan error // Quit channel to stop the metrics collection before closing the databaselog log.Logger // Contextual logger tracking the database path }- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 1
- 2
- 3
- 4
- 5
- 6
- 7
總結(jié)
以上是生活随笔為你收集整理的以太坊geth结构解析和源码分析的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Ethereum Bootstrap 以
- 下一篇: 智能合约调用示例