以太坊ブロックデータストレージと検索プロセス

6775 ワード

イーサー坊ブロックデータストレージ


接頭辞
core/rawdb/schema.go
// databaseVerisionKey tracks the current database version.
databaseVerisionKey = []byte("DatabaseVersion")

// headHeaderKey tracks the latest know header's hash.
headHeaderKey = []byte("LastHeader")

// headBlockKey tracks the latest know full block's hash.
headBlockKey = []byte("LastBlock")

// headFastBlockKey tracks the latest known incomplete block's hash during fast sync.
headFastBlockKey = []byte("LastFast")

// fastTrieProgressKey tracks the number of trie entries imported during fast sync.
fastTrieProgressKey = []byte("TrieSync")

// Data item prefixes (use single byte to avoid mixing data types, avoid `i`, used for indexes).
headerPrefix       = []byte("h") // headerPrefix + num (uint64 big endian) + hash -> header
headerTDSuffix     = []byte("t") // headerPrefix + num (uint64 big endian) + hash + headerTDSuffix -> td
headerHashSuffix   = []byte("n") // headerPrefix + num (uint64 big endian) + headerHashSuffix -> hash
headerNumberPrefix = []byte("H") // headerNumberPrefix + hash -> num (uint64 big endian)

blockBodyPrefix     = []byte("b") // blockBodyPrefix + num (uint64 big endian) + hash -> block body
blockReceiptsPrefix = []byte("r") // blockReceiptsPrefix + num (uint64 big endian) + hash -> block receipts

txLookupPrefix  = []byte("l") // txLookupPrefix + hash -> transaction/receipt lookup metadata
bloomBitsPrefix = []byte("B") // bloomBitsPrefix + bit (uint16 big endian) + section (uint64 big endian) + hash -> bloom bits

preimagePrefix = []byte("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

ブロックヘッダhashに基づいてブロック高さを格納し、ブロック高さとブロックヘッダhashに基づいてブロックヘッダRLPを符号化して格納する
core/rawdb/accessors_chain.go
func WriteHeader(db DatabaseWriter, header *types.Header) {
	// Write the hash -> number mapping
	var (
		hash    = header.Hash()
		number  = header.Number.Uint64()
		encoded = encodeBlockNumber(number)	//  number 
	)

	key := headerNumberKey(hash)  // key="H"+hash
	if err := db.Put(key, encoded); err != nil {  //   number  
		log.Crit("Failed to store hash to number mapping", "err", err)
	}

	// Write the encoded header
	data, err := rlp.EncodeToBytes(header)		//  RLP 
	if err != nil {
		log.Crit("Failed to RLP encode header", "err", err)
	}

	key = headerKey(number, hash)	// key="h"+number+hash
	if err := db.Put(key, data); err != nil {
		log.Crit("Failed to store header", "err", err)
	}
}

ブロックのRLPを符号化して記憶する

func WriteBody(db DatabaseWriter, hash common.Hash, number uint64, body *types.Body) {
	data, err := rlp.EncodeToBytes(body)
	if err != nil {
		log.Crit("Failed to RLP encode body", "err", err)
	}
	WriteBodyRLP(db, hash, number, data)
}

func WriteBodyRLP(db DatabaseWriter, hash common.Hash, number uint64, rlp rlp.RawValue) {
	if err := db.Put(blockBodyKey(number, hash), rlp); err != nil { // key="b"+number+hash
		log.Crit("Failed to store block body", "err", err)
	}
}

ブロックとブロックヘッダは別々に格納されます

func WriteBlock(db DatabaseWriter, block *types.Block) {
	WriteBody(db, block.Hash(), block.NumberU64(), block.Body())
	WriteHeader(db, block.Header())
}

ブロック高さに応じてブロックヘッダhashを書き込む

func WriteCanonicalHash(db DatabaseWriter, hash common.Hash, number uint64) {
	if err := db.Put(headerHashKey(number), hash.Bytes()); err != nil {	// key="h"+number+"n"
		log.Crit("Failed to store number to hash mapping", "err", err)
	}
}

ブロック高さに基づいてブロックヘッダhashを削除する

func DeleteCanonicalHash(db DatabaseDeleter, number uint64) {
	if err := db.Delete(headerHashKey(number)); err != nil { // key="h"+number+"n"
		log.Crit("Failed to delete number to hash mapping", "err", err)
	}
}

エーテル坊ブロッククエリー


ブロック全体のデータをブロック高で問い合わせる


ブロック番号に基づいてブロックヘッダhashを取得する

func ReadCanonicalHash(db DatabaseReader, number uint64) common.Hash {
	data, _ := db.Get(headerHashKey(number)) // key="h"+number+"n"
	if len(data) == 0 {
		return common.Hash{}
	}
	return common.BytesToHash(data)
}

ブロック番号、ブロックヘッダhashに基づいて、ブロックヘッダのRLP符号化後の値を取得する

func ReadHeaderRLP(db DatabaseReader, hash common.Hash, number uint64) rlp.RawValue {
	data, _ := db.Get(headerKey(number, hash)) // key="h"+number+hash
	return data
}

ブロック番号、ブロックヘッダhashに基づいて、ブロック体のRLP符号化後の値を取得する

func ReadBodyRLP(db DatabaseReader, hash common.Hash, number uint64) rlp.RawValue {
	data, _ := db.Get(blockBodyKey(number, hash))	// key="b"+number+hash
	return data
}

ブロックhashによるブロック全体のデータのクエリー


ブロックヘッダhashに基づいてブロック高さを取得する

func ReadHeaderNumber(db DatabaseReader, hash common.Hash) *uint64 {
	data, _ := db.Get(headerNumberKey(hash))  // key="H"+hash
	if len(data) != 8 {
		return nil
	}
	number := binary.BigEndian.Uint64(data)
	return &number
}

メモリブロックデータ


func (bc *BlockChain) WriteBlockWithState(block *types.Block, receipts []*types.Receipt, state *state.StateDB) (status WriteStatus, err error) {
	...
	rawdb.WriteBlock(bc.db, block)	//  
	bc.insert(block)	
	...
}

func (bc *BlockChain) insert(block *types.Block) {
	...
	rawdb.WriteCanonicalHash(bc.db, block.Hash(), block.NumberU64())	//  hash  
	rawdb.WriteHeadBlockHash(bc.db, block.Hash())
	...
}

まとめ:
  • はブロックを記憶する、ブロックRLPを符号化して記憶する:「b」+number+hash=rlp(body)
  • .
  • 格納ブロックヘッダ、格納ブロック高さ:「H」+hash=number
  • はブロックヘッダを記憶する、ブロックヘッダRLPを符号化して記憶する:「h」+number+hash=rlp(header)
  • .
  • はブロックヘッダhashを記憶し、ブロックヘッダhashを記憶する:key="h"+number+"n"=hashこれでブロックデータ
  • をブロック高さまたはhashで検索することができる.