IBM openblockchain学习(三)--Ledger源码分析

Ledger是总账簿的意思,也就是blockchain中存储交易记录的部分。其代码包含如下,这块代码量大,可能分析时间会很长,希望读者耐心等待。

blockchain

先看下Blockchain在内存中保存的基本信息,Blockchain中的操作不是线程安全的

type blockchain struct {
    size               uint64  //块大小
    previousBlockHash  []byte   //上一个块的哈希
    indexer            blockchainIndexer //块索引
    lastProcessedBlock *lastProcessedBlock  //最后处理的块
}

最后处理的块的结构

type lastProcessedBlock struct {
    block       *protos.Block
    blockNumber uint64  块数
    blockHash   []byte 块哈希值
}

newBlockchain

newBlockchain()用于创建一个区块

func newBlockchain() (*blockchain, error) {
    size, err := fetchBlockchainSizeFromDB()//从数据库中读取blockchain的大小
    if err != nil {
        return nil, err
    }
    blockchain := &blockchain{0, nil, nil, nil}
    blockchain.size = size
    if size > 0 {
        previousBlock, err := fetchBlockFromDB(size - 1)
        //如果为创世区块,则上一个块是创世区块的大小减一
        if err != nil {
            return nil, err
        }
        previousBlockHash, err := previousBlock.GetHash()
        //获取前驱块的哈希
        if err != nil {
            return nil, err
        }
        blockchain.previousBlockHash = previousBlockHash
    }

    err = blockchain.startIndexer()
    //开始创建索引
    if err != nil {
        return nil, err
    }
    return blockchain, nil
}

startIndexer()

创建索引

func (blockchain *blockchain) startIndexer() (err error) {
    if indexBlockDataSynchronously {
        blockchain.indexer = newBlockchainIndexerSync()
        //同步创建区块链索引
    } else {
        blockchain.indexer = newBlockchainIndexerAsync()
    }
    err = blockchain.indexer.start(blockchain)
    return
}

getLastBlock

getLastBlock创建最后区块

func (blockchain *blockchain) getLastBlock() (*protos.Block, error) {
    if blockchain.size == 0 {
        return nil, nil
    }
    return blockchain.getBlock(blockchain.size - 1)
}

getSize

getSize用于返回块大小

func (blockchain *blockchain) getSize() uint64 {
    return blockchain.size
}

getBlock

在blockchain中通过任意高度获取块


func (blockchain *blockchain) getBlock(blockNumber uint64) (*protos.Block, error) {
    return fetchBlockFromDB(blockNumber)
}

getBlockByHash

通过块的哈希获取块

func (blockchain *blockchain) getBlockByHash(blockHash []byte) (*protos.Block, error) {
    blockNumber, err := blockchain.indexer.fetchBlockNumberByBlockHash(blockHash)
    if err != nil {
        return nil, err
    }
    return blockchain.getBlock(blockNumber)
}

getTransactionByUUID

通过UUID获取交易记录

func (blockchain *blockchain) getTransactionByUUID(txUUID string) (*protos.Transaction, error) {
    blockNumber, txIndex, err := blockchain.indexer.fetchTransactionIndexByUUID(txUUID)
    if err != nil {
        return nil, err
    }
    block, err := blockchain.getBlock(blockNumber)
    if err != nil {
        return nil, err
    }
    transaction := block.GetTransactions()[txIndex]
    return transaction, nil
}

getTransactions

通过有块号标识的块获取所有的交易

func (blockchain *blockchain) getTransactions(blockNumber uint64) ([]*protos.Transaction, error) {
    block, err := blockchain.getBlock(blockNumber)
    if err != nil {
        return nil, err
    }
    return block.GetTransactions(), nil
}

getTransactionsByBlockHash

通过块的哈希获取所有的交易

func (blockchain *blockchain) getTransactionsByBlockHash(blockHash []byte) ([]*protos.Transaction, error) {
    block, err := blockchain.getBlockByHash(blockHash)
    if err != nil {
        return nil, err
    }
    return block.GetTransactions(), nil
}

getTransaction

通过数块和确定块内索引获取交易

func (blockchain *blockchain) getTransaction(blockNumber uint64, txIndex uint64) (*protos.Transaction, error) {
    block, err := blockchain.getBlock(blockNumber)
    if err != nil {
        return nil, err
    }
    return block.GetTransactions()[txIndex], nil
}

getTransactionByBlockHash

通过块内块的哈希和标识索引获取交易

func (blockchain *blockchain) getTransactionByBlockHash(blockHash []byte, txIndex uint64) (*protos.Transaction, error) {
    block, err := blockchain.getBlockByHash(blockHash)
    if err != nil {
        return nil, err
    }
    return block.GetTransactions()[txIndex], nil
}

getBlockchainInfo

获取区块链的信息

func (blockchain *blockchain) getBlockchainInfo() (*protos.BlockchainInfo, error) {
    if blockchain.getSize() == 0 {
        return &protos.BlockchainInfo{Height: 0}, nil
    }

    lastBlock, err := blockchain.getLastBlock()
    if err != nil {
        return nil, err
    }

    info := &protos.BlockchainInfo{
        Height:            blockchain.getSize(),
        CurrentBlockHash:  blockchain.previousBlockHash,
        PreviousBlockHash: lastBlock.PreviousBlockHash}

    return info, nil
}

buildBlock

创建块

func (blockchain *blockchain) buildBlock(block *protos.Block, stateHash []byte) *protos.Block {
    block.SetPreviousBlockHash(blockchain.previousBlockHash)
    block.StateHash = stateHash
    return block
}

addPersistenceChangesForNewBlock

对于新块添加持久性的更改

func (blockchain *blockchain) addPersistenceChangesForNewBlock(ctx context.Context,
    block *protos.Block, stateHash []byte, writeBatch *gorocksdb.WriteBatch) (uint64, error) {
    block = blockchain.buildBlock(block, stateHash)
    if block.NonHashData == nil {
        block.NonHashData = &protos.NonHashData{LocalLedgerCommitTimestamp: util.CreateUtcTimestamp()}
    } else {
        block.NonHashData.LocalLedgerCommitTimestamp = util.CreateUtcTimestamp()
    }
    blockNumber := blockchain.size
    blockHash, err := block.GetHash()
    if err != nil {
        return 0, err
    }
    blockBytes, blockBytesErr := block.Bytes()
    if blockBytesErr != nil {
        return 0, blockBytesErr
    }
    writeBatch.PutCF(db.GetDBHandle().BlockchainCF, encodeBlockNumberDBKey(blockNumber), blockBytes)
    writeBatch.PutCF(db.GetDBHandle().BlockchainCF, blockCountKey, encodeUint64(blockNumber+1))
    if blockchain.indexer.isSynchronous() {
        blockchain.indexer.createIndexesSync(block, blockNumber, blockHash, writeBatch)
    }
    blockchain.lastProcessedBlock = &lastProcessedBlock{block, blockNumber, blockHash}
    return blockNumber, nil
}

blockPersistenceStatus

块持久状态

func (blockchain *blockchain) blockPersistenceStatus(success bool) {
    if success {
        blockchain.size++
        blockchain.previousBlockHash = blockchain.lastProcessedBlock.blockHash
        if !blockchain.indexer.isSynchronous() {
            blockchain.indexer.createIndexesAsync(blockchain.lastProcessedBlock.block,
                blockchain.lastProcessedBlock.blockNumber, blockchain.lastProcessedBlock.blockHash)
        }
    }
    blockchain.lastProcessedBlock = nil
}

persistRawBlock

持久化原始块

func (blockchain *blockchain) persistRawBlock(block *protos.Block, blockNumber uint64) error {
    blockBytes, blockBytesErr := block.Bytes()
    if blockBytesErr != nil {
        return blockBytesErr
    }
    writeBatch := gorocksdb.NewWriteBatch()
    defer writeBatch.Destroy()
    writeBatch.PutCF(db.GetDBHandle().BlockchainCF, encodeBlockNumberDBKey(blockNumber), blockBytes)

    // 它需要检查,因为我们在这样的情况下块/状态同步支持乱序块。其真正意义区块链的高度,而不是规模。
    if blockchain.getSize() < blockNumber+1 {
        sizeBytes := encodeUint64(blockNumber + 1)
        writeBatch.PutCF(db.GetDBHandle().BlockchainCF, blockCountKey, sizeBytes)
        blockchain.size = blockNumber + 1
    }
    blockHash, err := block.GetHash()
    if err != nil {
        return err
    }

    if blockchain.indexer.isSynchronous() {
        blockchain.indexer.createIndexesSync(block, blockNumber, blockHash, writeBatch)
    }

    opt := gorocksdb.NewDefaultWriteOptions()
    defer opt.Destroy()
    err = db.GetDBHandle().DB.Write(opt, writeBatch)
    if err != nil {
        return err
    }
    return nil
}

fetchBlockFromDB

从数据库中获取块

func fetchBlockFromDB(blockNumber uint64) (*protos.Block, error) {
    blockBytes, err := db.GetDBHandle().GetFromBlockchainCF(encodeBlockNumberDBKey(blockNumber))
    if err != nil {
        return nil, err
    }
    if blockBytes == nil {
        return nil, nil
    }
    return protos.UnmarshallBlock(blockBytes)
}

fetchTransactionFromDB

从数据库中获取交易记录

func fetchTransactionFromDB(blockNum uint64, txIndex uint64) (*protos.Transaction, error) {
    block, err := fetchBlockFromDB(blockNum)
    if err != nil {
        return nil, err
    }
    return block.GetTransactions()[txIndex], nil
}

fetchBlockchainSizeFromDB

从数据库中获取区块链的大小

func fetchBlockchainSizeFromDB() (uint64, error) {
    bytes, err := db.GetDBHandle().GetFromBlockchainCF(blockCountKey)
    if err != nil {
        return 0, err
    }
    if bytes == nil {
        return 0, nil
    }
    return decodeToUint64(bytes), nil
}

fetchBlockchainSizeFromSnapshot

从快照中获取区块链大小

func fetchBlockchainSizeFromSnapshot(snapshot *gorocksdb.Snapshot) (uint64, error) {
    blockNumberBytes, err := db.GetDBHandle().GetFromBlockchainCFSnapshot(snapshot, blockCountKey)
    if err != nil {
        return 0, err
    }
    var blockNumber uint64
    if blockNumberBytes != nil {
        blockNumber = decodeToUint64(blockNumberBytes)
    }
    return blockNumber, nil
}

String

将区块链的信息以字符串形式输出

