github.com/kchristidis/fabric@v1.0.4-0.20171028114726-837acd08cde1/examples/events/block-listener/block-listener.go (about)

     1  /*
     2   Copyright IBM Corp All Rights Reserved.
     3  
     4   Licensed under the Apache License, Version 2.0 (the "License");
     5   you may not use this file except in compliance with the License.
     6   You may obtain a copy of the License at
     7  
     8        http://www.apache.org/licenses/LICENSE-2.0
     9  
    10   Unless required by applicable law or agreed to in writing, software
    11   distributed under the License is distributed on an "AS IS" BASIS,
    12   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13   See the License for the specific language governing permissions and
    14   limitations under the License.
    15  */
    16  
    17  package main
    18  
    19  import (
    20  	"errors"
    21  	"flag"
    22  	"fmt"
    23  	"os"
    24  
    25  	"github.com/hyperledger/fabric/core/ledger/util"
    26  	"github.com/hyperledger/fabric/events/consumer"
    27  	"github.com/hyperledger/fabric/msp/mgmt"
    28  	"github.com/hyperledger/fabric/msp/mgmt/testtools"
    29  	"github.com/hyperledger/fabric/protos/common"
    30  	pb "github.com/hyperledger/fabric/protos/peer"
    31  	"github.com/hyperledger/fabric/protos/utils"
    32  )
    33  
    34  type adapter struct {
    35  	notfy chan *pb.Event_Block
    36  }
    37  
    38  //GetInterestedEvents implements consumer.EventAdapter interface for registering interested events
    39  func (a *adapter) GetInterestedEvents() ([]*pb.Interest, error) {
    40  	return []*pb.Interest{{EventType: pb.EventType_BLOCK}}, nil
    41  }
    42  
    43  //Recv implements consumer.EventAdapter interface for receiving events
    44  func (a *adapter) Recv(msg *pb.Event) (bool, error) {
    45  	if o, e := msg.Event.(*pb.Event_Block); e {
    46  		a.notfy <- o
    47  		return true, nil
    48  	}
    49  	return false, fmt.Errorf("Receive unknown type event: %v", msg)
    50  }
    51  
    52  //Disconnected implements consumer.EventAdapter interface for disconnecting
    53  func (a *adapter) Disconnected(err error) {
    54  	fmt.Print("Disconnected...exiting\n")
    55  	os.Exit(1)
    56  }
    57  
    58  func createEventClient(eventAddress string, _ string) *adapter {
    59  	var obcEHClient *consumer.EventsClient
    60  
    61  	done := make(chan *pb.Event_Block)
    62  	adapter := &adapter{notfy: done}
    63  	obcEHClient, _ = consumer.NewEventsClient(eventAddress, 5, adapter)
    64  	if err := obcEHClient.Start(); err != nil {
    65  		fmt.Printf("could not start chat. err: %s\n", err)
    66  		obcEHClient.Stop()
    67  		return nil
    68  	}
    69  
    70  	return adapter
    71  }
    72  func getTxPayload(tdata []byte) (*common.Payload, error) {
    73  	if tdata == nil {
    74  		return nil, errors.New("Cannot extract payload from nil transaction")
    75  	}
    76  
    77  	if env, err := utils.GetEnvelopeFromBlock(tdata); err != nil {
    78  		return nil, fmt.Errorf("Error getting tx from block(%s)", err)
    79  	} else if env != nil {
    80  		// get the payload from the envelope
    81  		payload, err := utils.GetPayload(env)
    82  		if err != nil {
    83  			return nil, fmt.Errorf("Could not extract payload from envelope, err %s", err)
    84  		}
    85  		return payload, nil
    86  	}
    87  	return nil, nil
    88  }
    89  
    90  // getChainCodeEvents parses block events for chaincode events associated with individual transactions
    91  func getChainCodeEvents(tdata []byte) (*pb.ChaincodeEvent, error) {
    92  	if tdata == nil {
    93  		return nil, errors.New("Cannot extract payload from nil transaction")
    94  	}
    95  
    96  	if env, err := utils.GetEnvelopeFromBlock(tdata); err != nil {
    97  		return nil, fmt.Errorf("Error getting tx from block(%s)", err)
    98  	} else if env != nil {
    99  		// get the payload from the envelope
   100  		payload, err := utils.GetPayload(env)
   101  		if err != nil {
   102  			return nil, fmt.Errorf("Could not extract payload from envelope, err %s", err)
   103  		}
   104  
   105  		chdr, err := utils.UnmarshalChannelHeader(payload.Header.ChannelHeader)
   106  		if err != nil {
   107  			return nil, fmt.Errorf("Could not extract channel header from envelope, err %s", err)
   108  		}
   109  
   110  		if common.HeaderType(chdr.Type) == common.HeaderType_ENDORSER_TRANSACTION {
   111  			tx, err := utils.GetTransaction(payload.Data)
   112  			if err != nil {
   113  				return nil, fmt.Errorf("Error unmarshalling transaction payload for block event: %s", err)
   114  			}
   115  			chaincodeActionPayload, err := utils.GetChaincodeActionPayload(tx.Actions[0].Payload)
   116  			if err != nil {
   117  				return nil, fmt.Errorf("Error unmarshalling transaction action payload for block event: %s", err)
   118  			}
   119  			propRespPayload, err := utils.GetProposalResponsePayload(chaincodeActionPayload.Action.ProposalResponsePayload)
   120  			if err != nil {
   121  				return nil, fmt.Errorf("Error unmarshalling proposal response payload for block event: %s", err)
   122  			}
   123  			caPayload, err := utils.GetChaincodeAction(propRespPayload.Extension)
   124  			if err != nil {
   125  				return nil, fmt.Errorf("Error unmarshalling chaincode action for block event: %s", err)
   126  			}
   127  			ccEvent, err := utils.GetChaincodeEvents(caPayload.Events)
   128  
   129  			if ccEvent != nil {
   130  				return ccEvent, nil
   131  			}
   132  		}
   133  	}
   134  	return nil, errors.New("No events found")
   135  }
   136  
   137  func main() {
   138  	var eventAddress string
   139  	var chaincodeID string
   140  	var mspDir string
   141  	var mspId string
   142  	flag.StringVar(&eventAddress, "events-address", "0.0.0.0:7053", "address of events server")
   143  	flag.StringVar(&chaincodeID, "events-from-chaincode", "", "listen to events from given chaincode")
   144  	flag.StringVar(&mspDir, "events-mspdir", "", "set up the msp direction")
   145  	flag.StringVar(&mspId, "events-mspid", "", "set up the mspid")
   146  	flag.Parse()
   147  
   148  	//if no msp info provided, we use the default MSP under fabric/sampleconfig
   149  	if mspDir == "" {
   150  		err := msptesttools.LoadMSPSetupForTesting()
   151  		if err != nil {
   152  			fmt.Printf("Could not initialize msp, err: %s\n", err)
   153  			os.Exit(-1)
   154  		}
   155  	} else {
   156  		//load msp info
   157  		err := mgmt.LoadLocalMsp(mspDir, nil, mspId)
   158  		if err != nil {
   159  			fmt.Printf("Could not initialize msp, err: %s\n", err)
   160  			os.Exit(-1)
   161  		}
   162  	}
   163  
   164  	fmt.Printf("Event Address: %s\n", eventAddress)
   165  
   166  	a := createEventClient(eventAddress, chaincodeID)
   167  	if a == nil {
   168  		fmt.Println("Error creating event client")
   169  		return
   170  	}
   171  
   172  	for {
   173  		select {
   174  		case b := <-a.notfy:
   175  			fmt.Println("")
   176  			fmt.Println("")
   177  			fmt.Println("Received block")
   178  			fmt.Println("--------------")
   179  			txsFltr := util.TxValidationFlags(b.Block.Metadata.Metadata[common.BlockMetadataIndex_TRANSACTIONS_FILTER])
   180  			for i, r := range b.Block.Data.Data {
   181  				tx, _ := getTxPayload(r)
   182  				if tx != nil {
   183  					chdr, err := utils.UnmarshalChannelHeader(tx.Header.ChannelHeader)
   184  					if err != nil {
   185  						fmt.Print("Error extracting channel header\n")
   186  						return
   187  					}
   188  					if txsFltr.IsInvalid(i) {
   189  						fmt.Println("")
   190  						fmt.Println("")
   191  						fmt.Printf("Received invalid transaction from channel '%s'\n", chdr.ChannelId)
   192  						fmt.Println("--------------")
   193  						fmt.Printf("Transaction invalid: TxID: %s\n", chdr.TxId)
   194  					} else {
   195  						fmt.Printf("Received transaction from channel '%s': \n\t[%v]\n", chdr.ChannelId, tx)
   196  						if event, err := getChainCodeEvents(r); err == nil {
   197  							if len(chaincodeID) != 0 && event.ChaincodeId == chaincodeID {
   198  								fmt.Println("")
   199  								fmt.Println("")
   200  								fmt.Printf("Received chaincode event from channel '%s'\n", chdr.ChannelId)
   201  								fmt.Println("------------------------")
   202  								fmt.Printf("Chaincode Event:%+v\n", event)
   203  							}
   204  						}
   205  					}
   206  				}
   207  			}
   208  		}
   209  	}
   210  }