github.com/leonlxy/hyperledger@v1.0.0-alpha.0.20170427033203-34922035d248/bddtests/steps/orderer_util.py (about)

     1  
     2  # Copyright IBM Corp. 2016 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  import time
    18  import datetime
    19  import Queue
    20  from orderer import ab_pb2, ab_pb2_grpc
    21  from common import common_pb2
    22  
    23  import bdd_test_util
    24  import bootstrap_util
    25  import bdd_grpc_util
    26  
    27  
    28  from grpc.beta import implementations
    29  from grpc.framework.interfaces.face.face import AbortionError
    30  from grpc.beta.interfaces import StatusCode
    31  
    32  # The default chain ID when the system is statically bootstrapped for testing
    33  TEST_CHAIN_ID = "testchainid"
    34  
    35  def _defaultDataFunction(index):
    36      payload = common_pb2.Payload(
    37          header = common_pb2.Header(
    38              chainHeader = common_pb2.ChainHeader(
    39                  chainID = TEST_CHAIN_ID,
    40                  type = common_pb2.ENDORSER_TRANSACTION,
    41              ),
    42              signatureHeader = common_pb2.SignatureHeader(),
    43          ),
    44          data = str("BDD test: {0}".format(datetime.datetime.utcnow())),
    45      )
    46      envelope = common_pb2.Envelope(
    47          payload = payload.SerializeToString()
    48      )
    49      return envelope
    50  
    51  
    52  class StreamHelper:
    53  
    54      def __init__(self):
    55          self.streamClosed = False
    56          self.sendQueue = Queue.Queue()
    57          self.receivedMessages = []
    58          self.replyGenerator = None
    59  
    60      def setReplyGenerator(self, replyGenerator):
    61          assert self.replyGenerator == None, "reply generator already set!!"
    62          self.replyGenerator = replyGenerator
    63  
    64      def createSendGenerator(self, timeout = 2):
    65        while True:
    66          try:
    67              nextMsg = self.sendQueue.get(True, timeout)
    68              if nextMsg:
    69                yield nextMsg
    70              else:
    71                #None indicates desire to close send
    72                return
    73          except Queue.Empty:
    74              return
    75  
    76      def readMessage(self):
    77          for reply in self.readMessages(1):
    78              return reply
    79          assert False, "Received no messages"
    80  
    81      def readMessages(self, expectedCount):
    82          msgsReceived = []
    83          counter = 0
    84          try:
    85              for reply in self.replyGenerator:
    86                  counter += 1
    87                  #print("received reply: {0}, counter = {1}".format(reply, counter))
    88                  msgsReceived.append(reply)
    89                  if counter == int(expectedCount):
    90                      break
    91          except AbortionError as networkError:
    92              self.handleNetworkError(networkError)
    93          return msgsReceived
    94  
    95      def handleNetworkError(self, networkError):
    96          if networkError.code == StatusCode.OUT_OF_RANGE and networkError.details == "EOF":
    97              print("Error received and ignored: {0}".format(networkError))
    98              print()
    99              self.streamClosed = True
   100          else:
   101              raise Exception("Unexpected NetworkError: {0}".format(networkError))
   102  
   103  
   104  class DeliverStreamHelper(StreamHelper):
   105  
   106      def __init__(self, ordererStub, entity, directory, nodeAdminTuple, timeout = 110):
   107          StreamHelper.__init__(self)
   108          self.nodeAdminTuple = nodeAdminTuple
   109          self.directory = directory
   110          self.entity = entity
   111          # Set the UpdateMessage and start the stream
   112          sendGenerator = self.createSendGenerator(timeout)
   113          self.replyGenerator = ordererStub.Deliver(sendGenerator, timeout + 1)
   114  
   115      def createSeekInfo(self, chainID, start = 'Oldest', end = 'Newest',  behavior = 'FAIL_IF_NOT_READY'):
   116          seekInfo = ab_pb2.SeekInfo(
   117              start = seekPosition(start),
   118              stop = seekPosition(end),
   119              behavior = ab_pb2.SeekInfo.SeekBehavior.Value(behavior),
   120          )
   121          print("SeekInfo = {0}".format(seekInfo))
   122          print("")
   123          return seekInfo
   124  
   125      def seekToRange(self, chainID = TEST_CHAIN_ID, start = 'Oldest', end = 'Newest'):
   126          seekInfo = self.createSeekInfo(start = start, end = end, chainID = chainID)
   127          envelope = bootstrap_util.createEnvelopeForMsg(directory=self.directory, chainId=chainID, msg=seekInfo, typeAsString="DELIVER_SEEK_INFO", nodeAdminTuple=self.nodeAdminTuple)
   128          self.sendQueue.put(envelope)
   129  
   130      def getBlocks(self):
   131          blocks = []
   132          try:
   133              while True:
   134                  reply = self.readMessage()
   135                  if reply.HasField("block"):
   136                      blocks.append(reply.block)
   137                      #print("received reply: {0}, len(blocks) = {1}".format(reply, len(blocks)))
   138                  else:
   139                      if reply.status != common_pb2.SUCCESS:
   140                          print("Got error: {0}".format(reply.status))
   141                      print("Done receiving blocks")
   142                      break
   143          except Exception as e:
   144              print("getBlocks got error: {0}".format(e) )
   145          return blocks
   146  
   147  
   148  class UserRegistration:
   149  
   150      def __init__(self, userName, directory):
   151          self.userName= userName
   152          self.directory = directory
   153          self.tags = {}
   154          # Dictionary of composeService->atomic broadcast grpc Stub
   155          self.atomicBroadcastStubsDict = {}
   156          # composeService->StreamHelper
   157          self.abDeliversStreamHelperDict = {}
   158  
   159      def getUserName(self):
   160          return self.userName
   161  
   162      def closeStreams(self):
   163          for compose_service, deliverStreamHelper in self.abDeliversStreamHelperDict.iteritems():
   164              deliverStreamHelper.sendQueue.put(None)
   165  
   166      def connectToDeliverFunction(self, context, composeService, certAlias, nodeAdminTuple, timeout=1):
   167          'Connect to the deliver function and drain messages to associated orderer queue'
   168          assert not composeService in self.abDeliversStreamHelperDict, "Already connected to deliver stream on {0}".format(composeService)
   169          streamHelper = DeliverStreamHelper(directory=self.directory,
   170                                             ordererStub=self.getABStubForComposeService(context=context,
   171                                                                                         composeService=composeService),
   172                                             entity=self, nodeAdminTuple=nodeAdminTuple)
   173          self.abDeliversStreamHelperDict[composeService] = streamHelper
   174          return streamHelper
   175  
   176      def getDelivererStreamHelper(self, context, composeService):
   177          assert composeService in self.abDeliversStreamHelperDict, "NOT connected to deliver stream on {0}".format(composeService)
   178          return self.abDeliversStreamHelperDict[composeService]
   179  
   180      def broadcastMessages(self, context, numMsgsToBroadcast, composeService, chainID=TEST_CHAIN_ID, dataFunc=_defaultDataFunction):
   181          abStub = self.getABStubForComposeService(context, composeService)
   182          replyGenerator = abStub.Broadcast(generateBroadcastMessages(chainID=chainID, numToGenerate = int(numMsgsToBroadcast), dataFunc=dataFunc), 2)
   183          counter = 0
   184          try:
   185              for reply in replyGenerator:
   186                  counter += 1
   187                  print("{0} received reply: {1}, counter = {2}".format(self.getUserName(), reply, counter))
   188                  if counter == int(numMsgsToBroadcast):
   189                      break
   190          except Exception as e:
   191              print("Got error: {0}".format(e) )
   192              print("Got error")
   193          print("Done")
   194          assert counter == int(numMsgsToBroadcast), "counter = {0}, expected {1}".format(counter, numMsgsToBroadcast)
   195  
   196      def getABStubForComposeService(self, context, composeService):
   197          'Return a Stub for the supplied composeService, will cache'
   198          if composeService in self.atomicBroadcastStubsDict:
   199              return self.atomicBroadcastStubsDict[composeService]
   200          # Get the IP address of the server that the user registered on
   201          root_certificates = self.directory.getTrustedRootsForOrdererNetworkAsPEM()
   202          ipAddress, port = bdd_test_util.getPortHostMapping(context.compose_containers, composeService, 7050)
   203          print("ipAddress in getABStubForComposeService == {0}:{1}".format(ipAddress, port))
   204          channel = bdd_grpc_util.getGRPCChannel(ipAddress=ipAddress, port=port, root_certificates=root_certificates, ssl_target_name_override=composeService)
   205          newABStub = ab_pb2_grpc.AtomicBroadcastStub(channel)
   206          self.atomicBroadcastStubsDict[composeService] = newABStub
   207          return newABStub
   208  
   209  
   210  # Registerses a user on a specific composeService
   211  def registerUser(context, secretMsg, composeService):
   212      userName = secretMsg['enrollId']
   213      if 'ordererUsers' in context:
   214          pass
   215      else:
   216          context.ordererUsers = {}
   217      if userName in context.ordererUsers:
   218          raise Exception("Orderer user already registered: {0}".format(userName))
   219      userRegistration = UserRegistration(secretMsg)
   220      context.ordererUsers[userName] = userRegistration
   221      return userRegistration
   222  
   223  def getUserRegistration(context, enrollId):
   224      userRegistration = None
   225      if 'ordererUsers' in context:
   226          pass
   227      else:
   228          ordererContext.ordererUsers = {}
   229      if enrollId in context.ordererUsers:
   230          userRegistration = context.ordererUsers[enrollId]
   231      else:
   232          raise Exception("Orderer user has not been registered: {0}".format(enrollId))
   233      return userRegistration
   234  
   235  def seekPosition(position):
   236      if position == 'Oldest':
   237          return ab_pb2.SeekPosition(oldest = ab_pb2.SeekOldest())
   238      elif  position == 'Newest':
   239          return ab_pb2.SeekPosition(newest = ab_pb2.SeekNewest())
   240      else:
   241          return ab_pb2.SeekPosition(specified = ab_pb2.SeekSpecified(number = position))
   242  
   243  def convertSeek(utfString):
   244      try:
   245          return int(utfString)
   246      except ValueError:
   247          return str(utfString)
   248  
   249  def createSeekInfo(chainID = TEST_CHAIN_ID, start = 'Oldest', end = 'Newest',  behavior = 'FAIL_IF_NOT_READY'):
   250      return common_pb2.Envelope(
   251          payload = common_pb2.Payload(
   252              header = common_pb2.Header(
   253                  channel_header = common_pb2.ChannelHeader( channel_id = chainID ).SerializeToString(),
   254                  signature_header = common_pb2.SignatureHeader().SerializeToString(),
   255              ),
   256              data = ab_pb2.SeekInfo(
   257                  start = seekPosition(start),
   258                  stop = seekPosition(end),
   259                  behavior = ab_pb2.SeekInfo.SeekBehavior.Value(behavior),
   260              ).SerializeToString(),
   261          ).SerializeToString(),
   262      )
   263  
   264  
   265  def generateBroadcastMessages(chainID = TEST_CHAIN_ID, numToGenerate = 3, timeToHoldOpen = 1, dataFunc =_defaultDataFunction):
   266      messages = []
   267      for i in range(0, numToGenerate):
   268          messages.append(dataFunc(i))
   269      for msg in messages:
   270          yield msg
   271      time.sleep(timeToHoldOpen)