func (blockchain *blockchain) String() string {
    var buffer bytes.Buffer
    size := blockchain.getSize()
    for i := uint64(0); i < size; i++ {
        block, blockErr := blockchain.getBlock(i)
        if blockErr != nil {
            return ""
        }
        buffer.WriteString("
----------<block #")
        buffer.WriteString(strconv.FormatUint(i, 10))
        buffer.WriteString(">----------
")
        buffer.WriteString(block.String())
        buffer.WriteString("
----------<\block #")
        buffer.WriteString(strconv.FormatUint(i, 10))
        buffer.WriteString(">----------
")
    }
    return buffer.String()
}

blockchain_indexes

blockchainIndexer定义了以下几个接口

type blockchainIndexer interface {
    //同步标识
    isSynchronous() bool
    //开始创建
    start(blockchain *blockchain) error
    //同步创建索引
    createIndexesSync(block *protos.Block, blockNumber uint64, blockHash []byte, writeBatch *gorocksdb.WriteBatch) error
    //异步创建索引
    createIndexesAsync(block *protos.Block, blockNumber uint64, blockHash []byte) error
    //通过块哈希获取块号
    fetchBlockNumberByBlockHash(blockHash []byte) (uint64, error)
    //通过UUID获取块号
    fetchTransactionIndexByUUID(txUUID string) (uint64, uint64, error)
    //停止创建
    stop()
}

addIndexDataForPersistence

持久化并且检索索引数据

func addIndexDataForPersistence(block *protos.Block, blockNumber uint64, blockHash []byte, writeBatch *gorocksdb.WriteBatch) error {
    openchainDB := db.GetDBHandle()
    cf := openchainDB.IndexesCF

    // 块号映射成块哈希值
    indexLogger.Debug("Indexing block number [%d] by hash = [%x]", blockNumber, blockHash)
    writeBatch.PutCF(cf, encodeBlockHashKey(blockHash), encodeBlockNumber(blockNumber))

    addressToTxIndexesMap := make(map[string][]uint64)
    addressToChaincodeIDsMap := make(map[string][]*protos.ChaincodeID)

    transactions := block.GetTransactions()
    for txIndex, tx := range transactions {
        // 添加TXT UUID - >(块号,索引中块)
        writeBatch.PutCF(cf, encodeTxUUIDKey(tx.Uuid), encodeBlockNumTxIndex(blockNumber, uint64(txIndex)))

        txExecutingAddress := getTxExecutingAddress(tx)
        addressToTxIndexesMap[txExecutingAddress] = append(addressToTxIndexesMap[txExecutingAddress], uint64(txIndex))

        switch tx.Type {
        case protos.Transaction_CHAINCODE_NEW, protos.Transaction_CHAINCODE_UPDATE:
            authroizedAddresses, chaincodeID := getAuthorisedAddresses(tx)
            for _, authroizedAddress := range authroizedAddresses {
                addressToChaincodeIDsMap[authroizedAddress] = append(addressToChaincodeIDsMap[authroizedAddress], chaincodeID)
            }
        }
    }
    for address, txsIndexes := range addressToTxIndexesMap {
        writeBatch.PutCF(cf, encodeAddressBlockNumCompositeKey(address, blockNumber), encodeListTxIndexes(txsIndexes))
    }
    return nil
}

getAuthorisedAddresses

获得授权地址

func getAuthorisedAddresses(tx *protos.Transaction) ([]string, *protos.ChaincodeID) {
    // 从chaincode的部署TX中获取取地址
    // 这个方法也会返回错误
    data := tx.ChaincodeID
    cID := &protos.ChaincodeID{}
    err := proto.Unmarshal(data, cID)
    if err != nil {
        return nil, nil
    }
    return []string{"address1", "address2"}, cID
}

encodeBlockNumber

编码/解码数据库键/值函数,索引数据编码/解码块数


func encodeBlockNumber(blockNumber uint64) []byte {
    return proto.EncodeVarint(blockNumber)
}
func decodeBlockNumber(blockNumberBytes []byte) (blockNumber uint64) {
    blockNumber, _ = proto.DecodeVarint(blockNumberBytes)
    return
}

encodeBlockNumTxIndex

对 块号的Tx索引进行编码/解码

func encodeBlockNumTxIndex(blockNumber uint64, txIndexInBlock uint64) []byte {
    b := proto.NewBuffer([]byte{})
    b.EncodeVarint(blockNumber)
    b.EncodeVarint(txIndexInBlock)
    return b.Bytes()
}

func decodeBlockNumTxIndex(bytes []byte) (blockNum uint64, txIndex uint64, err error) {
    b := proto.NewBuffer(bytes)
    blockNum, err = b.DecodeVarint()
    if err != nil {
        return
    }
    txIndex, err = b.DecodeVarint()
    if err != nil {
        return
    }
    return
}

对区块哈希的键值进行编码


func encodeBlockHashKey(blockHash []byte) []byte {
    return prependKeyPrefix(prefixBlockHashKey, blockHash)
}

对TxUUID的键值进行编码

func encodeTxUUIDKey(txUUID string) []byte {
    return prependKeyPrefix(prefixTxUUIDKey, []byte(txUUID))
}

对区块号地址的复合键值进行编码

func encodeAddressBlockNumCompositeKey(address string, blockNumber uint64) []byte {
    b := proto.NewBuffer([]byte{prefixAddressBlockNumCompositeKey})
    b.EncodeRawBytes([]byte(address))
    b.EncodeVarint(blockNumber)
    return b.Bytes()
}

对Tx的索引清单进行编码

func encodeListTxIndexes(listTx []uint64) []byte {
    b := proto.NewBuffer([]byte{})
    for i := range listTx {
        b.EncodeVarint(listTx[i])
    }
    return b.Bytes()
}

对chaincode的ID进行编码

func encodeChaincodeID(c *protos.ChaincodeID) []byte {
    // 序列化chaincode ID
    return []byte{}
}

前置键值前缀

func prependKeyPrefix(prefix byte, key []byte) []byte {
    modifiedKey := []byte{}
    modifiedKey = append(modifiedKey, prefix)
    modifiedKey = append(modifiedKey, key...)
    return modifiedKey
}

blockchain_indexes_async

整个代码主要执行对blockchain的异步创建索引

type blockchainIndexerAsync struct {
    blockchain *blockchain
    //从块链转移块索引的通道
    blockChan    chan blockWrapper
    indexerState *blockchainIndexerState
}

createIndexesInternal

创建索引条目并逐步添加到数据库,用于创建各种属性的索引

func (indexer *blockchainIndexerAsync) createIndexesInternal(block *protos.Block, blockNumber uint64, blockHash []byte) error {
    openchainDB := db.GetDBHandle()
    writeBatch := gorocksdb.NewWriteBatch()
    defer writeBatch.Destroy()
    addIndexDataForPersistence(block, blockNumber, blockHash, writeBatch)
    writeBatch.PutCF(openchainDB.IndexesCF, lastIndexedBlockKey, encodeBlockNumber(blockNumber))
    opt := gorocksdb.NewDefaultWriteOptions()
    defer opt.Destroy()
    err := openchainDB.DB.Write(opt, writeBatch)
    if err != nil {
        return err
    }
    indexer.indexerState.blockIndexed(blockNumber)
    return nil
}

indexPendingBlocks

待定块的索引

func (indexer *blockchainIndexerAsync) indexPendingBlocks() error {
    blockchain := indexer.blockchain
    if blockchain.getSize() == 0 {
        // 链至今为空
        return nil
    }

    lastCommittedBlockNum := blockchain.getSize() - 1
    lastIndexedBlockNum := indexer.indexerState.getLastIndexedBlockNumber()
    if lastCommittedBlockNum == lastIndexedBlockNum {
        //所有块索引的提交
        return nil
    }

    for ; lastIndexedBlockNum < lastCommittedBlockNum; lastIndexedBlockNum++ {
        blockNumToIndex := lastIndexedBlockNum + 1
        blockToIndex, errBlockFetch := blockchain.getBlock(blockNumToIndex)
        if errBlockFetch != nil {
            return errBlockFetch
        }

        blockHash, errBlockHash := blockToIndex.GetHash()
        if errBlockHash != nil {
            return errBlockHash
        }
        indexer.createIndexesInternal(blockToIndex, blockNumToIndex, blockHash)
    }
    return nil
}

blockIndexed

块索引

func (indexerState *blockchainIndexerState) blockIndexed(blockNumber uint64) {
    indexerState.newBlockIndexed.L.Lock()
    defer indexerState.newBlockIndexed.L.Unlock()
    indexerState.lastBlockIndexed = blockNumber
    indexerState.zerothBlockIndexed = true
    indexerState.newBlockIndexed.Broadcast()
}

waitForLastCommittedBlock

等待最后一个块的创建

func (indexerState *blockchainIndexerState) waitForLastCommittedBlock() (err error) {
    chain := indexerState.indexer.blockchain
    if err != nil || chain.getSize() == 0 {
        return
    }

    lastBlockCommitted := chain.getSize() - 1

    indexerState.newBlockIndexed.L.Lock()
    defer indexerState.newBlockIndexed.L.Unlock()

    if !indexerState.zerothBlockIndexed {
        indexLogger.Debug(
            "Waiting for zeroth block to be indexed. lastBlockCommitted=[%d] and lastBlockIndexed=[%d]",
            lastBlockCommitted, indexerState.lastBlockIndexed)
        indexerState.newBlockIndexed.Wait()
    }

    for indexerState.lastBlockIndexed < lastBlockCommitted {
        indexLogger.Debug(
            "Waiting for index to catch up with block chain. lastBlockCommitted=[%d] and lastBlockIndexed=[%d]",
            lastBlockCommitted, indexerState.lastBlockIndexed)
        indexerState.newBlockIndexed.Wait()
    }
    return
}

fetchLastIndexedBlockNumFromDB

获取从数据库中得到上一个块号的块索引

func fetchLastIndexedBlockNumFromDB() (zerothBlockIndexed bool, lastIndexedBlockNum uint64, err error) {
    lastIndexedBlockNumberBytes, err := db.GetDBHandle().GetFromIndexesCF(lastIndexedBlockKey)
    if err != nil {
        return
    }
    if lastIndexedBlockNumberBytes == nil {
        return
    }
    lastIndexedBlockNum = decodeBlockNumber(lastIndexedBlockNumberBytes)
    zerothBlockIndexed = true
    return
}

ledger

先看下ledger的结构

type Ledger struct {
    blockchain *blockchain //区块链
    state      *state.State //状态
    currentID  interface{} //当前ID
}

GetLedger

给出”单个“ledger的引用

func GetLedger() (*Ledger, error) {
    once.Do(func() {
        ledger, ledgerError = newLedger()
    })
    return ledger, ledgerError
}

BeginTxBatch

开始批量发出

func (ledger *Ledger) BeginTxBatch(id interface{}) error {
    err := ledger.checkValidIDBegin()
    if err != nil {
        return err
    }
    ledger.currentID = id
    return nil
}

GetTXBatchPreviewBlock

返回将具有相同块的哈希,如果ledger.CommitTxBatch使用相同的参数则提交到数据库。如果该状态是由一个事务这两个调用之间修改,散列将不同。该块预览不包括非散列数据,如本地时间戳。

func (ledger *Ledger) GetTXBatchPreviewBlock(id interface{},
    transactions []*protos.Transaction, metadata []byte) (*protos.Block, error) {
    err := ledger.checkValidIDCommitORRollback(id)
    if err != nil {
        return nil, err
    }
    stateHash, err := ledger.state.GetHash()
    if err != nil {
        return nil, err
    }
    return ledger.blockchain.buildBlock(protos.NewBlock(transactions, metadata), stateHash), nil
}

CommitTxBatch

CommitTxBatch被调用时,当前事务需要分批次提交,该函数成功返回了交易的细节和状态变化(可能在这个交易批量的执行过程中发生)一直致力于持久化存储

func (ledger *Ledger) CommitTxBatch(id interface{}, transactions []*protos.Transaction, transactionResults []*protos.TransactionResult, metadata []byte) error {
    err := ledger.checkValidIDCommitORRollback(id)
    if err != nil {
        return err
    }

    stateHash, err := ledger.state.GetHash()
    if err != nil {
        ledger.resetForNextTxGroup(false)
        ledger.blockchain.blockPersistenceStatus(false)
        return err
    }

    writeBatch := gorocksdb.NewWriteBatch()
    defer writeBatch.Destroy()
    block := protos.NewBlock(transactions, metadata)
    block.NonHashData = &protos.NonHashData{TransactionResults: transactionResults}
    newBlockNumber, err := ledger.blockchain.addPersistenceChangesForNewBlock(context.TODO(), block, stateHash, writeBatch)
    if err != nil {
        ledger.resetForNextTxGroup(false)
        ledger.blockchain.blockPersistenceStatus(false)
        return err
    }
    ledger.state.AddChangesForPersistence(newBlockNumber, writeBatch)
    opt := gorocksdb.NewDefaultWriteOptions()
    defer opt.Destroy()
    dbErr := db.GetDBHandle().DB.Write(opt, writeBatch)
    if dbErr != nil {
        ledger.resetForNextTxGroup(false)
        ledger.blockchain.blockPersistenceStatus(false)
        return dbErr
    }

    ledger.resetForNextTxGroup(true)
    ledger.blockchain.blockPersistenceStatus(true)

    sendProducerBlockEvent(block)
    return nil
}

RollbackTxBatch

批处理回滚时放弃当前事务批次执行过程中可能发生的所有状态变化

func (ledger *Ledger) RollbackTxBatch(id interface{}) error {
    ledgerLogger.Debug("RollbackTxBatch for id = [%s]", id)
    err := ledger.checkValidIDCommitORRollback(id)
    if err != nil {
        return err
    }
    ledger.resetForNextTxGroup(false)
    return nil
}

TxBegin

标志着在持续一批新的交易开始

func (ledger *Ledger) TxBegin(txUUID string) {
    ledger.state.TxBegin(txUUID)
}

TxFinished

标志着正在进行交易的完成。如果成功话设置为false,丢弃事务的状态变化

func (ledger *Ledger) TxFinished(txUUID string, txSuccessful bool) {
    ledger.state.TxFinish(txUUID, txSuccessful)
}

GetTempStateHash

计算哈希状态并考虑到当前事务批次执行过程中可能发生的状态变化

func (ledger *Ledger) GetTempStateHash() ([]byte, error) {
    return ledger.state.GetHash()
}

GetTempStateHashWithTxDeltaStateHashes

除状态散列(如在方法GetTempStateHash定义),
此方法返回一个映射[TX的txUuid - > cryptoHash(stateChange MadeBySIx),只有TX成功,才会出现在该映射中

func (ledger *Ledger) GetTempStateHashWithTxDeltaStateHashes() ([]byte, map[string][]byte, error) {
    stateHash, err := ledger.state.GetHash()
    return stateHash, ledger.state.GetTxStateDeltaHash(), err
}

GetState

获取chaincode的id和键值。如果提交为false,它首先会在内存中查看。如果丢失的话,将从数据库中获取。如果提交为true,则仅仅只能在数据库中获取。

func (ledger *Ledger) GetState(chaincodeID string, key string, committed bool) ([]byte, error) {
    return ledger.state.Get(chaincodeID, key, committed)
}

GetStateRangeScanIterator

返回一个迭代器来获取所有startKey和endKey之间的键(和值)(假设键的词汇顺序)为chaincodeID。如果提交为true,则从数据库检索的键值是唯一。如果提交为false,从数据库被mergerd后的结果与在存储器中的结果(优先考虑在内存中的数据)在返回的迭代的键值是不同的

 guaranteed to be in any specific order
func (ledger *Ledger) GetStateRangeScanIterator(chaincodeID string, startKey string, endKey string, committed bool) (statemgmt.RangeScanIterator, error) {
    return ledger.state.GetRangeScanIterator(chaincodeID, startKey, endKey, committed)
}

GetStateSnapshot

返回当前块点对点全局状态。 这个是在从一个端到另一个端转化中的状态时使用。必须调用状态Snapshot.Release()方法一旦你与快照是以释放资源完成的。

func (ledger *Ledger) GetStateSnapshot() (*state.StateSnapshot, error) {
    dbSnapshot := db.GetDBHandle().GetSnapshot()
    blockHeight, err := fetchBlockchainSizeFromSnapshot(dbSnapshot)
    if err != nil {
        dbSnapshot.Release()
        return nil, err
    }
    if 0 == blockHeight {
        dbSnapshot.Release()
        return nil, fmt.Errorf("Blockchain has no blocks, cannot determine block number")
    }
    return ledger.state.GetSnapshot(blockHeight-1, dbSnapshot)
}

GetStateDelta

如果可用,则返回指定块的状态增量。

func (ledger *Ledger) GetStateDelta(blockNumber uint64) (*statemgmt.StateDelta, error) {
    if blockNumber >= ledger.GetBlockchainSize() {
        return nil, ErrOutOfBounds
    }
    return ledger.state.FetchStateDeltaFromDB(blockNumber)
}

ApplyStateDelta

即适用于一个当前的状态状态增量。它只在内存改变。必须调用ledger.CommitStateDelta持久化到数据库。这应该只被用来作为状态同步的一部分。状态增量可以从另一对等虽然Ledger.GetStateDelta函数检索或者与来自Ledger.GetStateshot()获取密钥创​​建的状态增量。举一个例子,在ledger_test.go定义的TestSetRawState。请注意,没有在此功能上检查它是否被调用,以确保增量是在正确的顺序中使用。例如,如果你目前正处于块8,并调用Ledger.GetStateDelta(10)的功能检索增量,您现在会是在一个糟糕的状态,因为你没有块9.申请增量这是可能的回滚状态向前或向后使用stateDelta.RollBackwards。默认情况下,块3检索的增量可以被用来从状态向前回滚在块2到状态在块3.如果
stateDelta.RollBackwards =false,增量检索块3可用于向后滚动块3状态和块2的状态。

func (ledger *Ledger) ApplyStateDelta(id interface{}, delta *statemgmt.StateDelta) error {
    err := ledger.checkValidIDBegin()
    if err != nil {
        return err
    }
    ledger.currentID = id
    ledger.state.ApplyStateDelta(delta)
    return nil
}

CommitStateDelta

将提交ledger.ApplyState状态增量并传递到到数据库

func (ledger *Ledger) CommitStateDelta(id interface{}) error {
    err := ledger.checkValidIDCommitORRollback(id)
    if err != nil {
        return err
    }
    defer ledger.resetForNextTxGroup(true)
    return ledger.state.CommitStateDelta()
}

RollbackStateDelta

放弃到ledger.ApplyStateDelta状态增量

func (ledger *Ledger) RollbackStateDelta(id interface{}) error {
    err := ledger.checkValidIDCommitORRollback(id)
    if err != nil {
        return err
    }
    ledger.resetForNextTxGroup(false)
    return nil
}

VerifyChain

将验证blockchain的integrety。完成这一步
通过确保存储在每个块中的前一个块的哈希链中的前块的实际散列相匹配。返回值是包含不匹配的前一个块的散列块的块号。例如,如果验证链(0,99)称为与prevous哈希值存储在块8中,32和42不相匹配各自前块42的实际的哈希值将是从该函数的返回值。 highBlock在链中高级验证。 如果你要验证的整个链条中,使用ledger.GetBlockchainsize() - 1。低块是在链中被低级验证。如果您想验证整个链条,为创世区块使用0。

func (ledger *Ledger) VerifyChain(highBlock, lowBlock uint64) (uint64, error) {
    if highBlock >= ledger.GetBlockchainSize() {
        return highBlock, ErrOutOfBounds
    }
    if highBlock <= lowBlock {
        return lowBlock, ErrOutOfBounds
    }

    for i := highBlock; i > lowBlock; i-- {
        currentBlock, err := ledger.GetBlockByNumber(i)
        if err != nil {
            return i, fmt.Errorf("Error fetching block %d.", i)
        }
        if currentBlock == nil {
            return i, fmt.Errorf("Block %d is nil.", i)
        }
        previousBlock, err := ledger.GetBlockByNumber(i - 1)
        if err != nil {
            return i - 1, fmt.Errorf("Error fetching block %d.", i)
        }
        if previousBlock == nil {
            return i - 1, fmt.Errorf("Block %d is nil.", i-1)
        }

        previousBlockHash, err := previousBlock.GetHash()
        if err != nil {
            return i - 1, fmt.Errorf("Error calculating block hash for block %d.", i-1)
        }
        if bytes.Compare(previousBlockHash, currentBlock.PreviousBlockHash) != 0 {
            return i, nil
        }
    }

    return 0, nil
}

sendProducerBlockEvent

func sendProducerBlockEvent(block *protos.Block) {

    // 从部署删除交易的有效载荷。这样做是为了创建块
    //这些类型的交易使事件更轻巧,有效载荷有可能非常大
    blockTransactions := block.GetTransactions()
    for _, transaction := range blockTransactions {
        if transaction.Type == protos.Transaction_CHAINCODE_NEW {
            deploymentSpec := &protos.ChaincodeDeploymentSpec{}
            err := proto.Unmarshal(transaction.Payload, deploymentSpec)
            if err != nil {
                ledgerLogger.Error(fmt.Sprintf("Error unmarshalling deployment transaction for block event: %s", err))
                continue
            }
            deploymentSpec.CodePackage = nil
            deploymentSpecBytes, err := proto.Marshal(deploymentSpec)
            if err != nil {
                ledgerLogger.Error(fmt.Sprintf("Error marshalling deployment transaction for block event: %s", err))
                continue
            }
            transaction.Payload = deploymentSpecBytes
        }
    }

    producer.Send(producer.CreateBlockEvent(block))
}

genesis

类似于chaincode,调用go-logging中logging库的MustGetLogger函数对genesis package进行记录

var genesisLogger = logging.MustGetLogger("genesis")

MakeGenesis

MakeGenesis基于在openchain.yaml中配置创建创世区块,并把它添加到blockchain。

func MakeGenesis() error {
    once.Do(func() {
        ledger, err := ledger.GetLedger()
        if err != nil {
            makeGenesisError = err
            return
        }

        if ledger.GetBlockchainSize() > 0 {
            // 获取blockchain的大小,如果大于0代表创世区块已经存在
            return
        }

        genesisLogger.Info("Creating genesis block.")

        ledger.BeginTxBatch(0)
        var genesisTransactions []*protos.Transaction
        //我们现在禁用在有效期内部署,甚至不应该允许它在配置中启用,将其设置为false
        allowDeployValidityPeriod := false

        if(deploySystemChaincodeEnabled() && allowDeployValidityPeriod){
            vpTransaction, deployErr :=  deployUpdateValidityPeriodChaincode()

            if deployErr != nil {
                genesisLogger.Error("Error deploying validity period system chaincode for genesis block.", deployErr)
                makeGenesisError = deployErr
                return
            }

            genesisTransactions = append(genesisTransactions, vpTransaction)
        }

        genesis := viper.GetStringMap("ledger.blockchain.genesisBlock")

        if genesis == nil {
            genesisLogger.Info("No genesis block chaincodes defined.")
        } else {

            chaincodes, chaincodesOK := genesis["chaincode"].([]interface{})
            if !chaincodesOK {
                genesisLogger.Info("No genesis block chaincodes defined.")
                ledger.CommitTxBatch(0, genesisTransactions, nil, nil)
                return
            }

            genesisLogger.Debug("Genesis chaincodes are %s", chaincodes)


            for i := 0; i < len(chaincodes); i++ {
                genesisLogger.Debug("Chaincode %d is %s", i, chaincodes[i])

                chaincodeMap, chaincodeMapOK := chaincodes[i].(map[interface{}]interface{})
                if !chaincodeMapOK {
                    genesisLogger.Error("Invalid chaincode defined in genesis configuration:", chaincodes[i])
                    makeGenesisError = fmt.Errorf("Invalid chaincode defined in genesis configuration: %s", chaincodes[i])
                    return
                }

                path, pathOK := chaincodeMap["path"].(string)
                if !pathOK {
                    genesisLogger.Error("Invalid chaincode URL defined in genesis configuration:", chaincodeMap["path"])
                    makeGenesisError = fmt.Errorf("Invalid chaincode URL defined in genesis configuration: %s", chaincodeMap["path"])
                    return
                }

                chaincodeType, chaincodeTypeOK := chaincodeMap["type"].(string)
                if !chaincodeTypeOK {
                    genesisLogger.Error("Invalid chaincode type defined in genesis configuration:", chaincodeMap["type"])
                    makeGenesisError = fmt.Errorf("Invalid chaincode type defined in genesis configuration: %s", chaincodeMap["type"])
                    return
                }

                chaincodeID := &protos.ChaincodeID{Path: path, Name: ""}

                genesisLogger.Debug("Genesis chaincodeID %s", chaincodeID)
                genesisLogger.Debug("Genesis chaincode type %s", chaincodeType)

                constructorMap, constructorMapOK := chaincodeMap["constructor"].(map[interface{}]interface{})
                if !constructorMapOK {
                    genesisLogger.Error("Invalid chaincode constructor defined in genesis configuration:", chaincodeMap["constructor"])
                    makeGenesisError = fmt.Errorf("Invalid chaincode constructor defined in genesis configuration: %s", chaincodeMap["constructor"])
                    return
                }

                var spec protos.ChaincodeSpec
                if constructorMap == nil {
                    genesisLogger.Debug("Genesis chaincode has no constructor.")
                    spec = protos.ChaincodeSpec{Type: protos.ChaincodeSpec_Type(protos.ChaincodeSpec_Type_value[chaincodeType]), ChaincodeID: chaincodeID}
                } else {

                    ctorFunc, ctorFuncOK := constructorMap["func"].(string)
                    if !ctorFuncOK {
                        genesisLogger.Error("Invalid chaincode constructor function defined in genesis configuration:", constructorMap["func"])
                        makeGenesisError = fmt.Errorf("Invalid chaincode constructor function args defined in genesis configuration: %s", constructorMap["func"])
                        return
                    }

                    ctorArgs, ctorArgsOK := constructorMap["args"].([]interface{})
                    if !ctorArgsOK {
                        genesisLogger.Error("Invalid chaincode constructor args defined in genesis configuration:", constructorMap["args"])
                        makeGenesisError = fmt.Errorf("Invalid chaincode constructor args defined in genesis configuration: %s", constructorMap["args"])
                        return
                    }

                    genesisLogger.Debug("Genesis chaincode constructor func %s", ctorFunc)
                    genesisLogger.Debug("Genesis chaincode constructor args %s", ctorArgs)
                    var ctorArgsStringArray []string
                    for j := 0; j < len(ctorArgs); j++ {
                        ctorArgsStringArray = append(ctorArgsStringArray, ctorArgs[j].(string))
                    }

                    spec = protos.ChaincodeSpec{Type: protos.ChaincodeSpec_Type(protos.ChaincodeSpec_Type_value[chaincodeType]), ChaincodeID: chaincodeID, CtorMsg: &protos.ChaincodeInput{Function: ctorFunc, Args: ctorArgsStringArray}}
                }

                transaction, _, deployErr := DeployLocal(context.Background(), &spec)
                if deployErr != nil {
                    genesisLogger.Error("Error deploying chaincode for genesis block.", deployErr)
                    makeGenesisError = deployErr
                    return
                }

                genesisTransactions = append(genesisTransactions, transaction)

            }//for

        }//else

        genesisLogger.Info("Adding %d system chaincodes to the genesis block.", len(genesisTransactions))
        ledger.CommitTxBatch(0, genesisTransactions, nil, nil)

    })
    return makeGenesisError
}

BuildLocal

构建一个指定的chaincode码

func BuildLocal(context context.Context, spec *protos.ChaincodeSpec) (*protos.ChaincodeDeploymentSpec, error) {
    genesisLogger.Debug("Received build request for chaincode spec: %v", spec)
    mode := viper.GetString("chaincode.chaincoderunmode")
    var codePackageBytes []byte
    if mode != chaincode.DevModeUserRunsChaincode {
        if err := openchain.CheckSpec(spec); err != nil {
            genesisLogger.Debug("check spec failed: %s", err)
            return nil, err
        }
        // 规范构建
        var err error
        codePackageBytes, err = container.GetChaincodePackageBytes(spec)
        if err != nil {
            genesisLogger.Error(fmt.Sprintf("Error getting VM: %s", err))
            return nil, err
        }
    }
    chaincodeDeploymentSpec := &protos.ChaincodeDeploymentSpec{ChaincodeSpec: spec, CodePackage: codePackageBytes}
    return chaincodeDeploymentSpec, nil
}

DeployLocal

部署供应链代码的映像到本地端

func DeployLocal(ctx context.Context, spec *protos.ChaincodeSpec) (*protos.Transaction, []byte, error) {
    // 首先建立并得到部署规范
    chaincodeDeploymentSpec, err := BuildLocal(ctx, spec)

    if err != nil {
        genesisLogger.Error(fmt.Sprintf("Error deploying chaincode spec: %v

 error: %s", spec, err))
        return nil, nil, err
    }

    transaction, err := protos.NewChaincodeDeployTransaction(chaincodeDeploymentSpec, chaincodeDeploymentSpec.ChaincodeSpec.ChaincodeID.Name)
    if err != nil {
        return nil, nil, fmt.Errorf("Error deploying chaincode: %s ", err)
    }
    //chaincode.NewChaincodeSupport(chaincode.DefaultChain, peer.GetPeerEndpoint, false, 120000)
    // secHelper设置在ChaincodeSupport创建期间,因此我们不需要这一步
    //ctx = context.WithValue(ctx, "security", secCxt)
    result, err := chaincode.Execute(ctx, chaincode.GetChain(chaincode.DefaultChain), transaction)
    return transaction, result, err
}

设置是否部署系统chaincode

func deploySystemChaincodeEnabled() bool {
    // 如果系统chaincode的部署配置文件中能够返回所配置的值
    if viper.IsSet("ledger.blockchain.deploy-system-chaincode") {
        return viper.GetBool("ledger.blockchain.deploy-system-chaincode")
    }

    // 如果没有指定配置能够启用,系统chaincode将采用默认情况部署
    return true
} 

deployUpdateValidityPeriodChaincode

部署更新chaincode的有效期

func deployUpdateValidityPeriodChaincode() (*protos.Transaction, error) {
    //它应该是可配置的,不采取硬编码
    vpChaincodePath := "github.com/openblockchain/obc-peer/openchain/system_chaincode/validity_period_update"
    vpFunction := "init"

    //这应该是负责有效期更新的组件的登录凭证。
    //该组件需要在系统中注册,以便能够调用更新chaincode的有效期
    vpToken := "system_chaincode_invoker"

    var vpCtorArgsStringArray []string

    validityPeriodSpec := &protos.ChaincodeSpec{Type: protos.ChaincodeSpec_GOLANG,
        ChaincodeID: &protos.ChaincodeID{Path: vpChaincodePath,
            Name: "",
        },
        CtorMsg: &protos.ChaincodeInput{Function: vpFunction,
            Args: vpCtorArgsStringArray,
        },
    }

    validityPeriodSpec.SecureContext = string(vpToken)

    vpTransaction, _, deployErr := DeployLocal(context.Background(), validityPeriodSpec)

    if deployErr != nil {
        genesisLogger.Error("Error deploying validity period chaincode for genesis block.", deployErr)
        makeGenesisError = deployErr
        return nil, deployErr
    }

    return vpTransaction, nil
} 

util

EncodeOrderPreservingVarUint64

返回一个字节表示要的int64数使得起始字节全零比特,以减少阵列的长度被修整,用于保存在一个缺省字节对比的顺序,第一个字节包含剩余的第一字节的bytes。存在的数量也允许使用返回的字节作为其它较大字节阵列的一部分,如以数据库复合键表示

func EncodeOrderPreservingVarUint64(number uint64) []byte {
    bytes := make([]byte, 8)
    binary.BigEndian.PutUint64(bytes, number)
    startingIndex := 0
    size := 0
    for i, b := range bytes {
        if b != 0x00 {
            startingIndex = i
            size = 8 - i
            break
        }
    }
    sizeBytes := proto.EncodeVarint(uint64(size))
    if len(sizeBytes) > 1 {
        panic(fmt.Errorf("[]sizeBytes should not be more than one byte because the max number it needs to hold is 8. size=%d", size))
    }
    encodedBytes := make([]byte, size+1)
    encodedBytes[0] = sizeBytes[0]
    copy(encodedBytes[1:], bytes[startingIndex:])
    return encodedBytes
}

DecodeOrderPreservingVarUint64

解码从由方法“EncodeOrderPreservingVarUint64’得到的字节数。
此外,返回在该过程中所消耗的字节数

func DecodeOrderPreservingVarUint64(bytes []byte) (uint64, int) {
    s, _ := proto.DecodeVarint(bytes)
    size := int(s)
    decodedBytes := make([]byte, 8)
    copy(decodedBytes[8-size:], bytes[1:size+1])
    numBytesConsumed := size + 1
    return binary.BigEndian.Uint64(decodedBytes), numBytesConsumed
}

buckettree

bucket_hash

addNextNode

这个方法假定数据节点都按键的增加顺序添加

func (c *bucketHashCalculator) addNextNode(dataNode *dataNode) {
    chaincodeID, _ := dataNode.getKeyElements()
    if chaincodeID != c.currentChaincodeID {
        c.appendCurrentChaincodeData()
        c.currentChaincodeID = chaincodeID
        c.dataNodes = nil
    }
    c.dataNodes = append(c.dataNodes, dataNode)
}

computeCryptoHash

计算加密哈希

func (c *bucketHashCalculator) computeCryptoHash() []byte {
    if c.currentChaincodeID != "" {
        c.appendCurrentChaincodeData()
        c.currentChaincodeID = ""
        c.dataNodes = nil
    }
    logger.Debug("Hashable content for bucket [%s]: length=%d, contentInStringForm=[%s]", c.bucketKey, len(c.hashingData), string(c.hashingData))
    if util.IsNil(c.hashingData) {
        return nil
    }
    return openchainUtil.ComputeCryptoHash(c.hashingData)
}

appendCurrentChaincodeData

添加当前chaincode数据

func (c *bucketHashCalculator) appendCurrentChaincodeData() {
    if c.currentChaincodeID == "" {
        return
    }
    c.appendSizeAndData([]byte(c.currentChaincodeID))
    c.appendSize(len(c.dataNodes))
    for _, dataNode := range c.dataNodes {
        _, key := dataNode.getKeyElements()
        value := dataNode.getValue()
        c.appendSizeAndData([]byte(key))
        c.appendSizeAndData(value)
    }
}

appendSizeAndData

添加数据和容量

func (c *bucketHashCalculator) appendSizeAndData(b []byte) {
    c.appendSize(len(b))
    c.hashingData = append(c.hashingData, b...)
}

appendSize

增加容量

func (c *bucketHashCalculator) appendSize(size int) {
    c.hashingData = append(c.hashingData, proto.EncodeVarint(uint64(size))...)
}

bucket_key

bucket key的结构如下

type bucketKey struct {
    level        int  //级别
    bucketNumber int  //bucket号
}

newBucketKey

当level为0,bucketNumber为1时,构造bucket树根节点;
当level为bucketKey.level-1, bucketNumber为conf.computeParentBucketNumber(bucketKey.bucketNumber)
时构建的是父节点的bucketkey

func newBucketKey(level int, bucketNumber int) *bucketKey {
    if level > conf.getLowestLevel() || level < 0 {
        panic(fmt.Errorf("Invalid Level [%d] for bucket key. Level can be between 0 and [%d]", level, conf.lowestLevel))
        //如果级别大于最低级别或者级别小于0,则输出当前级别以及最小级别
    }
//如果bucket号小于1或者大于bucket级别对应的级别好,则返回bucketkey的级别和级别号
    if bucketNumber < 1 || bucketNumber > conf.getNumBuckets(level) {
        panic(fmt.Errorf("Invalid bucket number [%d]. Bucket nuber at level [%d] can be between 1 and [%d]", bucketNumber, level, conf.getNumBuckets(level)))
    }
    return &bucketKey{level, bucketNumber}
}

getChildIndex

获取子节点的索引

func (bucketKey *bucketKey) getChildIndex(childKey *bucketKey) int {
    bucketNumberOfFirstChild := ((bucketKey.bucketNumber - 1) * conf.getMaxGroupingAtEachLevel()) + 1
    bucketNumberOfLastChild := bucketKey.bucketNumber * conf.getMaxGroupingAtEachLevel()
    if childKey.bucketNumber < bucketNumberOfFirstChild || childKey.bucketNumber > bucketNumberOfLastChild {
        panic(fmt.Errorf("[%#v] is not a valid child bucket of [%#v]", childKey, bucketKey))
    }
    return childKey.bucketNumber - bucketNumberOfFirstChild
}

bucket_node

bucketnode的结构如下

type bucketNode struct {
    bucketKey          *bucketKey 
    childrenCryptoHash [][]byte //子节点的加密哈希
    childrenUpdated    []bool  //子节点更新
    markedForDeletion  bool  //删除标记
}

unmarshalBucketNode

重组bucketnode

func unmarshalBucketNode(bucketKey *bucketKey, serializedBytes []byte) *bucketNode {
    bucketNode := newBucketNode(bucketKey)
    buffer := proto.NewBuffer(serializedBytes)
    for i := 0; i < conf.getMaxGroupingAtEachLevel(); i++ {
        childCryptoHash, err := buffer.DecodeRawBytes(false)
        if err != nil {
            panic(fmt.Errorf("this error should not occur: %s", err))
        }
        if !util.IsNil(childCryptoHash) {
            bucketNode.childrenCryptoHash[i] = childCryptoHash
        }
    }
    return bucketNode
}

mergeBucketNode

合并bucket节点

func (bucketNode *bucketNode) mergeBucketNode(anotherBucketNode *bucketNode) {
    if !bucketNode.bucketKey.equals(anotherBucketNode.bucketKey) {
        panic(fmt.Errorf("Nodes with different keys can not be merged. BaseKey=[%#v], MergeKey=[%#v]", bucketNode.bucketKey, anotherBucketNode.bucketKey))
    }
    for i, childCryptoHash := range anotherBucketNode.childrenCryptoHash {
        if !bucketNode.childrenUpdated[i] && util.IsNil(bucketNode.childrenCryptoHash[i]) {
            bucketNode.childrenCryptoHash[i] = childCryptoHash
        }
    }
}

bucket_tree_delta

包含的功能比较少,直接上代码

//创建bucket树增量
func newBucketTreeDelta() *bucketTreeDelta {
    return &bucketTreeDelta{make(map[int]byBucketNumber)}
}
//获取或者创建Bucket节点
func (bucketTreeDelta *bucketTreeDelta) getOrCreateBucketNode(bucketKey *bucketKey) *bucketNode {
    byBucketNumber := bucketTreeDelta.byLevel[bucketKey.level]
    if byBucketNumber == nil {
        byBucketNumber = make(map[int]*bucketNode)
        bucketTreeDelta.byLevel[bucketKey.level] = byBucketNumber
    }
    bucketNode := byBucketNumber[bucketKey.bucketNumber]
    if bucketNode == nil {
        bucketNode = newBucketNode(bucketKey)
        byBucketNumber[bucketKey.bucketNumber] = bucketNode
    }
    return bucketNode
}

//获取某一级别下的bucket节点
func (bucketTreeDelta *bucketTreeDelta) getBucketNodesAt(level int) []*bucketNode {
    bucketNodes := []*bucketNode{}
    byBucketNumber := bucketTreeDelta.byLevel[level]
    if byBucketNumber == nil {
        return nil
    }
    for _, bucketNode := range byBucketNumber {
        bucketNodes = append(bucketNodes, bucketNode)
    }
    return bucketNodes
}
//获取根节点
func (bucketTreeDelta *bucketTreeDelta) getRootNode() *bucketNode {
    bucketNodes := bucketTreeDelta.getBucketNodesAt(0)
    if bucketNodes == nil || len(bucketNodes) == 0 {
        panic("This method should be called after processing is completed (i.e., the root node has been created)")
    }
    return bucketNodes[0]
}

config

计算父节点的bucket数量

func (config *config) computeParentBucketNumber(bucketNumber int) int {
    logger.Debug("Computing parent bucket number for bucketNumber [%d]", bucketNumber)
    parentBucketNumber := bucketNumber / config.getMaxGroupingAtEachLevel()
    if bucketNumber%config.getMaxGroupingAtEachLevel() != 0 {
        parentBucketNumber++
    }
    return parentBucketNumber
}

Datakey

//创建datakey
func newDataKey(chaincodeID string, key string) *dataKey {
    logger.Debug("Enter - newDataKey. chaincodeID=[%s], key=[%s]", chaincodeID, key)
    compositeKey := statemgmt.ConstructCompositeKey(chaincodeID, key)
    bucketHash := conf.computeBucketHash(compositeKey)
    // 添加一个,因为 - 我们开始启动bucket的数为1
    bucketNumber := int(bucketHash)%conf.getNumBucketsAtLowestLevel() + 1
    dataKey := &dataKey{newBucketKeyAtLowestLevel(bucketNumber), compositeKey}
    logger.Debug("Exit - newDataKey=[%s]", dataKey)
    return dataKey
}
//最小化DataKey可能的字节
func minimumPossibleDataKeyBytesFor(bucketKey *bucketKey) []byte {
    min := encodeBucketNumber(bucketKey.bucketNumber)
    min = append(min, byte(0))
    return min
}

func minimumPossibleDataKeyBytes(bucketNumber int, chaincodeID string, key string) []byte {
    b := encodeBucketNumber(bucketNumber)
    b = append(b, statemgmt.ConstructCompositeKey(chaincodeID, key)...)
    return b
}

data_nodes_delta

newDataNodesDelta

创建datanode增量

func newDataNodesDelta(stateDelta *statemgmt.StateDelta) *dataNodesDelta {
    dataNodesDelta := &dataNodesDelta{make(map[bucketKey]dataNodes)}
    chaincodeIDs := stateDelta.GetUpdatedChaincodeIds(false)
    for _, chaincodeID := range chaincodeIDs {
        updates := stateDelta.GetUpdates(chaincodeID)
        for key, updatedValue := range updates {
            if stateDelta.RollBackwards {
                dataNodesDelta.add(chaincodeID, key, updatedValue.GetPreviousValue())
            } else {
                dataNodesDelta.add(chaincodeID, key, updatedValue.GetValue())
            }
        }
    }
    for _, dataNodes := range dataNodesDelta.byBucket {
        sort.Sort(dataNodes)
    }
    return dataNodesDelta
}

getAffectedBuckets

获取受到影响的buckets

func (dataNodesDelta *dataNodesDelta) getAffectedBuckets() []*bucketKey {
    changedBuckets := []*bucketKey{}
    for bucketKey := range dataNodesDelta.byBucket {
        copyOfBucketKey := bucketKey.clone()
        logger.Debug("Adding changed bucket [%s]", copyOfBucketKey)
        changedBuckets = append(changedBuckets, copyOfBucketKey)
    }
    logger.Debug("Changed buckets are = [%s]", changedBuckets)
    return changedBuckets
}

range_scan_iterator

RangeScanIterator实现了 ‘statemgmt.RangeScanIterator’接口

type RangeScanIterator struct {
    dbItr               *gorocksdb.Iterator
    chaincodeID         string
    startKey            string
    endKey              string
    currentBucketNumber int
    currentKey          string
    currentValue        []byte
    done                bool
}

这是其中接口实现的一些细节

func (itr *RangeScanIterator) Next() bool {
    if itr.done {
        return false
    }

    for itr.dbItr.Valid() {

        //创建键 - 值字节的副本,因为潜在的键值字节由UTR重用。关闭时没有必要为迭代器释放内存而释放切片。
        keyBytes := statemgmt.Copy(itr.dbItr.Key().Data())
        valueBytes := statemgmt.Copy(itr.dbItr.Value().Data())

        dataNode := unmarshalDataNodeFromBytes(keyBytes, valueBytes)
        dataKey := dataNode.dataKey
        chaincodeID, key := statemgmt.DecodeCompositeKey(dataNode.getCompositeKey())
        value := dataNode.value
        logger.Debug("Evaluating data-key = %s", dataKey)

        bucketNumber := dataKey.bucketKey.bucketNumber
        if bucketNumber > itr.currentBucketNumber {
            itr.seekForStartKeyWithinBucket(bucketNumber)
            continue
        }

        if chaincodeID == itr.chaincodeID && (itr.endKey == "" || key <= itr.endKey) {
            logger.Debug("including data-key = %s", dataKey)
            itr.currentKey = key
            itr.currentValue = value
            itr.dbItr.Next()
            return true
        }

        itr.seekForStartKeyWithinBucket(bucketNumber + 1)
        continue
    }
    itr.done = true
    return false
}

snapshot_iterator

//接口实现
type StateSnapshotIterator struct {
    dbItr *gorocksdb.Iterator
}
//创建迭代器
func newStateSnapshotIterator(snapshot *gorocksdb.Snapshot) (*StateSnapshotIterator, error) {
    dbItr := db.GetDBHandle().GetStateCFSnapshotIterator(snapshot)
    dbItr.Seek([]byte{0x01})
    dbItr.Prev()
    return &StateSnapshotIterator{dbItr}, nil
}

// 接口实现细节-Next
func (snapshotItr *StateSnapshotIterator) Next() bool {
    snapshotItr.dbItr.Next()
    return snapshotItr.dbItr.Valid()
}

// 接口实现细节-GetRawKeyValue
func (snapshotItr *StateSnapshotIterator) GetRawKeyValue() ([]byte, []byte) {
//创建键 - 值字节的副本,因为潜在的键值字节由UTR重用。关闭时没有必要为迭代器释放内存而释放切片。

    keyBytes := statemgmt.Copy(snapshotItr.dbItr.Key().Data())
    valueBytes := statemgmt.Copy(snapshotItr.dbItr.Value().Data())
    dataNode := unmarshalDataNodeFromBytes(keyBytes, valueBytes)
    return dataNode.getCompositeKey(), dataNode.getValue()
}

// 接口实现细节-Close 
func (snapshotItr *StateSnapshotIterator) Close() {
    snapshotItr.dbItr.Close()
}

state_impl

实现了 ‘statemgmt.HashableState’接口

NewStateImpl

构建一个新的StateImpl

func NewStateImpl() *StateImpl {
    return &StateImpl{}
}

Initialize

状态初始化

func (stateImpl *StateImpl) Initialize(configs map[string]interface{}) error {
    initConfig(configs)
    rootBucketNode, err := fetchBucketNodeFromDB(constructRootBucketKey())
    if err != nil {
        return err
    }
    if rootBucketNode != nil {
        stateImpl.persistedStateHash = rootBucketNode.computeCryptoHash()
        stateImpl.lastComputedCryptoHash = stateImpl.persistedStateHash
    }
    return nil
//我们可以创建一个高速缓存,并保持所有的bucket节点预加载。
//因为,铲斗节点不包含实际数据和最大可能的bucket是预先确定的,所述存储器需求
//可能不是非常高,或者可以容易地控制 - 通过保持在高速缓存中选择性bucket(bucket
//树的最可能的前面几级 - 因为,较高的bucket的水平,
//更是将需要散列重新计算的几率)

}

PrepareWorkingSet

准备工作集

func (stateImpl *StateImpl) PrepareWorkingSet(stateDelta *statemgmt.StateDelta) error {
    logger.Debug("Enter - PrepareWorkingSet()")
    if stateDelta.IsEmpty() {
        logger.Debug("Ignoring working-set as it is empty")
        return nil
    }
    stateImpl.dataNodesDelta = newDataNodesDelta(stateDelta)
    stateImpl.bucketTreeDelta = newBucketTreeDelta()
    stateImpl.recomputeCryptoHash = true
    return nil
}

computeDataNodesCryptoHash

计算datanodes的哈希加密计算

func computeDataNodesCryptoHash(bucketKey *bucketKey, updatedNodes dataNodes, existingNodes dataNodes) []byte {
    logger.Debug("Computing crypto-hash for bucket [%s]. numUpdatedNodes=[%d], numExistingNodes=[%d]", bucketKey, len(updatedNodes), len(existingNodes))
    bucketHashCalculator := newBucketHashCalculator(bucketKey)
    i := 0
    j := 0
    for i < len(updatedNodes) && j < len(existingNodes) {
        updatedNode := updatedNodes[i]
        existingNode := existingNodes[j]
        c := bytes.Compare(updatedNode.dataKey.compositeKey, existingNode.dataKey.compositeKey)
        var nextNode *dataNode
        switch c {
        case -1:
            nextNode = updatedNode
            i++
        case 0:
            nextNode = updatedNode
            i++
            j++
        case 1:
            nextNode = existingNode
            j++
        }
        if !nextNode.isDelete() {
            bucketHashCalculator.addNextNode(nextNode)
        }
    }

    var remainingNodes dataNodes
    if i < len(updatedNodes) {
        remainingNodes = updatedNodes[i:]
    } else if j < len(existingNodes) {
        remainingNodes = existingNodes[j:]
    }

    for _, remainingNode := range remainingNodes {
        if !remainingNode.isDelete() {
            bucketHashCalculator.addNextNode(remainingNode)
        }
    }
    return bucketHashCalculator.computeCryptoHash()
}

state

composite_range_scan_iterator

包装了一个以上的潜在迭代,下面是具体实施,从第一底层迭代器开始,
耗尽第一底层迭代后,移动到第二个潜在的迭代器。实施重复这个直到已经耗尽之前的底层迭代器此外,如果键值是找到从底层迭代器的键值被跳过任一前代的迭代器

func (itr *CompositeRangeScanIterator) Next() bool {
    currentItrNumber := itr.currentItrNumber
    currentItr := itr.itrs[currentItrNumber]
    logger.Debug("Operating on iterator number = %d", currentItrNumber)
    keyAvailable := currentItr.Next()
    for keyAvailable {
        key, _ := currentItr.GetKeyValue()
        logger.Debug("Retrieved key = %s", key)
        skipKey := false
        for i := currentItrNumber - 1; i >= 0; i-- {
            logger.Debug("Evaluating key = %s in itr number = %d. currentItrNumber = %d", key, i, currentItrNumber)
            previousItr := itr.itrs[i]
            if previousItr.(*statemgmt.StateDeltaIterator).ContainsKey(key) {
                skipKey = true
                break
            }
        }
        if skipKey {
            logger.Debug("Skipping key = %s", key)
            keyAvailable = currentItr.Next()
            continue
        }
        break
    }

    if keyAvailable || currentItrNumber == 2 {
        logger.Debug("Returning for current key")
        return keyAvailable
    }

    logger.Debug("Moving to next iterator")
    itr.currentItrNumber++
    return itr.Next()
}

state_snapshot

// 按实际的实施和数据库快照封装了对状态快照的迭代
type StateSnapshot struct {
    blockNumber  uint64
    stateImplItr statemgmt.StateSnapshotIterator
    dbSnapshot   *gorocksdb.Snapshot
}

// 创建当前块全局状态的新快照
func newStateSnapshot(blockNumber uint64, dbSnapshot *gorocksdb.Snapshot) (*StateSnapshot, error) {
    itr, err := stateImpl.GetStateSnapshotIterator(dbSnapshot)
    if err != nil {
        return nil, err
    }
    snapshot := &StateSnapshot{blockNumber, itr, dbSnapshot}
    return snapshot, nil
}

//当您使用这个资源做这必须调用释放快照
func (ss *StateSnapshot) Release() {
    ss.stateImplItr.Close()
    ss.dbSnapshot.Release()
}

//接下来将迭代器移动到下一个键/值对的状态
func (ss *StateSnapshot) Next() bool {
    return ss.stateImplItr.Next()
}

//返回在当前迭代器位置的键和值的原始字节
func (ss *StateSnapshot) GetRawKeyValue() ([]byte, []byte) {
    return ss.stateImplItr.GetRawKeyValue()
}

// 返回与此全局状态的快照相关联的块号
func (ss *StateSnapshot) GetBlockNumber() uint64 {
    return ss.blockNumber
}

state

构造全局状态,封装状态持久性的特定管理实现,它不是线程安全的

NewState

构造一个新的状态。对初始化状态的实现进行封装

func NewState() *State {
    stateImplName := viper.GetString("ledger.state.dataStructure.name")
    stateImplConfigs := viper.GetStringMap("ledger.state.dataStructure.configs")

    if len(stateImplName) == 0 {
        stateImplName = detaultStateImpl
        stateImplConfigs = nil
    }

    switch stateImplName {
    case "buckettree":
        stateImpl = buckettree.NewStateImpl()
    case "trie":
        stateImpl = trie.NewStateTrie()
    default:
        panic(fmt.Errorf("Error during initialization of state implementation. State data structure '%s' is not valid.", stateImplName))
    }

    err := stateImpl.Initialize(stateImplConfigs)
    if err != nil {
        panic(fmt.Errorf("Error during initialization of state implementation: %s", err))
    }
    deltaHistorySize := viper.GetInt("ledger.state.deltaHistorySize")
    if deltaHistorySize < 0 {
        panic(fmt.Errorf("Delta history size must be greater than or equal to 0. Current value is %d.", deltaHistorySize))
    }
    return &State{stateImpl, statemgmt.NewStateDelta(), statemgmt.NewStateDelta(), "", make(map[string][]byte),
        false, uint64(deltaHistorySize)}
}

TxBegin

标记开始新的tx。如果tx已在进行中,将调用混乱

func (state *State) TxBegin(txUUID string) {
    logger.Debug("txBegin() for txUuid [%s]", txUUID)
    if state.txInProgress() {
        panic(fmt.Errorf("A tx [%s] is already in progress. Received call for begin of another tx [%s]", state.currentTxUUID, txUUID))
    }
    state.currentTxUUID = txUUID
}

Get

返回chaincodeID和键的状态。如果提交为false,首先从内存中查找,如果缺失,从数据库获取。如果为true,仅仅可以从数据库中获取。

func (state *State) Get(chaincodeID string, key string, committed bool) ([]byte, error) {
    if !committed {
        valueHolder := state.currentTxStateDelta.Get(chaincodeID, key)
        if valueHolder != nil {
            return valueHolder.GetValue(), nil
        }
        valueHolder = state.stateDelta.Get(chaincodeID, key)
        if valueHolder != nil {
            return valueHolder.GetValue(), nil
        }
    }
    return state.stateImpl.Get(chaincodeID, key)
}

GetRangeScanIterator

返回一来获取所有startKey和endKey之间的键(和值)的迭代器
对于chaincodeID(假设按照键的词汇顺序)。

func (state *State) GetRangeScanIterator(chaincodeID string, startKey string, endKey string, committed bool) (statemgmt.RangeScanIterator, error) {
    stateImplItr, err := state.stateImpl.GetRangeScanIterator(chaincodeID, startKey, endKey)
    if err != nil {
        return nil, err
    }

    if committed {
        return stateImplItr, nil
    }
    return newCompositeRangeScanIterator(
        statemgmt.NewStateDeltaRangeScanIterator(state.currentTxStateDelta, chaincodeID, startKey, endKey),
        statemgmt.NewStateDeltaRangeScanIterator(state.stateDelta, chaincodeID, startKey, endKey),
        stateImplItr), nil
}

GetHash

如果计算要应用的状态增量如果是新状态的哈希值。
如果stateDelta已最近一次调用后,想要更改此功能只能重新计算

func (state *State) GetHash() ([]byte, error) {
    logger.Debug("Enter - GetHash()")
    if state.updateStateImpl {
        logger.Debug("updating stateImpl with working-set")
        state.stateImpl.PrepareWorkingSet(state.stateDelta)
        state.updateStateImpl = false
    }
    hash, err := state.stateImpl.ComputeCryptoHash()
    if err != nil {
        return nil, err
    }
    logger.Debug("Exit - GetHash()")
    return hash, nil
}

trie

trie,又称前缀树或字典树,是一种有序树,用于保存关联数组,其中的键通常是字符串。与二叉查找树不同,键不是直接保存在节点中,而是由节点在树中的位置决定。

TrieKey

如下是trie key的接口定义

type trieKeyInterface interface {
    getLevel() int //获取级别
    getParentTrieKey() trieKeyInterface //获取父 trie key
    getIndexInParent() int  //获取索引
    getEncodedBytes() []byte
}

newTrieKey

创建一个trie key

func newTrieKey(chaincodeID string, key string) *trieKey {
    compositeKey := statemgmt.ConstructCompositeKey(chaincodeID, key)
    return newTrieKeyFromCompositeKey(compositeKey)
}

newTrieKeyFromCompositeKey

从组合键中创建trie key

func newTrieKeyFromCompositeKey(compositeKey []byte) *trieKey {
    return &trieKey{trieKeyEncoderImpl.newTrieKey(compositeKey)}
}

getIndexInParent

获取父triekey的索引


func (key *trieKey) getIndexInParent() int {
    if key.isRootKey() {
        panic(fmt.Errorf("Parent for Trie root shoould not be asked for"))
    }
    return key.trieKeyImpl.getIndexInParent()
}

getParentTrieKey

获取父 trie key

func (key *trieKey) getParentTrieKey() *trieKey {
    if key.isRootKey() {
        panic(fmt.Errorf("Parent for Trie root shoould not be asked for"))
    }
    return &trieKey{key.trieKeyImpl.getParentTrieKey()}
}

getEncodedBytes

获得字节编码,如果字节编码为0,代表为根的键值

func (key *trieKey) getEncodedBytes() []byte {
    return key.trieKeyImpl.getEncodedBytes()
}

assertIsChildOf

断言是否为孩子节点的trie key

func (key *trieKey) assertIsChildOf(parentTrieKey *trieKey) {
    if !bytes.Equal(key.getParentTrieKey().getEncodedBytes(), parentTrieKey.getEncodedBytes()) {
        panic(fmt.Errorf("trie key [%s] is not a child of trie key [%s]", key, parentTrieKey))
    }
}

trie_node

trienode的结构如下

type trieNode struct {
    trieKey              *trieKey
    value                []byte //值
    childrenCryptoHashes map[int][]byte//孩子节点的哈希加密,key为int,value为byte

    valueUpdated                bool //值是否更新
    childrenCryptoHashesUpdated map[int]bool//是否产生新的哈希加密
    markedForDeletion           bool //节店删除状态标记
}

setChildCryptoHash

设置孩子节点加密哈希

func (trieNode *trieNode) setChildCryptoHash(index int, childCryptoHash []byte) {
    if index >= trieKeyEncoderImpl.getMaxTrieWidth() {
        panic(fmt.Errorf("Index for child crypto-hash cannot be greater than [%d]. Tried to access index value [%d]", trieKeyEncoderImpl.getMaxTrieWidth(), index))
    }
    if childCryptoHash != nil {
        trieNode.childrenCryptoHashes[index] = childCryptoHash
    }
    trieNode.childrenCryptoHashesUpdated[index] = true
}

mergeMissingAttributesFrom

合并丢失属性

func (trieNode *trieNode) mergeMissingAttributesFrom(dbTrieNode *trieNode) {
    stateTrieLogger.Debug("Enter mergeMissingAttributesFrom() baseNode=[%s], mergeNode=[%s]", trieNode, dbTrieNode)
    if !trieNode.valueUpdated {
        trieNode.value = dbTrieNode.value
    }
    for k, v := range dbTrieNode.childrenCryptoHashes {
        if !trieNode.childrenCryptoHashesUpdated[k] {
            trieNode.childrenCryptoHashes[k] = v
        }
    }
    stateTrieLogger.Debug("Exit mergeMissingAttributesFrom() mergedNode=[%s]", trieNode)
}

computeCryptoHash

哈希加密计算

func (trieNode *trieNode) computeCryptoHash() []byte {
    stateTrieLogger.Debug("Enter computeCryptoHash() for trieNode [%s]", trieNode)
    var cryptoHashContent []byte
    if trieNode.containsValue() {
        stateTrieLogger.Debug("Adding value to hash computation for trieNode [%s]", trieNode)
        key := trieNode.trieKey.getEncodedBytes()
        cryptoHashContent = append(cryptoHashContent, proto.EncodeVarint(uint64(len(key)))...)
        cryptoHashContent = append(cryptoHashContent, key...)
        cryptoHashContent = append(cryptoHashContent, trieNode.value...)
    }

    sortedChildrenIndexes := trieNode.getSortedChildrenIndex()
    for _, index := range sortedChildrenIndexes {
        childCryptoHash := trieNode.childrenCryptoHashes[index]
        stateTrieLogger.Debug("Adding hash [%#v] for child number [%d] to hash computation for trieNode [%s]", childCryptoHash, index, trieNode)
        cryptoHashContent = append(cryptoHashContent, childCryptoHash...)
    }

    if cryptoHashContent == nil {
        // 节点没有关联值,也没有关联孩子节点。
        stateTrieLogger.Debug("Returning nil as hash for trieNode = [%s]. Also, marking this key for deletion.", trieNode)
        trieNode.markedForDeletion = true
        return nil
    }

    if !trieNode.containsValue() && trieNode.getNumChildren() == 1 {
        // 节点没有关联值,并且只有一个孩子节点,传递的孩子hash丢失
        stateTrieLogger.Debug("Returning hash as of a single child for trieKey = [%s]", trieNode.trieKey)
        return cryptoHashContent
    }

    stateTrieLogger.Debug("Recomputing hash for trieKey = [%s]", trieNode)
    return util.ComputeCryptoHash(cryptoHashContent)
}

marshal

func (trieNode *trieNode) marshal() ([]byte, error) {
    buffer := proto.NewBuffer([]byte{})

    // 写入值
    err := buffer.EncodeRawBytes(trieNode.value)
    if err != nil {
        return nil, err
    }

    numCryptoHashes := trieNode.getNumChildren()

    //写加密哈希数
    err = buffer.EncodeVarint(uint64(numCryptoHashes))
    if err != nil {
        return nil, err
    }

    if numCryptoHashes == 0 {
        return buffer.Bytes(), nil
    }

    for i, cryptoHash := range trieNode.childrenCryptoHashes {
        //写入加密哈希索引
        err = buffer.EncodeVarint(uint64(i))
        if err != nil {
            return nil, err
        }
        // 写入加密哈希
        err = buffer.EncodeRawBytes(cryptoHash)
        if err != nil {
            return nil, err
        }
    }
    return buffer.Bytes(), nil
}

getSortedChildrenIndex

获得孩子节点排序后的索引

func (trieNode *trieNode) getSortedChildrenIndex() []int {
    keys := make([]int, trieNode.getNumChildren())
    i := 0
    for k := range trieNode.childrenCryptoHashes {
        keys[i] = k
        i++
    }
    sort.Ints(keys)
    return keys
}

newTrieDelta

创建trie的增量

func newTrieDelta(stateDelta *statemgmt.StateDelta) *trieDelta {
    trieDelta := &trieDelta{0, make(map[int]levelDeltaMap)}
    chaincodes := stateDelta.GetUpdatedChaincodeIds(false)
    for _, chaincodeID := range chaincodes {
        updates := stateDelta.GetUpdates(chaincodeID)
        for key, updatedvalue := range updates {
            if updatedvalue.IsDelete() {
                trieDelta.delete(chaincodeID, key)
            } else {
                if stateDelta.RollBackwards {
                    trieDelta.set(chaincodeID, key, updatedvalue.GetPreviousValue())
                } else {
                    trieDelta.set(chaincodeID, key, updatedvalue.GetValue())
                }
            }
        }
    }
    return trieDelta
}

trie_db_helper

从数据库中获取trie节点

func fetchTrieNodeFromDB(key *trieKey) (*trieNode, error) {
    stateTrieLogger.Debug("Enter fetchTrieNodeFromDB() for trieKey [%s]", key)
    openchainDB := db.GetDBHandle()
    trieNodeBytes, err := openchainDB.GetFromStateCF(key.getEncodedBytes())
    if err != nil {
        stateTrieLogger.Error("Error in retrieving trie node from DB for triekey [%s]. Error:%s", key, err)
        return nil, err
    }

    if trieNodeBytes == nil {
        return nil, nil
    }

    trieNode, err := unmarshalTrieNode(key, trieNodeBytes)
    if err != nil {
        stateTrieLogger.Error("Error in unmarshalling trie node for triekey [%s]. Error:%s", key, err)
        return nil, err
    }
    stateTrieLogger.Debug("Exit fetchTrieNodeFromDB() for trieKey [%s]", key)
    return trieNode, nil
}

byteTrieKey

func (encoder *byteTrieKeyEncoder) newTrieKey(originalBytes []byte) trieKeyInterface {
    len := len(originalBytes)
    remainingBytes := len % numBytesAtEachLevel
    //剩余字节=长度和每一个级别字节数的余数
    bytesToAppend := 0
    if remainingBytes != 0 {
        bytesToAppend = numBytesAtEachLevel - remainingBytes
    }
    for i := 0; i < bytesToAppend; i++ {
        originalBytes = append(originalBytes, byte(0))
    }
    return byteTrieKey(originalBytes)
}

hexTrieKey

首先定义一个对于索引的映射,类十余bytetriekey,实现了 trieKeyInterface接口

var charIndexMap = map[hexTrieKey]int{
    "0": 0,
    "1": 1,
    "2": 2,
    "3": 3,
    "4": 4,
    "5": 5,
    "6": 6,
    "7": 7,
    "8": 8,
    "9": 9,
    "a": 10,
    "b": 11,
    "c": 12,
    "d": 13,
    "e": 14,
    "f": 15,
}

func (encoder *hexTrieKeyEncoder) newTrieKey(originalBytes []byte) trieKeyInterface {
    return hexTrieKey(hex.EncodeToString(originalBytes))
}

range_scan_iterator

func (itr *RangeScanIterator) Next() bool {
    if itr.done {
        return false
    }
    for ; itr.dbItr.Valid(); itr.dbItr.Next() {

        //使得键 - 值字节的副本,以至于使得潜在的键值字节由ITR重用。
        //关闭时没有必要为迭代器释放内存释放切片。
        trieKeyBytes := statemgmt.Copy(itr.dbItr.Key().Data())
        trieNodeBytes := statemgmt.Copy(itr.dbItr.Value().Data())
        value := unmarshalTrieNodeValue(trieNodeBytes)
        if util.IsNil(value) {
            continue
        }

        // 找到一个实际的键值
        currentCompositeKey := trieKeyEncoderImpl.decodeTrieKeyBytes(statemgmt.Copy(trieKeyBytes))
        currentChaincodeID, currentKey := statemgmt.DecodeCompositeKey(currentCompositeKey)
        if currentChaincodeID == itr.chaincodeID && (itr.endKey == "" || currentKey <= itr.endKey) {
            itr.currentKey = currentKey
            itr.currentValue = value
            itr.dbItr.Next()
            return true
        }

        // 检索指定的范围内的所有的密钥
        break
    }
    itr.done = true
    return false
}

snapshot_iterator

和range_scan_iterator的实现方式类似

func (snapshotItr *StateSnapshotIterator) Next() bool {
    var available bool
    for ; snapshotItr.dbItr.Valid(); snapshotItr.dbItr.Next() {

        trieKeyBytes := statemgmt.Copy(snapshotItr.dbItr.Key().Data())
        trieNodeBytes := statemgmt.Copy(snapshotItr.dbItr.Value().Data())
        value := unmarshalTrieNodeValue(trieNodeBytes)
        if util.NotNil(value) {
            snapshotItr.currentKey = trieKeyEncoderImpl.decodeTrieKeyBytes(statemgmt.Copy(trieKeyBytes))
            snapshotItr.currentValue = value
            available = true
            snapshotItr.dbItr.Next()
            break
        }
    }
    return available
}

state_trie

结构如下

type StateTrie struct {
    trieDelta              *trieDelta
    persistedStateHash     []byte 持久化状态哈希
    lastComputedCryptoHash []byte  最后哈希加密计算
    recomputeCryptoHash    bool 重新哈希加密计算
}

processChangedNode

节点改变流程

func (stateTrie *StateTrie) processChangedNode(changedNode *trieNode) error {
    stateTrieLogger.Debug("Enter - processChangedNode() for node [%s]", changedNode)
    dbNode, err := fetchTrieNodeFromDB(changedNode.trieKey)
    if err != nil {
        return err
    }
    if dbNode != nil {
        stateTrieLogger.Debug("processChangedNode() - merging attributes from db node [%s]", dbNode)
        changedNode.mergeMissingAttributesFrom(dbNode)
    }
    newCryptoHash := changedNode.computeCryptoHash()
    parentNode := stateTrie.trieDelta.getParentOf(changedNode)
    if parentNode == nil {
        parentNode = newTrieNode(changedNode.getParentTrieKey(), nil, false)
        stateTrie.trieDelta.addTrieNode(parentNode)
    }
    parentNode.setChildCryptoHash(changedNode.getIndexInParent(), newCryptoHash)
    if logHashOfEveryNode {
        stateTrieLogger.Debug("Hash for changedNode[%s]", changedNode)
        stateTrieLogger.Debug("%#v", newCryptoHash)
    }
    stateTrieLogger.Debug("Exit - processChangedNode() for node [%s]", changedNode)
    return nil
}

AddChangesForPersistence

为持久化添加更改

func (stateTrie *StateTrie) AddChangesForPersistence(writeBatch *gorocksdb.WriteBatch) error {
    if stateTrie.recomputeCryptoHash {
        _, err := stateTrie.ComputeCryptoHash()
        if err != nil {
            return err
        }
    }

    if stateTrie.trieDelta == nil {
        stateTrieLogger.Info("trieDelta is nil. Not writing anything to DB")
        return nil
    }

    openchainDB := db.GetDBHandle()
    lowestLevel := stateTrie.trieDelta.getLowestLevel()
    for level := lowestLevel; level >= 0; level-- {
        changedNodes := stateTrie.trieDelta.deltaMap[level]
        for _, changedNode := range changedNodes {
            if changedNode.markedForDeletion {
                writeBatch.DeleteCF(openchainDB.StateCF, changedNode.trieKey.getEncodedBytes())
                continue
            }
            serializedContent, err := changedNode.marshal()
            if err != nil {
                return err
            }
            writeBatch.PutCF(openchainDB.StateCF, changedNode.trieKey.getEncodedBytes(), serializedContent)
        }
    }
    stateTrieLogger.Debug("Added changes to DB")
    return nil
}

commons

commons位于statemgmt目录下

// 构建复合键,并返回唯一代表一个指定的chaincodeID和 []byte字节。
//这假定chaincodeID不包含0×00字节
//但键值的可以强制实施的限制chaincodeID或使用长度前缀,而不是这里的分隔符
func ConstructCompositeKey(chaincodeID string, key string) []byte {
    return bytes.Join([][]byte{[]byte(chaincodeID), []byte(key)}, stateKeyDelimiter)
}

//通过解码构建了compositeKey构造复合键的方法,返回原始chaincodeID和键形式
func DecodeCompositeKey(compositeKey []byte) (string, string) {
    split := bytes.SplitN(compositeKey, stateKeyDelimiter, 2)
    return string(split[0]), string(split[1])
}

//返回指定字节的副本
func Copy(src []byte) []byte {
    dest := make([]byte, len(src))
    copy(dest, src)
    return dest
}

hashable_state

由stat实现不同的状态管理来实现接口,可以高效地为不同的工作负载条件下,计算加密哈希状态。

type HashableState interface {

    //提供了一个机会来初始化。例如, 可以加载数据库的一些数据来实现state
    Initialize(configs map[string]interface{}) error

    // 从数据库获取值
    Get(chaincodeID string, key string) ([]byte, error)

    // 需要施加到状态,通过捕获需要的变化的stateDelta
    PrepareWorkingSet(stateDelta *StateDelta) error

    //计算状态加密哈希来实现state假设状态增量适用以PrepareWorkingSet方法传递
    ComputeCryptoHash() ([]byte, error)

    //添加的所有键值对,它需要为数据库持续触发statedelta(在、、//PrepareWorkingSet方法传递)。
//除了在StateDelta中的信息,实现还可能希望
//更快进行持久化中间结果的加密哈希计算
    AddChangesForPersistence(writeBatch *gorocksdb.WriteBatch) error

    // ClearWorkingSet可能会清除state实现,它可能已经建立了计算哈希加密和持续变化的状态增量的数据结构
    ClearWorkingSet(changesPersisted bool)


    GetStateSnapshotIterator(snapshot *gorocksdb.Snapshot) (StateSnapshotIterator, error)

    //提供一种应该给一个给定的chaincodeID使得返回键应该词法更大//所有键值迭代大于或等于startKey且小于或等于endKey。如果startKey参//数的值是假设一个空字符串startKey是在DB的chaincodeID可用最小的关//键。同样,对于endKey参数为空字符串假定endKey可用的分贝为chaincodeID//的最大键
    GetRangeScanIterator(chaincodeID string, startKey string, endKey string) (RangeScanIterator, error)

    //与StateDelta之前一些提示制备和PrepareWorkingSet方法通//过提供了可能。一个state的实现可以使用这个提示的预取相关数据,因此,//如果这可以提高哈希加密计算方法的性能(当被调用在以后的时间)
    PerfHintKeyChanged(chaincodeID string, key string)
}


state_delta_iterator

state增量迭代器结构如下

type StateDeltaIterator struct {
    updates         map[string]*UpdatedValue //更新
    relevantKeys    []string   // 关联键
    currentKeyIndex int  // 当前键的索引
    done            bool //完成标识
}

state_delta

控制变现有的状态。这个结构被用于TX-batchAlso的执行期间中保持未提交的变化,以用于以块的状态转移到另一peer

type StateDelta struct {
    ChaincodeStateDeltas map[string]*ChaincodeStateDelta
    //允许一个控制此增量是否会向前或向后回滚的状态
    RollBackwards bool
}

IsUpdatedValueSet

如果更新值已经设置为给定的chaincode ID和密钥,则为true

func (stateDelta *StateDelta) IsUpdatedValueSet(chaincodeID, key string) bool {
    chaincodeStateDelta, ok := stateDelta.ChaincodeStateDeltas[chaincodeID]
    if !ok {
        return false
    }
    if _, ok := chaincodeStateDelta.UpdatedKVs[key]; ok {
        return true
    }
    return false
}

ApplyChanges

合并另一增量- 如果一个键值存在,则现有键的值被覆盖

func (stateDelta *StateDelta) ApplyChanges(anotherStateDelta *StateDelta) {
    for chaincodeID, chaincodeStateDelta := range anotherStateDelta.ChaincodeStateDeltas {
        existingChaincodeStateDelta, existingChaincode := stateDelta.ChaincodeStateDeltas[chaincodeID]
        for key, valueHolder := range chaincodeStateDelta.UpdatedKVs {
            var previousValue []byte
            if existingChaincode {
                existingUpdateValue, existingUpdate := existingChaincodeStateDelta.UpdatedKVs[key]
                if existingUpdate {
                    // 现有的状态增量已经为这个键值的更新值
                    previousValue = existingUpdateValue.PreviousValue
                } else {
                    //使用以前的值在新的状态增量的设置
                    previousValue = valueHolder.PreviousValue
                }
            } else {
                //使用之前值的状态增量
                previousValue = valueHolder.PreviousValue
            }

            if valueHolder.IsDelete() {
                stateDelta.Delete(chaincodeID, key, previousValue)
            } else {
                stateDelta.Set(chaincodeID, key, valueHolder.Value, previousValue)
            }
        }
    }
}

GetUpdatedChaincodeIds

返回在存在于chaincodeIDs的状态增量
如果排序为true,方法按照字典顺序返回在排序之前的chaincodeIDs的排序顺序

func (stateDelta *StateDelta) GetUpdatedChaincodeIds(sorted bool) []string {
    updatedChaincodeIds := make([]string, len(stateDelta.ChaincodeStateDeltas))
    i := 0
    for k := range stateDelta.ChaincodeStateDeltas {
        updatedChaincodeIds[i] = k
        i++
    }
    if sorted {
        sort.Strings(updatedChaincodeIds)
    }
    return updatedChaincodeIds
}

好了,ledger源码就分析到这里,其实仔细观察,会发现只要有一个iterrator,就会重写对应的next、getvalue方法等,各个模块之间相互协作,比较难的就是hash加密算法,以及状态增量的计算。小编接下来将对各个模块之间进行结构功能图解,敬请期待

原文地址:https://www.cnblogs.com/ainima/p/6331786.html