github.com/adnan-c/fabric_e2e_couchdb@v0.6.1-preview.0.20170228180935-21ce6b23cf91/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  
    20  if sys.version_info < (3, 6):
    21      import sha3
    22  
    23  from OpenSSL import crypto
    24  from OpenSSL import rand
    25  import ecdsa
    26  
    27  from collections import namedtuple
    28  from itertools import groupby
    29  from enum import Enum
    30  
    31  from google.protobuf import timestamp_pb2
    32  from common import common_pb2 as common_dot_common_pb2
    33  from common import configtx_pb2 as common_dot_configtx_pb2
    34  from common import configuration_pb2 as common_dot_configuration_pb2
    35  from common import policies_pb2 as common_dot_policies_pb2
    36  from common import msp_principal_pb2
    37  from msp import mspconfig_pb2
    38  from peer import configuration_pb2 as peer_dot_configuration_pb2
    39  from orderer import configuration_pb2 as orderer_dot_configuration_pb2
    40  import orderer_util
    41  
    42  from contexthelper import ContextHelper
    43  
    44  import os
    45  import re
    46  import shutil
    47  import compose
    48  
    49  # Type to represent tuple of user, nodeName, ogranization
    50  NodeAdminTuple = namedtuple("NodeAdminTuple", ['user', 'nodeName', 'organization'])
    51  
    52  
    53  ApplicationGroup = "Application"
    54  OrdererGroup     = "Orderer"
    55  MSPKey           = "MSP"
    56  toValue = lambda message: message.SerializeToString()
    57  
    58  
    59  class Network(Enum):
    60      Orderer = 1
    61      Peer = 2
    62  
    63  
    64  def GetUUID():
    65      return compose.Composition.GetUUID()
    66  
    67  
    68  def createRSAKey():
    69      # Create RSA key, 2048 bit
    70      pk = crypto.PKey()
    71      pk.generate_key(crypto.TYPE_RSA, 2048)
    72      assert pk.check() == True
    73      return pk
    74  
    75  
    76  def createECDSAKey(curve=ecdsa.NIST256p):
    77      # Create ECDSA key
    78      sk = ecdsa.SigningKey.generate(curve=curve)
    79      return sk
    80  
    81  
    82  def computeCryptoHash(data):
    83      ' This will currently return 128 hex characters'
    84      # s = hashlib.sha3_256()
    85      s = hashlib.sha256()
    86      # s = hashlib.shake_256()
    87      #return s.digest(64)
    88      s.update(data)
    89      return s.digest()
    90  
    91  
    92  def createCertRequest(pkey, digest="sha256", **name):
    93      """
    94      Create a certificate request.
    95      Arguments: pkey   - The key to associate with the request
    96                 digest - Digestion method to use for signing, default is sha256
    97                 **name - The name of the subject of the request, possible
    98                          arguments are:
    99                            C     - Country name
   100                            ST    - State or province name
   101                            L     - Locality name
   102                            O     - Organization name
   103                            OU    - Organizational unit name
   104                            CN    - Common name
   105                            emailAddress - E-mail address
   106      Returns:   The certificate request in an X509Req object
   107      """
   108      req = crypto.X509Req()
   109      subj = req.get_subject()
   110  
   111      for key, value in name.items():
   112          setattr(subj, key, value)
   113  
   114      req.set_pubkey(pkey)
   115      req.sign(pkey, digest)
   116      return req
   117  
   118  
   119  def createCertificate(req, issuerCertKey, serial, validityPeriod, digest="sha256", isCA=False):
   120      """
   121      Generate a certificate given a certificate request.
   122      Arguments: req        - Certificate request to use
   123                 issuerCert - The certificate of the issuer
   124                 issuerKey  - The private key of the issuer
   125                 serial     - Serial number for the certificate
   126                 notBefore  - Timestamp (relative to now) when the certificate
   127                              starts being valid
   128                 notAfter   - Timestamp (relative to now) when the certificate
   129                              stops being valid
   130                 digest     - Digest method to use for signing, default is sha256
   131      Returns:   The signed certificate in an X509 object
   132      """
   133      issuerCert, issuerKey = issuerCertKey
   134      notBefore, notAfter = validityPeriod
   135      cert = crypto.X509()
   136      cert.set_version(3)
   137      cert.set_serial_number(serial)
   138      cert.gmtime_adj_notBefore(notBefore)
   139      cert.gmtime_adj_notAfter(notAfter)
   140      cert.set_issuer(issuerCert.get_subject())
   141      cert.set_subject(req.get_subject())
   142      cert.set_pubkey(req.get_pubkey())
   143      if isCA:
   144          cert.add_extensions([crypto.X509Extension("basicConstraints", True,
   145                                                    "CA:TRUE, pathlen:0"),
   146                               crypto.X509Extension("subjectKeyIdentifier", False, "hash",
   147                                                    subject=cert)])
   148          #TODO: This only is appropriate for root self signed!!!!
   149          cert.add_extensions([crypto.X509Extension("authorityKeyIdentifier", False, "keyid:always", issuer=cert)])
   150      else:
   151          cert.add_extensions([crypto.X509Extension("basicConstraints", True,
   152                                                    "CA:FALSE"),
   153                               crypto.X509Extension("subjectKeyIdentifier", False, "hash",
   154                                                    subject=cert)])
   155          cert.add_extensions([crypto.X509Extension("authorityKeyIdentifier", False, "keyid:always", issuer=issuerCert)])
   156  
   157      cert.sign(issuerKey, digest)
   158      return cert
   159  
   160  
   161  # SUBJECT_DEFAULT = {countryName : "US", stateOrProvinceName : "NC", localityName : "RTP", organizationName : "IBM", organizationalUnitName : "Blockchain"}
   162  
   163  class Entity:
   164      def __init__(self, name):
   165          self.name = name
   166          # Create a ECDSA key, then a crypto pKey from the DER for usage with cert requests, etc.
   167          self.ecdsaSigningKey = createECDSAKey()
   168          self.pKey = crypto.load_privatekey(crypto.FILETYPE_ASN1, self.ecdsaSigningKey.to_der())
   169          # Signing related ecdsa config
   170          self.hashfunc = hashlib.sha256
   171          self.sigencode = ecdsa.util.sigencode_der_canonize
   172          self.sigdecode = ecdsa.util.sigdecode_der
   173  
   174      def createCertRequest(self, nodeName):
   175          req = createCertRequest(self.pKey, CN=nodeName)
   176          # print("request => {0}".format(crypto.dump_certificate_request(crypto.FILETYPE_PEM, req)))
   177          return req
   178  
   179      def computeHash(self, data):
   180          s = self.hashfunc()
   181          s.update(data)
   182          return s.digest()
   183  
   184      def sign(self, dataAsBytearray):
   185          return self.ecdsaSigningKey.sign(dataAsBytearray, hashfunc=self.hashfunc, sigencode=self.sigencode)
   186  
   187      def verifySignature(self, signature, signersCert, data):
   188          'Will verify the signature of an entity based upon public cert'
   189          vk = ecdsa.VerifyingKey.from_der(crypto.dump_publickey(crypto.FILETYPE_ASN1, signersCert.get_pubkey()))
   190          assert vk.verify(signature, data, hashfunc=self.hashfunc, sigdecode=self.sigdecode), "Invalid signature!!"
   191  
   192      def getPrivateKeyAsPEM(self):
   193          return self.ecdsaSigningKey.to_pem()
   194  
   195  
   196  class User(Entity, orderer_util.UserRegistration):
   197      def __init__(self, name):
   198          Entity.__init__(self, name)
   199          orderer_util.UserRegistration.__init__(self, name)
   200          self.tags = {}
   201  
   202      def setTagValue(self, tagKey, tagValue, overwrite=False):
   203          if tagKey in self.tags:
   204              assert not overwrite,"TagKey '{0}' already exists for user {1}, and did not provide overwrite=True".format(tagKey, self.getUserName())
   205          self.tags[tagKey] = tagValue
   206          return tagValue
   207  
   208  
   209  class Organization(Entity):
   210  
   211      def __init__(self, name):
   212          Entity.__init__(self, name)
   213          req = createCertRequest(self.pKey, CN=name)
   214          numYrs = 1
   215          self.signedCert = createCertificate(req, (req, self.pKey), 1000, (0, 60 * 60 * 24 * 365 * numYrs), isCA=True)
   216          # Which networks this organization belongs to
   217          self.networks = []
   218  
   219      def getSelfSignedCert(self):
   220          return self.signedCert
   221  
   222      def getCertAsPEM(self):
   223          return crypto.dump_certificate(crypto.FILETYPE_PEM, self.getSelfSignedCert())
   224  
   225      def getMSPConfig(self):
   226          certPemsList = [crypto.dump_certificate(crypto.FILETYPE_PEM, self.getSelfSignedCert())]
   227          # For now, admin certs and CA certs are the same per @ASO
   228          adminCerts = certPemsList
   229          cacerts = adminCerts
   230          # Currently only 1 component, CN=<orgName>
   231          # name = self.getSelfSignedCert().get_subject().getComponents()[0][1]
   232          name = self.name
   233          fabricMSPConfig = mspconfig_pb2.FabricMSPConfig(admins=adminCerts, root_certs=cacerts, name=name)
   234          mspConfig = mspconfig_pb2.MSPConfig(config=fabricMSPConfig.SerializeToString(), type=0)
   235          return mspConfig
   236  
   237      def createCertificate(self, certReq):
   238          numYrs = 1
   239          return createCertificate(certReq, (self.signedCert, self.pKey), 1000, (0, 60 * 60 * 24 * 365 * numYrs))
   240  
   241      def addToNetwork(self, network):
   242          'Used to track which network this organization is defined in.'
   243          # assert network in Network, 'Network not recognized ({0}), expected to be one of ({1})'.format(network, list(Network))
   244          if not network in self.networks:
   245              self.networks.append(network)
   246  
   247  
   248  class Directory:
   249      def __init__(self):
   250          self.organizations = {}
   251          self.users = {}
   252          self.ordererAdminTuples = {}
   253  
   254      def getNamedCtxTuples(self):
   255          return self.ordererAdminTuples
   256  
   257      def _registerOrg(self, orgName):
   258          assert orgName not in self.organizations, "Organization already registered {0}".format(orgName)
   259          self.organizations[orgName] = Organization(orgName)
   260          return self.organizations[orgName]
   261  
   262      def _registerUser(self, userName):
   263          assert userName not in self.users, "User already registered {0}".format(userName)
   264          self.users[userName] = User(userName)
   265          return self.users[userName]
   266  
   267      def getUser(self, userName, shouldCreate=False):
   268          if not userName in self.users and shouldCreate:
   269              # self.users[userName] = User(userName)
   270              self._registerUser(userName)
   271          return self.users[userName]
   272  
   273      def getUsers(self):
   274          return self.users
   275  
   276      def getOrganization(self, orgName, shouldCreate=False):
   277          if not orgName in self.organizations and shouldCreate:
   278              # self.organizations[orgName] = Organization(orgName)
   279              self._registerOrg(orgName)
   280          return self.organizations[orgName]
   281  
   282      def getOrganizations(self):
   283          return self.organizations
   284  
   285      def findCertByTuple(self, userName, contextName, orgName):
   286          ordererAdminTuple = NodeAdminTuple(user=userName, nodeName=contextName, organization=orgName)
   287          return self.ordererAdminTuples[ordererAdminTuple]
   288  
   289      def findCertForNodeAdminTuple(self, nodeAdminTuple):
   290          assert nodeAdminTuple in self.ordererAdminTuples, "Node admin tuple not found for: {0}".format(nodeAdminTuple)
   291          return self.ordererAdminTuples[nodeAdminTuple]
   292  
   293      def getCertAsPEM(self, nodeAdminTuple):
   294          assert nodeAdminTuple in self.ordererAdminTuples, "Node admin tuple not found for: {0}".format(nodeAdminTuple)
   295          return crypto.dump_certificate(crypto.FILETYPE_PEM, self.ordererAdminTuples[nodeAdminTuple])
   296  
   297      def findNodeAdminTuple(self, userName, contextName, orgName):
   298          nodeAdminTuple = NodeAdminTuple(user=userName, nodeName=contextName, organization=orgName)
   299          assert nodeAdminTuple in self.ordererAdminTuples, "Node admin tuple not found for: {0}".format(nodeAdminTuple)
   300          return nodeAdminTuple
   301  
   302      def registerOrdererAdminTuple(self, userName, ordererName, organizationName):
   303          ' Assign the user as orderer admin'
   304          ordererAdminTuple = NodeAdminTuple(user=userName, nodeName=ordererName, organization=organizationName)
   305          assert ordererAdminTuple not in self.ordererAdminTuples, "Orderer admin tuple already registered {0}".format(
   306              ordererAdminTuple)
   307          assert organizationName in self.organizations, "Orderer Organization not defined {0}".format(organizationName)
   308  
   309          user = self.getUser(userName, shouldCreate=True)
   310          certReq = user.createCertRequest(ordererAdminTuple.nodeName)
   311          userCert = self.getOrganization(organizationName).createCertificate(certReq)
   312  
   313          # Verify the newly created certificate
   314          store = crypto.X509Store()
   315          # Assuming a list of trusted certs
   316          for trustedCert in [self.getOrganization(organizationName).signedCert]:
   317              store.add_cert(trustedCert)
   318          # Create a certificate context using the store and the certificate to verify
   319          store_ctx = crypto.X509StoreContext(store, userCert)
   320          # Verify the certificate, returns None if it can validate the certificate
   321          store_ctx.verify_certificate()
   322          self.ordererAdminTuples[ordererAdminTuple] = userCert
   323          return ordererAdminTuple
   324  
   325  
   326  class AuthDSLHelper:
   327      @classmethod
   328      def Envelope(cls, signaturePolicy, identities):
   329          'Envelope builds an envelope message embedding a SignaturePolicy'
   330          return common_dot_policies_pb2.SignaturePolicyEnvelope(
   331              version=0,
   332              policy=signaturePolicy,
   333              identities=identities)
   334  
   335      @classmethod
   336      def NOutOf(cls, n, policies):
   337          'NOutOf creates a policy which requires N out of the slice of policies to evaluate to true'
   338          return common_dot_policies_pb2.SignaturePolicy(
   339              n_out_of=common_dot_policies_pb2.SignaturePolicy.NOutOf(
   340                  N=n,
   341                  policies=policies,
   342              ),
   343          )
   344  
   345  class BootstrapHelper:
   346      KEY_CONSENSUS_TYPE = "ConsensusType"
   347      KEY_CHAIN_CREATION_POLICY_NAMES = "ChainCreationPolicyNames"
   348      KEY_ACCEPT_ALL_POLICY = "AcceptAllPolicy"
   349      KEY_INGRESS_POLICY = "IngressPolicyNames"
   350      KEY_EGRESS_POLICY = "EgressPolicyNames"
   351      KEY_HASHING_ALGORITHM = "HashingAlgorithm"
   352      KEY_BATCH_SIZE = "BatchSize"
   353      KEY_BATCH_TIMEOUT = "BatchTimeout"
   354      KEY_CREATIONPOLICY = "CreationPolicy"
   355      KEY_MSP_INFO = "MSP"
   356      KEY_ANCHOR_PEERS = "AnchorPeers"
   357  
   358      KEY_NEW_CONFIGURATION_ITEM_POLICY = "NewConfigurationItemPolicy"
   359      DEFAULT_CHAIN_CREATORS = [KEY_ACCEPT_ALL_POLICY]
   360  
   361      DEFAULT_NONCE_SIZE = 24
   362  
   363      @classmethod
   364      def getNonce(cls):
   365          return rand.bytes(BootstrapHelper.DEFAULT_NONCE_SIZE)
   366  
   367      @classmethod
   368      def addSignatureToSignedConfigItem(cls, configUpdateEnvelope, (entity, cert)):
   369          sigHeader = common_dot_common_pb2.SignatureHeader(creator=crypto.dump_certificate(crypto.FILETYPE_ASN1, cert),
   370                                                            nonce=BootstrapHelper.getNonce())
   371          sigHeaderBytes = sigHeader.SerializeToString()
   372          # Signature over the concatenation of configurationItem bytes and signatureHeader bytes
   373          signature = entity.sign(sigHeaderBytes + configUpdateEnvelope.config_update)
   374          # Now add new signature to Signatures repeated field
   375          newConfigSig = configUpdateEnvelope.signatures.add()
   376          newConfigSig.signature_header = sigHeaderBytes
   377          newConfigSig.signature = signature
   378  
   379      def __init__(self, chainId, lastModified=0, msgVersion=1, epoch=0, consensusType="solo", batchSize=10,
   380                   batchTimeout="10s", absoluteMaxBytes=100000000, preferredMaxBytes=512 * 1024, signers=[]):
   381          self.chainId = str(chainId)
   382          self.lastModified = lastModified
   383          self.msgVersion = msgVersion
   384          self.epoch = epoch
   385          self.consensusType = consensusType
   386          self.batchSize = batchSize
   387          self.batchTimeout = batchTimeout
   388          self.absoluteMaxBytes = absoluteMaxBytes
   389          self.preferredMaxBytes = preferredMaxBytes
   390          self.signers = signers
   391  
   392      def makeChainHeader(self, type, txID="", extension='',
   393                          version=1,
   394                          timestamp=timestamp_pb2.Timestamp(seconds=int(time.time()), nanos=0)):
   395          return common_dot_common_pb2.ChannelHeader(type=type,
   396                                                   version=version,
   397                                                   timestamp=timestamp,
   398                                                   channel_id=self.chainId,
   399                                                   epoch=self.epoch,
   400                                                   tx_id=txID,
   401                                                   extension=extension)
   402  
   403      def makeSignatureHeader(self, serializeCertChain, nonce):
   404          return common_dot_common_pb2.SignatureHeader(creator=serializeCertChain,
   405                                                       nonce=nonce)
   406  
   407      def signConfigItem(self, configItem):
   408          # signedConfigItem = common_dot_configuration_pb2.SignedConfigurationItem(
   409          #     ConfigurationItem=configItem.SerializeToString(), Signatures=None)
   410          # return signedConfigItem
   411          return configItem
   412  
   413      def getConfigItem(self, commonConfigType, key, value):
   414          configItem = common_dot_configtx_pb2.ConfigItem(
   415              version=self.lastModified,
   416              configPath=commonConfigType,
   417              key=key,
   418              mod_policy=BootstrapHelper.KEY_NEW_CONFIGURATION_ITEM_POLICY,
   419              value=value)
   420          return configItem
   421  
   422      def encodeAnchorInfo(self, ciValue):
   423          configItem = self.getConfigItem(
   424              commonConfigType=common_dot_configtx_pb2.ConfigItem.ConfigType.Value("PEER"),
   425              key=BootstrapHelper.KEY_ANCHOR_PEERS,
   426              value=ciValue.SerializeToString())
   427          return self.signConfigItem(configItem)
   428  
   429      def encodeMspInfo(self, mspUniqueId, ciValue):
   430          configItem = self.getConfigItem(
   431              commonConfigType=common_dot_configtx_pb2.ConfigItem.ConfigType.Value("MSP"),
   432              key=mspUniqueId,
   433              value=ciValue.SerializeToString())
   434          return self.signConfigItem(configItem)
   435  
   436      def encodeHashingAlgorithm(self, hashingAlgorithm="SHAKE256"):
   437          configItem = self.getConfigItem(
   438              commonConfigType=common_dot_configtx_pb2.ConfigItem.ConfigType.Value("CHAIN"),
   439              key=BootstrapHelper.KEY_HASHING_ALGORITHM,
   440              value=common_dot_configuration_pb2.HashingAlgorithm(name=hashingAlgorithm).SerializeToString())
   441          return self.signConfigItem(configItem)
   442  
   443      def encodeBatchSize(self):
   444          configItem = self.getConfigItem(
   445              commonConfigType=common_dot_configtx_pb2.ConfigItem.ConfigType.Value("ORDERER"),
   446              key=BootstrapHelper.KEY_BATCH_SIZE,
   447              value=orderer_dot_configuration_pb2.BatchSize(maxMessageCount=self.batchSize,
   448                                                            absoluteMaxBytes=self.absoluteMaxBytes,
   449                                                            preferredMaxBytes=self.preferredMaxBytes).SerializeToString())
   450          return self.signConfigItem(configItem)
   451  
   452      def encodeBatchTimeout(self):
   453          configItem = self.getConfigItem(
   454              commonConfigType=common_dot_configtx_pb2.ConfigItem.ConfigType.Value("ORDERER"),
   455              key=BootstrapHelper.KEY_BATCH_TIMEOUT,
   456              value=orderer_dot_configuration_pb2.BatchTimeout(timeout=self.batchTimeout).SerializeToString())
   457          return self.signConfigItem(configItem)
   458  
   459      def encodeConsensusType(self):
   460          configItem = self.getConfigItem(
   461              commonConfigType=common_dot_configtx_pb2.ConfigItem.ConfigType.Value("ORDERER"),
   462              key=BootstrapHelper.KEY_CONSENSUS_TYPE,
   463              value=orderer_dot_configuration_pb2.ConsensusType(type=self.consensusType).SerializeToString())
   464          return self.signConfigItem(configItem)
   465  
   466      def encodeChainCreators(self, ciValue=orderer_dot_configuration_pb2.ChainCreationPolicyNames(
   467          names=DEFAULT_CHAIN_CREATORS).SerializeToString()):
   468          configItem = self.getConfigItem(
   469              commonConfigType=common_dot_configtx_pb2.ConfigItem.ConfigType.Value("ORDERER"),
   470              key=BootstrapHelper.KEY_CHAIN_CREATION_POLICY_NAMES,
   471              value=ciValue)
   472          return self.signConfigItem(configItem)
   473  
   474      def encodePolicy(self, key, policy=common_dot_policies_pb2.Policy(
   475          type=common_dot_policies_pb2.Policy.PolicyType.Value("SIGNATURE"),
   476          policy=AuthDSLHelper.Envelope(signaturePolicy=AuthDSLHelper.NOutOf(0, []), identities=[]).SerializeToString())):
   477          configItem = self.getConfigItem(
   478              commonConfigType=common_dot_configtx_pb2.ConfigItem.ConfigType.Value("POLICY"),
   479              key=key,
   480              value=policy.SerializeToString())
   481          return self.signConfigItem(configItem)
   482  
   483      def encodeEgressPolicy(self):
   484          configItem = self.getConfigItem(
   485              commonConfigType=common_dot_configtx_pb2.ConfigItem.ConfigType.Value("ORDERER"),
   486              key=BootstrapHelper.KEY_EGRESS_POLICY,
   487              value=orderer_dot_configuration_pb2.EgressPolicyNames(
   488                  names=[BootstrapHelper.KEY_ACCEPT_ALL_POLICY]).SerializeToString())
   489          return self.signConfigItem(configItem)
   490  
   491      def encodeIngressPolicy(self):
   492          configItem = self.getConfigItem(
   493              commonConfigType=common_dot_configtx_pb2.ConfigItem.ConfigType.Value("ORDERER"),
   494              key=BootstrapHelper.KEY_INGRESS_POLICY,
   495              value=orderer_dot_configuration_pb2.IngressPolicyNames(
   496                  names=[BootstrapHelper.KEY_ACCEPT_ALL_POLICY]).SerializeToString())
   497          return self.signConfigItem(configItem)
   498  
   499      def encodeAcceptAllPolicy(self):
   500          configItem = self.getConfigItem(
   501              commonConfigType=common_dot_configtx_pb2.ConfigItem.ConfigType.Value("POLICY"),
   502              key=BootstrapHelper.KEY_ACCEPT_ALL_POLICY,
   503              value=common_dot_policies_pb2.Policy(type=1, policy=AuthDSLHelper.Envelope(
   504                  signaturePolicy=AuthDSLHelper.NOutOf(0, []), identities=[]).SerializeToString()).SerializeToString())
   505          return self.signConfigItem(configItem)
   506  
   507      def lockDefaultModificationPolicy(self):
   508          configItem = self.getConfigItem(
   509              commonConfigType=common_dot_configtx_pb2.ConfigItem.ConfigType.Value("POLICY"),
   510              key=BootstrapHelper.KEY_NEW_CONFIGURATION_ITEM_POLICY,
   511              value=common_dot_policies_pb2.Policy(type=1, policy=AuthDSLHelper.Envelope(
   512                  signaturePolicy=AuthDSLHelper.NOutOf(1, []), identities=[]).SerializeToString()).SerializeToString())
   513          return self.signConfigItem(configItem)
   514  
   515      def computeBlockDataHash(self, blockData):
   516          return computeCryptoHash(blockData.SerializeToString())
   517  
   518      def signInitialChainConfig(self, signedConfigItems, chainCreationPolicyName):
   519          'Create a signedConfigItem using previous config items'
   520          # Create byte array to store concatenated bytes
   521          # concatenatedConfigItemsBytes = bytearray()
   522          # for sci in signedConfigItems:
   523          #     concatenatedConfigItemsBytes = concatenatedConfigItemsBytes + bytearray(sci.ConfigurationItem)
   524          # hash = computeCryptoHash(concatenatedConfigItemsBytes)
   525          # data = ''
   526          # for sci in signedConfigItems:
   527          #     data = data + sci.ConfigurationItem
   528          # # Compute hash over concatenated bytes
   529          # hash = computeCryptoHash(data)
   530          configItem = self.getConfigItem(
   531              commonConfigType=common_dot_configtx_pb2.ConfigItem.ConfigType.Value("ORDERER"),
   532              key=BootstrapHelper.KEY_CREATIONPOLICY,
   533              value=orderer_dot_configuration_pb2.CreationPolicy(policy=chainCreationPolicyName).SerializeToString())
   534          return [self.signConfigItem(configItem)] + signedConfigItems
   535  
   536  
   537  def createConfigUpdateEnvelope(channelConfigGroup, chainId, chainCreationPolicyName):
   538      # Returns a list prepended with a signedConfiguration
   539      channelConfigGroup.groups[OrdererGroup].values[BootstrapHelper.KEY_CREATIONPOLICY].value = toValue(
   540          orderer_dot_configuration_pb2.CreationPolicy(policy=chainCreationPolicyName))
   541      config_update_envelope = createNewConfigUpdateEnvelope(channelConfig=channelConfigGroup, chainId=chainId)
   542      return config_update_envelope
   543  
   544  
   545  def getDirectory(context):
   546      if 'bootstrapDirectory' not in context:
   547          context.bootstrapDirectory = Directory()
   548      return context.bootstrapDirectory
   549  
   550  
   551  def getOrdererBootstrapAdmin(context, shouldCreate=False):
   552      directory = getDirectory(context)
   553      ordererBootstrapAdmin = directory.getUser(userName="ordererBootstrapAdmin", shouldCreate=shouldCreate)
   554      return ordererBootstrapAdmin
   555  
   556  
   557  def addOrdererBootstrapAdminOrgReferences(context, policyName, orgNames):
   558      'Adds a key/value pair of policyName/[orgName,...]'
   559      directory = getDirectory(context)
   560      ordererBootstrapAdmin = directory.getUser(userName="ordererBootstrapAdmin", shouldCreate=False)
   561      if not 'OrgReferences' in ordererBootstrapAdmin.tags:
   562          ordererBootstrapAdmin.tags['OrgReferences'] = {}
   563      policyNameToOrgNamesDict = ordererBootstrapAdmin.tags['OrgReferences']
   564      assert not policyName in policyNameToOrgNamesDict, "PolicyName '{0}' already registered with ordererBootstrapAdmin".format(
   565          policyName)
   566      policyNameToOrgNamesDict[policyName] = orgNames
   567      return policyNameToOrgNamesDict
   568  
   569  
   570  def getOrdererBootstrapAdminOrgReferences(context):
   571      directory = getDirectory(context)
   572      ordererBootstrapAdmin = directory.getUser(userName="ordererBootstrapAdmin", shouldCreate=False)
   573      if not 'OrgReferences' in ordererBootstrapAdmin.tags:
   574          ordererBootstrapAdmin.tags['OrgReferences'] = {}
   575      return ordererBootstrapAdmin.tags['OrgReferences']
   576  
   577  
   578  def getSignedMSPConfigItems(context, orgNames):
   579      directory = getDirectory(context)
   580      orgs = [directory.getOrganization(orgName) for orgName in orgNames]
   581  
   582      channel = common_dot_configtx_pb2.ConfigGroup()
   583      for org in orgs:
   584          channel.groups[ApplicationGroup].groups[org.name].values[BootstrapHelper.KEY_MSP_INFO].value = toValue(
   585              org.getMSPConfig())
   586      return [channel]
   587  
   588  
   589  def getAnchorPeersConfigGroup(context, nodeAdminTuples):
   590      directory = getDirectory(context)
   591      config_group = common_dot_configtx_pb2.ConfigGroup()
   592      for orgName, group in groupby([(nat.organization, nat) for nat in nodeAdminTuples], lambda x: x[0]):
   593          anchorPeers = peer_dot_configuration_pb2.AnchorPeers()
   594          for (k,nodeAdminTuple) in group:
   595              anchorPeer = anchorPeers.anchor_peers.add()
   596              anchorPeer.host = nodeAdminTuple.nodeName
   597              anchorPeer.port = 5611
   598              anchorPeer.cert = crypto.dump_certificate(crypto.FILETYPE_PEM,
   599                                                        directory.findCertForNodeAdminTuple(nodeAdminTuple))
   600          config_group.groups[ApplicationGroup].groups[orgName].values[BootstrapHelper.KEY_ANCHOR_PEERS].value=toValue(anchorPeers)
   601      return [config_group]
   602  
   603  
   604  def getMspConfigItemsForPolicyNames(context, policyNames):
   605      policyNameToOrgNamesDict = getOrdererBootstrapAdminOrgReferences(context)
   606      # Get unique set of org names and return set of signed MSP ConfigItems
   607      orgNamesReferenced = list(
   608          set([orgName for policyName in policyNames for orgName in policyNameToOrgNamesDict[policyName]]))
   609      orgNamesReferenced.sort()
   610      return getSignedMSPConfigItems(context=context, orgNames=orgNamesReferenced)
   611  
   612  
   613  def createSignedConfigItems(configGroups=[]):
   614  
   615      channelConfig = createChannelConfigGroup()
   616      for configGroup in configGroups:
   617          mergeConfigGroups(channelConfig, configGroup)
   618      return channelConfig
   619  
   620  
   621  def createChannelConfigGroup(hashingAlgoName="SHA256", consensusType="solo", batchTimeout="10s", batchSizeMaxMessageCount=10, batchSizeAbsoluteMaxBytes=100000000, batchSizePreferredMaxBytes=512 * 1024):
   622  
   623      channel = common_dot_configtx_pb2.ConfigGroup()
   624      # channel.groups[ApplicationGroup] = common_dot_configtx_pb2.ConfigGroup()
   625      # channel.groups[OrdererGroup] = common_dot_configtx_pb2.ConfigGroup()
   626      channel.groups[ApplicationGroup]
   627      channel.groups[OrdererGroup]
   628      # v = common_dot_configtx_pb2.ConfigItem.ConfigType.Value
   629      # configItems.append(bootstrapHelper.encodeHashingAlgorithm())
   630      channel.values[BootstrapHelper.KEY_HASHING_ALGORITHM].value = toValue(
   631          common_dot_configuration_pb2.HashingAlgorithm(name=hashingAlgoName))
   632  
   633      channel.groups[OrdererGroup].values[BootstrapHelper.KEY_BATCH_SIZE].value = toValue(orderer_dot_configuration_pb2.BatchSize(maxMessageCount=batchSizeMaxMessageCount,absoluteMaxBytes=batchSizeAbsoluteMaxBytes,preferredMaxBytes=batchSizePreferredMaxBytes))
   634      channel.groups[OrdererGroup].values[BootstrapHelper.KEY_BATCH_TIMEOUT].value = toValue(orderer_dot_configuration_pb2.BatchTimeout(timeout=batchTimeout))
   635      channel.groups[OrdererGroup].values[BootstrapHelper.KEY_CONSENSUS_TYPE].value = toValue(orderer_dot_configuration_pb2.ConsensusType(type=consensusType))
   636  
   637      acceptAllPolicy = common_dot_policies_pb2.Policy(type=1, policy=AuthDSLHelper.Envelope(
   638          signaturePolicy=AuthDSLHelper.NOutOf(0, []), identities=[]).SerializeToString())
   639      channel.policies[BootstrapHelper.KEY_ACCEPT_ALL_POLICY].policy.CopyFrom(acceptAllPolicy)
   640      channel.groups[OrdererGroup].values[
   641          BootstrapHelper.KEY_INGRESS_POLICY].value = toValue(
   642          orderer_dot_configuration_pb2.IngressPolicyNames(
   643              names=[BootstrapHelper.KEY_ACCEPT_ALL_POLICY]))
   644      channel.groups[OrdererGroup].values[
   645          BootstrapHelper.KEY_EGRESS_POLICY].value = toValue(
   646          orderer_dot_configuration_pb2.EgressPolicyNames(
   647              names=[BootstrapHelper.KEY_ACCEPT_ALL_POLICY]))
   648      return channel
   649  
   650  def createConfigUpdateTxEnvelope(chainId, configUpdateEnvelope):
   651      'The Join channel flow'
   652      bootstrapHelper = BootstrapHelper(chainId=chainId)
   653      payloadChainHeader = bootstrapHelper.makeChainHeader(
   654          type=common_dot_common_pb2.HeaderType.Value("CONFIG_UPDATE"))
   655  
   656      # Now the SignatureHeader
   657      serializedCreatorCertChain = None
   658      nonce = None
   659      payloadSignatureHeader = common_dot_common_pb2.SignatureHeader(
   660          creator=serializedCreatorCertChain,
   661          nonce=bootstrapHelper.getNonce(),
   662      )
   663  
   664      payloadHeader = common_dot_common_pb2.Header(
   665          channel_header=payloadChainHeader,
   666          signature_header=payloadSignatureHeader,
   667      )
   668      payload = common_dot_common_pb2.Payload(header=payloadHeader, data=configUpdateEnvelope.SerializeToString())
   669      envelope = common_dot_common_pb2.Envelope(payload=payload.SerializeToString(), signature=None)
   670      return envelope
   671  
   672  def createConfigTxEnvelope(chainId, config_envelope):
   673      # configEnvelope = common_dot_configtx_pb2.ConfigEnvelope(last_update=envelope.SerializeToString())
   674      bootstrapHelper = BootstrapHelper(chainId=chainId)
   675      payloadChainHeader = bootstrapHelper.makeChainHeader(
   676          type=common_dot_common_pb2.HeaderType.Value("CONFIG"))
   677  
   678      # Now the SignatureHeader
   679      serializedCreatorCertChain = None
   680      nonce = None
   681      payloadSignatureHeader = common_dot_common_pb2.SignatureHeader(
   682          creator=serializedCreatorCertChain,
   683          nonce=bootstrapHelper.getNonce(),
   684      )
   685  
   686      payloadHeader = common_dot_common_pb2.Header(
   687          channel_header=payloadChainHeader,
   688          signature_header=payloadSignatureHeader,
   689      )
   690      payload = common_dot_common_pb2.Payload(header=payloadHeader, data=config_envelope.SerializeToString())
   691      envelope = common_dot_common_pb2.Envelope(payload=payload.SerializeToString(), signature=None)
   692      return envelope
   693  
   694      return configEnvelope
   695  
   696  def createNewConfigUpdateEnvelope(channelConfig, chainId):
   697      configUpdate = common_dot_configtx_pb2.ConfigUpdate(header=common_dot_common_pb2.ChannelHeader(channel_id=chainId,
   698                                                                                                     type=common_dot_common_pb2.HeaderType.Value(
   699                                                                                                         "CONFIG_UPDATE")),
   700                                                          write_set=channelConfig)
   701      configUpdateEnvelope = common_dot_configtx_pb2.ConfigUpdateEnvelope(config_update=configUpdate.SerializeToString(), signatures =[])
   702      return configUpdateEnvelope
   703  
   704  
   705  def mergeConfigGroups(configGroupTarget, configGroupSource):
   706      for k, v in configGroupSource.groups.iteritems():
   707          if k in configGroupTarget.groups.keys():
   708              mergeConfigGroups(configGroupTarget.groups[k], configGroupSource.groups[k])
   709          else:
   710              configGroupTarget.groups[k].MergeFrom(v)
   711      for k, v in configGroupSource.policies.iteritems():
   712          if k in configGroupTarget.policies.keys():
   713              mergeConfigGroups(configGroupTarget.policies[k], configGroupSource.policies[k])
   714          else:
   715              configGroupTarget.policies[k].MergeFrom(v)
   716      for k, v in configGroupSource.values.iteritems():
   717          assert not k in configGroupTarget.values.keys(), "Value already exists in target config group: {0}".format(k)
   718          configGroupTarget.values[k].CopyFrom(v)
   719  
   720  
   721  def createGenesisBlock(context, chainId, consensusType, signedConfigItems=[]):
   722      'Generates the genesis block for starting the oderers and for use in the chain config transaction by peers'
   723      # assert not "bootstrapGenesisBlock" in context,"Genesis block already created:\n{0}".format(context.bootstrapGenesisBlock)
   724      directory = getDirectory(context)
   725      assert len(directory.ordererAdminTuples) > 0, "No orderer admin tuples defined!!!"
   726  
   727      channelConfig = createChannelConfigGroup()
   728      for configGroup in signedConfigItems:
   729          mergeConfigGroups(channelConfig, configGroup)
   730  
   731      # (fileName, fileExist) = ContextHelper.GetHelper(context=context).getTmpPathForName(name="t",extension="protobuf")
   732      # with open(fileName, 'w') as f:
   733      #     f.write(channelConfig.SerializeToString())
   734  
   735      config = common_dot_configtx_pb2.Config(
   736          header=common_dot_common_pb2.ChannelHeader(channel_id=chainId,
   737                                                     type=common_dot_common_pb2.HeaderType.Value("CONFIG")),
   738          channel=channelConfig)
   739  
   740      configEnvelope = common_dot_configtx_pb2.ConfigEnvelope(config=config)
   741      envelope = createConfigTxEnvelope(chainId=chainId, config_envelope=configEnvelope)
   742      blockData = common_dot_common_pb2.BlockData(data=[envelope.SerializeToString()])
   743  
   744      # Spoke with kostas, for orderer in general
   745      signaturesMetadata = ""
   746      lastConfigurationBlockMetadata = common_dot_common_pb2.Metadata(
   747          value=common_dot_common_pb2.LastConfig(index=0).SerializeToString()).SerializeToString()
   748      ordererConfigMetadata = ""
   749      transactionFilterMetadata = ""
   750      bootstrapHelper = BootstrapHelper(chainId="NOT_USED")
   751      block = common_dot_common_pb2.Block(
   752          header=common_dot_common_pb2.BlockHeader(
   753              number=0,
   754              previous_hash=None,
   755              data_hash=bootstrapHelper.computeBlockDataHash(blockData),
   756          ),
   757          data=blockData,
   758          metadata=common_dot_common_pb2.BlockMetadata(
   759              metadata=[signaturesMetadata, lastConfigurationBlockMetadata, transactionFilterMetadata,
   760                        ordererConfigMetadata]),
   761      )
   762  
   763      # Add this back once crypto certs are required
   764      for nodeAdminTuple in directory.ordererAdminTuples:
   765          userCert = directory.ordererAdminTuples[nodeAdminTuple]
   766          certAsPEM = crypto.dump_certificate(crypto.FILETYPE_PEM, userCert)
   767          # print("UserCert for orderer genesis:\n{0}\n".format(certAsPEM))
   768          # print("")
   769  
   770      return (block, envelope)
   771  
   772  
   773  class PathType(Enum):
   774      'Denotes whether Path relative to Local filesystem or Containers volume reference.'
   775      Local = 1
   776      Container = 2
   777  
   778  
   779  class CallbackHelper:
   780      def __init__(self, discriminator, volumeRootPathInContainer = "/var/hyperledger/bddtests"):
   781          self.volumeRootPathInContainer = volumeRootPathInContainer
   782          self.discriminator = discriminator
   783  
   784      def getVolumePath(self, composition, pathType=PathType.Local):
   785          assert pathType in PathType, "Expected pathType of {0}".format(PathType)
   786          basePath = "."
   787          if pathType == PathType.Container:
   788              basePath = self.volumeRootPathInContainer
   789          return "{0}/volumes/{1}/{2}".format(basePath, self.discriminator, composition.projectName)
   790  
   791      def getLocalMspConfigPath(self, composition, compose_service, pathType=PathType.Local):
   792          return "{0}/{1}/localMspConfig".format(self.getVolumePath(composition, pathType), compose_service)
   793  
   794      def _writeMspFiles(self, directory , composition, compose_service, network):
   795          localMspConfigPath = self.getLocalMspConfigPath(composition, compose_service=compose_service)
   796          os.makedirs("{0}/{1}".format(localMspConfigPath, "signcerts"))
   797          os.makedirs("{0}/{1}".format(localMspConfigPath, "admincerts"))
   798          os.makedirs("{0}/{1}".format(localMspConfigPath, "cacerts"))
   799          os.makedirs("{0}/{1}".format(localMspConfigPath, "keystore"))
   800          # Loop through directory and place Organization Certs into cacerts folder
   801          for targetOrg in [org for orgName, org in directory.organizations.items() if network in org.networks]:
   802              with open("{0}/cacerts/{1}.pem".format(localMspConfigPath, targetOrg.name), "w") as f:
   803                  f.write(crypto.dump_certificate(crypto.FILETYPE_PEM, targetOrg.getSelfSignedCert()))
   804  
   805          # Loop through directory and place Organization Certs into admincerts folder
   806          # TODO: revisit this, ASO recommended for now
   807          for targetOrg in [org for orgName, org in directory.organizations.items() if network in org.networks]:
   808              with open("{0}/admincerts/{1}.pem".format(localMspConfigPath, targetOrg.name), "w") as f:
   809                  f.write(crypto.dump_certificate(crypto.FILETYPE_PEM, targetOrg.getSelfSignedCert()))
   810  
   811          # Find the peer signer Tuple for this peer and add to signcerts folder
   812          for pnt, cert in [(peerNodeTuple, cert) for peerNodeTuple, cert in directory.ordererAdminTuples.items() if
   813                            compose_service in peerNodeTuple.user and "signer" in peerNodeTuple.user.lower()]:
   814              # Put the PEM file in the signcerts folder
   815              with open("{0}/signcerts/{1}.pem".format(localMspConfigPath, pnt.user), "w") as f:
   816                  f.write(crypto.dump_certificate(crypto.FILETYPE_PEM, cert))
   817              # Put the associated private key into the keystore folder
   818              user = directory.getUser(pnt.user, shouldCreate=False)
   819              with open("{0}/keystore/{1}.pem".format(localMspConfigPath, pnt.user), "w") as f:
   820                  f.write(user.ecdsaSigningKey.to_pem())
   821                  # f.write(crypto.dump_privatekey(crypto.FILETYPE_PEM, user.pKey))
   822  
   823  
   824  class OrdererGensisBlockCompositionCallback(compose.CompositionCallback, CallbackHelper):
   825      'Responsible for setting the GensisBlock for the Orderer nodes upon composition'
   826  
   827      def __init__(self, context, genesisBlock, genesisFileName="genesis_file"):
   828          CallbackHelper.__init__(self, discriminator="orderer")
   829          self.context = context
   830          self.genesisFileName = genesisFileName
   831          self.genesisBlock = genesisBlock
   832          self.volumeRootPathInContainer = "/var/hyperledger/bddtests"
   833          compose.Composition.RegisterCallbackInContext(context, self)
   834  
   835      def getVolumePath(self, composition, pathType=PathType.Local):
   836          assert pathType in PathType, "Expected pathType of {0}".format(PathType)
   837          basePath = "."
   838          if pathType == PathType.Container:
   839              basePath = self.volumeRootPathInContainer
   840          return "{0}/volumes/orderer/{1}".format(basePath, composition.projectName)
   841  
   842      def getGenesisFilePath(self, composition, pathType=PathType.Local):
   843          return "{0}/{1}".format(self.getVolumePath(composition, pathType), self.genesisFileName)
   844  
   845      def getOrdererList(self, composition):
   846          return [serviceName for serviceName in composition.getServiceNames() if "orderer" in serviceName]
   847  
   848      def composing(self, composition, context):
   849          print("Will copy gensisiBlock over at this point ")
   850          os.makedirs(self.getVolumePath(composition))
   851          with open(self.getGenesisFilePath(composition), "wb") as f:
   852              f.write(self.genesisBlock.SerializeToString())
   853          directory = getDirectory(context)
   854  
   855          for ordererService in self.getOrdererList(composition):
   856              self._writeMspFiles(directory=directory,
   857                                  compose_service=ordererService,
   858                                  composition=composition,
   859                                  network=Network.Orderer)
   860  
   861      def decomposing(self, composition, context):
   862          'Will remove the orderer volume path folder for the context'
   863          shutil.rmtree(self.getVolumePath(composition))
   864  
   865      def getEnv(self, composition, context, env):
   866          env["ORDERER_GENERAL_GENESISMETHOD"] = "file"
   867          env["ORDERER_GENERAL_GENESISFILE"] = self.getGenesisFilePath(composition, pathType=PathType.Container)
   868          for ordererService in self.getOrdererList(composition):
   869              localMspConfigPath = self.getLocalMspConfigPath(composition, ordererService, pathType=PathType.Container)
   870              env["{0}_ORDERER_GENERAL_LOCALMSPDIR".format(ordererService.upper())] = localMspConfigPath
   871  
   872  
   873  class PeerCompositionCallback(compose.CompositionCallback):
   874      'Responsible for setting up Peer nodes upon composition'
   875  
   876      def __init__(self, context):
   877          self.context = context
   878          self.volumeRootPathInContainer = "/var/hyperledger/bddtests"
   879          compose.Composition.RegisterCallbackInContext(context, self)
   880  
   881      def getVolumePath(self, composition, pathType=PathType.Local):
   882          assert pathType in PathType, "Expected pathType of {0}".format(PathType)
   883          basePath = "."
   884          if pathType == PathType.Container:
   885              basePath = self.volumeRootPathInContainer
   886          return "{0}/volumes/peer/{1}".format(basePath, composition.projectName)
   887  
   888      def getPeerList(self, composition):
   889          return [serviceName for serviceName in composition.getServiceNames() if "peer" in serviceName]
   890  
   891      def getLocalMspConfigPath(self, composition, peerService, pathType=PathType.Local):
   892          return "{0}/{1}/localMspConfig".format(self.getVolumePath(composition, pathType), peerService)
   893  
   894      def _createLocalMspConfigDirs(self, mspConfigPath):
   895          os.makedirs("{0}/{1}".format(mspConfigPath, "signcerts"))
   896          os.makedirs("{0}/{1}".format(mspConfigPath, "admincerts"))
   897          os.makedirs("{0}/{1}".format(mspConfigPath, "cacerts"))
   898          os.makedirs("{0}/{1}".format(mspConfigPath, "keystore"))
   899  
   900      def composing(self, composition, context):
   901          'Will copy local MSP info over at this point for each peer node'
   902  
   903          directory = getDirectory(context)
   904  
   905          for peerService in self.getPeerList(composition):
   906              localMspConfigPath = self.getLocalMspConfigPath(composition, peerService)
   907              self._createLocalMspConfigDirs(localMspConfigPath)
   908              # Loop through directory and place Peer Organization Certs into cacerts folder
   909              for peerOrg in [org for orgName, org in directory.organizations.items() if Network.Peer in org.networks]:
   910                  with open("{0}/cacerts/{1}.pem".format(localMspConfigPath, peerOrg.name), "w") as f:
   911                      f.write(crypto.dump_certificate(crypto.FILETYPE_PEM, peerOrg.getSelfSignedCert()))
   912  
   913              # Loop through directory and place Peer Organization Certs into admincerts folder
   914              # TODO: revisit this, ASO recommended for now
   915              for peerOrg in [org for orgName, org in directory.organizations.items() if Network.Peer in org.networks]:
   916                  with open("{0}/admincerts/{1}.pem".format(localMspConfigPath, peerOrg.name), "w") as f:
   917                      f.write(crypto.dump_certificate(crypto.FILETYPE_PEM, peerOrg.getSelfSignedCert()))
   918  
   919              # Find the peer signer Tuple for this peer and add to signcerts folder
   920              for pnt, cert in [(peerNodeTuple, cert) for peerNodeTuple, cert in directory.ordererAdminTuples.items() if
   921                                peerService in peerNodeTuple.user and "signer" in peerNodeTuple.user.lower()]:
   922                  # Put the PEM file in the signcerts folder
   923                  with open("{0}/signcerts/{1}.pem".format(localMspConfigPath, pnt.user), "w") as f:
   924                      f.write(crypto.dump_certificate(crypto.FILETYPE_PEM, cert))
   925                  # Put the associated private key into the keystore folder
   926                  user = directory.getUser(pnt.user, shouldCreate=False)
   927                  with open("{0}/keystore/{1}.pem".format(localMspConfigPath, pnt.user), "w") as f:
   928                      f.write(user.ecdsaSigningKey.to_pem())
   929                      # f.write(crypto.dump_privatekey(crypto.FILETYPE_PEM, user.pKey))
   930  
   931      def decomposing(self, composition, context):
   932          'Will remove the orderer volume path folder for the context'
   933          shutil.rmtree(self.getVolumePath(composition))
   934  
   935      def getEnv(self, composition, context, env):
   936          for peerService in self.getPeerList(composition):
   937              localMspConfigPath = self.getLocalMspConfigPath(composition, peerService, pathType=PathType.Container)
   938              env["{0}_CORE_PEER_MSPCFGPATH".format(peerService.upper())] = localMspConfigPath
   939  
   940  
   941  def createChainCreationPolicyNames(context, chainCreationPolicyNames, chaindId):
   942      channel = common_dot_configtx_pb2.ConfigGroup()
   943      channel.groups[OrdererGroup].values[BootstrapHelper.KEY_CHAIN_CREATION_POLICY_NAMES].value = toValue(
   944          orderer_dot_configuration_pb2.ChainCreationPolicyNames(
   945              names=chainCreationPolicyNames))
   946      return channel
   947  
   948  
   949  def createChainCreatorsPolicy(context, chainCreatePolicyName, chaindId, orgNames):
   950      'Creates the chain Creator Policy with name'
   951      directory = getDirectory(context)
   952      bootstrapHelper = BootstrapHelper(chainId=chaindId)
   953  
   954      # This represents the domain of organization which can create channels for the orderer
   955      # First create org MSPPrincicpal
   956  
   957      # Collect the orgs from the table
   958      mspPrincipalList = []
   959      for org in [directory.getOrganization(orgName) for orgName in orgNames]:
   960          mspPrincipalList.append(msp_principal_pb2.MSPPrincipal(
   961              PrincipalClassification=msp_principal_pb2.MSPPrincipal.Classification.Value("ByIdentity"),
   962              Principal=crypto.dump_certificate(crypto.FILETYPE_ASN1, org.getSelfSignedCert())))
   963      policy = common_dot_policies_pb2.Policy(
   964          type=common_dot_policies_pb2.Policy.PolicyType.Value("SIGNATURE"),
   965          policy=AuthDSLHelper.Envelope(
   966              signaturePolicy=AuthDSLHelper.NOutOf(
   967                  0, []),
   968              identities=mspPrincipalList).SerializeToString())
   969      channel = common_dot_configtx_pb2.ConfigGroup()
   970      channel.policies[chainCreatePolicyName].policy.CopyFrom(policy)
   971  
   972      # print("signed Config Item:\n{0}\n".format(chainCreationPolicyNamesSignedConfigItem))
   973      # print("chain Creation orgs signed Config Item:\n{0}\n".format(chainCreatorsOrgsPolicySignedConfigItem))
   974      return channel
   975  
   976  
   977  def setOrdererBootstrapGenesisBlock(genesisBlock):
   978      'Responsible for setting the GensisBlock for the Orderer nodes upon composition'
   979  
   980  
   981  def broadcastCreateChannelConfigTx(context, composeService, chainId, configTxEnvelope, user):
   982      dataFunc = lambda x: configTxEnvelope
   983      user.broadcastMessages(context=context, numMsgsToBroadcast=1, composeService=composeService, chainID=chainId,
   984                             dataFunc=dataFunc)
   985  
   986  
   987  def getArgsFromContextForUser(context, userName):
   988      directory = getDirectory(context)
   989      # Update the chaincodeSpec ctorMsg for invoke
   990      args = []
   991      if 'table' in context:
   992          if context.table:
   993              # There are function arguments
   994              user = directory.getUser(userName)
   995              # Allow the user to specify expressions referencing tags in the args list
   996              pattern = re.compile('\{(.*)\}$')
   997              for arg in context.table[0].cells:
   998                  m = pattern.match(arg)
   999                  if m:
  1000                      # tagName reference found in args list
  1001                      tagName = m.groups()[0]
  1002                      # make sure the tagName is found in the users tags
  1003                      assert tagName in user.tags, "TagName '{0}' not found for user '{1}'".format(tagName,
  1004                                                                                                   user.getUserName())
  1005                      args.append(user.tags[tagName])
  1006                  else:
  1007                      # No tag referenced, pass the arg
  1008                      args.append(arg)
  1009      return args
  1010