github.com/yimialmonte/fabric@v2.1.1+incompatible/core/peer/deliverevents.go (about) 1 /* 2 Copyright IBM Corp. All Rights Reserved. 3 4 SPDX-License-Identifier: Apache-2.0 5 */ 6 7 package peer 8 9 import ( 10 "runtime/debug" 11 12 "github.com/hyperledger/fabric-protos-go/common" 13 "github.com/hyperledger/fabric-protos-go/ledger/rwset" 14 "github.com/hyperledger/fabric-protos-go/peer" 15 "github.com/hyperledger/fabric/common/deliver" 16 "github.com/hyperledger/fabric/common/flogging" 17 "github.com/hyperledger/fabric/core/aclmgmt/resources" 18 "github.com/hyperledger/fabric/core/common/privdata" 19 "github.com/hyperledger/fabric/core/ledger" 20 "github.com/hyperledger/fabric/core/ledger/util" 21 "github.com/hyperledger/fabric/msp" 22 "github.com/hyperledger/fabric/msp/mgmt" 23 "github.com/hyperledger/fabric/protoutil" 24 "github.com/pkg/errors" 25 ) 26 27 var logger = flogging.MustGetLogger("common.deliverevents") 28 29 // PolicyCheckerProvider provides the corresponding policy checker for a 30 // given resource name 31 type PolicyCheckerProvider func(resourceName string) deliver.PolicyCheckerFunc 32 33 // DeliverServer holds the dependencies necessary to create a deliver server 34 type DeliverServer struct { 35 DeliverHandler *deliver.Handler 36 PolicyCheckerProvider PolicyCheckerProvider 37 CollectionPolicyChecker CollectionPolicyChecker 38 IdentityDeserializerMgr IdentityDeserializerManager 39 } 40 41 // Chain adds Ledger() to deliver.Chain 42 type Chain interface { 43 deliver.Chain 44 Ledger() ledger.PeerLedger 45 } 46 47 // CollectionPolicyChecker is an interface that encapsulates the CheckCollectionPolicy method 48 type CollectionPolicyChecker interface { 49 CheckCollectionPolicy(blockNum uint64, ccName string, collName string, cfgHistoryRetriever ledger.ConfigHistoryRetriever, deserializer msp.IdentityDeserializer, signedData *protoutil.SignedData) (bool, error) 50 } 51 52 // IdentityDeserializerManager returns instances of Deserializer 53 type IdentityDeserializerManager interface { 54 // Deserializer returns an instance of transaction.Deserializer for the passed channel 55 // if the channel exists 56 Deserializer(channel string) (msp.IdentityDeserializer, error) 57 } 58 59 // blockResponseSender structure used to send block responses 60 type blockResponseSender struct { 61 peer.Deliver_DeliverServer 62 } 63 64 // SendStatusResponse generates status reply proto message 65 func (brs *blockResponseSender) SendStatusResponse(status common.Status) error { 66 reply := &peer.DeliverResponse{ 67 Type: &peer.DeliverResponse_Status{Status: status}, 68 } 69 return brs.Send(reply) 70 } 71 72 // SendBlockResponse generates deliver response with block message. 73 func (brs *blockResponseSender) SendBlockResponse( 74 block *common.Block, 75 channelID string, 76 chain deliver.Chain, 77 signedData *protoutil.SignedData, 78 ) error { 79 // Generates filtered block response 80 response := &peer.DeliverResponse{ 81 Type: &peer.DeliverResponse_Block{Block: block}, 82 } 83 return brs.Send(response) 84 } 85 86 func (brs *blockResponseSender) DataType() string { 87 return "block" 88 } 89 90 // filteredBlockResponseSender structure used to send filtered block responses 91 type filteredBlockResponseSender struct { 92 peer.Deliver_DeliverFilteredServer 93 } 94 95 // SendStatusResponse generates status reply proto message 96 func (fbrs *filteredBlockResponseSender) SendStatusResponse(status common.Status) error { 97 response := &peer.DeliverResponse{ 98 Type: &peer.DeliverResponse_Status{Status: status}, 99 } 100 return fbrs.Send(response) 101 } 102 103 // IsFiltered is a marker method which indicates that this response sender 104 // sends filtered blocks. 105 func (fbrs *filteredBlockResponseSender) IsFiltered() bool { 106 return true 107 } 108 109 // SendBlockResponse generates deliver response with filtered block message 110 func (fbrs *filteredBlockResponseSender) SendBlockResponse( 111 block *common.Block, 112 channelID string, 113 chain deliver.Chain, 114 signedData *protoutil.SignedData, 115 ) error { 116 // Generates filtered block response 117 b := blockEvent(*block) 118 filteredBlock, err := b.toFilteredBlock() 119 if err != nil { 120 logger.Warningf("Failed to generate filtered block due to: %s", err) 121 return fbrs.SendStatusResponse(common.Status_BAD_REQUEST) 122 } 123 response := &peer.DeliverResponse{ 124 Type: &peer.DeliverResponse_FilteredBlock{FilteredBlock: filteredBlock}, 125 } 126 return fbrs.Send(response) 127 } 128 129 func (fbrs *filteredBlockResponseSender) DataType() string { 130 return "filtered_block" 131 } 132 133 // blockResponseSender structure used to send block responses 134 type blockAndPrivateDataResponseSender struct { 135 peer.Deliver_DeliverWithPrivateDataServer 136 CollectionPolicyChecker 137 IdentityDeserializerManager 138 } 139 140 // SendStatusResponse generates status reply proto message 141 func (bprs *blockAndPrivateDataResponseSender) SendStatusResponse(status common.Status) error { 142 reply := &peer.DeliverResponse{ 143 Type: &peer.DeliverResponse_Status{Status: status}, 144 } 145 return bprs.Send(reply) 146 } 147 148 // SendBlockResponse gets private data and generates deliver response with both block and private data 149 func (bprs *blockAndPrivateDataResponseSender) SendBlockResponse( 150 block *common.Block, 151 channelID string, 152 chain deliver.Chain, 153 signedData *protoutil.SignedData, 154 ) error { 155 pvtData, err := bprs.getPrivateData(block, chain, channelID, signedData) 156 if err != nil { 157 return err 158 } 159 160 blockAndPvtData := &peer.BlockAndPrivateData{ 161 Block: block, 162 PrivateDataMap: pvtData, 163 } 164 response := &peer.DeliverResponse{ 165 Type: &peer.DeliverResponse_BlockAndPrivateData{BlockAndPrivateData: blockAndPvtData}, 166 } 167 return bprs.Send(response) 168 } 169 170 func (bprs *blockAndPrivateDataResponseSender) DataType() string { 171 return "block_and_pvtdata" 172 } 173 174 // getPrivateData returns private data for the block 175 func (bprs *blockAndPrivateDataResponseSender) getPrivateData( 176 block *common.Block, 177 chain deliver.Chain, 178 channelID string, 179 signedData *protoutil.SignedData, 180 ) (map[uint64]*rwset.TxPvtReadWriteSet, error) { 181 182 channel, ok := chain.(Chain) 183 if !ok { 184 return nil, errors.New("wrong chain type") 185 } 186 187 pvtData, err := channel.Ledger().GetPvtDataByNum(block.Header.Number, nil) 188 if err != nil { 189 logger.Errorf("Error getting private data by block number %d on channel %s", block.Header.Number, channelID) 190 return nil, errors.Wrapf(err, "error getting private data by block number %d", block.Header.Number) 191 } 192 193 seqs2Namespaces := aggregatedCollections(make(map[seqAndDataModel]map[string][]*rwset.CollectionPvtReadWriteSet)) 194 195 configHistoryRetriever, err := channel.Ledger().GetConfigHistoryRetriever() 196 if err != nil { 197 return nil, err 198 } 199 200 identityDeserializer, err := bprs.IdentityDeserializerManager.Deserializer(channelID) 201 if err != nil { 202 return nil, err 203 } 204 205 // check policy for each collection and add the collection if passing the policy requirement 206 for _, item := range pvtData { 207 logger.Debugf("Got private data for block number %d, tx sequence %d", block.Header.Number, item.SeqInBlock) 208 if item.WriteSet == nil { 209 continue 210 } 211 for _, ns := range item.WriteSet.NsPvtRwset { 212 for _, col := range ns.CollectionPvtRwset { 213 logger.Debugf("Checking policy for namespace %s, collection %s", ns.Namespace, col.CollectionName) 214 215 eligible, err := bprs.CollectionPolicyChecker.CheckCollectionPolicy(block.Header.Number, 216 ns.Namespace, col.CollectionName, configHistoryRetriever, identityDeserializer, signedData) 217 if err != nil { 218 return nil, err 219 } 220 221 if eligible { 222 logger.Debugf("Adding private data for namespace %s, collection %s", ns.Namespace, col.CollectionName) 223 seqs2Namespaces.addCollection(item.SeqInBlock, item.WriteSet.DataModel, ns.Namespace, col) 224 } 225 } 226 } 227 } 228 229 return seqs2Namespaces.asPrivateDataMap(), nil 230 } 231 232 // transactionActions aliasing for peer.TransactionAction pointers slice 233 type transactionActions []*peer.TransactionAction 234 235 // blockEvent an alias for common.Block structure, used to 236 // extend with auxiliary functionality 237 type blockEvent common.Block 238 239 // DeliverFiltered sends a stream of blocks to a client after commitment 240 func (s *DeliverServer) DeliverFiltered(srv peer.Deliver_DeliverFilteredServer) error { 241 logger.Debugf("Starting new DeliverFiltered handler") 242 defer dumpStacktraceOnPanic() 243 // getting policy checker based on resources.Event_FilteredBlock resource name 244 deliverServer := &deliver.Server{ 245 Receiver: srv, 246 PolicyChecker: s.PolicyCheckerProvider(resources.Event_FilteredBlock), 247 ResponseSender: &filteredBlockResponseSender{ 248 Deliver_DeliverFilteredServer: srv, 249 }, 250 } 251 return s.DeliverHandler.Handle(srv.Context(), deliverServer) 252 } 253 254 // Deliver sends a stream of blocks to a client after commitment 255 func (s *DeliverServer) Deliver(srv peer.Deliver_DeliverServer) (err error) { 256 logger.Debugf("Starting new Deliver handler") 257 defer dumpStacktraceOnPanic() 258 // getting policy checker based on resources.Event_Block resource name 259 deliverServer := &deliver.Server{ 260 PolicyChecker: s.PolicyCheckerProvider(resources.Event_Block), 261 Receiver: srv, 262 ResponseSender: &blockResponseSender{ 263 Deliver_DeliverServer: srv, 264 }, 265 } 266 return s.DeliverHandler.Handle(srv.Context(), deliverServer) 267 } 268 269 // DeliverWithPrivateData sends a stream of blocks and pvtdata to a client after commitment 270 func (s *DeliverServer) DeliverWithPrivateData(srv peer.Deliver_DeliverWithPrivateDataServer) (err error) { 271 logger.Debug("Starting new DeliverWithPrivateData handler") 272 defer dumpStacktraceOnPanic() 273 if s.CollectionPolicyChecker == nil { 274 s.CollectionPolicyChecker = &collPolicyChecker{} 275 } 276 if s.IdentityDeserializerMgr == nil { 277 s.IdentityDeserializerMgr = &identityDeserializerMgr{} 278 } 279 // getting policy checker based on resources.Event_Block resource name 280 deliverServer := &deliver.Server{ 281 PolicyChecker: s.PolicyCheckerProvider(resources.Event_Block), 282 Receiver: srv, 283 ResponseSender: &blockAndPrivateDataResponseSender{ 284 Deliver_DeliverWithPrivateDataServer: srv, 285 CollectionPolicyChecker: s.CollectionPolicyChecker, 286 IdentityDeserializerManager: s.IdentityDeserializerMgr, 287 }, 288 } 289 err = s.DeliverHandler.Handle(srv.Context(), deliverServer) 290 return err 291 } 292 293 func (block *blockEvent) toFilteredBlock() (*peer.FilteredBlock, error) { 294 filteredBlock := &peer.FilteredBlock{ 295 Number: block.Header.Number, 296 } 297 298 txsFltr := util.TxValidationFlags(block.Metadata.Metadata[common.BlockMetadataIndex_TRANSACTIONS_FILTER]) 299 for txIndex, ebytes := range block.Data.Data { 300 var env *common.Envelope 301 var err error 302 303 if ebytes == nil { 304 logger.Debugf("got nil data bytes for tx index %d, block num %d", txIndex, block.Header.Number) 305 continue 306 } 307 308 env, err = protoutil.GetEnvelopeFromBlock(ebytes) 309 if err != nil { 310 logger.Errorf("error getting tx from block, %s", err) 311 continue 312 } 313 314 // get the payload from the envelope 315 payload, err := protoutil.UnmarshalPayload(env.Payload) 316 if err != nil { 317 return nil, errors.WithMessage(err, "could not extract payload from envelope") 318 } 319 320 if payload.Header == nil { 321 logger.Debugf("transaction payload header is nil, %d, block num %d", txIndex, block.Header.Number) 322 continue 323 } 324 chdr, err := protoutil.UnmarshalChannelHeader(payload.Header.ChannelHeader) 325 if err != nil { 326 return nil, err 327 } 328 329 filteredBlock.ChannelId = chdr.ChannelId 330 331 filteredTransaction := &peer.FilteredTransaction{ 332 Txid: chdr.TxId, 333 Type: common.HeaderType(chdr.Type), 334 TxValidationCode: txsFltr.Flag(txIndex), 335 } 336 337 if filteredTransaction.Type == common.HeaderType_ENDORSER_TRANSACTION { 338 tx, err := protoutil.UnmarshalTransaction(payload.Data) 339 if err != nil { 340 return nil, errors.WithMessage(err, "error unmarshal transaction payload for block event") 341 } 342 343 filteredTransaction.Data, err = transactionActions(tx.Actions).toFilteredActions() 344 if err != nil { 345 logger.Errorf(err.Error()) 346 return nil, err 347 } 348 } 349 350 filteredBlock.FilteredTransactions = append(filteredBlock.FilteredTransactions, filteredTransaction) 351 } 352 353 return filteredBlock, nil 354 } 355 356 func (ta transactionActions) toFilteredActions() (*peer.FilteredTransaction_TransactionActions, error) { 357 transactionActions := &peer.FilteredTransactionActions{} 358 for _, action := range ta { 359 chaincodeActionPayload, err := protoutil.UnmarshalChaincodeActionPayload(action.Payload) 360 if err != nil { 361 return nil, errors.WithMessage(err, "error unmarshal transaction action payload for block event") 362 } 363 364 if chaincodeActionPayload.Action == nil { 365 logger.Debugf("chaincode action, the payload action is nil, skipping") 366 continue 367 } 368 propRespPayload, err := protoutil.UnmarshalProposalResponsePayload(chaincodeActionPayload.Action.ProposalResponsePayload) 369 if err != nil { 370 return nil, errors.WithMessage(err, "error unmarshal proposal response payload for block event") 371 } 372 373 caPayload, err := protoutil.UnmarshalChaincodeAction(propRespPayload.Extension) 374 if err != nil { 375 return nil, errors.WithMessage(err, "error unmarshal chaincode action for block event") 376 } 377 378 ccEvent, err := protoutil.UnmarshalChaincodeEvents(caPayload.Events) 379 if err != nil { 380 return nil, errors.WithMessage(err, "error unmarshal chaincode event for block event") 381 } 382 383 if ccEvent.GetChaincodeId() != "" { 384 filteredAction := &peer.FilteredChaincodeAction{ 385 ChaincodeEvent: &peer.ChaincodeEvent{ 386 TxId: ccEvent.TxId, 387 ChaincodeId: ccEvent.ChaincodeId, 388 EventName: ccEvent.EventName, 389 }, 390 } 391 transactionActions.ChaincodeActions = append(transactionActions.ChaincodeActions, filteredAction) 392 } 393 } 394 return &peer.FilteredTransaction_TransactionActions{ 395 TransactionActions: transactionActions, 396 }, nil 397 } 398 399 func dumpStacktraceOnPanic() { 400 func() { 401 if r := recover(); r != nil { 402 logger.Criticalf("Deliver client triggered panic: %s\n%s", r, debug.Stack()) 403 } 404 logger.Debugf("Closing Deliver stream") 405 }() 406 } 407 408 type seqAndDataModel struct { 409 seq uint64 410 dataModel rwset.TxReadWriteSet_DataModel 411 } 412 413 // Below map temporarily stores the private data that have passed the corresponding collection policy. 414 // outer map is from seqAndDataModel to inner map, 415 // and innner map is from namespace to []*rwset.CollectionPvtReadWriteSet 416 type aggregatedCollections map[seqAndDataModel]map[string][]*rwset.CollectionPvtReadWriteSet 417 418 // addCollection adds private data based on seq, namespace, and collection. 419 func (ac aggregatedCollections) addCollection(seqInBlock uint64, dm rwset.TxReadWriteSet_DataModel, namespace string, col *rwset.CollectionPvtReadWriteSet) { 420 seq := seqAndDataModel{ 421 dataModel: dm, 422 seq: seqInBlock, 423 } 424 if _, exists := ac[seq]; !exists { 425 ac[seq] = make(map[string][]*rwset.CollectionPvtReadWriteSet) 426 } 427 ac[seq][namespace] = append(ac[seq][namespace], col) 428 } 429 430 // asPrivateDataMap converts aggregatedCollections to map[uint64]*rwset.TxPvtReadWriteSet 431 // as defined in BlockAndPrivateData protobuf message. 432 func (ac aggregatedCollections) asPrivateDataMap() map[uint64]*rwset.TxPvtReadWriteSet { 433 var pvtDataMap = make(map[uint64]*rwset.TxPvtReadWriteSet) 434 for seq, ns := range ac { 435 // create a txPvtReadWriteSet and add collection data to it 436 txPvtRWSet := &rwset.TxPvtReadWriteSet{ 437 DataModel: seq.dataModel, 438 } 439 440 for namespaceName, cols := range ns { 441 txPvtRWSet.NsPvtRwset = append(txPvtRWSet.NsPvtRwset, &rwset.NsPvtReadWriteSet{ 442 Namespace: namespaceName, 443 CollectionPvtRwset: cols, 444 }) 445 } 446 447 pvtDataMap[seq.seq] = txPvtRWSet 448 } 449 return pvtDataMap 450 } 451 452 // identityDeserializerMgr implements an IdentityDeserializerManager 453 // by routing the call to the msp/mgmt package 454 type identityDeserializerMgr struct { 455 } 456 457 func (*identityDeserializerMgr) Deserializer(channelID string) (msp.IdentityDeserializer, error) { 458 id, ok := mgmt.GetDeserializers()[channelID] 459 if !ok { 460 return nil, errors.Errorf("channel %s not found", channelID) 461 } 462 return id, nil 463 } 464 465 // collPolicyChecker is the default implementation for CollectionPolicyChecker interface 466 type collPolicyChecker struct { 467 } 468 469 // CheckCollectionPolicy checks if the CollectionCriteria meets the policy requirement 470 func (cs *collPolicyChecker) CheckCollectionPolicy( 471 blockNum uint64, 472 ccName string, 473 collName string, 474 cfgHistoryRetriever ledger.ConfigHistoryRetriever, 475 deserializer msp.IdentityDeserializer, 476 signedData *protoutil.SignedData, 477 ) (bool, error) { 478 configInfo, err := cfgHistoryRetriever.MostRecentCollectionConfigBelow(blockNum, ccName) 479 if err != nil { 480 return false, errors.WithMessagef(err, "error getting most recent collection config below block sequence = %d for chaincode %s", blockNum, ccName) 481 } 482 483 staticCollConfig := extractStaticCollectionConfig(configInfo.CollectionConfig, collName) 484 if staticCollConfig == nil { 485 return false, errors.Errorf("no collection config was found for collection %s for chaincode %s", collName, ccName) 486 } 487 488 if !staticCollConfig.MemberOnlyRead { 489 return true, nil 490 } 491 492 // get collection access policy and access filter to check eligibility 493 collAP := &privdata.SimpleCollection{} 494 err = collAP.Setup(staticCollConfig, deserializer) 495 if err != nil { 496 return false, errors.WithMessagef(err, "error setting up collection %s", staticCollConfig.Name) 497 } 498 logger.Debugf("got collection access policy") 499 500 collFilter := collAP.AccessFilter() 501 if collFilter == nil { 502 logger.Debugf("collection %s has no access filter, skipping...", collName) 503 return false, nil 504 } 505 506 eligible := collFilter(*signedData) 507 return eligible, nil 508 } 509 510 func extractStaticCollectionConfig(configPackage *peer.CollectionConfigPackage, collectionName string) *peer.StaticCollectionConfig { 511 for _, config := range configPackage.Config { 512 switch cconf := config.Payload.(type) { 513 case *peer.CollectionConfig_StaticCollectionConfig: 514 if cconf.StaticCollectionConfig.Name == collectionName { 515 return cconf.StaticCollectionConfig 516 } 517 default: 518 return nil 519 } 520 } 521 return nil 522 }