Fabric2.0.0 区块交易校验流程解析

2023-02-28  本文已影响0人  liurenhao

gossip/privdata/coordinator.goStoreBlock方法中分别对区块交易和读写集进行了校验,关键代码如下:

// 此方法对区块信息和交易签名等进行了校验
err := c.Validator.Validate(block)
......
......
// 此方法中对读写集进行了校验
err = c.CommitLegacy(blockAndPvtData, &ledger.CommitOptions{})

区块和交易校验

先看区块和交易的校验,在core/committer/txvalidator/v20/validator.go中的Validate(block *common.Block)方法:

func (v *TxValidator) Validate(block *common.Block) error {
    var err error
    var errPos int

    startValidation := time.Now() // timer to log Validate block duration
    logger.Debugf("[%s] START Block Validation for block [%d]", v.ChannelID, block.Header.Number)

    // Initialize trans as valid here, then set invalidation reason code upon invalidation below
    txsfltr := ledgerUtil.NewTxValidationFlags(len(block.Data.Data))
    // array of txids
    txidArray := make([]string, len(block.Data.Data))

    results := make(chan *blockValidationResult)
    go func() {
        for tIdx, d := range block.Data.Data {
            // ensure that we don't have too many concurrent validation workers
            v.Semaphore.Acquire(context.Background())

            go func(index int, data []byte) {
                defer v.Semaphore.Release()

                v.validateTx(&blockValidationRequest{
                    d:     data,
                    block: block,
                    tIdx:  index,
                }, results)
            }(tIdx, d)
        }
    }()

读写集校验

core/ledger/kvledger/kv_ledger.goCommitLegacy方法中

// 此处进行读写集校验
txstatsInfo, updateBatchBytes, err := l.txtmgmt.ValidateAndPrepare(pvtdataAndBlock, true)

上述方法实现在core/ledger/kvledger/txmgmt/txmgr/lockbasedtxmgr/lockbased_txmgr.go

batch, txstatsInfo, err := txmgr.validator.ValidateAndPrepareBatch(blockAndPvtdata, doMVCCValidation)

实现在core/ledger/kvledger/txmgmt/validator/valimpl/default_impl.go

func (impl *DefaultImpl) ValidateAndPrepareBatch(blockAndPvtdata *ledger.BlockAndPvtData,
    doMVCCValidation bool) (*privacyenabledstate.UpdateBatch, []*txmgr.TxStatInfo, error) {
       // 此处进行第一次读写集校验   levelDB为空校验
    if internalBlock, txsStatInfo, err = preprocessProtoBlock(
        impl.txmgr,
        impl.db.ValidateKeyValue,
        block,
        doMVCCValidation,
        impl.customTxProcessors,
    ); err != nil {
        return nil, nil, err
    }
        // 此处进行读写集校验,包括了“双花”校验等
    if pubAndHashUpdates, err = impl.internalValidator.ValidateAndPrepareBatch(internalBlock, doMVCCValidation); err != nil {
        return nil, nil, err
    }
        // 此处是隐私数据读写集校验
    logger.Debug("validating rwset...")
    if pvtUpdates, err = validateAndPreparePvtBatch(
        internalBlock,
        impl.db,
        pubAndHashUpdates,
        blockAndPvtdata.PvtData,
        impl.customTxProcessors,
    ); err != nil {
        return nil, nil, err
    }

}

跟到core/ledger/kvledger/txmgmt/validator/statebasedval/state_based_validator.go中的validateEndorserTX方法

func (v *Validator) validateEndorserTX(
    txRWSet *rwsetutil.TxRwSet,
    doMVCCValidation bool,
    updates *internal.PubAndHashUpdates) (peer.TxValidationCode, error) {

    var validationCode = peer.TxValidationCode_VALID
    var err error
    // 此处进行MVCC校验  
    if doMVCCValidation {
        validationCode, err = v.validateTx(txRWSet, updates)
    }
    return validationCode, err
}

MVCC Check是在读取账本中的键值对时进行的一种检查机制。在Hyperledger Fabric中,账本的每个版本都有一个对应的版本号,称为“交易编号”(transaction ID)。在读取账本中的某个键值对时,Peer节点首先获取当前账本中该键的最新版本号,并将该版本号与请求读取该键的事务的版本号进行比较,如果两个版本号相同,则表示读取操作是有效的。如果事务的版本号小于最新版本号,则Peer节点会拒绝读取请求,因为该事务读取的版本已经过期,不再是当前有效的版本。

func (v *Validator) validateTx(txRWSet *rwsetutil.TxRwSet, updates *internal.PubAndHashUpdates) (peer.TxValidationCode, error) {
    // Uncomment the following only for local debugging. Don't want to print data in the logs in production
    //logger.Debugf("validateTx - validating txRWSet: %s", spew.Sdump(txRWSet))
    for _, nsRWSet := range txRWSet.NsRwSets {
        ns := nsRWSet.NameSpace
        // Validate public reads
        if valid, err := v.validateReadSet(ns, nsRWSet.KvRwSet.Reads, updates.PubUpdates); !valid || err != nil {
            if err != nil {
                return peer.TxValidationCode(-1), err
            }
            return peer.TxValidationCode_MVCC_READ_CONFLICT, nil
        }
        // Validate range queries for phantom items
        if valid, err := v.validateRangeQueries(ns, nsRWSet.KvRwSet.RangeQueriesInfo, updates.PubUpdates); !valid || err != nil {
            if err != nil {
                return peer.TxValidationCode(-1), err
            }
            return peer.TxValidationCode_PHANTOM_READ_CONFLICT, nil
        }
        // Validate hashes for private reads
        if valid, err := v.validateNsHashedReadSets(ns, nsRWSet.CollHashedRwSets, updates.HashUpdates); !valid || err != nil {
            if err != nil {
                return peer.TxValidationCode(-1), err
            }
            return peer.TxValidationCode_MVCC_READ_CONFLICT, nil
        }
    }
    return peer.TxValidationCode_VALID, nil
}
上一篇下一篇

猜你喜欢

热点阅读