Fabric2.0.0 区块交易校验流程解析
2023-02-28 本文已影响0人
liurenhao
gossip/privdata/coordinator.go
的StoreBlock
方法中分别对区块交易和读写集进行了校验,关键代码如下:
// 此方法对区块信息和交易签名等进行了校验
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.go
的CommitLegacy
方法中
// 此处进行读写集校验
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
}