github.com/sykesm/fabric@v1.1.0-preview.0.20200129034918-2aa12b1a0181/core/ledger/kvledger/hashcheck_pvtdata.go (about) 1 /* 2 Copyright IBM Corp. All Rights Reserved. 3 4 SPDX-License-Identifier: Apache-2.0 5 */ 6 7 package kvledger 8 9 import ( 10 "bytes" 11 12 "github.com/hyperledger/fabric-protos-go/ledger/rwset" 13 "github.com/hyperledger/fabric/common/util" 14 "github.com/hyperledger/fabric/core/ledger" 15 "github.com/hyperledger/fabric/core/ledger/kvledger/txmgmt/rwsetutil" 16 "github.com/hyperledger/fabric/core/ledger/ledgerstorage" 17 "github.com/hyperledger/fabric/protoutil" 18 ) 19 20 // constructValidAndInvalidPvtData computes the valid pvt data and hash mismatch list 21 // from a received pvt data list of old blocks. 22 func constructValidAndInvalidPvtData(reconciledPvtdata []*ledger.ReconciledPvtdata, blockStore *ledgerstorage.Store) ( 23 map[uint64][]*ledger.TxPvtData, []*ledger.PvtdataHashMismatch, error, 24 ) { 25 // for each block, for each transaction, retrieve the txEnvelope to 26 // compare the hash of pvtRwSet in the block and the hash of the received 27 // txPvtData. On a mismatch, add an entry to hashMismatch list. 28 // On a match, add the pvtData to the validPvtData list 29 validPvtData := make(map[uint64][]*ledger.TxPvtData) 30 var invalidPvtData []*ledger.PvtdataHashMismatch 31 32 for _, pvtdata := range reconciledPvtdata { 33 validData, invalidData, err := findValidAndInvalidPvtdata(pvtdata, blockStore) 34 if err != nil { 35 return nil, nil, err 36 } 37 if len(validData) > 0 { 38 validPvtData[pvtdata.BlockNum] = validData 39 } 40 invalidPvtData = append(invalidPvtData, invalidData...) 41 } // for each block's pvtData 42 return validPvtData, invalidPvtData, nil 43 } 44 45 func findValidAndInvalidPvtdata(reconciledPvtdata *ledger.ReconciledPvtdata, blockStore *ledgerstorage.Store) ( 46 []*ledger.TxPvtData, []*ledger.PvtdataHashMismatch, error, 47 ) { 48 var validPvtData []*ledger.TxPvtData 49 var invalidPvtData []*ledger.PvtdataHashMismatch 50 for _, txPvtData := range reconciledPvtdata.WriteSets { 51 // (1) retrieve the txrwset from the blockstore 52 logger.Debugf("Retrieving rwset of blockNum:[%d], txNum:[%d]", reconciledPvtdata.BlockNum, txPvtData.SeqInBlock) 53 txRWSet, err := retrieveRwsetForTx(reconciledPvtdata.BlockNum, txPvtData.SeqInBlock, blockStore) 54 if err != nil { 55 return nil, nil, err 56 } 57 58 // (2) validate passed pvtData against the pvtData hash in the tx rwset. 59 logger.Debugf("Constructing valid and invalid pvtData using rwset of blockNum:[%d], txNum:[%d]", 60 reconciledPvtdata.BlockNum, txPvtData.SeqInBlock) 61 validData, invalidData := findValidAndInvalidTxPvtData(txPvtData, txRWSet, reconciledPvtdata.BlockNum) 62 63 // (3) append validData to validPvtDataPvt list of this block and 64 // invalidData to invalidPvtData list 65 if validData != nil { 66 validPvtData = append(validPvtData, validData) 67 } 68 invalidPvtData = append(invalidPvtData, invalidData...) 69 } // for each tx's pvtData 70 return validPvtData, invalidPvtData, nil 71 } 72 73 func retrieveRwsetForTx(blkNum uint64, txNum uint64, blockStore *ledgerstorage.Store) (*rwsetutil.TxRwSet, error) { 74 // retrieve the txEnvelope from the block store so that the hash of 75 // the pvtData can be retrieved for comparison 76 txEnvelope, err := blockStore.RetrieveTxByBlockNumTranNum(blkNum, txNum) 77 if err != nil { 78 return nil, err 79 } 80 // retrieve pvtRWset hash from the txEnvelope 81 responsePayload, err := protoutil.GetActionFromEnvelopeMsg(txEnvelope) 82 if err != nil { 83 return nil, err 84 } 85 txRWSet := &rwsetutil.TxRwSet{} 86 if err := txRWSet.FromProtoBytes(responsePayload.Results); err != nil { 87 return nil, err 88 } 89 return txRWSet, nil 90 } 91 92 func findValidAndInvalidTxPvtData(txPvtData *ledger.TxPvtData, txRWSet *rwsetutil.TxRwSet, blkNum uint64) ( 93 *ledger.TxPvtData, []*ledger.PvtdataHashMismatch, 94 ) { 95 var invalidPvtData []*ledger.PvtdataHashMismatch 96 var toDeleteNsColl []*nsColl 97 // Compare the hash of pvtData with the hash present in the rwset to 98 // find valid and invalid pvt data 99 for _, nsRwset := range txPvtData.WriteSet.NsPvtRwset { 100 txNum := txPvtData.SeqInBlock 101 invalidData, invalidNsColl := findInvalidNsPvtData(nsRwset, txRWSet, blkNum, txNum) 102 invalidPvtData = append(invalidPvtData, invalidData...) 103 toDeleteNsColl = append(toDeleteNsColl, invalidNsColl...) 104 } 105 for _, nsColl := range toDeleteNsColl { 106 removeCollFromTxPvtReadWriteSet(txPvtData.WriteSet, nsColl.ns, nsColl.coll) 107 } 108 if len(txPvtData.WriteSet.NsPvtRwset) == 0 { 109 // denotes that all namespaces had 110 // invalid pvt data 111 return nil, invalidPvtData 112 } 113 return txPvtData, invalidPvtData 114 } 115 116 // Remove removes the rwset for the given <ns, coll> tuple. If after this removal, 117 // there are no more collection in the namespace <ns>, the whole namespace entry is removed 118 func removeCollFromTxPvtReadWriteSet(p *rwset.TxPvtReadWriteSet, ns, coll string) { 119 for i := 0; i < len(p.NsPvtRwset); i++ { 120 n := p.NsPvtRwset[i] 121 if n.Namespace != ns { 122 continue 123 } 124 removeCollFromNsPvtWriteSet(n, coll) 125 if len(n.CollectionPvtRwset) == 0 { 126 p.NsPvtRwset = append(p.NsPvtRwset[:i], p.NsPvtRwset[i+1:]...) 127 } 128 return 129 } 130 } 131 132 func removeCollFromNsPvtWriteSet(n *rwset.NsPvtReadWriteSet, collName string) { 133 for i := 0; i < len(n.CollectionPvtRwset); i++ { 134 c := n.CollectionPvtRwset[i] 135 if c.CollectionName != collName { 136 continue 137 } 138 n.CollectionPvtRwset = append(n.CollectionPvtRwset[:i], n.CollectionPvtRwset[i+1:]...) 139 return 140 } 141 } 142 143 type nsColl struct { 144 ns, coll string 145 } 146 147 func findInvalidNsPvtData(nsRwset *rwset.NsPvtReadWriteSet, txRWSet *rwsetutil.TxRwSet, blkNum, txNum uint64) ( 148 []*ledger.PvtdataHashMismatch, []*nsColl, 149 ) { 150 var invalidPvtData []*ledger.PvtdataHashMismatch 151 var invalidNsColl []*nsColl 152 153 ns := nsRwset.Namespace 154 for _, collPvtRwset := range nsRwset.CollectionPvtRwset { 155 coll := collPvtRwset.CollectionName 156 rwsetHash := txRWSet.GetPvtDataHash(ns, coll) 157 if rwsetHash == nil { 158 logger.Warningf("namespace: %s collection: %s was not accessed by txNum %d in BlkNum %d. "+ 159 "Unnecessary pvtdata has been passed", ns, coll, txNum, blkNum) 160 invalidNsColl = append(invalidNsColl, &nsColl{ns, coll}) 161 continue 162 } 163 164 if !bytes.Equal(util.ComputeSHA256(collPvtRwset.Rwset), rwsetHash) { 165 invalidPvtData = append(invalidPvtData, &ledger.PvtdataHashMismatch{ 166 BlockNum: blkNum, 167 TxNum: txNum, 168 Namespace: ns, 169 Collection: coll, 170 ExpectedHash: rwsetHash}) 171 invalidNsColl = append(invalidNsColl, &nsColl{ns, coll}) 172 } 173 } 174 return invalidPvtData, invalidNsColl 175 }