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