持续更新中,目前更新到PeerLedgerProvider的实现部分
首先在core/ledger/ledger_interface.go文件中确定了ledger用到的各种接口
PeerLedgerProvider :
给ledger实例提供handle ,代码实现如下
type PeerLedgerProvider interface {
// Create creates a new ledger with the given genesis block.
// This function guarantees that the creation of ledger and committing the genesis block would an atomic action
// The chain id retrieved from the genesis block is treated as a ledger id
Create(genesisBlock *common.Block) (PeerLedger, error)
// Open opens an already created ledger
Open(ledgerID string) (PeerLedger, error)
// Exists tells whether the ledger with given id exists
Exists(ledgerID string) (bool, error)
// List lists the ids of the existing ledgers
List() ([]string, error)
// Close closes the PeerLedgerProvider
Close()
}
方法的实现在core/ledger/kvldger/kv_ledger_provider.go里,在这个文件中还有与blockstore相关的部分。provider与blockstore相关。
provider的结构:
一个DB
三个接口,分别是
1.BlockStoreProvider
2.VersionedDBProvider
3.HistoryDBProvider
新建一个provider,函数实现如下
func NewProvider() (ledger.PeerLedgerProvider, error)
create方法:
从Block中获取chain的id,为chain/block获取Block进行存储,然后commit创始区块
func (provider *Provider) Create(genesisBlock *common.Block) (ledger.PeerLedger, error)
create先从block中获取chaincode的id
ledgerID, err := utils.GetChainIDFromBlock(genesisBlock)
接着创建上面提到的三个provider,并打开相关DB的连接,为chain/block获取存储空间,返回的是一个PeerLdger
ledger, err := provider.openInternal(ledgerID)
过程中创建了kvLedger(Ledger的数据结构实现),代码实现如下:
type kvLedger struct {
ledgerID string
blockStore blkstorage.BlockStore
txtmgmt txmgr.TxMgr
historyDB historydb.HistoryDB
}
最后:
err := ledger.Commit(genesisBlock)
这句是提交create中传入的genesisBlock。具体实现在kv_ledger.go文件中,commit的过程:
1.是验证块,涉及到的新的接口在core/ledger/txmgmt/txmgr/txmgr.go中的TxMgr(具体细节放到以后看);
2.是向storage提交block(获取存储空间);
3.把block中的交易存入state database(注意这里又用到了另一个commit()方法)
4.根据配置文件的配置,决定是否将交易信息写入history database。(这一步可能没有)
到这commit的流程结束。
open方法:
首先根据ledgerID判断kvledger是否存在,代码如下:
exists, err := provider.idStore.ledgerIDExists(ledgerID)
存在就直接根据ledgerID获取存储空间,代码如下:
return provider.openInternal(ledgerID)
不存在就返回nil,并报错。
openinternal方法
为chain/block获取存储空间
func (provider *Provider) openInternal(ledgerID string) (ledger.PeerLedger, error)
具体流程如下:
1.与其他provider连接,代码如下:
blockStore, err := provider.blockStoreProvider.OpenBlockStore(ledgerID)
vDB, err := provider.vdbProvider.GetDBHandle(ledgerID)
historyDB, err := provider.historydbProvider.GetDBHandle(ledgerID)
2.新建一个kvledger,代码如下:
l, err := newKVLedger(ledgerID, blockStore, vDB, historyDB)
newKVLedger代码如下:
func newKVLedger(ledgerID string, blockStore blkstorage.BlockStore,versionedDB statedb.VersionedDB, historyDB historydb.HistoryDB) (*kvLedger, error)
流程如下:
2.1.初始化一个transaction manager,代码如下:
var txmgmt txmgr.TxMgr
txmgmt = lockbasedtxmgr.NewLockBasedTxMgr(versionedDB)
2.2.赋值,代码如下:
l := &kvLedger{ledgerID, blockStore, txmgmt, historyDB}
2.3如果它们与块存储不同步,则可以恢复状态数据库和历史数据库,代码如下:
err := l.recoverDBs()
PeerLedger :
与OrderLedger不同的是维护一个位掩码,用来区分有效交易和无效交易,代码实现如下:
type PeerLedger interface {
commonledger.Ledger
// GetTransactionByID retrieves a transaction by id
GetTransactionByID(txID string) (*peer.ProcessedTransaction, error)
// GetBlockByHash returns a block given it's hash
GetBlockByHash(blockHash []byte) (*common.Block, error)
// GetBlockByTxID returns a block which contains a transaction
GetBlockByTxID(txID string) (*common.Block, error)
// GetTxValidationCodeByTxID returns reason code of transaction validation
GetTxValidationCodeByTxID(txID string) (peer.TxValidationCode, error)
// NewTxSimulator gives handle to a transaction simulator.
// A client can obtain more than one 'TxSimulator's for parallel execution.
// Any snapshoting/synchronization should be performed at the implementation level if required
NewTxSimulator() (TxSimulator, error)
// NewQueryExecutor gives handle to a query executor.
// A client can obtain more than one 'QueryExecutor's for parallel execution.
// Any synchronization should be performed at the implementation level if required
NewQueryExecutor() (QueryExecutor, error)
// NewHistoryQueryExecutor gives handle to a history query executor.
// A client can obtain more than one 'HistoryQueryExecutor's for parallel execution.
// Any synchronization should be performed at the implementation level if required
NewHistoryQueryExecutor() (HistoryQueryExecutor, error)
//Prune prunes the blocks/transactions that satisfy the given policy
Prune(policy commonledger.PrunePolicy) error
}
ValidatedLedger :
代表的是去掉所有无效交易的PeerLedger,代码实现如下:
type ValidatedLedger interface {
commonledger.Ledger
}
QueryExecutor :
字面意思用来执行查询,代码实现如下:
type QueryExecutor interface {
// GetState gets the value for given namespace and key. For a chaincode, the namespace corresponds to the chaincodeId
GetState(namespace string, key string) ([]byte, error)
// GetStateMultipleKeys gets the values for multiple keys in a single call
GetStateMultipleKeys(namespace string, keys []string) ([][]byte, error)
// GetStateRangeScanIterator returns an iterator that contains all the key-values between given key ranges.
// startKey is included in the results and endKey is excluded. An empty startKey refers to the first available key
// and an empty endKey refers to the last available key. For scanning all the keys, both the startKey and the endKey
// can be supplied as empty strings. However, a full scan shuold be used judiciously for performance reasons.
// The returned ResultsIterator contains results of type *KV which is defined in protos/ledger/queryresult.
GetStateRangeScanIterator(namespace string, startKey string, endKey string) (commonledger.ResultsIterator, error)
// ExecuteQuery executes the given query and returns an iterator that contains results of type specific to the underlying data store.
// Only used for state databases that support query
// For a chaincode, the namespace corresponds to the chaincodeId
// The returned ResultsIterator contains results of type *KV which is defined in protos/ledger/queryresult.
ExecuteQuery(namespace, query string) (commonledger.ResultsIterator, error)
// Done releases resources occupied by the QueryExecutor
Done()
}
HistoryQueryExecutor:
执行历史查询,代码实现如下:
type HistoryQueryExecutor interface {
// GetHistoryForKey retrieves the history of values for a key.
// The returned ResultsIterator contains results of type *KeyModification which is defined in protos/ledger/queryresult.
GetHistoryForKey(namespace string, key string) (commonledger.ResultsIterator, error)
}
TxSimulator :
模拟了一条交易,该交易的快照是“尽可能是最近状态”,代码如下:
type TxSimulator interface {
QueryExecutor
// SetState sets the given value for the given namespace and key. For a chaincode, the namespace corresponds to the chaincodeId
SetState(namespace string, key string, value []byte) error
// DeleteState deletes the given namespace and key
DeleteState(namespace string, key string) error
// SetMultipleKeys sets the values for multiple keys in a single call
SetStateMultipleKeys(namespace string, kvs map[string][]byte) error
// ExecuteUpdate for supporting rich data model (see comments on QueryExecutor above)
ExecuteUpdate(query string) error
// GetTxSimulationResults encapsulates the results of the transaction simulation.
// This should contain enough detail for
// - The update in the state that would be caused if the transaction is to be committed
// - The environment in which the transaction is executed so as to be able to decide the validity of the environment
// (at a later time on a different peer) during committing the transactions
// Different ledger implementation (or configurations of a single implementation) may want to represent the above two pieces
// of information in different way in order to support different data-models or optimize the information representations.
GetTxSimulationResults() ([]byte, error)
}
以上接口涉及到的其他文件中的接口:
在common/ledger/ledger_interface.go中:
Ledger接口:
Ledger捕捉“PeerLedger”,“OrdererLedger”和“ValidatedLedger”中常见的方法。代码实现如下:
type Ledger interface {
// GetBlockchainInfo returns basic info about blockchain
GetBlockchainInfo() (*common.BlockchainInfo, error)
// GetBlockByNumber returns block at a given height
// blockNumber of math.MaxUint64 will return last block
GetBlockByNumber(blockNumber uint64) (*common.Block, error)
// GetBlocksIterator returns an iterator that starts from `startBlockNumber`(inclusive).
// The iterator is a blocking iterator i.e., it blocks till the next block gets available in the ledger
// ResultsIterator contains type BlockHolder
GetBlocksIterator(startBlockNumber uint64) (ResultsIterator, error)
// Close closes the ledger
Close()
// Commit adds a new block
Commit(block *common.Block) error
}