中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

如何進行go-ethereum區塊存儲的源碼剖析

發布時間:2022-01-17 17:10:56 來源:億速云 閱讀:173 作者:柒染 欄目:互聯網科技

這篇文章主要為大家分析了如何進行go-ethereum區塊存儲的源碼剖析的相關知識點,內容詳細易懂,操作細節合理,具有一定參考價值。如果感興趣的話,不妨跟著跟隨小編一起來看看,下面跟著小編一起深入學習“如何進行go-ethereum區塊存儲的源碼剖析”的知識吧。

區塊和交易等數據最終都是存儲在leveldb數據庫中的,數據庫的存儲位置在datadir/geth/chaindata中,本文介紹區塊和交易在leveldb中的存儲格式。在core/database_util.go中封裝了所有與區塊存儲和讀取相關的代碼,通過這些代碼可以弄清楚區塊、交易等數據結構在數據庫中是如何存儲的。

區塊存儲

leveldb是一個key-value數據庫,所有數據都是以鍵-值對的形式存儲。key一般與hash相關,value一般是要存儲的數據結構的RLP編碼。區塊存儲時將區塊頭和區塊體分開存儲。

區塊頭的存儲格式為:

headerPrefix + num (uint64 big endian) + hash -> rlpEncode(header)

其中key由區塊頭前綴、區塊號(uint64大端格式)、區塊hash構成,value是區塊頭的RLP編碼。

區塊體的存儲格式為:

bodyPrefix + num (uint64 big endian) + hash -> rlpEncode(block body)

其中key由區塊體前綴、區塊號(uint64大端格式)、區塊hash構成,value是區塊體的RLP編碼。

key中的前綴可以用來區分數據的類型,在core/database_util.go中定義了各種前綴:

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

其中headerPrefix定義了區塊頭key的前綴為hbodyPrefix定義了區塊體key的前綴為b

下面是存儲區塊頭的函數:

// WriteHeader serializes a block header into the database.
func WriteHeader(db ethdb.Database, header *types.Header) error {
	data, err := rlp.EncodeToBytes(header)
	if err != nil {
		return err
	}
	hash := header.Hash().Bytes()
	num := header.Number.Uint64()
	encNum := encodeBlockNumber(num)
	key := append(blockHashPrefix, hash...)
	if err := db.Put(key, encNum); err != nil {
		glog.Fatalf("failed to store hash to number mapping into database: %v", err)
	}
	key = append(append(headerPrefix, encNum...), hash...)
	if err := db.Put(key, data); err != nil {
		glog.Fatalf("failed to store header into database: %v", err)
	}
	glog.V(logger.Debug).Infof("stored header #%v [%x…]", header.Number, hash[:4])
	return nil
}

它是先對區塊頭進行RLP編碼,encodeBlockNumber將區塊號轉換成大端格式,然后組裝key。這里先向數據庫中存儲一條 區塊hash->區塊號 的記錄,最后將區塊頭的RLP編碼寫到數據庫中。

下面是存儲區塊體的函數:

// WriteBody serializes the body of a block into the database.
func WriteBody(db ethdb.Database, hash common.Hash, number uint64, body *types.Body) error {
	data, err := rlp.EncodeToBytes(body)
	if err != nil {
		return err
	}
	return WriteBodyRLP(db, hash, number, data)
}

// WriteBodyRLP writes a serialized body of a block into the database.
func WriteBodyRLP(db ethdb.Database, hash common.Hash, number uint64, rlp rlp.RawValue) error {
	key := append(append(bodyPrefix, encodeBlockNumber(number)...), hash.Bytes()...)
	if err := db.Put(key, rlp); err != nil {
		glog.Fatalf("failed to store block body into database: %v", err)
	}
	glog.V(logger.Debug).Infof("stored block body [%x…]", hash.Bytes()[:4])
	return nil
}

WriteBody先對區塊體進行RLP編碼,然后調用WriteBodyRLP將區塊體的RLP編碼寫到數據庫中。WriteBodyRLP根據上面的規則組裝key,然后向數據庫中寫入一條記錄。

還有一個WriteBlock函數分別調用WriteBodyWriteHeader將區塊寫到數據庫中。此外還有GetHeader GetBody GetBlock函數用于從數據庫中讀取區塊。

交易存儲

除了區塊外,數據庫中還存儲了所有的交易,每條交易的存儲格式如下:

txHash -> rlpEncode(tx)
txHash + txMetaSuffix -> rlpEncode(txMeta)

每條交易對應存儲兩條數據,一條是交易本身,一條是交易的元信息(meta)。交易以交易的hash為key、交易的RLP編碼為value存儲;元信息以txHash+txMetaSuffix為key、元信息的RLP編碼為value存儲。元信息中包含交易所在區塊的區塊hash、區塊號、交易在區塊中的索引。具體可以看WriteTransactions函數:

// WriteTransactions stores the transactions associated with a specific block
// into the given database. Beside writing the transaction, the function also
// stores a metadata entry along with the transaction, detailing the position
// of this within the blockchain.
func WriteTransactions(db ethdb.Database, block *types.Block) error {
	batch := db.NewBatch()

	// Iterate over each transaction and encode it with its metadata
	for i, tx := range block.Transactions() {
		// Encode and queue up the transaction for storage
		data, err := rlp.EncodeToBytes(tx)
		if err != nil {
			return err
		}
		if err := batch.Put(tx.Hash().Bytes(), data); err != nil {
			return err
		}
		// Encode and queue up the transaction metadata for storage
		meta := struct {
			BlockHash  common.Hash
			BlockIndex uint64
			Index      uint64
		}{
			BlockHash:  block.Hash(),
			BlockIndex: block.NumberU64(),
			Index:      uint64(i),
		}
		data, err = rlp.EncodeToBytes(meta)
		if err != nil {
			return err
		}
		if err := batch.Put(append(tx.Hash().Bytes(), txMetaSuffix...), data); err != nil {
			return err
		}
	}
	// Write the scheduled data into the database
	if err := batch.Write(); err != nil {
		glog.Fatalf("failed to store transactions into database: %v", err)
	}
	return nil
}

此外還有GetTransaction函數,根據交易hash從數據庫中讀取交易,它返回對應的交易、交易所在區塊的區塊hash、交易所在區塊的區塊號、交易在區塊中的索引。

關于“如何進行go-ethereum區塊存儲的源碼剖析”就介紹到這了,更多相關內容可以搜索億速云以前的文章,希望能夠幫助大家答疑解惑,請多多支持億速云網站!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

塔河县| 烟台市| 安顺市| 伊川县| 新泰市| 云霄县| 安远县| 望城县| 长阳| 金川县| 古田县| 紫阳县| 大埔县| 西丰县| 绿春县| 南京市| 苍溪县| 马关县| 象山县| 新宁县| 隆昌县| 神木县| 沽源县| 泗阳县| 新民市| 交口县| 扎鲁特旗| 江山市| 鞍山市| 拜泉县| 阜康市| 上林县| 望江县| 靖州| 余江县| 张家口市| 玉门市| 韶关市| 卓资县| 广州市| 兴海县|