github.com/tenywen/fabric@v1.0.0-beta.0.20170620030522-a5b1ed380643/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      adminCerts = [org.getCertAsPEM()]
   828      # Find the mspAdmin Tuple for org and add to admincerts folder
   829      for pnt, cert in [(nat, cert) for nat, cert in directory.ordererAdminTuples.items() if
   830                        org.name == nat.organization and "configadmin" in nat.nodeName.lower()]:
   831          adminCerts.append(crypto.dump_certificate(crypto.FILETYPE_PEM, cert))
   832      cacerts = [org.getCertAsPEM()]
   833      # Currently only 1 component, CN=<orgName>
   834      # name = self.getSelfSignedCert().get_subject().getComponents()[0][1]
   835      fabricMSPConfig = msp_config_pb2.FabricMSPConfig(admins=adminCerts, root_certs=cacerts, name=org.name)
   836      mspConfig = msp_config_pb2.MSPConfig(config=fabricMSPConfig.SerializeToString(), type=0)
   837      return mspConfig
   838  
   839  
   840  class CallbackHelper:
   841      def __init__(self, discriminator, volumeRootPathInContainer = "/var/hyperledger/bddtests"):
   842          self.volumeRootPathInContainer = volumeRootPathInContainer
   843          self.discriminator = discriminator
   844  
   845      def getVolumePath(self, project_name, pathType=PathType.Local):
   846          assert pathType in PathType, "Expected pathType of {0}".format(PathType)
   847          basePath = "."
   848          if pathType == PathType.Container:
   849              basePath = self.volumeRootPathInContainer
   850          return "{0}/volumes/{1}/{2}".format(basePath, self.discriminator, project_name)
   851  
   852      def getLocalMspConfigPath(self, project_name, compose_service, pathType=PathType.Local):
   853          return "{0}/{1}/localMspConfig".format(self.getVolumePath(project_name=project_name, pathType=pathType), compose_service)
   854  
   855      def getLocalTLSConfigPath(self, project_name, compose_service, pathType=PathType.Local):
   856          return os.path.join(self.getVolumePath(project_name=project_name, pathType=pathType), compose_service, "tls_config")
   857  
   858      def _getPathAndUserInfo(self, directory , project_name, compose_service, nat_discriminator="Signer", pathType=PathType.Local):
   859          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)))]
   860          assert len(matchingNATs)==1, "Unexpected number of matching NodeAdminTuples: {0}".format(matchingNATs)
   861          localMspConfigPath = self.getLocalMspConfigPath(project_name=project_name, compose_service=compose_service,pathType=pathType)
   862          return (localMspConfigPath, matchingNATs[0])
   863  
   864      def getLocalMspConfigPrivateKeyPath(self, directory , project_name, compose_service, pathType=PathType.Local):
   865          (localMspConfigPath, nodeAdminTuple) = self._getPathAndUserInfo(directory=directory, project_name=project_name, compose_service=compose_service, pathType=pathType)
   866          return "{0}/keystore/{1}.pem".format(localMspConfigPath, nodeAdminTuple.user)
   867  
   868      def getLocalMspConfigPublicCertPath(self, directory , project_name, compose_service, pathType=PathType.Local):
   869          (localMspConfigPath, nodeAdminTuple) = self._getPathAndUserInfo(directory=directory, project_name=project_name, compose_service=compose_service, pathType=pathType)
   870          return "{0}/signcerts/{1}.pem".format(localMspConfigPath, nodeAdminTuple.user)
   871  
   872      def getTLSKeyPaths(self, pnt , project_name, compose_service, pathType=PathType.Local):
   873          localTLSConfigPath = self.getLocalTLSConfigPath(project_name=project_name, compose_service=compose_service, pathType=pathType)
   874          certPath = os.path.join(localTLSConfigPath,
   875                                  "{0}-{1}-{2}-tls.crt".format(pnt.user, pnt.nodeName, pnt.organization))
   876          keyPath = os.path.join(localTLSConfigPath,
   877                                 "{0}-{1}-{2}-tls.key".format(pnt.user, pnt.nodeName, pnt.organization))
   878          return (keyPath, certPath)
   879  
   880  
   881      def getLocalMspConfigRootCertPath(self, directory , project_name, compose_service, pathType=PathType.Local):
   882          (localMspConfigPath, nodeAdminTuple) = self._getPathAndUserInfo(directory=directory, project_name=project_name, compose_service=compose_service, pathType=pathType)
   883          return "{0}/cacerts/{1}.pem".format(localMspConfigPath, nodeAdminTuple.organization)
   884  
   885      def _createCryptoMaterial(self,directory , project_name, compose_service, network):
   886          self._writeMspFiles(directory , project_name=project_name, compose_service=compose_service, network=network)
   887          self._writeTLSFiles(directory , project_name=project_name, compose_service=compose_service, network=network)
   888  
   889      def _writeMspFiles(self, directory , project_name, compose_service, network):
   890          localMspConfigPath = self.getLocalMspConfigPath(project_name, compose_service)
   891          os.makedirs("{0}/{1}".format(localMspConfigPath, "signcerts"))
   892          os.makedirs("{0}/{1}".format(localMspConfigPath, "admincerts"))
   893          os.makedirs("{0}/{1}".format(localMspConfigPath, "cacerts"))
   894          os.makedirs("{0}/{1}".format(localMspConfigPath, "keystore"))
   895  
   896          # Find the peer signer Tuple for this peer and add to signcerts folder
   897          for pnt, cert in [(peerNodeTuple, cert) for peerNodeTuple, cert in directory.ordererAdminTuples.items() if
   898                            compose_service in peerNodeTuple.user and "signer" in peerNodeTuple.user.lower()]:
   899              # Put the PEM file in the signcerts folder
   900              with open("{0}/signcerts/{1}.pem".format(localMspConfigPath, pnt.user), "w") as f:
   901                  f.write(crypto.dump_certificate(crypto.FILETYPE_PEM, cert))
   902              # Put the associated private key into the keystore folder
   903              user = directory.getUser(pnt.user, shouldCreate=False)
   904              with open("{0}/keystore/{1}.pem".format(localMspConfigPath, pnt.user), "w") as f:
   905                  f.write(user.ecdsaSigningKey.to_pem())
   906  
   907              #Now put the signing Orgs cert in the cacerts folder
   908              org_cert_as_pem =  directory.getOrganization(pnt.organization).getCertAsPEM()
   909              with open("{0}/cacerts/{1}.pem".format(localMspConfigPath, pnt.organization), "w") as f:
   910                  f.write(org_cert_as_pem)
   911  
   912          # Find the peer admin Tuple for this peer and add to admincerts folder
   913          for pnt, cert in [(peerNodeTuple, cert) for peerNodeTuple, cert in directory.ordererAdminTuples.items() if
   914                            compose_service in peerNodeTuple.user and "admin" in peerNodeTuple.user.lower()]:
   915              # Put the PEM file in the signcerts folder
   916              with open("{0}/admincerts/{1}.pem".format(localMspConfigPath, pnt.user), "w") as f:
   917                  f.write(crypto.dump_certificate(crypto.FILETYPE_PEM, cert))
   918  
   919      def _writeTLSFiles(self, directory , project_name, compose_service, network):
   920          localTLSConfigPath = self.getLocalTLSConfigPath(project_name, compose_service)
   921          os.makedirs(localTLSConfigPath)
   922          # Find the peer signer Tuple for this peer and add to signcerts folder
   923          for pnt, cert in [(peerNodeTuple, cert) for peerNodeTuple, cert in directory.ordererAdminTuples.items() if
   924                            compose_service in peerNodeTuple.user and "signer" in peerNodeTuple.user.lower()]:
   925              user = directory.getUser(userName=pnt.user)
   926              # Add the subjectAlternativeName if the current entity is a signer, and the nodeName contains peer or orderer
   927              extensions = directory._get_cert_extensions_ip_sans(user.name, pnt.nodeName)
   928              userTLSCert = directory.getOrganization(pnt.organization).createCertificate(user.createTLSCertRequest(pnt.nodeName), extensions=extensions)
   929              (keyPath, certPath) = self.getTLSKeyPaths(pnt=pnt, project_name=project_name, compose_service=compose_service, pathType=PathType.Local)
   930              with open(keyPath, 'w') as f:
   931                  f.write(crypto.dump_privatekey(crypto.FILETYPE_PEM, user.rsaSigningKey))
   932              with open(certPath, 'w') as f:
   933                  f.write(crypto.dump_certificate(crypto.FILETYPE_PEM, userTLSCert))
   934  
   935      def _getMspId(self, compose_service, directory):
   936          matchingNATs = [nat for nat in directory.getNamedCtxTuples() if ((compose_service in nat.user) and ("Signer" in nat.user) and ((compose_service in nat.nodeName)))]
   937          assert len(matchingNATs)==1, "Unexpected number of matching NodeAdminTuples: {0}".format(matchingNATs)
   938          return matchingNATs[0].organization
   939  
   940  
   941  class OrdererGensisBlockCompositionCallback(compose.CompositionCallback, CallbackHelper):
   942      'Responsible for setting the GensisBlock for the Orderer nodes upon composition'
   943  
   944      def __init__(self, context, genesisBlock, genesisFileName="genesis_file"):
   945          CallbackHelper.__init__(self, discriminator="orderer")
   946          self.context = context
   947          self.genesisFileName = genesisFileName
   948          self.genesisBlock = genesisBlock
   949          compose.Composition.RegisterCallbackInContext(context, self)
   950  
   951      def getGenesisFilePath(self, project_name, pathType=PathType.Local):
   952          return "{0}/{1}".format(self.getVolumePath(project_name=project_name, pathType=pathType), self.genesisFileName)
   953  
   954      def getOrdererList(self, composition):
   955          return [serviceName for serviceName in composition.getServiceNames() if "orderer" in serviceName]
   956  
   957      def composing(self, composition, context):
   958          print("Will copy gensisiBlock over at this point ")
   959          os.makedirs(self.getVolumePath(composition.projectName))
   960          with open(self.getGenesisFilePath(composition.projectName), "wb") as f:
   961              f.write(self.genesisBlock.SerializeToString())
   962          directory = getDirectory(context)
   963  
   964          for ordererService in self.getOrdererList(composition):
   965              self._createCryptoMaterial(directory=directory,
   966                                         compose_service=ordererService,
   967                                         project_name=composition.projectName,
   968                                         network=Network.Orderer)
   969  
   970      def decomposing(self, composition, context):
   971          'Will remove the orderer volume path folder for the context'
   972          shutil.rmtree(self.getVolumePath(composition.projectName))
   973  
   974      def getEnv(self, composition, context, env):
   975          directory = getDirectory(context)
   976          env["ORDERER_GENERAL_GENESISMETHOD"] = "file"
   977          env["ORDERER_GENERAL_GENESISFILE"] = self.getGenesisFilePath(composition.projectName, pathType=PathType.Container)
   978          for ordererService in self.getOrdererList(composition):
   979              localMspConfigPath = self.getLocalMspConfigPath(composition.projectName, ordererService, pathType=PathType.Container)
   980              env["{0}_ORDERER_GENERAL_LOCALMSPDIR".format(ordererService.upper())] = localMspConfigPath
   981              env["{0}_ORDERER_GENERAL_LOCALMSPID".format(ordererService.upper())] = self._getMspId(compose_service=ordererService, directory=directory)
   982              # TLS Settings
   983              (_, pnt) = self._getPathAndUserInfo(directory=directory, project_name=composition.projectName, compose_service=ordererService, pathType=PathType.Container)
   984              (keyPath, certPath) = self.getTLSKeyPaths(pnt=pnt, project_name=composition.projectName, compose_service=ordererService, pathType=PathType.Container)
   985              env["{0}_ORDERER_GENERAL_TLS_CERTIFICATE".format(ordererService.upper())] = certPath
   986              env["{0}_ORDERER_GENERAL_TLS_PRIVATEKEY".format(ordererService.upper())] = keyPath
   987              env["{0}_ORDERER_GENERAL_TLS_ROOTCAS".format(ordererService.upper())] = "[{0}]".format(self.getLocalMspConfigRootCertPath(
   988                  directory=directory, project_name=composition.projectName, compose_service=ordererService, pathType=PathType.Container))
   989  
   990  class PeerCompositionCallback(compose.CompositionCallback, CallbackHelper):
   991      'Responsible for setting up Peer nodes upon composition'
   992  
   993      def __init__(self, context):
   994          CallbackHelper.__init__(self, discriminator="peer")
   995          self.context = context
   996          compose.Composition.RegisterCallbackInContext(context, self)
   997  
   998      def getPeerList(self, composition):
   999          return [serviceName for serviceName in composition.getServiceNames() if "peer" in serviceName]
  1000  
  1001      def composing(self, composition, context):
  1002          'Will copy local MSP info over at this point for each peer node'
  1003  
  1004          directory = getDirectory(context)
  1005  
  1006          for peerService in self.getPeerList(composition):
  1007              self._createCryptoMaterial(directory=directory,
  1008                                         compose_service=peerService,
  1009                                         project_name=composition.projectName,
  1010                                         network=Network.Peer)
  1011  
  1012      def decomposing(self, composition, context):
  1013          'Will remove the orderer volume path folder for the context'
  1014          shutil.rmtree(self.getVolumePath(composition.projectName))
  1015  
  1016      def getEnv(self, composition, context, env):
  1017          directory = getDirectory(context)
  1018          # First figure out which organization provided the signer cert for this
  1019          for peerService in self.getPeerList(composition):
  1020              localMspConfigPath = self.getLocalMspConfigPath(composition.projectName, peerService, pathType=PathType.Container)
  1021              env["{0}_CORE_PEER_MSPCONFIGPATH".format(peerService.upper())] = localMspConfigPath
  1022              env["{0}_CORE_PEER_LOCALMSPID".format(peerService.upper())] = self._getMspId(compose_service=peerService, directory=directory)
  1023              # TLS Settings
  1024              # env["{0}_CORE_PEER_TLS_ENABLED".format(peerService.upper())] = self._getMspId(compose_service=peerService, directory=directory)
  1025              (_, pnt) = self._getPathAndUserInfo(directory=directory, project_name=composition.projectName, compose_service=peerService, pathType=PathType.Container)
  1026              (keyPath, certPath) = self.getTLSKeyPaths(pnt=pnt, project_name=composition.projectName, compose_service=peerService, pathType=PathType.Container)
  1027              env["{0}_CORE_PEER_TLS_CERT_FILE".format(peerService.upper())] = certPath
  1028              env["{0}_CORE_PEER_TLS_KEY_FILE".format(peerService.upper())] = keyPath
  1029              env["{0}_CORE_PEER_TLS_ROOTCERT_FILE".format(peerService.upper())] = self.getLocalMspConfigRootCertPath(
  1030                  directory=directory, project_name=composition.projectName, compose_service=peerService, pathType=PathType.Container)
  1031              env["{0}_CORE_PEER_TLS_SERVERHOSTOVERRIDE".format(peerService.upper())] = peerService
  1032  
  1033  
  1034  def getDefaultConsortiumGroup(consortiums_mod_policy):
  1035      default_config_group = common_dot_configtx_pb2.ConfigGroup()
  1036      default_config_group.groups[ConsortiumsGroup].mod_policy=consortiums_mod_policy
  1037      return default_config_group
  1038  
  1039  
  1040  def create_config_update_envelope(config_update):
  1041      return  common_dot_configtx_pb2.ConfigUpdateEnvelope(config_update=config_update.SerializeToString(), signatures =[])
  1042  
  1043  def create_orderer_consortium_config_update(orderer_system_chain_id, orderer_channel_group, config_groups):
  1044      'Creates the orderer config update'
  1045      # First determine read set
  1046      read_set = common_dot_configtx_pb2.ConfigGroup()
  1047      read_set.groups[ConsortiumsGroup].CopyFrom(orderer_channel_group.groups[ConsortiumsGroup])
  1048  
  1049      write_set = common_dot_configtx_pb2.ConfigGroup()
  1050      write_set.groups[ConsortiumsGroup].CopyFrom(orderer_channel_group.groups[ConsortiumsGroup])
  1051      write_set.groups[ConsortiumsGroup].version += 1
  1052      for config_group in config_groups:
  1053          mergeConfigGroups(write_set, config_group)
  1054      config_update = common_dot_configtx_pb2.ConfigUpdate(channel_id=orderer_system_chain_id,
  1055                                                          read_set=read_set,
  1056                                                          write_set=write_set)
  1057      # configUpdateEnvelope = common_dot_configtx_pb2.ConfigUpdateEnvelope(config_update=configUpdate.SerializeToString(), signatures =[])
  1058      return config_update
  1059  
  1060  def create_channel_config_update(system_channel_version, channel_id, consortium_config_group):
  1061      read_set = common_dot_configtx_pb2.ConfigGroup()
  1062      read_set.version = system_channel_version
  1063      read_set.values[BootstrapHelper.KEY_CONSORTIUM].value=toValue(common_dot_configuration_pb2.Consortium(name=consortium_config_group.groups[ConsortiumsGroup].groups.keys()[0]))
  1064  
  1065      # Copying all of the consortium orgs into the ApplicationGroup
  1066      read_set.groups[ApplicationGroup].CopyFrom(consortium_config_group.groups[ConsortiumsGroup].groups.values()[0])
  1067      read_set.groups[ApplicationGroup].values.clear()
  1068      read_set.groups[ApplicationGroup].policies.clear()
  1069      read_set.groups[ApplicationGroup].mod_policy=""
  1070      for k, v in read_set.groups[ApplicationGroup].groups.iteritems():
  1071          v.values.clear()
  1072          v.policies.clear()
  1073          v.mod_policy=""
  1074  
  1075      # Now the write_set
  1076      write_set = common_dot_configtx_pb2.ConfigGroup()
  1077      write_set.CopyFrom(read_set)
  1078      write_set.groups[ApplicationGroup].version += 1
  1079      # For now, setting same policies for each 'Non-Org' group
  1080      typeImplicitMeta = common_dot_policies_pb2.Policy.PolicyType.Value("IMPLICIT_META")
  1081      Policy = common_dot_policies_pb2.Policy
  1082      IMP = common_dot_policies_pb2.ImplicitMetaPolicy
  1083      ruleAny = common_dot_policies_pb2.ImplicitMetaPolicy.Rule.Value("ANY")
  1084      ruleMajority = common_dot_policies_pb2.ImplicitMetaPolicy.Rule.Value("MAJORITY")
  1085      write_set.groups[ApplicationGroup].policies[BootstrapHelper.KEY_POLICY_READERS].policy.CopyFrom(
  1086          Policy(type=typeImplicitMeta, value=IMP(
  1087              rule=ruleAny, sub_policy=BootstrapHelper.KEY_POLICY_READERS).SerializeToString()))
  1088      write_set.groups[ApplicationGroup].policies[BootstrapHelper.KEY_POLICY_WRITERS].policy.CopyFrom(
  1089          Policy(type=typeImplicitMeta, value=IMP(
  1090              rule=ruleAny, sub_policy=BootstrapHelper.KEY_POLICY_WRITERS).SerializeToString()))
  1091      write_set.groups[ApplicationGroup].policies[BootstrapHelper.KEY_POLICY_ADMINS].policy.CopyFrom(
  1092          Policy(type=typeImplicitMeta, value=IMP(
  1093              rule=ruleMajority, sub_policy=BootstrapHelper.KEY_POLICY_ADMINS).SerializeToString()))
  1094      write_set.groups[ApplicationGroup].mod_policy = "Admins"
  1095      for k, v in write_set.groups[ApplicationGroup].groups.iteritems():
  1096          v.mod_policy=BootstrapHelper.KEY_POLICY_ADMINS
  1097      config_update = common_dot_configtx_pb2.ConfigUpdate(channel_id=channel_id,
  1098                                                           read_set=read_set,
  1099                                                           write_set=write_set)
  1100      return config_update
  1101  
  1102  def get_group_paths_from_config_group(config_group, paths, current_path = ""):
  1103      if len(config_group.groups)==0:
  1104          paths.append(current_path)
  1105      else:
  1106          for group_name, group in config_group.groups.iteritems():
  1107              get_group_paths_from_config_group(config_group=group, current_path="{0}/{1}".format(current_path, group_name), paths=paths)
  1108      return paths
  1109  
  1110  
  1111  def get_group_from_config_path(config_group, config_path):
  1112      from os import path
  1113      current_config_group = config_group
  1114      for group_id in [g.strip("/") for g in path.split(config_path)]:
  1115          current_config_group = current_config_group.groups[group_id]
  1116      return current_config_group
  1117  
  1118  def create_existing_channel_config_update(system_channel_version, channel_id, input_config_update, config_groups):
  1119      # First make a copy of the input config update msg to manipulate
  1120      read_set = common_dot_configtx_pb2.ConfigGroup()
  1121      read_set.version = system_channel_version
  1122      read_set.CopyFrom(input_config_update)
  1123  
  1124      # Now the write_set
  1125      write_set = common_dot_configtx_pb2.ConfigGroup()
  1126      write_set.CopyFrom(read_set)
  1127  
  1128      # Merge all of the supplied config_groups
  1129      for config_group in config_groups:
  1130          mergeConfigGroups(write_set, config_group)
  1131  
  1132      # Will build a unique list of group paths from the supplied config_groups
  1133      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]))
  1134  
  1135      # Now increment the version for each path.
  1136      # TODO: This logic will only work for the case of insertions
  1137      for group in [get_group_from_config_path(write_set, g) for g in group_paths]:
  1138          group.version += 1
  1139  
  1140      # For now, setting same policies for each 'Non-Org' group
  1141      config_update = common_dot_configtx_pb2.ConfigUpdate(channel_id=channel_id,
  1142                                                           read_set=read_set,
  1143                                                           write_set=write_set)
  1144      return config_update
  1145  
  1146  def update_config_group_version_info(input_config_update, proposed_config_group):
  1147      for k,v in proposed_config_group.groups.iteritems():
  1148          if k in input_config_update.groups.keys():
  1149              # Make sure all keys of the current group match those of the proposed, if not either added or deleted.
  1150              if not set(proposed_config_group.groups[k].groups.keys()) == set(input_config_update.groups[k].groups.keys()):
  1151                  proposed_config_group.groups[k].version +=1
  1152              # Now recurse
  1153              update_config_group_version_info(input_config_update.groups[k], proposed_config_group.groups[k])
  1154  
  1155  # def create_existing_channel_config_update2(system_channel_version, channel_id, input_config_update, config_group):
  1156  #     # First make a copy of the input config update msg to manipulate
  1157  #     read_set = common_dot_configtx_pb2.ConfigGroup()
  1158  #     read_set.version = system_channel_version
  1159  #     read_set.CopyFrom(config_group)
  1160  #
  1161  #     # Now the write_set
  1162  #     write_set = common_dot_configtx_pb2.ConfigGroup()
  1163  #     write_set.CopyFrom(read_set)
  1164  #     mergeConfigGroups(write_set, config_groups[0])
  1165  #     write_set.groups['Application'].groups['peerOrg0'].version +=1
  1166  #
  1167  #     # write_set.groups[ApplicationGroup].version += 1
  1168  #     # For now, setting same policies for each 'Non-Org' group
  1169  #     config_update = common_dot_configtx_pb2.ConfigUpdate(channel_id=channel_id,
  1170  #                                                          read_set=read_set,
  1171  #                                                          write_set=write_set)
  1172  #     return config_update
  1173  
  1174  
  1175  def createConsortium(context, consortium_name, org_names, mod_policy):
  1176      channel = common_dot_configtx_pb2.ConfigGroup()
  1177      directory = getDirectory(context=context)
  1178      channel.groups[ConsortiumsGroup].groups[consortium_name].mod_policy = mod_policy
  1179      # Add the orderer org groups MSPConfig info to consortiums group
  1180      for consortium_org in [org for org in directory.getOrganizations().values() if org.name in org_names]:
  1181          # channel.groups[ConsortiumsGroup].groups[consortium_name].groups[consortium_org.name].mod_policy = BootstrapHelper.KEY_POLICY_ADMINS
  1182          channel.groups[ConsortiumsGroup].groups[consortium_name].groups[consortium_org.name].values[BootstrapHelper.KEY_MSP_INFO].value = toValue(
  1183              getMSPConfig(org=consortium_org, directory=directory))
  1184          channel.groups[ConsortiumsGroup].groups[consortium_name].groups[consortium_org.name].values[BootstrapHelper.KEY_MSP_INFO].mod_policy=BootstrapHelper.KEY_POLICY_ADMINS
  1185      typeImplicitMeta = common_dot_policies_pb2.Policy.PolicyType.Value("IMPLICIT_META")
  1186      Policy = common_dot_policies_pb2.Policy
  1187      IMP = common_dot_policies_pb2.ImplicitMetaPolicy
  1188      ruleAny = common_dot_policies_pb2.ImplicitMetaPolicy.Rule.Value("ANY")
  1189      ruleAll = common_dot_policies_pb2.ImplicitMetaPolicy.Rule.Value("ALL")
  1190      ruleMajority = common_dot_policies_pb2.ImplicitMetaPolicy.Rule.Value("MAJORITY")
  1191      channel.groups[ConsortiumsGroup].groups[consortium_name].values[BootstrapHelper.KEY_CHANNEL_CREATION_POLICY].value = toValue(
  1192          Policy(type=typeImplicitMeta, value=IMP(
  1193              rule=ruleAll, sub_policy=BootstrapHelper.KEY_POLICY_WRITERS).SerializeToString()))
  1194      channel.groups[ConsortiumsGroup].groups[consortium_name].values[BootstrapHelper.KEY_CHANNEL_CREATION_POLICY].mod_policy=BootstrapHelper.KEY_POLICY_ADMINS
  1195      # For now, setting same policies for each 'Non-Org' group
  1196      orgs = [directory.getOrganization(orgName) for orgName in org_names]
  1197      setDefaultPoliciesForOrgs(channel.groups[ConsortiumsGroup], orgs, consortium_name, version=0, policy_version=0)
  1198      return channel
  1199  
  1200  def setOrdererBootstrapGenesisBlock(genesisBlock):
  1201      'Responsible for setting the GensisBlock for the Orderer nodes upon composition'
  1202  
  1203  
  1204  def broadcastCreateChannelConfigTx(context, certAlias, composeService, configTxEnvelope, user):
  1205      dataFunc = lambda x: configTxEnvelope
  1206      user.broadcastMessages(context=context, numMsgsToBroadcast=1, composeService=composeService,
  1207                             dataFunc=dataFunc)
  1208  
  1209  def get_latest_configuration_block(deliverer_stream_helper, channel_id):
  1210      latest_config_block = None
  1211      deliverer_stream_helper.seekToRange(chainID=channel_id, start="Newest", end="Newest")
  1212      blocks = deliverer_stream_helper.getBlocks()
  1213      assert len(blocks) == 1, "Expected single block, received: {0} blocks".format(len(blocks))
  1214      newest_block = blocks[0]
  1215      last_config = common_dot_common_pb2.LastConfig()
  1216      metadata = common_dot_common_pb2.Metadata()
  1217      metadata.ParseFromString(newest_block.metadata.metadata[common_dot_common_pb2.BlockMetadataIndex.Value('LAST_CONFIG')])
  1218      last_config.ParseFromString(metadata.value)
  1219      if last_config.index == newest_block.header.number:
  1220          latest_config_block = newest_block
  1221      else:
  1222          deliverer_stream_helper.seekToRange(chainID=channel_id, start=last_config.index, end=last_config.index)
  1223          blocks = deliverer_stream_helper.getBlocks()
  1224          assert len(blocks) == 1, "Expected single block, received: {0} blocks".format(len(blocks))
  1225          assert len(blocks[0].data.data) == 1, "Expected single transaction for configuration block, instead found {0} transactions".format(len(block.data.data))
  1226          latest_config_block = blocks[0]
  1227      return latest_config_block
  1228  
  1229  def get_channel_group_from_config_block(block):
  1230      assert len(block.data.data) == 1, "Expected single transaction for configuration block, instead found {0} transactions".format(len(block.data.data))
  1231      e = common_dot_common_pb2.Envelope()
  1232      e.ParseFromString(block.data.data[0])
  1233      p = common_dot_common_pb2.Payload()
  1234      p.ParseFromString(e.payload)
  1235      config_envelope = common_dot_configtx_pb2.ConfigEnvelope()
  1236      config_envelope.ParseFromString(p.data)
  1237      return config_envelope.config.channel_group
  1238  
  1239  def getArgsFromContextForUser(context, userName):
  1240      directory = getDirectory(context)
  1241      # Update the chaincodeSpec ctorMsg for invoke
  1242      args = []
  1243      if 'table' in context:
  1244          if context.table:
  1245              # There are function arguments
  1246              user = directory.getUser(userName)
  1247              # Allow the user to specify expressions referencing tags in the args list
  1248              pattern = re.compile('\{(.*)\}$')
  1249              for arg in context.table[0].cells:
  1250                  m = pattern.match(arg)
  1251                  if m:
  1252                      # tagName reference found in args list
  1253                      tagName = m.groups()[0]
  1254                      # make sure the tagName is found in the users tags
  1255                      assert tagName in user.tags, "TagName '{0}' not found for user '{1}'".format(tagName,
  1256                                                                                                   user.getUserName())
  1257                      args.append(user.tags[tagName])
  1258                  else:
  1259                      # No tag referenced, pass the arg
  1260                      args.append(arg)
  1261      return args
  1262  
  1263  
  1264  def get_args_for_user(args_input, user):
  1265      args = []
  1266      pattern = re.compile('\{(.*)\}$')
  1267      for arg in args_input:
  1268          m = pattern.match(arg)
  1269          if m:
  1270              # tagName reference found in args list
  1271              tagName = m.groups()[0]
  1272              # make sure the tagName is found in the users tags
  1273              assert tagName in user.tags, "TagName '{0}' not found for user '{1}'".format(tagName,
  1274                                                                                           user.getUserName())
  1275              args.append(user.tags[tagName])
  1276          else:
  1277              # No tag referenced, pass the arg
  1278              args.append(arg)
  1279      return tuple(args)
  1280  
  1281  
  1282  def getChannelIdFromConfigUpdateEnvelope(config_update_envelope):
  1283      config_update = common_dot_configtx_pb2.ConfigUpdate()
  1284      config_update.ParseFromString(config_update_envelope.config_update)
  1285      return config_update