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