github.com/darrenli6/fabric-sdk-example@v0.0.0-20220109053535-94b13b56df8c/bddtests/steps/bootstrap_util.py (about)

     1  # Copyright IBM Corp. 2016 All Rights Reserved.
     2  #
     3  # Licensed under the Apache License, Version 2.0 (the "License");
     4  # you may not use this file except in compliance with the License.
     5  # You may obtain a copy of the License at
     6  #
     7  #      http://www.apache.org/licenses/LICENSE-2.0
     8  #
     9  # Unless required by applicable law or agreed to in writing, software
    10  # distributed under the License is distributed on an "AS IS" BASIS,
    11  # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  # See the License for the specific language governing permissions and
    13  # limitations under the License.
    14  #
    15  
    16  import time
    17  import sys
    18  import hashlib
    19  import uuid
    20  
    21  if sys.version_info < (3, 6):
    22      import sha3
    23  
    24  from OpenSSL import crypto
    25  from OpenSSL import rand
    26  import ecdsa
    27  
    28  from collections import namedtuple
    29  from itertools import groupby
    30  
    31  from enum import Enum
    32  
    33  from google.protobuf import timestamp_pb2
    34  from common import common_pb2 as common_dot_common_pb2
    35  from common import configtx_pb2 as common_dot_configtx_pb2
    36  from common import configuration_pb2 as common_dot_configuration_pb2
    37  from common import policies_pb2 as common_dot_policies_pb2
    38  from msp import msp_config_pb2, msp_principal_pb2, identities_pb2
    39  from peer import configuration_pb2 as peer_dot_configuration_pb2
    40  from orderer import configuration_pb2 as orderer_dot_configuration_pb2
    41  import orderer_util
    42  
    43  from contexthelper import ContextHelper
    44  
    45  import os
    46  import re
    47  import shutil
    48  import compose
    49  
    50  # Type to represent tuple of user, nodeName, ogranization
    51  NodeAdminTuple = namedtuple("NodeAdminTuple", ['user', 'nodeName', 'organization'])
    52  
    53  
    54  ApplicationGroup = "Application"
    55  OrdererGroup     = "Orderer"
    56  ConsortiumsGroup = "Consortiums"
    57  MSPKey           = "MSP"
    58  toValue = lambda message: message.SerializeToString()
    59  
    60  
    61  class Network(Enum):
    62      Orderer = 1
    63      Peer = 2
    64  
    65  
    66  def GetUUID():
    67      return compose.Composition.GetUUID()
    68  
    69  def GetUniqueChannelName():
    70      while True:
    71          guiid = uuid.uuid4().hex[:6].lower()
    72          if guiid[:1].isalpha():
    73              break
    74      return guiid
    75  
    76  def createRSAKey():
    77      # Create RSA key, 2048 bit
    78      pk = crypto.PKey()
    79      pk.generate_key(crypto.TYPE_RSA, 2048)
    80      assert pk.check() == True
    81      return pk
    82  
    83  
    84  def createECDSAKey(curve=ecdsa.NIST256p):
    85      # Create ECDSA key
    86      sk = ecdsa.SigningKey.generate(curve=curve)
    87      return sk
    88  
    89  
    90  def computeCryptoHash(data):
    91      ' This will currently return 128 hex characters'
    92      # s = hashlib.sha3_256()
    93      s = hashlib.sha256()
    94      # s = hashlib.shake_256()
    95      #return s.digest(64)
    96      s.update(data)
    97      return s.digest()
    98  
    99  
   100  def createCertRequest(pkey, extensions=[], digest="sha256", **name):
   101      """
   102      Create a certificate request.
   103      Arguments: pkey   - The key to associate with the request
   104                 digest - Digestion method to use for signing, default is sha256
   105                 **name - The name of the subject of the request, possible
   106                          arguments are:
   107                            C     - Country name
   108                            ST    - State or province name
   109                            L     - Locality name
   110                            O     - Organization name
   111                            OU    - Organizational unit name
   112                            CN    - Common name
   113                            emailAddress - E-mail address
   114      Returns:   The certificate request in an X509Req object
   115      """
   116      req = crypto.X509Req()
   117      subj = req.get_subject()
   118  
   119      for key, value in name.items():
   120          setattr(subj, key, value)
   121  
   122      req.add_extensions(extensions)
   123  
   124      req.set_pubkey(pkey)
   125      req.sign(pkey, digest)
   126      return req
   127  
   128  
   129  def createCertificate(req, issuerCertKey, serial, validityPeriod, digest="sha256", isCA=False, extensions=[]):
   130      """
   131      Generate a certificate given a certificate request.
   132      Arguments: req        - Certificate request to use
   133                 issuerCert - The certificate of the issuer
   134                 issuerKey  - The private key of the issuer
   135                 serial     - Serial number for the certificate
   136                 notBefore  - Timestamp (relative to now) when the certificate
   137                              starts being valid
   138                 notAfter   - Timestamp (relative to now) when the certificate
   139                              stops being valid
   140                 digest     - Digest method to use for signing, default is sha256
   141      Returns:   The signed certificate in an X509 object
   142      """
   143      issuerCert, issuerKey = issuerCertKey
   144      notBefore, notAfter = validityPeriod
   145      cert = crypto.X509()
   146      cert.set_version(3)
   147      cert.set_serial_number(serial)
   148      cert.gmtime_adj_notBefore(notBefore)
   149      cert.gmtime_adj_notAfter(notAfter)
   150      cert.set_issuer(issuerCert.get_subject())
   151      cert.set_subject(req.get_subject())
   152      cert.set_pubkey(req.get_pubkey())
   153      if isCA:
   154          cert.add_extensions([crypto.X509Extension("basicConstraints", True,
   155                                                    "CA:TRUE, pathlen:0"),
   156                               crypto.X509Extension("subjectKeyIdentifier", False, "hash",
   157                                                    subject=cert)])
   158          #TODO: This only is appropriate for root self signed!!!!
   159          cert.add_extensions([crypto.X509Extension("authorityKeyIdentifier", False, "keyid:always", issuer=cert)])
   160      else:
   161          cert.add_extensions([crypto.X509Extension("basicConstraints", True,
   162                                                    "CA:FALSE"),
   163                               crypto.X509Extension("subjectKeyIdentifier", False, "hash",
   164                                                    subject=cert)])
   165          cert.add_extensions([crypto.X509Extension("authorityKeyIdentifier", False, "keyid:always", issuer=issuerCert)])
   166  
   167      cert.add_extensions(extensions)
   168      cert.sign(issuerKey, digest)
   169      return cert
   170  
   171  
   172  # SUBJECT_DEFAULT = {countryName : "US", stateOrProvinceName : "NC", localityName : "RTP", organizationName : "IBM", organizationalUnitName : "Blockchain"}
   173  
   174  class Entity:
   175      def __init__(self, name, ecdsaSigningKey, rsaSigningKey):
   176          self.name = name
   177          # Create a ECDSA key, then a crypto pKey from the DER for usage with cert requests, etc.
   178          self.ecdsaSigningKey = ecdsaSigningKey
   179          self.rsaSigningKey = rsaSigningKey
   180          if self.ecdsaSigningKey:
   181              self.pKey = crypto.load_privatekey(crypto.FILETYPE_ASN1, self.ecdsaSigningKey.to_der())
   182          # Signing related ecdsa config
   183          self.hashfunc = hashlib.sha256
   184          self.sigencode = ecdsa.util.sigencode_der_canonize
   185          self.sigdecode = ecdsa.util.sigdecode_der
   186  
   187      def createCertRequest(self, nodeName, extensions = []):
   188          req = createCertRequest(self.pKey, extensions=extensions, C="US", ST="North Carolina", L="RTP", O="IBM", CN=nodeName)
   189          return req
   190  
   191      def createTLSCertRequest(self, nodeName):
   192          req = createCertRequest(self.rsaSigningKey, C="US", ST="North Carolina", L="RTP", O="IBM", CN=nodeName)
   193          # print("request => {0}".format(crypto.dump_certificate_request(crypto.FILETYPE_PEM, req)))
   194          return req
   195  
   196  
   197      def computeHash(self, data):
   198          s = self.hashfunc()
   199          s.update(data)
   200          return s.digest()
   201  
   202      def sign(self, dataAsBytearray):
   203          return self.ecdsaSigningKey.sign(dataAsBytearray, hashfunc=self.hashfunc, sigencode=self.sigencode)
   204  
   205      def verifySignature(self, signature, signersCert, data):
   206          'Will verify the signature of an entity based upon public cert'
   207          vk = ecdsa.VerifyingKey.from_der(crypto.dump_publickey(crypto.FILETYPE_ASN1, signersCert.get_pubkey()))
   208          assert vk.verify(signature, data, hashfunc=self.hashfunc, sigdecode=self.sigdecode), "Invalid signature!!"
   209  
   210      def getPrivateKeyAsPEM(self):
   211          return self.ecdsaSigningKey.to_pem()
   212  
   213      def __getstate__(self):
   214          state = dict(self.__dict__)
   215          del state['ecdsaSigningKey']
   216          del state['rsaSigningKey']
   217          del state['pKey']
   218          return state
   219  
   220  class User(Entity, orderer_util.UserRegistration):
   221      def __init__(self, name, directory, ecdsaSigningKey, rsaSigningKey):
   222          Entity.__init__(self, name, ecdsaSigningKey=ecdsaSigningKey, rsaSigningKey=rsaSigningKey)
   223          orderer_util.UserRegistration.__init__(self, name, directory)
   224          self.tags = {}
   225  
   226      def setTagValue(self, tagKey, tagValue, overwrite=False):
   227          if tagKey in self.tags:
   228              assert not overwrite,"TagKey '{0}' already exists for user {1}, and did not provide overwrite=True".format(tagKey, self.getUserName())
   229          self.tags[tagKey] = tagValue
   230          return tagValue
   231  
   232      def getTagValue(self, tagKey):
   233          return self.tags[tagKey]
   234  
   235      def cleanup(self):
   236          self.closeStreams()
   237  
   238  
   239  class Organization(Entity):
   240  
   241      def __init__(self, name, ecdsaSigningKey, rsaSigningKey):
   242          Entity.__init__(self, name, ecdsaSigningKey, rsaSigningKey)
   243          req = createCertRequest(self.pKey, C="US", ST="North Carolina", L="RTP", O="IBM", CN=name)
   244          numYrs = 1
   245          self.signedCert = createCertificate(req, (req, self.pKey), 1000, (0, 60 * 60 * 24 * 365 * numYrs), isCA=True)
   246          # Which networks this organization belongs to
   247          self.networks = []
   248  
   249      def __repr__(self):
   250          return "name:{0}, networks: {1}".format(self.name, self.networks)
   251  
   252      def getSelfSignedCert(self):
   253          return self.signedCert
   254  
   255      def getCertAsPEM(self):
   256          return crypto.dump_certificate(crypto.FILETYPE_PEM, self.getSelfSignedCert())
   257  
   258      def isInNetwork(self, network):
   259          for n in self.networks:
   260              if str(n)==str(network):
   261                  return True
   262          return False
   263  
   264      def getMspPrincipalAsRole(self, mspRoleTypeAsString):
   265          mspRole = msp_principal_pb2.MSPRole(msp_identifier=self.name, role=msp_principal_pb2.MSPRole.MSPRoleType.Value(mspRoleTypeAsString))
   266          mspPrincipal = msp_principal_pb2.MSPPrincipal(
   267              principal_classification=msp_principal_pb2.MSPPrincipal.Classification.Value('ROLE'),
   268              principal=mspRole.SerializeToString())
   269          return mspPrincipal
   270  
   271      def createCertificate(self, certReq, extensions=[]):
   272          numYrs = 1
   273          return createCertificate(certReq, (self.signedCert, self.pKey), 1000, (0, 60 * 60 * 24 * 365 * numYrs), extensions=extensions)
   274  
   275      def addToNetwork(self, network):
   276          'Used to track which network this organization is defined in.'
   277          # assert network in Network, 'Network not recognized ({0}), expected to be one of ({1})'.format(network, list(Network))
   278          if not network in self.networks:
   279              self.networks.append(network)
   280  
   281  
   282  class Directory:
   283      def __init__(self):
   284          import atexit
   285          self.organizations = {}
   286          self.users = {}
   287          self.ordererAdminTuples = {}
   288          atexit.register(self.cleanup)
   289  
   290      def getNamedCtxTuples(self):
   291          return self.ordererAdminTuples
   292  
   293      def _registerOrg(self, orgName):
   294          assert orgName not in self.organizations, "Organization already registered {0}".format(orgName)
   295          self.organizations[orgName] = Organization(orgName, ecdsaSigningKey = createECDSAKey(), rsaSigningKey = createRSAKey())
   296          return self.organizations[orgName]
   297  
   298      def _registerUser(self, userName):
   299          assert userName not in self.users, "User already registered {0}".format(userName)
   300          self.users[userName] = User(userName, directory=self, ecdsaSigningKey = createECDSAKey(), rsaSigningKey = createRSAKey())
   301          return self.users[userName]
   302  
   303      def getUser(self, userName, shouldCreate=False):
   304          if not userName in self.users and shouldCreate:
   305              # self.users[userName] = User(userName)
   306              self._registerUser(userName)
   307          return self.users[userName]
   308  
   309      def getUsers(self):
   310          return self.users
   311  
   312      def cleanup(self):
   313          '''Perform cleanup of resources'''
   314          [user.cleanup() for user in self.users.values()]
   315  
   316      def getOrganization(self, orgName, shouldCreate=False):
   317          if not orgName in self.organizations and shouldCreate:
   318              # self.organizations[orgName] = Organization(orgName)
   319              self._registerOrg(orgName)
   320          return self.organizations[orgName]
   321  
   322      def getOrganizations(self):
   323          return self.organizations
   324  
   325      def findCertByTuple(self, userName, contextName, orgName):
   326          ordererAdminTuple = NodeAdminTuple(user=userName, nodeName=contextName, organization=orgName)
   327          return self.ordererAdminTuples[ordererAdminTuple]
   328  
   329      def findCertForNodeAdminTuple(self, nodeAdminTuple):
   330          assert nodeAdminTuple in self.ordererAdminTuples, "Node admin tuple not found for: {0}".format(nodeAdminTuple)
   331          return self.ordererAdminTuples[nodeAdminTuple]
   332  
   333      def getCertAsPEM(self, nodeAdminTuple):
   334          assert nodeAdminTuple in self.ordererAdminTuples, "Node admin tuple not found for: {0}".format(nodeAdminTuple)
   335          return crypto.dump_certificate(crypto.FILETYPE_PEM, self.ordererAdminTuples[nodeAdminTuple])
   336  
   337      def findNodeAdminTuple(self, userName, contextName, orgName):
   338          nodeAdminTuple = NodeAdminTuple(user=userName, nodeName=contextName, organization=orgName)
   339          assert nodeAdminTuple in self.ordererAdminTuples, "Node admin tuple not found for: {0}".format(nodeAdminTuple)
   340          return nodeAdminTuple
   341  
   342      def getTrustedRootsForPeerNetworkAsPEM(self):
   343          pems = [peerOrg.getCertAsPEM() for peerOrg in [org for org in self.getOrganizations().values() if org.isInNetwork(Network.Peer)]]
   344          return "".join(pems)
   345  
   346      def getTrustedRootsForOrdererNetworkAsPEM(self):
   347          pems = [ordererOrg.getCertAsPEM() for ordererOrg in [org for org in self.getOrganizations().values() if org.isInNetwork(Network.Orderer)]]
   348          return "".join(pems)
   349  
   350  
   351      def _get_cert_extensions_ip_sans(self, user_name, node_name):
   352          extensions = []
   353          if 'signer' in user_name.lower():
   354              if ('peer' in node_name.lower() or 'orderer' in node_name.lower()):
   355                  san_list = ["DNS:{0}".format(node_name)]
   356                  extensions.append(crypto.X509Extension(b"subjectAltName", False, ", ".join(san_list)))
   357          return extensions
   358  
   359      def registerOrdererAdminTuple(self, userName, ordererName, organizationName):
   360          ' Assign the user as orderer admin'
   361          ordererAdminTuple = NodeAdminTuple(user=userName, nodeName=ordererName, organization=organizationName)
   362          assert ordererAdminTuple not in self.ordererAdminTuples, "Orderer admin tuple already registered {0}".format(
   363              ordererAdminTuple)
   364          assert organizationName in self.organizations, "Orderer Organization not defined {0}".format(organizationName)
   365  
   366          user = self.getUser(userName, shouldCreate=True)
   367          # Add the subjectAlternativeName if the current entity is a signer, and the nodeName contains peer or orderer
   368          extensions = self._get_cert_extensions_ip_sans(userName, ordererName)
   369          certReq = user.createCertRequest(ordererAdminTuple.nodeName, extensions=extensions)
   370          userCert = self.getOrganization(organizationName).createCertificate(certReq, extensions=extensions)
   371  
   372          # Verify the newly created certificate
   373          store = crypto.X509Store()
   374          # Assuming a list of trusted certs
   375          for trustedCert in [self.getOrganization(organizationName).signedCert]:
   376              store.add_cert(trustedCert)
   377          # Create a certificate context using the store and the certificate to verify
   378          store_ctx = crypto.X509StoreContext(store, userCert)
   379          # Verify the certificate, returns None if it can validate the certificate
   380          store_ctx.verify_certificate()
   381          self.ordererAdminTuples[ordererAdminTuple] = userCert
   382          return ordererAdminTuple
   383  
   384      def dump(self, output):
   385          'Will dump the directory to the provided store'
   386          import cPickle
   387          data = {'users' : {}, 'organizations' : {}, 'nats' : {}}
   388          dump_cert = lambda cert: crypto.dump_certificate(crypto.FILETYPE_PEM, cert)
   389          for userName, user in self.users.iteritems():
   390              # for k, v in user.tags.iteritems():
   391              #     try:
   392              #         cPickle.dumps(v)
   393              #     except:
   394              #         raise Exception("Failed on key {0}".format(k))
   395              data['users'][userName] = (user.ecdsaSigningKey.to_pem(), crypto.dump_privatekey(crypto.FILETYPE_PEM, user.rsaSigningKey), user.tags)
   396          for orgName, org in self.organizations.iteritems():
   397              networks = [n.name for n in  org.networks]
   398              data['organizations'][orgName] = (
   399                  org.ecdsaSigningKey.to_pem(), crypto.dump_privatekey(crypto.FILETYPE_PEM, org.rsaSigningKey),
   400                  dump_cert(org.getSelfSignedCert()), networks)
   401          for nat, cert in self.ordererAdminTuples.iteritems():
   402              data['nats'][nat] = dump_cert(cert)
   403          cPickle.dump(data, output)
   404  
   405      def initFromPath(self, path):
   406          'Will initialize the directory from the path supplied'
   407          import cPickle
   408          data = None
   409          with open(path,'r') as f:
   410              data = cPickle.load(f)
   411          assert data != None, "Expected some data, did not load any."
   412          priv_key_from_pem = lambda x: crypto.load_privatekey(crypto.FILETYPE_PEM, x)
   413          for userName, keyTuple in data['users'].iteritems():
   414              self.users[userName] = User(userName, directory=self,
   415                                          ecdsaSigningKey=ecdsa.SigningKey.from_pem(keyTuple[0]),
   416                                          rsaSigningKey=priv_key_from_pem(keyTuple[1]))
   417              self.users[userName].tags = keyTuple[2]
   418          for orgName, tuple in data['organizations'].iteritems():
   419              org = Organization(orgName, ecdsaSigningKey=ecdsa.SigningKey.from_pem(tuple[0]),
   420                                 rsaSigningKey=priv_key_from_pem(tuple[0]))
   421              org.signedCert = crypto.load_certificate(crypto.FILETYPE_PEM, tuple[2])
   422              org.networks = [Network[name] for name in tuple[3]]
   423              self.organizations[orgName] = org
   424          for nat, cert_as_pem in data['nats'].iteritems():
   425              self.ordererAdminTuples[nat] = crypto.load_certificate(crypto.FILETYPE_PEM, cert_as_pem)
   426  
   427  class AuthDSLHelper:
   428      @classmethod
   429      def Envelope(cls, signaturePolicy, identities):
   430          'Envelope builds an envelope message embedding a SignaturePolicy'
   431          return common_dot_policies_pb2.SignaturePolicyEnvelope(
   432              version=0,
   433              rule=signaturePolicy,
   434              identities=identities)
   435  
   436      @classmethod
   437      def NOutOf(cls, n, policies):
   438          'NOutOf creates a policy which requires N out of the slice of policies to evaluate to true'
   439          return common_dot_policies_pb2.SignaturePolicy(
   440              n_out_of=common_dot_policies_pb2.SignaturePolicy.NOutOf(
   441                  n=n,
   442                  rules=policies,
   443              ),
   444          )
   445  
   446      @classmethod
   447      def SignedBy(cls, index):
   448          'NOutOf creates a policy which requires N out of the slice of policies to evaluate to true'
   449          return common_dot_policies_pb2.SignaturePolicy(
   450              signed_by=index
   451          )
   452  
   453  class BootstrapHelper:
   454      KEY_CONSENSUS_TYPE = "ConsensusType"
   455      KEY_ORDERER_KAFKA_BROKERS = "KafkaBrokers"
   456      KEY_CHAIN_CREATION_POLICY_NAMES = "ChainCreationPolicyNames"
   457      KEY_CHANNEL_CREATION_POLICY = "ChannelCreationPolicy"
   458      KEY_CHANNEL_RESTRICTIONS = "ChannelRestrictions"
   459      KEY_CONSORTIUM = "Consortium"
   460      KEY_ACCEPT_ALL_POLICY = "AcceptAllPolicy"
   461      KEY_HASHING_ALGORITHM = "HashingAlgorithm"
   462      KEY_BLOCKDATA_HASHING_STRUCTURE = "BlockDataHashingStructure"
   463      KEY_BATCH_SIZE = "BatchSize"
   464      KEY_BATCH_TIMEOUT = "BatchTimeout"
   465      KEY_CREATIONPOLICY = "CreationPolicy"
   466      KEY_MSP_INFO = "MSP"
   467      KEY_ANCHOR_PEERS = "AnchorPeers"
   468  
   469      KEY_NEW_CONFIGURATION_ITEM_POLICY = "NewConfigurationItemPolicy"
   470      DEFAULT_CHAIN_CREATORS = [KEY_ACCEPT_ALL_POLICY]
   471  
   472      # ReadersPolicyKey is the key used for the read policy
   473      KEY_POLICY_READERS = "Readers"
   474      # WritersPolicyKey is the key used for the writer policy
   475      KEY_POLICY_WRITERS = "Writers"
   476      # AdminsPolicyKey is the key used for the admins policy
   477      KEY_POLICY_ADMINS = "Admins"
   478  
   479      KEY_POLICY_BLOCK_VALIDATION = "BlockValidation"
   480  
   481      # OrdererAddressesKey is the cb.ConfigItem type key name for the OrdererAddresses message
   482      KEY_ORDERER_ADDRESSES = "OrdererAddresses"
   483  
   484  
   485      DEFAULT_NONCE_SIZE = 24
   486  
   487      @classmethod
   488      def getNonce(cls):
   489          return rand.bytes(BootstrapHelper.DEFAULT_NONCE_SIZE)
   490  
   491      @classmethod
   492      def addSignatureToSignedConfigItem(cls, configUpdateEnvelope, (entity, mspId, cert)):
   493          serializedIdentity = identities_pb2.SerializedIdentity(mspid=mspId, id_bytes=crypto.dump_certificate(crypto.FILETYPE_PEM, cert))
   494          sigHeader = common_dot_common_pb2.SignatureHeader(creator=serializedIdentity.SerializeToString(),
   495                                                            nonce=BootstrapHelper.getNonce())
   496          sigHeaderBytes = sigHeader.SerializeToString()
   497          # Signature over the concatenation of configurationItem bytes and signatureHeader bytes
   498          signature = entity.sign(sigHeaderBytes + configUpdateEnvelope.config_update)
   499          # Now add new signature to Signatures repeated field
   500          newConfigSig = configUpdateEnvelope.signatures.add()
   501          newConfigSig.signature_header = sigHeaderBytes
   502          newConfigSig.signature = signature
   503  
   504      def __init__(self, chainId, lastModified=0, msgVersion=1, epoch=0, consensusType="solo", batchSize=10,
   505                   batchTimeout=".5s", absoluteMaxBytes=100000000, preferredMaxBytes=512 * 1024, signers=[]):
   506          self.chainId = str(chainId)
   507          self.lastModified = lastModified
   508          self.msgVersion = msgVersion
   509          self.epoch = epoch
   510          self.consensusType = consensusType
   511          self.batchSize = batchSize
   512          self.batchTimeout = batchTimeout
   513          self.absoluteMaxBytes = absoluteMaxBytes
   514          self.preferredMaxBytes = preferredMaxBytes
   515          self.signers = signers
   516  
   517      def makeChainHeader(self, type, txID="", extension='',
   518                          version=1,
   519                          timestamp=timestamp_pb2.Timestamp(seconds=int(time.time()), nanos=0)):
   520          return common_dot_common_pb2.ChannelHeader(type=type,
   521                                                   version=version,
   522                                                   timestamp=timestamp,
   523                                                   channel_id=self.chainId,
   524                                                   epoch=self.epoch,
   525                                                   tx_id=txID,
   526                                                   extension=extension)
   527  
   528      def makeSignatureHeader(self, serializeCertChain, nonce):
   529          return common_dot_common_pb2.SignatureHeader(creator=serializeCertChain,
   530                                                       nonce=nonce)
   531  
   532      def signConfigItem(self, configItem):
   533          # signedConfigItem = common_dot_configuration_pb2.SignedConfigurationItem(
   534          #     ConfigurationItem=configItem.SerializeToString(), Signatures=None)
   535          # return signedConfigItem
   536          return configItem
   537  
   538      def getConfigItem(self, commonConfigType, key, value):
   539          configItem = common_dot_configtx_pb2.ConfigItem(
   540              version=self.lastModified,
   541              configPath=commonConfigType,
   542              key=key,
   543              mod_policy=BootstrapHelper.KEY_NEW_CONFIGURATION_ITEM_POLICY,
   544              value=value)
   545          return configItem
   546  
   547      def computeBlockDataHash(self, blockData):
   548          return computeCryptoHash(blockData.SerializeToString())
   549  
   550  def getDirectory(context):
   551      if 'bootstrapDirectory' not in context:
   552          context.bootstrapDirectory = Directory()
   553      return context.bootstrapDirectory
   554  
   555  
   556  def getOrdererBootstrapAdmin(context, shouldCreate=False):
   557      directory = getDirectory(context)
   558      ordererBootstrapAdmin = directory.getUser(userName="ordererBootstrapAdmin", shouldCreate=shouldCreate)
   559      return ordererBootstrapAdmin
   560  
   561  
   562  def addOrdererBootstrapAdminOrgReferences(context, policyName, orgNames):
   563      'Adds a key/value pair of policyName/[orgName,...]'
   564      directory = getDirectory(context)
   565      ordererBootstrapAdmin = directory.getUser(userName="ordererBootstrapAdmin", shouldCreate=False)
   566      if not 'OrgReferences' in ordererBootstrapAdmin.tags:
   567          ordererBootstrapAdmin.tags['OrgReferences'] = {}
   568      policyNameToOrgNamesDict = ordererBootstrapAdmin.tags['OrgReferences']
   569      assert not policyName in policyNameToOrgNamesDict, "PolicyName '{0}' already registered with ordererBootstrapAdmin".format(
   570          policyName)
   571      policyNameToOrgNamesDict[policyName] = orgNames
   572      return policyNameToOrgNamesDict
   573  
   574  
   575  def getOrdererBootstrapAdminOrgReferences(context):
   576      directory = getDirectory(context)
   577      ordererBootstrapAdmin = directory.getUser(userName="ordererBootstrapAdmin", shouldCreate=False)
   578      if not 'OrgReferences' in ordererBootstrapAdmin.tags:
   579          ordererBootstrapAdmin.tags['OrgReferences'] = {}
   580      return ordererBootstrapAdmin.tags['OrgReferences']
   581  
   582  def getAnchorPeersConfigGroup(context, nodeAdminTuples, peer_port=7051, mod_policy=BootstrapHelper.KEY_POLICY_ADMINS):
   583      directory = getDirectory(context)
   584      config_group = common_dot_configtx_pb2.ConfigGroup()
   585      for orgName, group in groupby([(nat.organization, nat) for nat in nodeAdminTuples], lambda x: x[0]):
   586          anchorPeers = peer_dot_configuration_pb2.AnchorPeers()
   587          for (k,nodeAdminTuple) in group:
   588              anchorPeer = anchorPeers.anchor_peers.add()
   589              anchorPeer.host = nodeAdminTuple.nodeName
   590              anchorPeer.port = peer_port
   591              # anchorPeer.cert = crypto.dump_certificate(crypto.FILETYPE_PEM,
   592              #                                           directory.findCertForNodeAdminTuple(nodeAdminTuple))
   593          config_group.groups[ApplicationGroup].groups[orgName].values[BootstrapHelper.KEY_ANCHOR_PEERS].value=toValue(anchorPeers)
   594          config_group.groups[ApplicationGroup].groups[orgName].values[BootstrapHelper.KEY_ANCHOR_PEERS].mod_policy = BootstrapHelper.KEY_POLICY_ADMINS
   595      return config_group
   596  
   597  def setDefaultPoliciesForOrgs(channel, orgs, group_name, version=0, policy_version=0):
   598      for org in orgs:
   599          groupName = group_name
   600          channel.groups[groupName].groups[org.name].version=version
   601          channel.groups[groupName].groups[org.name].mod_policy = BootstrapHelper.KEY_POLICY_ADMINS
   602          mspPrincipalForMemberRole = org.getMspPrincipalAsRole(mspRoleTypeAsString='MEMBER')
   603          signedBy = AuthDSLHelper.SignedBy(0)
   604  
   605          memberSignaturePolicyEnvelope = AuthDSLHelper.Envelope(signaturePolicy=AuthDSLHelper.NOutOf(1, [signedBy]), identities=[mspPrincipalForMemberRole])
   606          memberPolicy = common_dot_policies_pb2.Policy(
   607              type=common_dot_policies_pb2.Policy.PolicyType.Value("SIGNATURE"),
   608              value=memberSignaturePolicyEnvelope.SerializeToString())
   609          channel.groups[groupName].groups[org.name].policies[BootstrapHelper.KEY_POLICY_READERS].version=policy_version
   610          channel.groups[groupName].groups[org.name].policies[BootstrapHelper.KEY_POLICY_READERS].policy.CopyFrom(memberPolicy)
   611          channel.groups[groupName].groups[org.name].policies[BootstrapHelper.KEY_POLICY_WRITERS].version=policy_version
   612          channel.groups[groupName].groups[org.name].policies[BootstrapHelper.KEY_POLICY_WRITERS].policy.CopyFrom(memberPolicy)
   613  
   614          mspPrincipalForAdminRole = org.getMspPrincipalAsRole(mspRoleTypeAsString='ADMIN')
   615          adminSignaturePolicyEnvelope = AuthDSLHelper.Envelope(signaturePolicy=AuthDSLHelper.NOutOf(1, [signedBy]), identities=[mspPrincipalForAdminRole])
   616          adminPolicy = common_dot_policies_pb2.Policy(
   617              type=common_dot_policies_pb2.Policy.PolicyType.Value("SIGNATURE"),
   618              value=adminSignaturePolicyEnvelope.SerializeToString())
   619          channel.groups[groupName].groups[org.name].policies[BootstrapHelper.KEY_POLICY_ADMINS].version=policy_version
   620          channel.groups[groupName].groups[org.name].policies[BootstrapHelper.KEY_POLICY_ADMINS].policy.CopyFrom(adminPolicy)
   621  
   622          for pKey, pVal in channel.groups[groupName].groups[org.name].policies.iteritems():
   623              pVal.mod_policy = BootstrapHelper.KEY_POLICY_ADMINS
   624  
   625          # signaturePolicyEnvelope = AuthDSLHelper.Envelope(signaturePolicy=AuthDSLHelper.SignedBy(0), identities=[mspPrincipal])
   626  
   627  
   628  
   629  def createChannelConfigGroup(directory, service_names, hashingAlgoName="SHA256", consensusType="solo", batchTimeout="1s", batchSizeMaxMessageCount=10, batchSizeAbsoluteMaxBytes=100000000, batchSizePreferredMaxBytes=512 * 1024, channel_max_count=0):
   630  
   631      channel = common_dot_configtx_pb2.ConfigGroup()
   632      # channel.groups[ApplicationGroup] = common_dot_configtx_pb2.ConfigGroup()
   633      # channel.groups[OrdererGroup] = common_dot_configtx_pb2.ConfigGroup()
   634      # channel.groups[ApplicationGroup]
   635      channel.groups[OrdererGroup]
   636      # v = common_dot_configtx_pb2.ConfigItem.ConfigType.Value
   637      # configItems.append(bootstrapHelper.encodeHashingAlgorithm())
   638      channel.values[BootstrapHelper.KEY_HASHING_ALGORITHM].value = toValue(
   639          common_dot_configuration_pb2.HashingAlgorithm(name=hashingAlgoName))
   640  
   641      golangMathMaxUint32 = 4294967295
   642      channel.values[BootstrapHelper.KEY_BLOCKDATA_HASHING_STRUCTURE].value = toValue(
   643          common_dot_configuration_pb2.BlockDataHashingStructure(width=golangMathMaxUint32))
   644  
   645      channel.groups[OrdererGroup].values[BootstrapHelper.KEY_BATCH_SIZE].value = toValue(orderer_dot_configuration_pb2.BatchSize(maxMessageCount=batchSizeMaxMessageCount,absoluteMaxBytes=batchSizeAbsoluteMaxBytes,preferredMaxBytes=batchSizePreferredMaxBytes))
   646      channel.groups[OrdererGroup].values[BootstrapHelper.KEY_BATCH_TIMEOUT].value = toValue(orderer_dot_configuration_pb2.BatchTimeout(timeout=batchTimeout))
   647      channel.groups[OrdererGroup].values[BootstrapHelper.KEY_CONSENSUS_TYPE].value = toValue(orderer_dot_configuration_pb2.ConsensusType(type=consensusType))
   648      channel.groups[OrdererGroup].values[BootstrapHelper.KEY_CHANNEL_RESTRICTIONS].value = toValue(orderer_dot_configuration_pb2.ChannelRestrictions(max_count=channel_max_count))
   649  
   650  
   651      acceptAllPolicy = common_dot_policies_pb2.Policy(type=1, value=AuthDSLHelper.Envelope(
   652          signaturePolicy=AuthDSLHelper.NOutOf(0, []), identities=[]).SerializeToString())
   653      # channel.policies[BootstrapHelper.KEY_ACCEPT_ALL_POLICY].policy.CopyFrom(acceptAllPolicy)
   654  
   655      # For now, setting same policies for each 'Non-Org' group
   656      typeImplicitMeta = common_dot_policies_pb2.Policy.PolicyType.Value("IMPLICIT_META")
   657      Policy = common_dot_policies_pb2.Policy
   658      IMP = common_dot_policies_pb2.ImplicitMetaPolicy
   659      ruleAny = common_dot_policies_pb2.ImplicitMetaPolicy.Rule.Value("ANY")
   660      ruleMajority = common_dot_policies_pb2.ImplicitMetaPolicy.Rule.Value("MAJORITY")
   661      for group in [channel, channel.groups[OrdererGroup]]:
   662          group.policies[BootstrapHelper.KEY_POLICY_READERS].policy.CopyFrom(Policy(type=typeImplicitMeta, value=IMP(
   663              rule=ruleAny, sub_policy=BootstrapHelper.KEY_POLICY_READERS).SerializeToString()))
   664          group.policies[BootstrapHelper.KEY_POLICY_WRITERS].policy.CopyFrom(Policy(type=typeImplicitMeta, value=IMP(
   665              rule=ruleAny, sub_policy=BootstrapHelper.KEY_POLICY_WRITERS).SerializeToString()))
   666          group.policies[BootstrapHelper.KEY_POLICY_ADMINS].policy.CopyFrom(Policy(type=typeImplicitMeta, value=IMP(
   667              rule=ruleMajority, sub_policy=BootstrapHelper.KEY_POLICY_ADMINS).SerializeToString()))
   668          for pKey, pVal in group.policies.iteritems():
   669              pVal.mod_policy = BootstrapHelper.KEY_POLICY_ADMINS
   670  
   671      # Setting block validation policy for the orderer group
   672      channel.groups[OrdererGroup].policies[BootstrapHelper.KEY_POLICY_BLOCK_VALIDATION].policy.CopyFrom(Policy(type=typeImplicitMeta, value=IMP(
   673          rule=ruleAny, sub_policy=BootstrapHelper.KEY_POLICY_WRITERS).SerializeToString()))
   674      channel.groups[OrdererGroup].policies[BootstrapHelper.KEY_POLICY_BLOCK_VALIDATION].mod_policy=BootstrapHelper.KEY_POLICY_ADMINS
   675  
   676      # Add the orderer org groups MSPConfig info
   677      for ordererOrg in [org for org in directory.getOrganizations().values() if Network.Orderer in org.networks]:
   678          channel.groups[OrdererGroup].groups[ordererOrg.name].values[BootstrapHelper.KEY_MSP_INFO].value = toValue(
   679              getMSPConfig(org=ordererOrg, directory=directory))
   680          channel.groups[OrdererGroup].groups[ordererOrg.name].values[BootstrapHelper.KEY_MSP_INFO].mod_policy=BootstrapHelper.KEY_POLICY_ADMINS
   681  
   682      #Kafka specific
   683      kafka_brokers = ["{0}:9092".format(service_name) for service_name in service_names if "kafka" in service_name]
   684      if len(kafka_brokers) > 0:
   685          channel.groups[OrdererGroup].values[BootstrapHelper.KEY_ORDERER_KAFKA_BROKERS].value = toValue(
   686              orderer_dot_configuration_pb2.KafkaBrokers(brokers=kafka_brokers))
   687  
   688      for vKey, vVal in channel.groups[OrdererGroup].values.iteritems():
   689          vVal.mod_policy=BootstrapHelper.KEY_POLICY_ADMINS
   690  
   691  
   692  
   693      # Now set policies for each org group (Both peer and orderer)
   694      #TODO: Revisit after Jason does a bit more refactoring on chain creation policy enforcement
   695      ordererOrgs = [o for o in directory.getOrganizations().values() if Network.Orderer in o.networks]
   696      setDefaultPoliciesForOrgs(channel, ordererOrgs , OrdererGroup, version=0, policy_version=0)
   697  
   698      #New OrdererAddress
   699      ordererAddress = common_dot_configuration_pb2.OrdererAddresses()
   700      for orderer_service_name in [service_name for service_name in service_names if "orderer" in service_name]:
   701          ordererAddress.addresses.append("{0}:7050".format(orderer_service_name))
   702      assert len(ordererAddress.addresses) > 0, "No orderer nodes were found while trying to create channel ConfigGroup"
   703      channel.values[BootstrapHelper.KEY_ORDERER_ADDRESSES].value = toValue(ordererAddress)
   704  
   705  
   706      for pKey, pVal in channel.values.iteritems():
   707          pVal.mod_policy = BootstrapHelper.KEY_POLICY_ADMINS
   708  
   709  
   710      return channel
   711  
   712  def createEnvelopeForMsg(directory, nodeAdminTuple, chainId, msg, typeAsString):
   713      # configEnvelope = common_dot_configtx_pb2.ConfigEnvelope(last_update=envelope.SerializeToString())
   714      bootstrapHelper = BootstrapHelper(chainId=chainId)
   715      payloadChainHeader = bootstrapHelper.makeChainHeader(
   716          type=common_dot_common_pb2.HeaderType.Value(typeAsString))
   717  
   718      # Now the SignatureHeader
   719      org = directory.getOrganization(nodeAdminTuple.organization)
   720      user = directory.getUser(nodeAdminTuple.user)
   721      cert = directory.findCertForNodeAdminTuple(nodeAdminTuple)
   722      serializedIdentity = identities_pb2.SerializedIdentity(mspid=org.name, id_bytes=crypto.dump_certificate(crypto.FILETYPE_PEM, cert))
   723      serializedCreatorCertChain = serializedIdentity.SerializeToString()
   724      nonce = None
   725      payloadSignatureHeader = common_dot_common_pb2.SignatureHeader(
   726          creator=serializedCreatorCertChain,
   727          nonce=bootstrapHelper.getNonce(),
   728      )
   729  
   730      payloadHeader = common_dot_common_pb2.Header(
   731          channel_header=payloadChainHeader.SerializeToString(),
   732          signature_header=payloadSignatureHeader.SerializeToString(),
   733      )
   734      payload = common_dot_common_pb2.Payload(header=payloadHeader, data=msg.SerializeToString())
   735      payloadBytes = payload.SerializeToString()
   736      envelope = common_dot_common_pb2.Envelope(payload=payloadBytes, signature=user.sign(payloadBytes))
   737      return envelope
   738  
   739      return configEnvelope
   740  
   741  
   742  def createNewConfigUpdateEnvelope(channelConfig, chainId, readset_version=0):
   743      read_set = common_dot_configtx_pb2.ConfigGroup()
   744      read_set.values[BootstrapHelper.KEY_CONSORTIUM].version=readset_version
   745      read_set.values[BootstrapHelper.KEY_CONSORTIUM].value=channelConfig.values[BootstrapHelper.KEY_CONSORTIUM].value
   746      read_set.groups[ApplicationGroup].version=readset_version
   747      for key, _ in channelConfig.groups['Application'].groups.iteritems():
   748          read_set.groups[ApplicationGroup].groups[key]
   749      configUpdate = common_dot_configtx_pb2.ConfigUpdate(channel_id=chainId,
   750                                                          read_set=read_set,
   751                                                          write_set=channelConfig)
   752      configUpdateEnvelope = common_dot_configtx_pb2.ConfigUpdateEnvelope(config_update=configUpdate.SerializeToString(), signatures =[])
   753      return configUpdateEnvelope
   754  
   755  
   756  def mergeConfigGroups(configGroupTarget, configGroupSource, allow_value_overwrite=False):
   757      for k, v in configGroupSource.groups.iteritems():
   758          if k in configGroupTarget.groups.keys():
   759              mergeConfigGroups(configGroupTarget.groups[k], configGroupSource.groups[k], allow_value_overwrite=allow_value_overwrite)
   760          else:
   761              configGroupTarget.groups[k].MergeFrom(v)
   762      for k, v in configGroupSource.policies.iteritems():
   763          if k in configGroupTarget.policies.keys():
   764              mergeConfigGroups(configGroupTarget.policies[k], configGroupSource.policies[k], allow_value_overwrite=allow_value_overwrite)
   765          else:
   766              configGroupTarget.policies[k].MergeFrom(v)
   767      for k, v in configGroupSource.values.iteritems():
   768          if not allow_value_overwrite:
   769              assert not k in configGroupTarget.values.keys(), "Value already exists in target config group: {0}".format(k)
   770          configGroupTarget.values[k].CopyFrom(v)
   771  
   772  
   773  def createGenesisBlock(context, service_names, chainId, consensusType, nodeAdminTuple, signedConfigItems=[]):
   774      'Generates the genesis block for starting the oderers and for use in the chain config transaction by peers'
   775      # assert not "bootstrapGenesisBlock" in context,"Genesis block already created:\n{0}".format(context.bootstrapGenesisBlock)
   776      directory = getDirectory(context)
   777      assert len(directory.ordererAdminTuples) > 0, "No orderer admin tuples defined!!!"
   778  
   779      channelConfig = createChannelConfigGroup(directory=directory, service_names=service_names, consensusType=consensusType)
   780      for configGroup in signedConfigItems:
   781          mergeConfigGroups(channelConfig, configGroup)
   782  
   783      config = common_dot_configtx_pb2.Config(
   784          sequence=0,
   785          channel_group=channelConfig)
   786  
   787      configEnvelope = common_dot_configtx_pb2.ConfigEnvelope(config=config)
   788      envelope = createEnvelopeForMsg(directory=directory, chainId=chainId, nodeAdminTuple=nodeAdminTuple, msg=configEnvelope, typeAsString="CONFIG")
   789      blockData = common_dot_common_pb2.BlockData(data=[envelope.SerializeToString()])
   790  
   791      # Spoke with kostas, for orderer in general
   792      signaturesMetadata = ""
   793      lastConfigurationBlockMetadata = common_dot_common_pb2.Metadata(
   794          value=common_dot_common_pb2.LastConfig(index=0).SerializeToString()).SerializeToString()
   795      ordererConfigMetadata = ""
   796      transactionFilterMetadata = ""
   797      bootstrapHelper = BootstrapHelper(chainId="NOT_USED")
   798      block = common_dot_common_pb2.Block(
   799          header=common_dot_common_pb2.BlockHeader(
   800              number=0,
   801              previous_hash=None,
   802              data_hash=bootstrapHelper.computeBlockDataHash(blockData),
   803          ),
   804          data=blockData,
   805          metadata=common_dot_common_pb2.BlockMetadata(
   806              metadata=[signaturesMetadata, lastConfigurationBlockMetadata, transactionFilterMetadata,
   807                        ordererConfigMetadata]),
   808      )
   809  
   810      # Add this back once crypto certs are required
   811      for nodeAdminTuple in directory.ordererAdminTuples:
   812          userCert = directory.ordererAdminTuples[nodeAdminTuple]
   813          certAsPEM = crypto.dump_certificate(crypto.FILETYPE_PEM, userCert)
   814          # print("UserCert for orderer genesis:\n{0}\n".format(certAsPEM))
   815          # print("")
   816  
   817      return (block, envelope, channelConfig)
   818  
   819  
   820  class PathType(Enum):
   821      'Denotes whether Path relative to Local filesystem or Containers volume reference.'
   822      Local = 1
   823      Container = 2
   824  
   825  
   826  def getMSPConfig(org, directory):
   827      # CA certificates can't be admins of an MSP
   828      # adminCerts = [org.getCertAsPEM()]
   829      adminCerts = []
   830      # Find the mspAdmin Tuple for org and add to admincerts folder
   831      for pnt, cert in [(nat, cert) for nat, cert in directory.ordererAdminTuples.items() if
   832                        org.name == nat.organization and "configadmin" in nat.nodeName.lower()]:
   833          adminCerts.append(crypto.dump_certificate(crypto.FILETYPE_PEM, cert))
   834      cacerts = [org.getCertAsPEM()]
   835      tls_root_certs = [org.getCertAsPEM()]
   836      # Currently only 1 component, CN=<orgName>
   837      # name = self.getSelfSignedCert().get_subject().getComponents()[0][1]
   838      fabricMSPConfig = msp_config_pb2.FabricMSPConfig(admins=adminCerts, root_certs=cacerts, name=org.name, tls_root_certs=tls_root_certs)
   839      mspConfig = msp_config_pb2.MSPConfig(config=fabricMSPConfig.SerializeToString(), type=0)
   840      return mspConfig
   841  
   842  
   843  class CallbackHelper:
   844      def __init__(self, discriminator, volumeRootPathInContainer = "/var/hyperledger/bddtests"):
   845          self.volumeRootPathInContainer = volumeRootPathInContainer
   846          self.discriminator = discriminator
   847  
   848      def getVolumePath(self, project_name, pathType=PathType.Local):
   849          assert pathType in PathType, "Expected pathType of {0}".format(PathType)
   850          basePath = "."
   851          if pathType == PathType.Container:
   852              basePath = self.volumeRootPathInContainer
   853          return "{0}/volumes/{1}/{2}".format(basePath, self.discriminator, project_name)
   854  
   855      def getLocalMspConfigPath(self, project_name, compose_service, pathType=PathType.Local):
   856          return "{0}/{1}/localMspConfig".format(self.getVolumePath(project_name=project_name, pathType=pathType), compose_service)
   857  
   858      def getLocalTLSConfigPath(self, project_name, compose_service, pathType=PathType.Local):
   859          return os.path.join(self.getVolumePath(project_name=project_name, pathType=pathType), compose_service, "tls_config")
   860  
   861      def _getPathAndUserInfo(self, directory , project_name, compose_service, nat_discriminator="Signer", pathType=PathType.Local):
   862          matchingNATs = [nat for nat in directory.getNamedCtxTuples() if ((compose_service in nat.user) and (nat_discriminator in nat.user) and ((compose_service in nat.nodeName)))]
   863          assert len(matchingNATs)==1, "Unexpected number of matching NodeAdminTuples: {0}".format(matchingNATs)
   864          localMspConfigPath = self.getLocalMspConfigPath(project_name=project_name, compose_service=compose_service,pathType=pathType)
   865          return (localMspConfigPath, matchingNATs[0])
   866  
   867      def getLocalMspConfigPrivateKeyPath(self, directory , project_name, compose_service, pathType=PathType.Local):
   868          (localMspConfigPath, nodeAdminTuple) = self._getPathAndUserInfo(directory=directory, project_name=project_name, compose_service=compose_service, pathType=pathType)
   869          return "{0}/keystore/{1}.pem".format(localMspConfigPath, nodeAdminTuple.user)
   870  
   871      def getLocalMspConfigPublicCertPath(self, directory , project_name, compose_service, pathType=PathType.Local):
   872          (localMspConfigPath, nodeAdminTuple) = self._getPathAndUserInfo(directory=directory, project_name=project_name, compose_service=compose_service, pathType=pathType)
   873          return "{0}/signcerts/{1}.pem".format(localMspConfigPath, nodeAdminTuple.user)
   874  
   875      def getTLSKeyPaths(self, pnt , project_name, compose_service, pathType=PathType.Local):
   876          localTLSConfigPath = self.getLocalTLSConfigPath(project_name=project_name, compose_service=compose_service, pathType=pathType)
   877          certPath = os.path.join(localTLSConfigPath,
   878                                  "{0}-{1}-{2}-tls.crt".format(pnt.user, pnt.nodeName, pnt.organization))
   879          keyPath = os.path.join(localTLSConfigPath,
   880                                 "{0}-{1}-{2}-tls.key".format(pnt.user, pnt.nodeName, pnt.organization))
   881          return (keyPath, certPath)
   882  
   883  
   884      def getLocalMspConfigRootCertPath(self, directory , project_name, compose_service, pathType=PathType.Local):
   885          (localMspConfigPath, nodeAdminTuple) = self._getPathAndUserInfo(directory=directory, project_name=project_name, compose_service=compose_service, pathType=pathType)
   886          return "{0}/cacerts/{1}.pem".format(localMspConfigPath, nodeAdminTuple.organization)
   887  
   888      def _createCryptoMaterial(self,directory , project_name, compose_service, network):
   889          self._writeMspFiles(directory , project_name=project_name, compose_service=compose_service, network=network)
   890          self._writeTLSFiles(directory , project_name=project_name, compose_service=compose_service, network=network)
   891  
   892      def _writeMspFiles(self, directory , project_name, compose_service, network):
   893          localMspConfigPath = self.getLocalMspConfigPath(project_name, compose_service)
   894          os.makedirs("{0}/{1}".format(localMspConfigPath, "signcerts"))
   895          os.makedirs("{0}/{1}".format(localMspConfigPath, "admincerts"))
   896          os.makedirs("{0}/{1}".format(localMspConfigPath, "cacerts"))
   897          #TODO: Consider how to accomodate intermediate CAs
   898          os.makedirs("{0}/{1}".format(localMspConfigPath, "intermediatecacerts"))
   899          os.makedirs("{0}/{1}".format(localMspConfigPath, "keystore"))
   900          os.makedirs("{0}/{1}".format(localMspConfigPath, "tlscacerts"))
   901          #TODO: Consider how to accomodate intermediate CAs
   902          os.makedirs("{0}/{1}".format(localMspConfigPath, "tlsintermediatecacerts"))
   903  
   904          # Find the peer signer Tuple for this peer and add to signcerts folder
   905          for pnt, cert in [(peerNodeTuple, cert) for peerNodeTuple, cert in directory.ordererAdminTuples.items() if
   906                            compose_service in peerNodeTuple.user and "signer" in peerNodeTuple.user.lower()]:
   907              # Put the PEM file in the signcerts folder
   908              with open("{0}/signcerts/{1}.pem".format(localMspConfigPath, pnt.user), "w") as f:
   909                  f.write(crypto.dump_certificate(crypto.FILETYPE_PEM, cert))
   910              # Put the associated private key into the keystore folder
   911              user = directory.getUser(pnt.user, shouldCreate=False)
   912              with open("{0}/keystore/{1}.pem".format(localMspConfigPath, pnt.user), "w") as f:
   913                  f.write(user.ecdsaSigningKey.to_pem())
   914  
   915              #Now put the signing Orgs cert in the cacerts folder
   916              org_cert_as_pem =  directory.getOrganization(pnt.organization).getCertAsPEM()
   917              with open("{0}/cacerts/{1}.pem".format(localMspConfigPath, pnt.organization), "w") as f:
   918                  f.write(org_cert_as_pem)
   919              with open("{0}/tlscacerts/{1}.pem".format(localMspConfigPath, pnt.organization), "w") as f:
   920                  f.write(org_cert_as_pem)
   921  
   922          # Find the peer admin Tuple for this peer and add to admincerts folder
   923          for pnt, cert in [(peerNodeTuple, cert) for peerNodeTuple, cert in directory.ordererAdminTuples.items() if
   924                            compose_service in peerNodeTuple.user and "admin" in peerNodeTuple.user.lower()]:
   925              # Put the PEM file in the signcerts folder
   926              with open("{0}/admincerts/{1}.pem".format(localMspConfigPath, pnt.user), "w") as f:
   927                  f.write(crypto.dump_certificate(crypto.FILETYPE_PEM, cert))
   928  
   929      def _writeTLSFiles(self, directory , project_name, compose_service, network):
   930          localTLSConfigPath = self.getLocalTLSConfigPath(project_name, compose_service)
   931          os.makedirs(localTLSConfigPath)
   932          # Find the peer signer Tuple for this peer and add to signcerts folder
   933          for pnt, cert in [(peerNodeTuple, cert) for peerNodeTuple, cert in directory.ordererAdminTuples.items() if
   934                            compose_service in peerNodeTuple.user and "signer" in peerNodeTuple.user.lower()]:
   935              user = directory.getUser(userName=pnt.user)
   936              # Add the subjectAlternativeName if the current entity is a signer, and the nodeName contains peer or orderer
   937              extensions = directory._get_cert_extensions_ip_sans(user.name, pnt.nodeName)
   938              userTLSCert = directory.getOrganization(pnt.organization).createCertificate(user.createTLSCertRequest(pnt.nodeName), extensions=extensions)
   939              (keyPath, certPath) = self.getTLSKeyPaths(pnt=pnt, project_name=project_name, compose_service=compose_service, pathType=PathType.Local)
   940              with open(keyPath, 'w') as f:
   941                  f.write(crypto.dump_privatekey(crypto.FILETYPE_PEM, user.rsaSigningKey))
   942              with open(certPath, 'w') as f:
   943                  f.write(crypto.dump_certificate(crypto.FILETYPE_PEM, userTLSCert))
   944  
   945      def _getMspId(self, compose_service, directory):
   946          matchingNATs = [nat for nat in directory.getNamedCtxTuples() if ((compose_service in nat.user) and ("Signer" in nat.user) and ((compose_service in nat.nodeName)))]
   947          assert len(matchingNATs)==1, "Unexpected number of matching NodeAdminTuples: {0}".format(matchingNATs)
   948          return matchingNATs[0].organization
   949  
   950  
   951  class OrdererGensisBlockCompositionCallback(compose.CompositionCallback, CallbackHelper):
   952      'Responsible for setting the GensisBlock for the Orderer nodes upon composition'
   953  
   954      def __init__(self, context, genesisBlock, genesisFileName="genesis_file"):
   955          CallbackHelper.__init__(self, discriminator="orderer")
   956          self.context = context
   957          self.genesisFileName = genesisFileName
   958          self.genesisBlock = genesisBlock
   959          compose.Composition.RegisterCallbackInContext(context, self)
   960  
   961      def getGenesisFilePath(self, project_name, pathType=PathType.Local):
   962          return "{0}/{1}".format(self.getVolumePath(project_name=project_name, pathType=pathType), self.genesisFileName)
   963  
   964      def getOrdererList(self, composition):
   965          return [serviceName for serviceName in composition.getServiceNames() if "orderer" in serviceName]
   966  
   967      def composing(self, composition, context):
   968          print("Will copy gensisiBlock over at this point ")
   969          os.makedirs(self.getVolumePath(composition.projectName))
   970          with open(self.getGenesisFilePath(composition.projectName), "wb") as f:
   971              f.write(self.genesisBlock.SerializeToString())
   972          directory = getDirectory(context)
   973  
   974          for ordererService in self.getOrdererList(composition):
   975              self._createCryptoMaterial(directory=directory,
   976                                         compose_service=ordererService,
   977                                         project_name=composition.projectName,
   978                                         network=Network.Orderer)
   979  
   980      def decomposing(self, composition, context):
   981          'Will remove the orderer volume path folder for the context'
   982          shutil.rmtree(self.getVolumePath(composition.projectName))
   983  
   984      def getEnv(self, composition, context, env):
   985          directory = getDirectory(context)
   986          env["ORDERER_GENERAL_GENESISMETHOD"] = "file"
   987          env["ORDERER_GENERAL_GENESISFILE"] = self.getGenesisFilePath(composition.projectName, pathType=PathType.Container)
   988          for ordererService in self.getOrdererList(composition):
   989              localMspConfigPath = self.getLocalMspConfigPath(composition.projectName, ordererService, pathType=PathType.Container)
   990              env["{0}_ORDERER_GENERAL_LOCALMSPDIR".format(ordererService.upper())] = localMspConfigPath
   991              env["{0}_ORDERER_GENERAL_LOCALMSPID".format(ordererService.upper())] = self._getMspId(compose_service=ordererService, directory=directory)
   992              # TLS Settings
   993              (_, pnt) = self._getPathAndUserInfo(directory=directory, project_name=composition.projectName, compose_service=ordererService, pathType=PathType.Container)
   994              (keyPath, certPath) = self.getTLSKeyPaths(pnt=pnt, project_name=composition.projectName, compose_service=ordererService, pathType=PathType.Container)
   995              env["{0}_ORDERER_GENERAL_TLS_CERTIFICATE".format(ordererService.upper())] = certPath
   996              env["{0}_ORDERER_GENERAL_TLS_PRIVATEKEY".format(ordererService.upper())] = keyPath
   997              env["{0}_ORDERER_GENERAL_TLS_ROOTCAS".format(ordererService.upper())] = "[{0}]".format(self.getLocalMspConfigRootCertPath(
   998                  directory=directory, project_name=composition.projectName, compose_service=ordererService, pathType=PathType.Container))
   999  
  1000  class PeerCompositionCallback(compose.CompositionCallback, CallbackHelper):
  1001      'Responsible for setting up Peer nodes upon composition'
  1002  
  1003      def __init__(self, context):
  1004          CallbackHelper.__init__(self, discriminator="peer")
  1005          self.context = context
  1006          compose.Composition.RegisterCallbackInContext(context, self)
  1007  
  1008      def getPeerList(self, composition):
  1009          return [serviceName for serviceName in composition.getServiceNames() if "peer" in serviceName]
  1010  
  1011      def composing(self, composition, context):
  1012          'Will copy local MSP info over at this point for each peer node'
  1013  
  1014          directory = getDirectory(context)
  1015  
  1016          for peerService in self.getPeerList(composition):
  1017              self._createCryptoMaterial(directory=directory,
  1018                                         compose_service=peerService,
  1019                                         project_name=composition.projectName,
  1020                                         network=Network.Peer)
  1021  
  1022      def decomposing(self, composition, context):
  1023          'Will remove the orderer volume path folder for the context'
  1024          shutil.rmtree(self.getVolumePath(composition.projectName))
  1025  
  1026      def getEnv(self, composition, context, env):
  1027          directory = getDirectory(context)
  1028          # First figure out which organization provided the signer cert for this
  1029          for peerService in self.getPeerList(composition):
  1030              localMspConfigPath = self.getLocalMspConfigPath(composition.projectName, peerService, pathType=PathType.Container)
  1031              env["{0}_CORE_PEER_MSPCONFIGPATH".format(peerService.upper())] = localMspConfigPath
  1032              env["{0}_CORE_PEER_LOCALMSPID".format(peerService.upper())] = self._getMspId(compose_service=peerService, directory=directory)
  1033              # TLS Settings
  1034              # env["{0}_CORE_PEER_TLS_ENABLED".format(peerService.upper())] = self._getMspId(compose_service=peerService, directory=directory)
  1035              (_, pnt) = self._getPathAndUserInfo(directory=directory, project_name=composition.projectName, compose_service=peerService, pathType=PathType.Container)
  1036              (keyPath, certPath) = self.getTLSKeyPaths(pnt=pnt, project_name=composition.projectName, compose_service=peerService, pathType=PathType.Container)
  1037              env["{0}_CORE_PEER_TLS_CERT_FILE".format(peerService.upper())] = certPath
  1038              env["{0}_CORE_PEER_TLS_KEY_FILE".format(peerService.upper())] = keyPath
  1039              env["{0}_CORE_PEER_TLS_ROOTCERT_FILE".format(peerService.upper())] = self.getLocalMspConfigRootCertPath(
  1040                  directory=directory, project_name=composition.projectName, compose_service=peerService, pathType=PathType.Container)
  1041              env["{0}_CORE_PEER_TLS_SERVERHOSTOVERRIDE".format(peerService.upper())] = peerService
  1042  
  1043  
  1044  def getDefaultConsortiumGroup(consortiums_mod_policy):
  1045      default_config_group = common_dot_configtx_pb2.ConfigGroup()
  1046      default_config_group.groups[ConsortiumsGroup].mod_policy=consortiums_mod_policy
  1047      return default_config_group
  1048  
  1049  
  1050  def create_config_update_envelope(config_update):
  1051      return  common_dot_configtx_pb2.ConfigUpdateEnvelope(config_update=config_update.SerializeToString(), signatures =[])
  1052  
  1053  def create_orderer_consortium_config_update(orderer_system_chain_id, orderer_channel_group, config_groups):
  1054      'Creates the orderer config update'
  1055      # First determine read set
  1056      read_set = common_dot_configtx_pb2.ConfigGroup()
  1057      read_set.groups[ConsortiumsGroup].CopyFrom(orderer_channel_group.groups[ConsortiumsGroup])
  1058  
  1059      write_set = common_dot_configtx_pb2.ConfigGroup()
  1060      write_set.groups[ConsortiumsGroup].CopyFrom(orderer_channel_group.groups[ConsortiumsGroup])
  1061      write_set.groups[ConsortiumsGroup].version += 1
  1062      for config_group in config_groups:
  1063          mergeConfigGroups(write_set, config_group)
  1064      config_update = common_dot_configtx_pb2.ConfigUpdate(channel_id=orderer_system_chain_id,
  1065                                                          read_set=read_set,
  1066                                                          write_set=write_set)
  1067      # configUpdateEnvelope = common_dot_configtx_pb2.ConfigUpdateEnvelope(config_update=configUpdate.SerializeToString(), signatures =[])
  1068      return config_update
  1069  
  1070  def create_channel_config_update(system_channel_version, channel_id, consortium_config_group):
  1071      read_set = common_dot_configtx_pb2.ConfigGroup()
  1072      read_set.version = system_channel_version
  1073      read_set.values[BootstrapHelper.KEY_CONSORTIUM].value=toValue(common_dot_configuration_pb2.Consortium(name=consortium_config_group.groups[ConsortiumsGroup].groups.keys()[0]))
  1074  
  1075      # Copying all of the consortium orgs into the ApplicationGroup
  1076      read_set.groups[ApplicationGroup].CopyFrom(consortium_config_group.groups[ConsortiumsGroup].groups.values()[0])
  1077      read_set.groups[ApplicationGroup].values.clear()
  1078      read_set.groups[ApplicationGroup].policies.clear()
  1079      read_set.groups[ApplicationGroup].mod_policy=""
  1080      for k, v in read_set.groups[ApplicationGroup].groups.iteritems():
  1081          v.values.clear()
  1082          v.policies.clear()
  1083          v.mod_policy=""
  1084  
  1085      # Now the write_set
  1086      write_set = common_dot_configtx_pb2.ConfigGroup()
  1087      write_set.CopyFrom(read_set)
  1088      write_set.groups[ApplicationGroup].version += 1
  1089      # For now, setting same policies for each 'Non-Org' group
  1090      typeImplicitMeta = common_dot_policies_pb2.Policy.PolicyType.Value("IMPLICIT_META")
  1091      Policy = common_dot_policies_pb2.Policy
  1092      IMP = common_dot_policies_pb2.ImplicitMetaPolicy
  1093      ruleAny = common_dot_policies_pb2.ImplicitMetaPolicy.Rule.Value("ANY")
  1094      ruleMajority = common_dot_policies_pb2.ImplicitMetaPolicy.Rule.Value("MAJORITY")
  1095      write_set.groups[ApplicationGroup].policies[BootstrapHelper.KEY_POLICY_READERS].policy.CopyFrom(
  1096          Policy(type=typeImplicitMeta, value=IMP(
  1097              rule=ruleAny, sub_policy=BootstrapHelper.KEY_POLICY_READERS).SerializeToString()))
  1098      write_set.groups[ApplicationGroup].policies[BootstrapHelper.KEY_POLICY_WRITERS].policy.CopyFrom(
  1099          Policy(type=typeImplicitMeta, value=IMP(
  1100              rule=ruleAny, sub_policy=BootstrapHelper.KEY_POLICY_WRITERS).SerializeToString()))
  1101      write_set.groups[ApplicationGroup].policies[BootstrapHelper.KEY_POLICY_ADMINS].policy.CopyFrom(
  1102          Policy(type=typeImplicitMeta, value=IMP(
  1103              rule=ruleMajority, sub_policy=BootstrapHelper.KEY_POLICY_ADMINS).SerializeToString()))
  1104      write_set.groups[ApplicationGroup].mod_policy = "Admins"
  1105      for k, v in write_set.groups[ApplicationGroup].policies.iteritems():
  1106          v.mod_policy=BootstrapHelper.KEY_POLICY_ADMINS
  1107      config_update = common_dot_configtx_pb2.ConfigUpdate(channel_id=channel_id,
  1108                                                           read_set=read_set,
  1109                                                           write_set=write_set)
  1110      return config_update
  1111  
  1112  def get_group_paths_from_config_group(config_group, paths, current_path = ""):
  1113      if len(config_group.groups)==0:
  1114          paths.append(current_path)
  1115      else:
  1116          for group_name, group in config_group.groups.iteritems():
  1117              get_group_paths_from_config_group(config_group=group, current_path="{0}/{1}".format(current_path, group_name), paths=paths)
  1118      return paths
  1119  
  1120  
  1121  def get_group_from_config_path(config_group, config_path):
  1122      from os import path
  1123      current_config_group = config_group
  1124      for group_id in [g.strip("/") for g in path.split(config_path)]:
  1125          current_config_group = current_config_group.groups[group_id]
  1126      return current_config_group
  1127  
  1128  def create_existing_channel_config_update(system_channel_version, channel_id, input_config_update, config_groups):
  1129      # First make a copy of the input config update msg to manipulate
  1130      read_set = common_dot_configtx_pb2.ConfigGroup()
  1131      read_set.version = system_channel_version
  1132      read_set.CopyFrom(input_config_update)
  1133  
  1134      # Now the write_set
  1135      write_set = common_dot_configtx_pb2.ConfigGroup()
  1136      write_set.CopyFrom(read_set)
  1137  
  1138      # Merge all of the supplied config_groups
  1139      for config_group in config_groups:
  1140          mergeConfigGroups(write_set, config_group)
  1141  
  1142      # Will build a unique list of group paths from the supplied config_groups
  1143      group_paths = list(set([p for sublist in [get_group_paths_from_config_group(cg, paths=[]) for cg in config_groups] for p in sublist]))
  1144  
  1145      # Now increment the version for each path.
  1146      # TODO: This logic will only work for the case of insertions
  1147      for group in [get_group_from_config_path(write_set, g) for g in group_paths]:
  1148          group.version += 1
  1149  
  1150      # For now, setting same policies for each 'Non-Org' group
  1151      config_update = common_dot_configtx_pb2.ConfigUpdate(channel_id=channel_id,
  1152                                                           read_set=read_set,
  1153                                                           write_set=write_set)
  1154      return config_update
  1155  
  1156  def update_config_group_version_info(input_config_update, proposed_config_group):
  1157      for k,v in proposed_config_group.groups.iteritems():
  1158          if k in input_config_update.groups.keys():
  1159              # Make sure all keys of the current group match those of the proposed, if not either added or deleted.
  1160              if not set(proposed_config_group.groups[k].groups.keys()) == set(input_config_update.groups[k].groups.keys()):
  1161                  proposed_config_group.groups[k].version +=1
  1162              # Now recurse
  1163              update_config_group_version_info(input_config_update.groups[k], proposed_config_group.groups[k])
  1164  
  1165  # def create_existing_channel_config_update2(system_channel_version, channel_id, input_config_update, config_group):
  1166  #     # First make a copy of the input config update msg to manipulate
  1167  #     read_set = common_dot_configtx_pb2.ConfigGroup()
  1168  #     read_set.version = system_channel_version
  1169  #     read_set.CopyFrom(config_group)
  1170  #
  1171  #     # Now the write_set
  1172  #     write_set = common_dot_configtx_pb2.ConfigGroup()
  1173  #     write_set.CopyFrom(read_set)
  1174  #     mergeConfigGroups(write_set, config_groups[0])
  1175  #     write_set.groups['Application'].groups['peerOrg0'].version +=1
  1176  #
  1177  #     # write_set.groups[ApplicationGroup].version += 1
  1178  #     # For now, setting same policies for each 'Non-Org' group
  1179  #     config_update = common_dot_configtx_pb2.ConfigUpdate(channel_id=channel_id,
  1180  #                                                          read_set=read_set,
  1181  #                                                          write_set=write_set)
  1182  #     return config_update
  1183  
  1184  
  1185  def createConsortium(context, consortium_name, org_names, mod_policy):
  1186      channel = common_dot_configtx_pb2.ConfigGroup()
  1187      directory = getDirectory(context=context)
  1188      channel.groups[ConsortiumsGroup].groups[consortium_name].mod_policy = mod_policy
  1189      # Add the orderer org groups MSPConfig info to consortiums group
  1190      for consortium_org in [org for org in directory.getOrganizations().values() if org.name in org_names]:
  1191          # channel.groups[ConsortiumsGroup].groups[consortium_name].groups[consortium_org.name].mod_policy = BootstrapHelper.KEY_POLICY_ADMINS
  1192          channel.groups[ConsortiumsGroup].groups[consortium_name].groups[consortium_org.name].values[BootstrapHelper.KEY_MSP_INFO].value = toValue(
  1193              getMSPConfig(org=consortium_org, directory=directory))
  1194          channel.groups[ConsortiumsGroup].groups[consortium_name].groups[consortium_org.name].values[BootstrapHelper.KEY_MSP_INFO].mod_policy=BootstrapHelper.KEY_POLICY_ADMINS
  1195      typeImplicitMeta = common_dot_policies_pb2.Policy.PolicyType.Value("IMPLICIT_META")
  1196      Policy = common_dot_policies_pb2.Policy
  1197      IMP = common_dot_policies_pb2.ImplicitMetaPolicy
  1198      ruleAny = common_dot_policies_pb2.ImplicitMetaPolicy.Rule.Value("ANY")
  1199      ruleAll = common_dot_policies_pb2.ImplicitMetaPolicy.Rule.Value("ALL")
  1200      ruleMajority = common_dot_policies_pb2.ImplicitMetaPolicy.Rule.Value("MAJORITY")
  1201      channel.groups[ConsortiumsGroup].groups[consortium_name].values[BootstrapHelper.KEY_CHANNEL_CREATION_POLICY].value = toValue(
  1202          Policy(type=typeImplicitMeta, value=IMP(
  1203              rule=ruleAll, sub_policy=BootstrapHelper.KEY_POLICY_WRITERS).SerializeToString()))
  1204      channel.groups[ConsortiumsGroup].groups[consortium_name].values[BootstrapHelper.KEY_CHANNEL_CREATION_POLICY].mod_policy=BootstrapHelper.KEY_POLICY_ADMINS
  1205      # For now, setting same policies for each 'Non-Org' group
  1206      orgs = [directory.getOrganization(orgName) for orgName in org_names]
  1207      setDefaultPoliciesForOrgs(channel.groups[ConsortiumsGroup], orgs, consortium_name, version=0, policy_version=0)
  1208      return channel
  1209  
  1210  def setOrdererBootstrapGenesisBlock(genesisBlock):
  1211      'Responsible for setting the GensisBlock for the Orderer nodes upon composition'
  1212  
  1213  
  1214  def broadcastCreateChannelConfigTx(context, certAlias, composeService, configTxEnvelope, user):
  1215      dataFunc = lambda x: configTxEnvelope
  1216      user.broadcastMessages(context=context, numMsgsToBroadcast=1, composeService=composeService,
  1217                             dataFunc=dataFunc)
  1218  
  1219  def get_latest_configuration_block(deliverer_stream_helper, channel_id):
  1220      latest_config_block = None
  1221      deliverer_stream_helper.seekToRange(chainID=channel_id, start="Newest", end="Newest")
  1222      blocks = deliverer_stream_helper.getBlocks()
  1223      assert len(blocks) == 1, "Expected single block, received: {0} blocks".format(len(blocks))
  1224      newest_block = blocks[0]
  1225      last_config = common_dot_common_pb2.LastConfig()
  1226      metadata = common_dot_common_pb2.Metadata()
  1227      metadata.ParseFromString(newest_block.metadata.metadata[common_dot_common_pb2.BlockMetadataIndex.Value('LAST_CONFIG')])
  1228      last_config.ParseFromString(metadata.value)
  1229      if last_config.index == newest_block.header.number:
  1230          latest_config_block = newest_block
  1231      else:
  1232          deliverer_stream_helper.seekToRange(chainID=channel_id, start=last_config.index, end=last_config.index)
  1233          blocks = deliverer_stream_helper.getBlocks()
  1234          assert len(blocks) == 1, "Expected single block, received: {0} blocks".format(len(blocks))
  1235          assert len(blocks[0].data.data) == 1, "Expected single transaction for configuration block, instead found {0} transactions".format(len(blocks.data.data))
  1236          latest_config_block = blocks[0]
  1237      return latest_config_block
  1238  
  1239  def get_channel_group_from_config_block(block):
  1240      assert len(block.data.data) == 1, "Expected single transaction for configuration block, instead found {0} transactions".format(len(block.data.data))
  1241      e = common_dot_common_pb2.Envelope()
  1242      e.ParseFromString(block.data.data[0])
  1243      p = common_dot_common_pb2.Payload()
  1244      p.ParseFromString(e.payload)
  1245      config_envelope = common_dot_configtx_pb2.ConfigEnvelope()
  1246      config_envelope.ParseFromString(p.data)
  1247      return config_envelope.config.channel_group
  1248  
  1249  def getArgsFromContextForUser(context, userName):
  1250      directory = getDirectory(context)
  1251      # Update the chaincodeSpec ctorMsg for invoke
  1252      args = []
  1253      if 'table' in context:
  1254          if context.table:
  1255              # There are function arguments
  1256              user = directory.getUser(userName)
  1257              # Allow the user to specify expressions referencing tags in the args list
  1258              pattern = re.compile('\{(.*)\}$')
  1259              for arg in context.table[0].cells:
  1260                  m = pattern.match(arg)
  1261                  if m:
  1262                      # tagName reference found in args list
  1263                      tagName = m.groups()[0]
  1264                      # make sure the tagName is found in the users tags
  1265                      assert tagName in user.tags, "TagName '{0}' not found for user '{1}'".format(tagName,
  1266                                                                                                   user.getUserName())
  1267                      args.append(user.tags[tagName])
  1268                  else:
  1269                      # No tag referenced, pass the arg
  1270                      args.append(arg)
  1271      return args
  1272  
  1273  
  1274  def get_args_for_user(args_input, user):
  1275      args = []
  1276      pattern = re.compile('\{(.*)\}$')
  1277      for arg in args_input:
  1278          m = pattern.match(arg)
  1279          if m:
  1280              # tagName reference found in args list
  1281              tagName = m.groups()[0]
  1282              # make sure the tagName is found in the users tags
  1283              assert tagName in user.tags, "TagName '{0}' not found for user '{1}'".format(tagName,
  1284                                                                                           user.getUserName())
  1285              args.append(user.tags[tagName])
  1286          else:
  1287              # No tag referenced, pass the arg
  1288              args.append(arg)
  1289      return tuple(args)
  1290  
  1291  
  1292  def getChannelIdFromConfigUpdateEnvelope(config_update_envelope):
  1293      config_update = common_dot_configtx_pb2.ConfigUpdate()
  1294      config_update.ParseFromString(config_update_envelope.config_update)
  1295      return config_update