In addition to Weibo, there is also WeChat
Please pay attention
WeChat public account
Shulou
2025-02-24 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Internet Technology >
Share
Shulou(Shulou.com)06/01 Report--
这篇文章主要为大家分析了如何进行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 -> headertdSuffix = []byte("t") // headerPrefix + num (uint64 big endian) + hash + tdSuffix -> tdnumSuffix = []byte("n") // headerPrefix + num (uint64 big endian) + numSuffix -> hashblockHashPrefix = []byte("H") // blockHashPrefix + hash -> num (uint64 big endian)bodyPrefix = []byte("b") // bodyPrefix + num (uint64 big endian) + hash -> block body
其中headerPrefix定义了区块头key的前缀为h,bodyPrefix定义了区块体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函数分别调用WriteBody和WriteHeader将区块写到数据库中。此外还有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区块存储的源码剖析"就介绍到这了,更多相关内容可以搜索以前的文章,希望能够帮助大家答疑解惑,请多多支持网站!
Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.
Views: 0
*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.
Continue with the installation of the previous hadoop.First, install zookooper1. Decompress zookoope
"Every 5-10 years, there's a rare product, a really special, very unusual product that's the most un
© 2024 shulou.com SLNews company. All rights reserved.