cool hit counter Derek Explains Bytom Source Code - Persistent Storage LevelDB_Intefrankly

Derek Explains Bytom Source Code - Persistent Storage LevelDB

By Derek

brief introduction

Github address.

Gitee address.

This chapter introduces Derek Explained - Bytom Source Code Analysis - Persistent Storage LevelDB

The author uses the MacOS operating system, and other platforms are much the same

Golang Version: 1.8

Introduction to LevelDB

By default, the Bjorn chain uses the leveldb database. Leveldb is a google implementation of a very efficient kv database. LevelDB is a single-process service with very high performance, over 40w per second of write data and over 10w per second of random read performance on a 4-core Q6600 CPU machine.

 Since Leveldb is a single-process service, you cannot have multiple processes reading and writing to a database at the same time. Only one process, or one process with multiple concurrent reads and writes, can be running at the same time.

The Bikara chain stores all on-chain addresses, asset transactions, and other information on the data storage layer.

LevelDB's add, delete, and check operations

LevelDB is a high performance K/V store developed by google, in this section we describe how LevelDB adds, deletes, and checks to LevelDB.

package main

import (

	dbm ""

var (
	Key        = "TESTKEY"
	LevelDBDir = "/tmp/data"

func main() {
	db := dbm.NewDB("test", "leveldb", LevelDBDir)
	defer db.Close()

	db.Set([]byte(Key), []byte("This is a test."))

	value := db.Get([]byte(Key))
	if value == nil {
	fmt.Printf("key:%v, value:%v
", Key, string(value))


// Output
// key:TESTKEY, value:This is a test.

Output above is the output obtained by executing the program.

The program performs add, delete, and check operations on leveld. dbm. NewDB gets the db object, and a directory called test.db is generated in the /tmp/data directory. This directory holds all the data for this database.

db. Set Set the value of the key, if the key does not exist, create a new one, if the key exists, modify it.

db. Get gets the value data in the key.

db. Delete Delete the data of key and value.

Database of the Bebop chain

By default, the data storage directory is in the data directory under the --home parameter. Using the Darwin platform as an example, the default database is stored in $HOME/Library/Bytom/data.

  • accesstoken.db token information (wallet access control permissions) core.db The core database, which stores data related to the master chain. Includes block information, transaction information, asset information, etc. discover.db End-to-end node information in a distributed network
  • trusthistory.db txdb.db stores transaction-related information txfeeds.db This feature is not currently used by the original chain code version and is not introduced at this time wallet.db Local wallet database. Store information about users, assets, transactions, utox, etc.

All the above databases are managed by the database module

Biebara database interface

The persistent storage of data in the Bjorn chain is managed by the database module, but the persistence-related interfaces are in protocol/store.go

type Store interface {
	BlockExist(*bc.Hash) bool

	GetBlock(*bc.Hash) (*types.Block, error)
	GetStoreStatus() *BlockStoreState
	GetTransactionStatus(*bc.Hash) (*bc.TransactionStatus, error)
	GetTransactionsUtxo(*state.UtxoViewpoint, []*bc.Tx) error
	GetUtxo(*bc.Hash) (*storage.UtxoEntry, error)

	LoadBlockIndex() (*state.BlockIndex, error)
	SaveBlock(*types.Block, *bc.TransactionStatus) error
	SaveChainStatus(*state.BlockNode, *state.UtxoViewpoint) error
  • BlockExist determines if a block exists based on its hash
  • GetBlock gets the block based on the hash
  • GetStoreStatus Get the store's storage status
  • GetTransactionStatus gets the status of all transactions in the block based on the hash
  • GetTransactionsUtxo cache all utxo associated with the input txs
  • GetUtxo(*bc. Hash) Get all utxo within the block based on the hash
  • LoadBlockIndex loads the block index, reads all block header information from the db and caches it in memory
  • SaveBlock Stores block and transaction status
  • SaveChainStatus sets the status of the master chain. When the node is first started, the node determines whether to initialize the master chain based on the content of the blockStore with key.

Key prefix of the Bjorn database


var (
	blockStoreKey     = []byte("blockStore")
	blockPrefix       = []byte("B:")
	blockHeaderPrefix = []byte("BH:")
	txStatusPrefix    = []byte("BTS:")
  • blockStoreKey Main chain status prefix
  • blockPrefix Block information prefix
  • blockHeaderPrefix Block header information prefix
  • txStatusPrefix Transaction status prefix

Analysis of the GetBlock query block process


func (s *Store) GetBlock(hash *bc.Hash) (*types.Block, error) {
	return s.cache.lookup(hash)


func (c *blockCache) lookup(hash *bc.Hash) (*types.Block, error) {
	if b, ok := c.get(hash); ok {
		return b, nil

	block, err := c.single.Do(hash.String(), func() (interface{}, error) {
		b := c.fillFn(hash)
		if b == nil {
			return nil, fmt.Errorf("There are no block with given hash %s", hash.String())

		return b, nil
	if err != nil {
		return nil, err
	return block.(*types.Block), nil

The GetBlock function will eventually execute the lookup function. The lookup function operates in a total of two steps.

  • Query the hash value from the cache and return it if found
  • If it is a query from the cache then the fillFn callback function is called back. The fillFn callback function stores the block information obtained from the disk into the cache and returns the information about the block.

The fillFn callback function actually calls GetBlock under database/leveldb/store.go, which gets the block information from the disk and returns it.

1、Worlds first Android mining worm outbreak turns smart TVs into mining machines

    已推荐到看一看 和朋友分享想法
    最多200字,当前共 发送