gossip/privdata/coordinator.go
的StoreBlock
方法中分別對區(qū)塊交易和讀寫集進行了校驗,關鍵代碼如下:
// 此方法對區(qū)塊信息和交易簽名等進行了校驗
err := c.Validator.Validate(block)
......
......
// 此方法中對讀寫集進行了校驗
err = c.CommitLegacy(blockAndPvtData, &ledger.CommitOptions{})
區(qū)塊和交易校驗
先看區(qū)塊和交易的校驗峭弟,在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)
上述方法實現(xiàn)在core/ledger/kvledger/txmgmt/txmgr/lockbasedtxmgr/lockbased_txmgr.go
中
batch, txstatsInfo, err := txmgr.validator.ValidateAndPrepareBatch(blockAndPvtdata, doMVCCValidation)
實現(xiàn)在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
}
// 此處是隱私數(shù)據(jù)讀寫集校驗
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
節(jié)點首先獲取當前賬本中該鍵的最新版本號年鸳,并將該版本號與請求讀取該鍵的事務的版本號進行比較剃氧,如果兩個版本號相同,則表示讀取操作是有效的阻星。如果事務的版本號小于最新版本號朋鞍,則Peer
節(jié)點會拒絕讀取請求已添,因為該事務讀取的版本已經(jīng)過期,不再是當前有效的版本滥酥。
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
}