github.com/hechain20/hechain@v0.0.0-20220316014945-b544036ba106/core/peer/deliverevents.go (about) 1 /* 2 Copyright hechain. 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/hechain20/hechain/common/deliver" 13 "github.com/hechain20/hechain/common/flogging" 14 "github.com/hechain20/hechain/core/aclmgmt/resources" 15 "github.com/hechain20/hechain/core/common/privdata" 16 "github.com/hechain20/hechain/core/ledger" 17 "github.com/hechain20/hechain/internal/pkg/txflags" 18 "github.com/hechain20/hechain/msp" 19 "github.com/hechain20/hechain/msp/mgmt" 20 "github.com/hechain20/hechain/protoutil" 21 "github.com/hyperledger/fabric-protos-go/common" 22 "github.com/hyperledger/fabric-protos-go/ledger/rwset" 23 "github.com/hyperledger/fabric-protos-go/peer" 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 channel, ok := chain.(Chain) 182 if !ok { 183 return nil, errors.New("wrong chain type") 184 } 185 186 pvtData, err := channel.Ledger().GetPvtDataByNum(block.Header.Number, nil) 187 if err != nil { 188 logger.Errorf("Error getting private data by block number %d on channel %s", block.Header.Number, channelID) 189 return nil, errors.Wrapf(err, "error getting private data by block number %d", block.Header.Number) 190 } 191 192 seqs2Namespaces := aggregatedCollections(make(map[seqAndDataModel]map[string][]*rwset.CollectionPvtReadWriteSet)) 193 194 configHistoryRetriever, err := channel.Ledger().GetConfigHistoryRetriever() 195 if err != nil { 196 return nil, err 197 } 198 199 identityDeserializer, err := bprs.IdentityDeserializerManager.Deserializer(channelID) 200 if err != nil { 201 return nil, err 202 } 203 204 // check policy for each collection and add the collection if passing the policy requirement 205 for _, item := range pvtData { 206 logger.Debugf("Got private data for block number %d, tx sequence %d", block.Header.Number, item.SeqInBlock) 207 if item.WriteSet == nil { 208 continue 209 } 210 for _, ns := range item.WriteSet.NsPvtRwset { 211 for _, col := range ns.CollectionPvtRwset { 212 logger.Debugf("Checking policy for namespace %s, collection %s", ns.Namespace, col.CollectionName) 213 214 eligible, err := bprs.CollectionPolicyChecker.CheckCollectionPolicy(block.Header.Number, 215 ns.Namespace, col.CollectionName, configHistoryRetriever, identityDeserializer, signedData) 216 if err != nil { 217 return nil, err 218 } 219 220 if eligible { 221 logger.Debugf("Adding private data for namespace %s, collection %s", ns.Namespace, col.CollectionName) 222 seqs2Namespaces.addCollection(item.SeqInBlock, item.WriteSet.DataModel, ns.Namespace, col) 223 } 224 } 225 } 226 } 227 228 return seqs2Namespaces.asPrivateDataMap(), nil 229 } 230 231 // transactionActions aliasing for peer.TransactionAction pointers slice 232 type transactionActions []*peer.TransactionAction 233 234 // blockEvent an alias for common.Block structure, used to 235 // extend with auxiliary functionality 236 type blockEvent common.Block 237 238 // DeliverFiltered sends a stream of blocks to a client after commitment 239 func (s *DeliverServer) DeliverFiltered(srv peer.Deliver_DeliverFilteredServer) error { 240 logger.Debugf("Starting new DeliverFiltered handler") 241 defer dumpStacktraceOnPanic() 242 // getting policy checker based on resources.Event_FilteredBlock resource name 243 deliverServer := &deliver.Server{ 244 Receiver: srv, 245 PolicyChecker: s.PolicyCheckerProvider(resources.Event_FilteredBlock), 246 ResponseSender: &filteredBlockResponseSender{ 247 Deliver_DeliverFilteredServer: srv, 248 }, 249 } 250 return s.DeliverHandler.Handle(srv.Context(), deliverServer) 251 } 252 253 // Deliver sends a stream of blocks to a client after commitment 254 func (s *DeliverServer) Deliver(srv peer.Deliver_DeliverServer) (err error) { 255 logger.Debugf("Starting new Deliver handler") 256 defer dumpStacktraceOnPanic() 257 // getting policy checker based on resources.Event_Block resource name 258 deliverServer := &deliver.Server{ 259 PolicyChecker: s.PolicyCheckerProvider(resources.Event_Block), 260 Receiver: srv, 261 ResponseSender: &blockResponseSender{ 262 Deliver_DeliverServer: srv, 263 }, 264 } 265 return s.DeliverHandler.Handle(srv.Context(), deliverServer) 266 } 267 268 // DeliverWithPrivateData sends a stream of blocks and pvtdata to a client after commitment 269 func (s *DeliverServer) DeliverWithPrivateData(srv peer.Deliver_DeliverWithPrivateDataServer) (err error) { 270 logger.Debug("Starting new DeliverWithPrivateData handler") 271 defer dumpStacktraceOnPanic() 272 if s.CollectionPolicyChecker == nil { 273 s.CollectionPolicyChecker = &collPolicyChecker{} 274 } 275 if s.IdentityDeserializerMgr == nil { 276 s.IdentityDeserializerMgr = &identityDeserializerMgr{} 277 } 278 // getting policy checker based on resources.Event_Block resource name 279 deliverServer := &deliver.Server{ 280 PolicyChecker: s.PolicyCheckerProvider(resources.Event_Block), 281 Receiver: srv, 282 ResponseSender: &blockAndPrivateDataResponseSender{ 283 Deliver_DeliverWithPrivateDataServer: srv, 284 CollectionPolicyChecker: s.CollectionPolicyChecker, 285 IdentityDeserializerManager: s.IdentityDeserializerMgr, 286 }, 287 } 288 err = s.DeliverHandler.Handle(srv.Context(), deliverServer) 289 return err 290 } 291 292 func (block *blockEvent) toFilteredBlock() (*peer.FilteredBlock, error) { 293 filteredBlock := &peer.FilteredBlock{ 294 Number: block.Header.Number, 295 } 296 297 txsFltr := txflags.ValidationFlags(block.Metadata.Metadata[common.BlockMetadataIndex_TRANSACTIONS_FILTER]) 298 for txIndex, ebytes := range block.Data.Data { 299 var env *common.Envelope 300 var err error 301 302 if ebytes == nil { 303 logger.Debugf("got nil data bytes for tx index %d, block num %d", txIndex, block.Header.Number) 304 continue 305 } 306 307 env, err = protoutil.GetEnvelopeFromBlock(ebytes) 308 if err != nil { 309 logger.Errorf("error getting tx from block, %s", err) 310 continue 311 } 312 313 // get the payload from the envelope 314 payload, err := protoutil.UnmarshalPayload(env.Payload) 315 if err != nil { 316 return nil, errors.WithMessage(err, "could not extract payload from envelope") 317 } 318 319 if payload.Header == nil { 320 logger.Debugf("transaction payload header is nil, %d, block num %d", txIndex, block.Header.Number) 321 continue 322 } 323 chdr, err := protoutil.UnmarshalChannelHeader(payload.Header.ChannelHeader) 324 if err != nil { 325 return nil, err 326 } 327 328 filteredBlock.ChannelId = chdr.ChannelId 329 330 filteredTransaction := &peer.FilteredTransaction{ 331 Txid: chdr.TxId, 332 Type: common.HeaderType(chdr.Type), 333 TxValidationCode: txsFltr.Flag(txIndex), 334 } 335 336 if filteredTransaction.Type == common.HeaderType_ENDORSER_TRANSACTION { 337 tx, err := protoutil.UnmarshalTransaction(payload.Data) 338 if err != nil { 339 return nil, errors.WithMessage(err, "error unmarshal transaction payload for block event") 340 } 341 342 filteredTransaction.Data, err = transactionActions(tx.Actions).toFilteredActions() 343 if err != nil { 344 logger.Errorf(err.Error()) 345 return nil, err 346 } 347 } 348 349 filteredBlock.FilteredTransactions = append(filteredBlock.FilteredTransactions, filteredTransaction) 350 } 351 352 return filteredBlock, nil 353 } 354 355 func (ta transactionActions) toFilteredActions() (*peer.FilteredTransaction_TransactionActions, error) { 356 transactionActions := &peer.FilteredTransactionActions{} 357 for _, action := range ta { 358 chaincodeActionPayload, err := protoutil.UnmarshalChaincodeActionPayload(action.Payload) 359 if err != nil { 360 return nil, errors.WithMessage(err, "error unmarshal transaction action payload for block event") 361 } 362 363 if chaincodeActionPayload.Action == nil { 364 logger.Debugf("chaincode action, the payload action is nil, skipping") 365 continue 366 } 367 propRespPayload, err := protoutil.UnmarshalProposalResponsePayload(chaincodeActionPayload.Action.ProposalResponsePayload) 368 if err != nil { 369 return nil, errors.WithMessage(err, "error unmarshal proposal response payload for block event") 370 } 371 372 caPayload, err := protoutil.UnmarshalChaincodeAction(propRespPayload.Extension) 373 if err != nil { 374 return nil, errors.WithMessage(err, "error unmarshal chaincode action for block event") 375 } 376 377 ccEvent, err := protoutil.UnmarshalChaincodeEvents(caPayload.Events) 378 if err != nil { 379 return nil, errors.WithMessage(err, "error unmarshal chaincode event for block event") 380 } 381 382 if ccEvent.GetChaincodeId() != "" { 383 filteredAction := &peer.FilteredChaincodeAction{ 384 ChaincodeEvent: &peer.ChaincodeEvent{ 385 TxId: ccEvent.TxId, 386 ChaincodeId: ccEvent.ChaincodeId, 387 EventName: ccEvent.EventName, 388 }, 389 } 390 transactionActions.ChaincodeActions = append(transactionActions.ChaincodeActions, filteredAction) 391 } 392 } 393 return &peer.FilteredTransaction_TransactionActions{ 394 TransactionActions: transactionActions, 395 }, nil 396 } 397 398 func dumpStacktraceOnPanic() { 399 func() { 400 if r := recover(); r != nil { 401 logger.Criticalf("Deliver client triggered panic: %s\n%s", r, debug.Stack()) 402 } 403 logger.Debugf("Closing Deliver stream") 404 }() 405 } 406 407 type seqAndDataModel struct { 408 seq uint64 409 dataModel rwset.TxReadWriteSet_DataModel 410 } 411 412 // Below map temporarily stores the private data that have passed the corresponding collection policy. 413 // outer map is from seqAndDataModel to inner map, 414 // and innner map is from namespace to []*rwset.CollectionPvtReadWriteSet 415 type aggregatedCollections map[seqAndDataModel]map[string][]*rwset.CollectionPvtReadWriteSet 416 417 // addCollection adds private data based on seq, namespace, and collection. 418 func (ac aggregatedCollections) addCollection(seqInBlock uint64, dm rwset.TxReadWriteSet_DataModel, namespace string, col *rwset.CollectionPvtReadWriteSet) { 419 seq := seqAndDataModel{ 420 dataModel: dm, 421 seq: seqInBlock, 422 } 423 if _, exists := ac[seq]; !exists { 424 ac[seq] = make(map[string][]*rwset.CollectionPvtReadWriteSet) 425 } 426 ac[seq][namespace] = append(ac[seq][namespace], col) 427 } 428 429 // asPrivateDataMap converts aggregatedCollections to map[uint64]*rwset.TxPvtReadWriteSet 430 // as defined in BlockAndPrivateData protobuf message. 431 func (ac aggregatedCollections) asPrivateDataMap() map[uint64]*rwset.TxPvtReadWriteSet { 432 pvtDataMap := make(map[uint64]*rwset.TxPvtReadWriteSet) 433 for seq, ns := range ac { 434 // create a txPvtReadWriteSet and add collection data to it 435 txPvtRWSet := &rwset.TxPvtReadWriteSet{ 436 DataModel: seq.dataModel, 437 } 438 439 for namespaceName, cols := range ns { 440 txPvtRWSet.NsPvtRwset = append(txPvtRWSet.NsPvtRwset, &rwset.NsPvtReadWriteSet{ 441 Namespace: namespaceName, 442 CollectionPvtRwset: cols, 443 }) 444 } 445 446 pvtDataMap[seq.seq] = txPvtRWSet 447 } 448 return pvtDataMap 449 } 450 451 // identityDeserializerMgr implements an IdentityDeserializerManager 452 // by routing the call to the msp/mgmt package 453 type identityDeserializerMgr struct{} 454 455 func (*identityDeserializerMgr) Deserializer(channelID string) (msp.IdentityDeserializer, error) { 456 id, ok := mgmt.GetDeserializers()[channelID] 457 if !ok { 458 return nil, errors.Errorf("channel %s not found", channelID) 459 } 460 return id, nil 461 } 462 463 // collPolicyChecker is the default implementation for CollectionPolicyChecker interface 464 type collPolicyChecker struct{} 465 466 // CheckCollectionPolicy checks if the CollectionCriteria meets the policy requirement 467 func (cs *collPolicyChecker) CheckCollectionPolicy( 468 blockNum uint64, 469 ccName string, 470 collName string, 471 cfgHistoryRetriever ledger.ConfigHistoryRetriever, 472 deserializer msp.IdentityDeserializer, 473 signedData *protoutil.SignedData, 474 ) (bool, error) { 475 configInfo, err := cfgHistoryRetriever.MostRecentCollectionConfigBelow(blockNum, ccName) 476 if err != nil { 477 return false, errors.WithMessagef(err, "error getting most recent collection config below block sequence = %d for chaincode %s", blockNum, ccName) 478 } 479 480 staticCollConfig := extractStaticCollectionConfig(configInfo.CollectionConfig, collName) 481 if staticCollConfig == nil { 482 return false, errors.Errorf("no collection config was found for collection %s for chaincode %s", collName, ccName) 483 } 484 485 if !staticCollConfig.MemberOnlyRead { 486 return true, nil 487 } 488 489 // get collection access policy and access filter to check eligibility 490 collAP := &privdata.SimpleCollection{} 491 err = collAP.Setup(staticCollConfig, deserializer) 492 if err != nil { 493 return false, errors.WithMessagef(err, "error setting up collection %s", staticCollConfig.Name) 494 } 495 logger.Debugf("got collection access policy") 496 497 collFilter := collAP.AccessFilter() 498 if collFilter == nil { 499 logger.Debugf("collection %s has no access filter, skipping...", collName) 500 return false, nil 501 } 502 503 eligible := collFilter(*signedData) 504 return eligible, nil 505 } 506 507 func extractStaticCollectionConfig(configPackage *peer.CollectionConfigPackage, collectionName string) *peer.StaticCollectionConfig { 508 for _, config := range configPackage.Config { 509 switch cconf := config.Payload.(type) { 510 case *peer.CollectionConfig_StaticCollectionConfig: 511 if cconf.StaticCollectionConfig.Name == collectionName { 512 return cconf.StaticCollectionConfig 513 } 514 default: 515 return nil 516 } 517 } 518 return nil 519 }