Blockchain tutorial Fabric1.0 source code analysis Ledger statedb (state database)

Keywords: Blockchain Database

Ledger (statedb) of Fabric 1.0 source code note

1. Overview of statedb

statedb, or VersionedDB, the state database, stores the latest values of all keys in the transaction log, also known as world state.
You can choose to implement it based on leveldb or cauchdb.

Statedb. The code is distributed in the core/ledger/kvledger/txmgmt/statedb directory. The directory structure is as follows:

  • statedb.go, which defines the core interfaces VersionedDBProvider, VersionedDB, resultsinterator and QueryResult, as well as the UpdateBatch and nsIterator structures and methods.
  • util.go, including the implementation of the utility functions EncodeValue and DecodeValue.
  • The stateleveldb directory, the level dB version implementation of the VersionedDBProvider and VersionedDB interfaces, namely the stateleveldb.VersionedDBProvider and stateleveldb.versionedDB structures and methods.
  • Statecouchdb directory, couchdb version implementation of VersionedDBProvider and VersionedDB interface, namely statecouchdb.VersionedDBProvider and statecouchdb.VersionedDB structure and method.

2. Definition of core interface

VersionedDBProvider interface definition:

type VersionedDBProvider interface {
    GetDBHandle(id string) (VersionedDB, error) //Get VersionedDB handle
    Close() //Close all VersionedDB instances
}
//The code is in core/ledger/kvledger/txmgmt/statedb/statedb.go

VersionedDB interface definition:

type VersionedDB interface {
    //Gets the value of the given namespace and key
    GetState(namespace string, key string) (*VersionedValue, error)
    //Get the value of multiple keys in a single call
    GetStateMultipleKeys(namespace string, keys []string) ([]*VersionedValue, error)
    //Returns an iterator containing all key values (including startKey, excluding endKey) between the given key ranges
    GetStateRangeScanIterator(namespace string, startKey string, endKey string) (ResultsIterator, error)
    //Executes the given query and returns the iterator
    ExecuteQuery(namespace, query string) (ResultsIterator, error)
    //Batch application
    ApplyUpdates(batch *UpdateBatch, height *version.Height) error
    //Returns the height of the highest consistent transaction of statedb
    GetLatestSavePoint() (*version.Height, error)
    //Test whether the database supports this key (leveldb supports any bytes, while couchdb only supports utf-8 strings)
    ValidateKey(key string) error
    //Open db
    Open() error
    //Close db
    Close()
}
//The code is in core/ledger/kvledger/txmgmt/statedb/statedb.go

ResultsIterator and QueryResult interface definitions:

type ResultsIterator interface {
    Next() (QueryResult, error)
    Close()
}

type QueryResult interface{}
//The code is in core/ledger/kvledger/txmgmt/statedb/statedb.go

Supplement CompositeKey, VersionedValue and VersionedKV structures:

type CompositeKey struct {
    Namespace string //Namespace
    Key       string //Key
}

type VersionedValue struct {
    Value   []byte //Value
    Version *version.Height //Edition
}

type VersionedKV struct {
    CompositeKey //Embed CompositeKey
    VersionedValue //Embedded VersionedValue
}
//The code is in core/ledger/kvledger/txmgmt/statedb/statedb.go

nsUpdates structure and method:

type nsUpdates struct {
    m map[string]*VersionedValue //string is Key
}

func newNsUpdates() *nsUpdates//Construct nsUpdates
//The code is in core/ledger/kvledger/txmgmt/statedb/statedb.go

UpdateBatch structure and method:

type UpdateBatch struct {
    updates map[string]*nsUpdates //string is Namespace
}

//Construct UpdateBatch
func NewUpdateBatch() *UpdateBatch
//Press namespace and key to get Value
func (batch *UpdateBatch) Get(ns string, key string) *VersionedValue
//Press namespace and key to add Value
func (batch *UpdateBatch) Put(ns string, key string, value []byte, version *version.Height)
//Press namespace and key to delete the Value, which is set to nil
func (batch *UpdateBatch) Delete(ns string, key string, version *version.Height)
//Press namespace and key to find if it exists
func (batch *UpdateBatch) Exists(ns string, key string) bool
//Get updated namespace list
func (batch *UpdateBatch) GetUpdatedNamespaces() []string
//Press namespace to get nsUpdates
func (batch *UpdateBatch) GetUpdates(ns string) map[string]*VersionedValue
//Construct nsIterator
func (batch *UpdateBatch) GetRangeScanIterator(ns string, startKey string, endKey string) ResultsIterator
//Get or create nsUpdates by namespace
func (batch *UpdateBatch) getOrCreateNsUpdates(ns string) *nsUpdates
//The code is in core/ledger/kvledger/txmgmt/statedb/statedb.go

Nstiterator structure and method:

type nsIterator struct {
    ns         string //namespace
    nsUpdates  *nsUpdates //batch.updates[ns]
    sortedKeys []string //key sorting in nsUpdates.m
    nextIndex  int //startKey
    lastIndex  int //endKey
}

//Construct nsIterator
func newNsIterator(ns string, startKey string, endKey string, batch *UpdateBatch) *nsIterator
func (itr *nsIterator) Next() (QueryResult, error) //Press itr.nextIndex to get VersionedKV
func (itr *nsIterator) Close() // do nothing
//The code is in core/ledger/kvledger/txmgmt/statedb/statedb.go

3. statedb based on leveldb

3.1 implementation of VersionedDB interface

The versioneddb interface implementation, that is, the versioneddb structure, is defined as follows:

type versionedDB struct {
    db     *leveldbhelper.DBHandle //leveldb
    dbName string //dbName
}
//The code is in core/ledger/kvledger/txmgmt/statedb/stateleveldb/stateleveldb.go

The methods involved are as follows:

//Construct versionedDB
func newVersionedDB(db *leveldbhelper.DBHandle, dbName string) *versionedDB
func (vdb *versionedDB) Open() error // do nothing
func (vdb *versionedDB) Close() // do nothing
func (vdb *versionedDB) ValidateKey(key string) error // do nothing
//Press namespace and key to get Value
func (vdb *versionedDB) GetState(namespace string, key string) (*statedb.VersionedValue, error)
//Get the value of multiple keys in a single call
func (vdb *versionedDB) GetStateMultipleKeys(namespace string, keys []string) ([]*statedb.VersionedValue, error)
//Returns an iterator containing all key values (including startKey, excluding endKey) between the given key ranges
func (vdb *versionedDB) GetStateRangeScanIterator(namespace string, startKey string, endKey string) (statedb.ResultsIterator, error)
//leveldb does not support the ExecuteQuery method
func (vdb *versionedDB) ExecuteQuery(namespace, query string) (statedb.ResultsIterator, error)
//Batch application
func (vdb *versionedDB) ApplyUpdates(batch *statedb.UpdateBatch, height *version.Height) error
//Returns the height of the highest consistent transaction of statedb
func (vdb *versionedDB) GetLatestSavePoint() (*version.Height, error)
//Splice ns and key, ns []byte{0x00} key
func constructCompositeKey(ns string, key string) []byte
//Split ns and key, separator [] byte{0x00}
func splitCompositeKey(compositeKey []byte) (string, string)
//The code is in core/ledger/kvledger/txmgmt/statedb/stateleveldb/stateleveldb.go

func (vdb *versionedDB) ApplyUpdates(batch *statedb.UpdateBatch, height *version.Height) error code is as follows:

dbBatch := leveldbhelper.NewUpdateBatch()
namespaces := batch.GetUpdatedNamespaces() //Get updated namespace list
for _, ns := range namespaces {
    updates := batch.GetUpdates(ns) //Press namespace to get nsUpdates
    for k, vv := range updates {
        compositeKey := constructCompositeKey(ns, k) //Splicing ns and key
        if vv.Value == nil {
            dbBatch.Delete(compositeKey)
        } else {
            dbBatch.Put(compositeKey, statedb.EncodeValue(vv.Value, vv.Version))
        }
    }
}
//statedb the height of the highest consistent transaction
dbBatch.Put(savePointKey, height.ToBytes()) //var savePointKey = []byte{0x00}
err := vdb.db.WriteBatch(dbBatch, true)
//The code is in core/ledger/kvledger/txmgmt/statedb/stateleveldb/stateleveldb.go

3.2. Implementation of ResultsIterator interface

The results iterator interface implementation is kvScanner structure and method.

type kvScanner struct {
    namespace string
    dbItr     iterator.Iterator
}

//Construct kvScanner
func newKVScanner(namespace string, dbItr iterator.Iterator) *kvScanner
//Get statedb.VersionedKV iteratively
func (scanner *kvScanner) Next() (statedb.QueryResult, error)
func (scanner *kvScanner) Close() //Release iterator
//The code is in core/ledger/kvledger/txmgmt/statedb/stateleveldb/stateleveldb.go

3.3 implementation of VersionedDBProvider interface

VersionedDBProvider interface implementation, that is, VersionedDBProvider structure and method.

type VersionedDBProvider struct {
    dbProvider *leveldbhelper.Provider
}

func NewVersionedDBProvider() *VersionedDBProvider //Construct VersionedDBProvider
//Get statedb.VersionedDB
func (provider *VersionedDBProvider) GetDBHandle(dbName string) (statedb.VersionedDB, error)
func (provider *VersionedDBProvider) Close() //Close statedb.VersionedDB
//The code is in core/ledger/kvledger/txmgmt/statedb/stateleveldb/stateleveldb.go

4. statedb based on cauchdb

Temporarily omitted, to be added. Welcome to continue to follow brotherhood blockchain tutorial sharing!

Posted by Nommy on Thu, 12 Dec 2019 06:47:44 -0800