From 692effee66802c6e05d8a7ef121c255433f10bb9 Mon Sep 17 00:00:00 2001 From: jeffgarratt Date: Tue, 7 Mar 2017 14:56:05 -0500 Subject: [PATCH] [FAB-1141] Incorporate latest changes to protos Regenerated orderer proto files. Removed references to ingress/egress policies. Added default policies for all groups. Now sign all envelopes. Added readers/writers/admins to each group. Now use SerializedIdentity as opposed to cert as PEM for certChain. Added value for BlockDataHashingDataStructure.width for channel configs. Removed peerOrg2 for now. Will add later. Addressed non-deterministic issue with lccc and MSP id sorting for default endorsement policy handling. Change-Id: I60b177ea6cf8464b3d35e85b45ef3f250941acdf Signed-off-by: jeffgarratt --- bddtests/environment.py | 2 +- bddtests/features/bootstrap.feature | 28 ++-- bddtests/orderer/ab_pb2_grpc.py | 3 +- bddtests/orderer/configuration_pb2.py | 88 +----------- bddtests/orderer/configuration_pb2_grpc.py | 1 + bddtests/orderer/kafka_pb2_grpc.py | 1 + bddtests/steps/bootstrap_impl.py | 67 ++++----- bddtests/steps/bootstrap_util.py | 153 ++++++++++++--------- bddtests/steps/docgen.py | 2 +- bddtests/steps/orderer_util.py | 28 ++-- bddtests/templates/html/graph.html | 2 +- core/scc/lccc/lccc.go | 2 + 12 files changed, 167 insertions(+), 210 deletions(-) diff --git a/bddtests/environment.py b/bddtests/environment.py index ad21576a6fb..fb6dfa53598 100644 --- a/bddtests/environment.py +++ b/bddtests/environment.py @@ -72,7 +72,7 @@ def after_scenario(context, scenario): # stop any running peer that could get in the way before starting the tests def before_all(context): - cli_call(["../build/bin/peer", "node", "stop"], expect_success=False) + pass # stop any running peer that could get in the way before starting the tests def after_all(context): diff --git a/bddtests/features/bootstrap.feature b/bddtests/features/bootstrap.feature index b0832c4b757..14673125be9 100644 --- a/bddtests/features/bootstrap.feature +++ b/bddtests/features/bootstrap.feature @@ -16,28 +16,36 @@ Feature: Bootstrap Scenario Outline: Bootstrap a development network with 4 peers (2 orgs) and 1 orderer (1 org), each having a single independent root of trust (No fabric-ca, just openssl) #creates 1 self-signed key/cert pair per orderer organization Given the orderer network has organizations: - | Organization | - | ordererOrg0 | + | Organization | Readers | Writers | Admins | + | ordererOrg0 | member | member | admin | And user requests role of orderer admin by creating a key and csr for orderer and acquires signed certificate from organization: | User | Orderer | Organization | | orderer0Signer | orderer0 | ordererOrg0 | + + # Rolenames : MspPrincipal.proto And the peer network has organizations: - | Organization | - | peerOrg0 | - | peerOrg1 | - | peerOrg2 | + | Organization | Readers | Writers | Admins | + | peerOrg0 | member | member | admin | + | peerOrg1 | member | member | admin | +# | peerOrg2 | member | member | admin | + + And a ordererBootstrapAdmin is identified and given access to all public certificates and orderer node info + And the ordererBootstrapAdmin creates a cert alias "bootstrapCertAlias" for orderer network bootstrap purposes for organizations + | Organization | + | ordererOrg0 | + And the ordererBootstrapAdmin generates a GUUID to identify the orderer system chain and refer to it by name as "OrdererSystemChainId" And the ordererBootstrapAdmin creates a chain creators policy "chainCreatePolicy1" (network name) for peer orgs who wish to form a network using orderer system chain "OrdererSystemChainId": | Organization | | peerOrg0 | | peerOrg1 | - | peerOrg2 | +# | peerOrg2 | And the ordererBoostrapAdmin creates the chain creation policy names "chainCreationPolicyNames" for orderer system chain "OrdererSystemChainId" with policies: |PolicyName | @@ -50,7 +58,7 @@ Feature: Bootstrap # Order info includes orderer admin/orderer information and address (host:port) from previous steps # Only the peer organizations can vary. - And the ordererBootstrapAdmin creates the genesis block "ordererGenesisBlock" for chain "OrdererSystemChainId" for network config policy "" and consensus "" using chain creators policies: + And the ordererBootstrapAdmin using cert alias "bootstrapCertAlias" creates the genesis block "ordererGenesisBlock" for chain "OrdererSystemChainId" for network config policy "" and consensus "" using chain creators policies: | ConfigGroup Names | | chainCreatePolicy1 | | chainCreationPolicyNames | @@ -108,14 +116,14 @@ Feature: Bootstrap | peerOrg0 | | peerOrg1 | - And the user "dev0Org0" creates a ConfigUpdate Tx "configUpdateTx1" using signed ConfigUpdateEnvelope "createChannelConfigUpdate1" + And the user "dev0Org0" creates a ConfigUpdate Tx "configUpdateTx1" using cert alias "dev0Org0App1" using signed ConfigUpdateEnvelope "createChannelConfigUpdate1" And the user "dev0Org0" broadcasts ConfigUpdate Tx "configUpdateTx1" to orderer "orderer0" to create channel "com.acme.blockchain.jdoe.Channel1" # Sleep as the deliver takes a bit to have the first block ready And I wait "2" seconds - When user "dev0Org0" connects to deliver function on orderer "orderer0" + When user "dev0Org0" using cert alias "dev0Org0App1" connects to deliver function on orderer "orderer0" And user "dev0Org0" sends deliver a seek request on orderer "orderer0" with properties: | ChainId | Start | End | | com.acme.blockchain.jdoe.Channel1 | 0 | 0 | diff --git a/bddtests/orderer/ab_pb2_grpc.py b/bddtests/orderer/ab_pb2_grpc.py index 842d956293b..322fc477c3d 100644 --- a/bddtests/orderer/ab_pb2_grpc.py +++ b/bddtests/orderer/ab_pb2_grpc.py @@ -1,11 +1,10 @@ +# Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT! import grpc from grpc.framework.common import cardinality from grpc.framework.interfaces.face import utilities as face_utilities import common.common_pb2 as common_dot_common__pb2 import orderer.ab_pb2 as orderer_dot_ab__pb2 -import common.common_pb2 as common_dot_common__pb2 -import orderer.ab_pb2 as orderer_dot_ab__pb2 class AtomicBroadcastStub(object): diff --git a/bddtests/orderer/configuration_pb2.py b/bddtests/orderer/configuration_pb2.py index 13741e704dd..e1505c8f5c8 100644 --- a/bddtests/orderer/configuration_pb2.py +++ b/bddtests/orderer/configuration_pb2.py @@ -19,7 +19,7 @@ name='orderer/configuration.proto', package='orderer', syntax='proto3', - serialized_pb=_b('\n\x1borderer/configuration.proto\x12\x07orderer\"\x1d\n\rConsensusType\x12\x0c\n\x04type\x18\x01 \x01(\t\"Y\n\tBatchSize\x12\x17\n\x0fmaxMessageCount\x18\x01 \x01(\r\x12\x18\n\x10\x61\x62soluteMaxBytes\x18\x02 \x01(\r\x12\x19\n\x11preferredMaxBytes\x18\x03 \x01(\r\"\x1f\n\x0c\x42\x61tchTimeout\x12\x0f\n\x07timeout\x18\x01 \x01(\t\" \n\x0e\x43reationPolicy\x12\x0e\n\x06policy\x18\x01 \x01(\t\"#\n\x12IngressPolicyNames\x12\r\n\x05names\x18\x01 \x03(\t\"\"\n\x11\x45gressPolicyNames\x12\r\n\x05names\x18\x01 \x03(\t\")\n\x18\x43hainCreationPolicyNames\x12\r\n\x05names\x18\x01 \x03(\t\"\x1f\n\x0cKafkaBrokers\x12\x0f\n\x07\x62rokers\x18\x01 \x03(\tB.Z,github.com/hyperledger/fabric/protos/ordererb\x06proto3') + serialized_pb=_b('\n\x1borderer/configuration.proto\x12\x07orderer\"\x1d\n\rConsensusType\x12\x0c\n\x04type\x18\x01 \x01(\t\"Y\n\tBatchSize\x12\x17\n\x0fmaxMessageCount\x18\x01 \x01(\r\x12\x18\n\x10\x61\x62soluteMaxBytes\x18\x02 \x01(\r\x12\x19\n\x11preferredMaxBytes\x18\x03 \x01(\r\"\x1f\n\x0c\x42\x61tchTimeout\x12\x0f\n\x07timeout\x18\x01 \x01(\t\" \n\x0e\x43reationPolicy\x12\x0e\n\x06policy\x18\x01 \x01(\t\")\n\x18\x43hainCreationPolicyNames\x12\r\n\x05names\x18\x01 \x03(\t\"\x1f\n\x0cKafkaBrokers\x12\x0f\n\x07\x62rokers\x18\x01 \x03(\tB.Z,github.com/hyperledger/fabric/protos/ordererb\x06proto3') ) _sym_db.RegisterFileDescriptor(DESCRIPTOR) @@ -164,68 +164,6 @@ ) -_INGRESSPOLICYNAMES = _descriptor.Descriptor( - name='IngressPolicyNames', - full_name='orderer.IngressPolicyNames', - filename=None, - file=DESCRIPTOR, - containing_type=None, - fields=[ - _descriptor.FieldDescriptor( - name='names', full_name='orderer.IngressPolicyNames.names', index=0, - number=1, type=9, cpp_type=9, label=3, - has_default_value=False, default_value=[], - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - options=None), - ], - extensions=[ - ], - nested_types=[], - enum_types=[ - ], - options=None, - is_extendable=False, - syntax='proto3', - extension_ranges=[], - oneofs=[ - ], - serialized_start=229, - serialized_end=264, -) - - -_EGRESSPOLICYNAMES = _descriptor.Descriptor( - name='EgressPolicyNames', - full_name='orderer.EgressPolicyNames', - filename=None, - file=DESCRIPTOR, - containing_type=None, - fields=[ - _descriptor.FieldDescriptor( - name='names', full_name='orderer.EgressPolicyNames.names', index=0, - number=1, type=9, cpp_type=9, label=3, - has_default_value=False, default_value=[], - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - options=None), - ], - extensions=[ - ], - nested_types=[], - enum_types=[ - ], - options=None, - is_extendable=False, - syntax='proto3', - extension_ranges=[], - oneofs=[ - ], - serialized_start=266, - serialized_end=300, -) - - _CHAINCREATIONPOLICYNAMES = _descriptor.Descriptor( name='ChainCreationPolicyNames', full_name='orderer.ChainCreationPolicyNames', @@ -252,8 +190,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=302, - serialized_end=343, + serialized_start=229, + serialized_end=270, ) @@ -283,16 +221,14 @@ extension_ranges=[], oneofs=[ ], - serialized_start=345, - serialized_end=376, + serialized_start=272, + serialized_end=303, ) DESCRIPTOR.message_types_by_name['ConsensusType'] = _CONSENSUSTYPE DESCRIPTOR.message_types_by_name['BatchSize'] = _BATCHSIZE DESCRIPTOR.message_types_by_name['BatchTimeout'] = _BATCHTIMEOUT DESCRIPTOR.message_types_by_name['CreationPolicy'] = _CREATIONPOLICY -DESCRIPTOR.message_types_by_name['IngressPolicyNames'] = _INGRESSPOLICYNAMES -DESCRIPTOR.message_types_by_name['EgressPolicyNames'] = _EGRESSPOLICYNAMES DESCRIPTOR.message_types_by_name['ChainCreationPolicyNames'] = _CHAINCREATIONPOLICYNAMES DESCRIPTOR.message_types_by_name['KafkaBrokers'] = _KAFKABROKERS @@ -324,20 +260,6 @@ )) _sym_db.RegisterMessage(CreationPolicy) -IngressPolicyNames = _reflection.GeneratedProtocolMessageType('IngressPolicyNames', (_message.Message,), dict( - DESCRIPTOR = _INGRESSPOLICYNAMES, - __module__ = 'orderer.configuration_pb2' - # @@protoc_insertion_point(class_scope:orderer.IngressPolicyNames) - )) -_sym_db.RegisterMessage(IngressPolicyNames) - -EgressPolicyNames = _reflection.GeneratedProtocolMessageType('EgressPolicyNames', (_message.Message,), dict( - DESCRIPTOR = _EGRESSPOLICYNAMES, - __module__ = 'orderer.configuration_pb2' - # @@protoc_insertion_point(class_scope:orderer.EgressPolicyNames) - )) -_sym_db.RegisterMessage(EgressPolicyNames) - ChainCreationPolicyNames = _reflection.GeneratedProtocolMessageType('ChainCreationPolicyNames', (_message.Message,), dict( DESCRIPTOR = _CHAINCREATIONPOLICYNAMES, __module__ = 'orderer.configuration_pb2' diff --git a/bddtests/orderer/configuration_pb2_grpc.py b/bddtests/orderer/configuration_pb2_grpc.py index c374a4d7d5b..d5557c12314 100644 --- a/bddtests/orderer/configuration_pb2_grpc.py +++ b/bddtests/orderer/configuration_pb2_grpc.py @@ -1,3 +1,4 @@ +# Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT! import grpc from grpc.framework.common import cardinality from grpc.framework.interfaces.face import utilities as face_utilities diff --git a/bddtests/orderer/kafka_pb2_grpc.py b/bddtests/orderer/kafka_pb2_grpc.py index c374a4d7d5b..d5557c12314 100644 --- a/bddtests/orderer/kafka_pb2_grpc.py +++ b/bddtests/orderer/kafka_pb2_grpc.py @@ -1,3 +1,4 @@ +# Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT! import grpc from grpc.framework.common import cardinality from grpc.framework.interfaces.face import utilities as face_utilities diff --git a/bddtests/steps/bootstrap_impl.py b/bddtests/steps/bootstrap_impl.py index 5f791a5f764..9cfde6197d4 100644 --- a/bddtests/steps/bootstrap_impl.py +++ b/bddtests/steps/bootstrap_impl.py @@ -22,21 +22,6 @@ import compose import time -class ChannelCreationInfo: - 'Used to store the information needed to construct Config TX for orderer broadcast to create a new channel' - def __init__(self, channelId, channelCreationPolicyName, signedConfigEnvelope): - self.channelId = channelId - self.channelCreationPolicyName = channelCreationPolicyName - self.config_update_envelope = signedConfigEnvelope - - def __repr__(self): - return "channelId = {0}\nchannelCreationPolicyName={1}\nconfigUpdateEnvelope={2}\n".format(self.channelId, - self.channelCreationPolicyName, - str( - self.config_update_envelope)) - - - @given(u'the orderer network has organizations') def step_impl(context): assert 'table' in context, "Expected table of orderer organizations" @@ -75,8 +60,9 @@ def step_impl(context): # Simply create the user bootstrap_util.getOrdererBootstrapAdmin(context, shouldCreate=True) -@given(u'the ordererBootstrapAdmin creates the genesis block "{ordererGenesisBlockName}" for chain "{ordererSystemChainIdName}" for network config policy "{networkConfigPolicy}" and consensus "{consensusType}" using chain creators policies') -def step_impl(context, ordererGenesisBlockName, ordererSystemChainIdName, networkConfigPolicy, consensusType): +@given(u'the ordererBootstrapAdmin using cert alias "{certAlias}" creates the genesis block "{ordererGenesisBlockName}" for chain "{ordererSystemChainIdName}" for network config policy "{networkConfigPolicy}" and consensus "{consensusType}" using chain creators policies') +def step_impl(context, certAlias, ordererGenesisBlockName, ordererSystemChainIdName, networkConfigPolicy, consensusType): + directory = bootstrap_util.getDirectory(context=context) ordererBootstrapAdmin = bootstrap_util.getOrdererBootstrapAdmin(context) ordererSystemChainIdGUUID = ordererBootstrapAdmin.tags[ordererSystemChainIdName] # Now collect the named signed config items @@ -87,7 +73,11 @@ def step_impl(context, ordererGenesisBlockName, ordererSystemChainIdName, networ # Concatenate signedConfigItems # Construct block - (genesisBlock,envelope) = bootstrap_util.createGenesisBlock(context, ordererSystemChainIdGUUID, consensusType, signedConfigItems=configGroups) + nodeAdminTuple = ordererBootstrapAdmin.tags[certAlias] + bootstrapCert = directory.findCertForNodeAdminTuple(nodeAdminTuple=nodeAdminTuple) + (genesisBlock, envelope) = bootstrap_util.createGenesisBlock(context, ordererSystemChainIdGUUID, consensusType, + nodeAdminTuple=nodeAdminTuple, + signedConfigItems=configGroups) ordererBootstrapAdmin.setTagValue(ordererGenesisBlockName, genesisBlock) bootstrap_util.OrdererGensisBlockCompositionCallback(context, genesisBlock) bootstrap_util.PeerCompositionCallback(context) @@ -170,7 +160,7 @@ def step_impl(context, userName, createChannelSignedConfigEnvelope): #NOTE: Conidered passing signing key for appDeveloper, but decided that the peer org signatures they need to collect subsequently should be proper way config_update_envelope = bootstrap_util.createConfigUpdateEnvelope(channelConfigGroup=channel_config_groups, chainId=channelID, chainCreationPolicyName=chainCreationPolicyName) - user.setTagValue(createChannelSignedConfigEnvelope, ChannelCreationInfo(channelID, chainCreationPolicyName, config_update_envelope)) + user.setTagValue(createChannelSignedConfigEnvelope, config_update_envelope) # Construct TX Config Envelope, broadcast, expect success, and then connect to deliver to revtrieve block. # Make sure the blockdata exactly the TxConfigEnvelope I submitted. @@ -192,23 +182,26 @@ def step_impl(context, userName, createChannelSignedConfigEnvelopeName): assert 'table' in context, "Expected table of peer organizations" directory = bootstrap_util.getDirectory(context) user = directory.getUser(userName=userName) - # Get the ChannelCreationInfo object that holds the signedConfigEnvelope - channelCreationInfo = user.tags[createChannelSignedConfigEnvelopeName] - config_update_envelope = channelCreationInfo.config_update_envelope + config_update_envelope = user.tags[createChannelSignedConfigEnvelopeName] for row in context.table.rows: org = directory.getOrganization(row['Organization']) assert bootstrap_util.Network.Peer in org.networks, "Organization '{0}' not in Peer network".format(org.name) bootstrap_util.BootstrapHelper.addSignatureToSignedConfigItem(config_update_envelope, (org, org.getSelfSignedCert())) # print("Signatures for signedConfigEnvelope:\n {0}\n".format(signedConfigEnvelope.Items[0])) -@given(u'the user "{userName}" creates a ConfigUpdate Tx "{configUpdateTxName}" using signed ConfigUpdateEnvelope "{createChannelSignedConfigEnvelopeName}"') -def step_impl(context, userName, configUpdateTxName, createChannelSignedConfigEnvelopeName): +@given(u'the user "{userName}" creates a ConfigUpdate Tx "{configUpdateTxName}" using cert alias "{certAlias}" using signed ConfigUpdateEnvelope "{createChannelSignedConfigEnvelopeName}"') +def step_impl(context, userName, certAlias, configUpdateTxName, createChannelSignedConfigEnvelopeName): directory = bootstrap_util.getDirectory(context) user = directory.getUser(userName=userName) - channelCreationInfo = user.tags[createChannelSignedConfigEnvelopeName] - #TODO: this is temporary until partial update is supported. Normally you would just return - # this message and send directly to broadcast. - envelope_for_config_update = bootstrap_util.createConfigUpdateTxEnvelope(channelCreationInfo.channelId, channelCreationInfo.config_update_envelope) + namedAdminTuple = user.tags[certAlias] + cert = directory.findCertForNodeAdminTuple(namedAdminTuple) + config_update_envelope = user.tags[createChannelSignedConfigEnvelopeName] + config_update = bootstrap_util.getChannelIdFromConfigUpdateEnvelope(config_update_envelope) + envelope_for_config_update = bootstrap_util.createEnvelopeForMsg(directory=directory, + nodeAdminTuple=namedAdminTuple, + chainId=config_update.channel_id, + msg=config_update_envelope, + typeAsString="CONFIG_UPDATE") user.setTagValue(configUpdateTxName, envelope_for_config_update) @given(u'the user "{userName}" broadcasts ConfigUpdate Tx "{configTxName}" to orderer "{orderer}" to create channel "{channelId}"') @@ -226,11 +219,13 @@ def step_impl(context, userName, transactionAlias, orderer, channelId): bootstrap_util.broadcastCreateChannelConfigTx(context=context, composeService=orderer, chainId=channelId, user=user, configTxEnvelope=transaction) -@when(u'user "{userName}" connects to deliver function on orderer "{composeService}"') -def step_impl(context, userName, composeService): +@when(u'user "{userName}" using cert alias "{certAlias}" connects to deliver function on orderer "{composeService}"') +def step_impl(context, userName, certAlias, composeService): directory = bootstrap_util.getDirectory(context) user = directory.getUser(userName=userName) - user.connectToDeliverFunction(context, composeService) + nodeAdminTuple = user.tags[certAlias] + cert = directory.findCertForNodeAdminTuple(nodeAdminTuple) + user.connectToDeliverFunction(context, composeService, cert, nodeAdminTuple=nodeAdminTuple) @when(u'user "{userName}" sends deliver a seek request on orderer "{composeService}" with properties') def step_impl(context, userName, composeService): @@ -336,3 +331,13 @@ def step_impl(context, userNameSource, objectAlias, userNameTarget): userSource = directory.getUser(userName=userNameSource) userTarget = directory.getUser(userName=userNameTarget) userTarget.setTagValue(objectAlias, userSource.tags[objectAlias]) + +@given(u'the ordererBootstrapAdmin creates a cert alias "{certAlias}" for orderer network bootstrap purposes for organizations') +def step_impl(context, certAlias): + assert "table" in context, "Expected table of Organizations" + directory = bootstrap_util.getDirectory(context) + ordererBootstrapAdmin = bootstrap_util.getOrdererBootstrapAdmin(context) + assert len(context.table.rows) == 1, "Only support single orderer orgnaization at moment" + for row in context.table.rows: + nodeAdminNamedTuple = directory.registerOrdererAdminTuple(ordererBootstrapAdmin.name, "ordererBootstrapAdmin", row['Organization']) + ordererBootstrapAdmin.setTagValue(certAlias, nodeAdminNamedTuple) diff --git a/bddtests/steps/bootstrap_util.py b/bddtests/steps/bootstrap_util.py index 0d062933876..3aa056ed20c 100644 --- a/bddtests/steps/bootstrap_util.py +++ b/bddtests/steps/bootstrap_util.py @@ -26,6 +26,7 @@ from collections import namedtuple from itertools import groupby + from enum import Enum from google.protobuf import timestamp_pb2 @@ -37,6 +38,7 @@ from msp import mspconfig_pb2 from peer import configuration_pb2 as peer_dot_configuration_pb2 from orderer import configuration_pb2 as orderer_dot_configuration_pb2 +import identities_pb2 import orderer_util from contexthelper import ContextHelper @@ -194,9 +196,9 @@ def getPrivateKeyAsPEM(self): class User(Entity, orderer_util.UserRegistration): - def __init__(self, name): + def __init__(self, name, directory): Entity.__init__(self, name) - orderer_util.UserRegistration.__init__(self, name) + orderer_util.UserRegistration.__init__(self, name, directory) self.tags = {} def setTagValue(self, tagKey, tagValue, overwrite=False): @@ -237,6 +239,13 @@ def getMSPConfig(self): mspConfig = mspconfig_pb2.MSPConfig(config=fabricMSPConfig.SerializeToString(), type=0) return mspConfig + def getMspPrincipalAsRole(self, mspRoleTypeAsString): + mspRole = msp_principal_pb2.MSPRole(msp_identifier=self.name, Role=msp_principal_pb2.MSPRole.MSPRoleType.Value(mspRoleTypeAsString)) + mspPrincipal = msp_principal_pb2.MSPPrincipal( + principal_classification=msp_principal_pb2.MSPPrincipal.Classification.Value('ROLE'), + principal=mspRole.SerializeToString()) + return mspPrincipal + def createCertificate(self, certReq): numYrs = 1 return createCertificate(certReq, (self.signedCert, self.pKey), 1000, (0, 60 * 60 * 24 * 365 * numYrs)) @@ -264,7 +273,7 @@ def _registerOrg(self, orgName): def _registerUser(self, userName): assert userName not in self.users, "User already registered {0}".format(userName) - self.users[userName] = User(userName) + self.users[userName] = User(userName, directory=self) return self.users[userName] def getUser(self, userName, shouldCreate=False): @@ -349,13 +358,19 @@ def NOutOf(cls, n, policies): ), ) + @classmethod + def SignedBy(cls, index): + 'NOutOf creates a policy which requires N out of the slice of policies to evaluate to true' + return common_dot_policies_pb2.SignaturePolicy( + signed_by=index + ) + class BootstrapHelper: KEY_CONSENSUS_TYPE = "ConsensusType" KEY_CHAIN_CREATION_POLICY_NAMES = "ChainCreationPolicyNames" KEY_ACCEPT_ALL_POLICY = "AcceptAllPolicy" - KEY_INGRESS_POLICY = "IngressPolicyNames" - KEY_EGRESS_POLICY = "EgressPolicyNames" KEY_HASHING_ALGORITHM = "HashingAlgorithm" + KEY_BLOCKDATA_HASHING_STRUCTURE = "BlockDataHashingStructure" KEY_BATCH_SIZE = "BatchSize" KEY_BATCH_TIMEOUT = "BatchTimeout" KEY_CREATIONPOLICY = "CreationPolicy" @@ -384,7 +399,8 @@ def getNonce(cls): @classmethod def addSignatureToSignedConfigItem(cls, configUpdateEnvelope, (entity, cert)): - sigHeader = common_dot_common_pb2.SignatureHeader(creator=crypto.dump_certificate(crypto.FILETYPE_ASN1, cert), + serializedIdentity = identities_pb2.SerializedIdentity(Mspid=entity.name, IdBytes=crypto.dump_certificate(crypto.FILETYPE_PEM, cert)) + sigHeader = common_dot_common_pb2.SignatureHeader(creator=serializedIdentity.SerializeToString(), nonce=BootstrapHelper.getNonce()) sigHeaderBytes = sigHeader.SerializeToString() # Signature over the concatenation of configurationItem bytes and signatureHeader bytes @@ -498,22 +514,6 @@ def encodePolicy(self, key, policy=common_dot_policies_pb2.Policy( value=policy.SerializeToString()) return self.signConfigItem(configItem) - def encodeEgressPolicy(self): - configItem = self.getConfigItem( - commonConfigType=common_dot_configtx_pb2.ConfigItem.ConfigType.Value("ORDERER"), - key=BootstrapHelper.KEY_EGRESS_POLICY, - value=orderer_dot_configuration_pb2.EgressPolicyNames( - names=[BootstrapHelper.KEY_ACCEPT_ALL_POLICY]).SerializeToString()) - return self.signConfigItem(configItem) - - def encodeIngressPolicy(self): - configItem = self.getConfigItem( - commonConfigType=common_dot_configtx_pb2.ConfigItem.ConfigType.Value("ORDERER"), - key=BootstrapHelper.KEY_INGRESS_POLICY, - value=orderer_dot_configuration_pb2.IngressPolicyNames( - names=[BootstrapHelper.KEY_ACCEPT_ALL_POLICY]).SerializeToString()) - return self.signConfigItem(configItem) - def encodeAcceptAllPolicy(self): configItem = self.getConfigItem( commonConfigType=common_dot_configtx_pb2.ConfigItem.ConfigType.Value("POLICY"), @@ -653,6 +653,7 @@ def setMetaPolicy(channelId, channgel_config_groups): rule=ruleAny).SerializeToString())) + def createChannelConfigGroup(directory, hashingAlgoName="SHA256", consensusType="solo", batchTimeout="1s", batchSizeMaxMessageCount=10, batchSizeAbsoluteMaxBytes=100000000, batchSizePreferredMaxBytes=512 * 1024): channel = common_dot_configtx_pb2.ConfigGroup() @@ -665,6 +666,10 @@ def createChannelConfigGroup(directory, hashingAlgoName="SHA256", consensusType= channel.values[BootstrapHelper.KEY_HASHING_ALGORITHM].value = toValue( common_dot_configuration_pb2.HashingAlgorithm(name=hashingAlgoName)) + golangMathMaxUint32 = 4294967295 + channel.values[BootstrapHelper.KEY_BLOCKDATA_HASHING_STRUCTURE].value = toValue( + common_dot_configuration_pb2.BlockDataHashingStructure(width=golangMathMaxUint32)) + channel.groups[OrdererGroup].values[BootstrapHelper.KEY_BATCH_SIZE].value = toValue(orderer_dot_configuration_pb2.BatchSize(maxMessageCount=batchSizeMaxMessageCount,absoluteMaxBytes=batchSizeAbsoluteMaxBytes,preferredMaxBytes=batchSizePreferredMaxBytes)) channel.groups[OrdererGroup].values[BootstrapHelper.KEY_BATCH_TIMEOUT].value = toValue(orderer_dot_configuration_pb2.BatchTimeout(timeout=batchTimeout)) channel.groups[OrdererGroup].values[BootstrapHelper.KEY_CONSENSUS_TYPE].value = toValue(orderer_dot_configuration_pb2.ConsensusType(type=consensusType)) @@ -672,26 +677,52 @@ def createChannelConfigGroup(directory, hashingAlgoName="SHA256", consensusType= acceptAllPolicy = common_dot_policies_pb2.Policy(type=1, policy=AuthDSLHelper.Envelope( signaturePolicy=AuthDSLHelper.NOutOf(0, []), identities=[]).SerializeToString()) channel.policies[BootstrapHelper.KEY_ACCEPT_ALL_POLICY].policy.CopyFrom(acceptAllPolicy) - channel.groups[OrdererGroup].values[ - BootstrapHelper.KEY_INGRESS_POLICY].value = toValue( - orderer_dot_configuration_pb2.IngressPolicyNames( - names=[BootstrapHelper.KEY_ACCEPT_ALL_POLICY])) - channel.groups[OrdererGroup].values[ - BootstrapHelper.KEY_EGRESS_POLICY].value = toValue( - orderer_dot_configuration_pb2.EgressPolicyNames( - names=[BootstrapHelper.KEY_ACCEPT_ALL_POLICY])) - #New meta policy info + + # For now, setting same policies for each 'Non-Org' group typeImplicitMeta = common_dot_policies_pb2.Policy.PolicyType.Value("IMPLICIT_META") Policy = common_dot_policies_pb2.Policy - IMP=common_dot_policies_pb2.ImplicitMetaPolicy + IMP = common_dot_policies_pb2.ImplicitMetaPolicy ruleAny = common_dot_policies_pb2.ImplicitMetaPolicy.Rule.Value("ANY") ruleMajority = common_dot_policies_pb2.ImplicitMetaPolicy.Rule.Value("MAJORITY") - channel.policies[BootstrapHelper.KEY_POLICY_READERS].policy.CopyFrom(Policy(type=typeImplicitMeta, policy=IMP( - rule=ruleAny, sub_policy=BootstrapHelper.KEY_POLICY_READERS).SerializeToString())) - channel.policies[BootstrapHelper.KEY_POLICY_WRITERS].policy.CopyFrom(Policy(type=typeImplicitMeta, policy=IMP( - rule=ruleAny, sub_policy=BootstrapHelper.KEY_POLICY_WRITERS).SerializeToString())) - channel.policies[BootstrapHelper.KEY_POLICY_ADMINS].policy.CopyFrom(Policy(type=typeImplicitMeta, policy=IMP( - rule=ruleMajority, sub_policy=BootstrapHelper.KEY_POLICY_ADMINS).SerializeToString())) + for group in [channel, channel.groups[ApplicationGroup], channel.groups[OrdererGroup]]: + group.policies[BootstrapHelper.KEY_POLICY_READERS].policy.CopyFrom(Policy(type=typeImplicitMeta, policy=IMP( + rule=ruleAny, sub_policy=BootstrapHelper.KEY_POLICY_READERS).SerializeToString())) + group.policies[BootstrapHelper.KEY_POLICY_WRITERS].policy.CopyFrom(Policy(type=typeImplicitMeta, policy=IMP( + rule=ruleAny, sub_policy=BootstrapHelper.KEY_POLICY_WRITERS).SerializeToString())) + group.policies[BootstrapHelper.KEY_POLICY_ADMINS].policy.CopyFrom(Policy(type=typeImplicitMeta, policy=IMP( + rule=ruleMajority, sub_policy=BootstrapHelper.KEY_POLICY_ADMINS).SerializeToString())) + + # Add the orderer org groups MSPConfig info + for ordererOrg in [org for org in directory.getOrganizations().values() if Network.Orderer in org.networks]: + channel.groups[OrdererGroup].groups[ordererOrg.name].values[BootstrapHelper.KEY_MSP_INFO].value = toValue( + ordererOrg.getMSPConfig()) + + + + # Now set policies for each org group (Both peer and orderer) + #TODO: Revisit after Jason does a bit more refactoring on chain creation policy enforcement + groupNameDict = {Network.Peer : ApplicationGroup, Network.Orderer : OrdererGroup} + for org in directory.getOrganizations().values(): + for network in org.networks: + groupName = groupNameDict[network] + mspPrincipalForMemberRole = org.getMspPrincipalAsRole(mspRoleTypeAsString='MEMBER') + memberSignaturePolicyEnvelope = AuthDSLHelper.Envelope(signaturePolicy=AuthDSLHelper.SignedBy(0), identities=[mspPrincipalForMemberRole]) + memberPolicy = common_dot_policies_pb2.Policy( + type=common_dot_policies_pb2.Policy.PolicyType.Value("SIGNATURE"), + policy=memberSignaturePolicyEnvelope.SerializeToString()) + channel.groups[groupName].groups[org.name].policies[BootstrapHelper.KEY_POLICY_READERS].policy.CopyFrom(memberPolicy) + channel.groups[groupName].groups[org.name].policies[BootstrapHelper.KEY_POLICY_WRITERS].policy.CopyFrom(memberPolicy) + + mspPrincipalForAdminRole = org.getMspPrincipalAsRole(mspRoleTypeAsString='ADMIN') + adminSignaturePolicyEnvelope = AuthDSLHelper.Envelope(signaturePolicy=AuthDSLHelper.SignedBy(0), identities=[mspPrincipalForAdminRole]) + adminPolicy = common_dot_policies_pb2.Policy( + type=common_dot_policies_pb2.Policy.PolicyType.Value("SIGNATURE"), + policy=adminSignaturePolicyEnvelope.SerializeToString()) + channel.groups[groupName].groups[org.name].policies[BootstrapHelper.KEY_POLICY_ADMINS].policy.CopyFrom(adminPolicy) + + # signaturePolicyEnvelope = AuthDSLHelper.Envelope(signaturePolicy=AuthDSLHelper.SignedBy(0), identities=[mspPrincipal]) + + #New OrdererAddress ordererAddress = common_dot_configuration_pb2.OrdererAddresses() for ordererNodeTuple, cert in [(user_node_tuple, cert) for user_node_tuple, cert in directory.ordererAdminTuples.iteritems() if @@ -701,36 +732,18 @@ def createChannelConfigGroup(directory, hashingAlgoName="SHA256", consensusType= channel.values[BootstrapHelper.KEY_ORDERER_ADDRESSES].value = toValue(ordererAddress) return channel -def createConfigUpdateTxEnvelope(chainId, configUpdateEnvelope): - 'The Join channel flow' - bootstrapHelper = BootstrapHelper(chainId=chainId) - payloadChainHeader = bootstrapHelper.makeChainHeader( - type=common_dot_common_pb2.HeaderType.Value("CONFIG_UPDATE")) - - # Now the SignatureHeader - serializedCreatorCertChain = None - nonce = None - payloadSignatureHeader = common_dot_common_pb2.SignatureHeader( - creator=serializedCreatorCertChain, - nonce=bootstrapHelper.getNonce(), - ) - - payloadHeader = common_dot_common_pb2.Header( - channel_header=payloadChainHeader.SerializeToString(), - signature_header=payloadSignatureHeader.SerializeToString(), - ) - payload = common_dot_common_pb2.Payload(header=payloadHeader, data=configUpdateEnvelope.SerializeToString()) - envelope = common_dot_common_pb2.Envelope(payload=payload.SerializeToString(), signature=None) - return envelope - -def createConfigTxEnvelope(chainId, config_envelope): +def createEnvelopeForMsg(directory, nodeAdminTuple, chainId, msg, typeAsString): # configEnvelope = common_dot_configtx_pb2.ConfigEnvelope(last_update=envelope.SerializeToString()) bootstrapHelper = BootstrapHelper(chainId=chainId) payloadChainHeader = bootstrapHelper.makeChainHeader( - type=common_dot_common_pb2.HeaderType.Value("CONFIG")) + type=common_dot_common_pb2.HeaderType.Value(typeAsString)) # Now the SignatureHeader - serializedCreatorCertChain = None + org = directory.getOrganization(nodeAdminTuple.organization) + user = directory.getUser(nodeAdminTuple.user) + cert = directory.findCertForNodeAdminTuple(nodeAdminTuple) + serializedIdentity = identities_pb2.SerializedIdentity(Mspid=org.name, IdBytes=crypto.dump_certificate(crypto.FILETYPE_PEM, cert)) + serializedCreatorCertChain = serializedIdentity.SerializeToString() nonce = None payloadSignatureHeader = common_dot_common_pb2.SignatureHeader( creator=serializedCreatorCertChain, @@ -741,8 +754,9 @@ def createConfigTxEnvelope(chainId, config_envelope): channel_header=payloadChainHeader.SerializeToString(), signature_header=payloadSignatureHeader.SerializeToString(), ) - payload = common_dot_common_pb2.Payload(header=payloadHeader, data=config_envelope.SerializeToString()) - envelope = common_dot_common_pb2.Envelope(payload=payload.SerializeToString(), signature=None) + payload = common_dot_common_pb2.Payload(header=payloadHeader, data=msg.SerializeToString()) + payloadBytes = payload.SerializeToString() + envelope = common_dot_common_pb2.Envelope(payload=payloadBytes, signature=user.sign(payloadBytes)) return envelope return configEnvelope @@ -770,7 +784,7 @@ def mergeConfigGroups(configGroupTarget, configGroupSource): configGroupTarget.values[k].CopyFrom(v) -def createGenesisBlock(context, chainId, consensusType, signedConfigItems=[]): +def createGenesisBlock(context, chainId, consensusType, nodeAdminTuple, signedConfigItems=[]): 'Generates the genesis block for starting the oderers and for use in the chain config transaction by peers' # assert not "bootstrapGenesisBlock" in context,"Genesis block already created:\n{0}".format(context.bootstrapGenesisBlock) directory = getDirectory(context) @@ -789,7 +803,7 @@ def createGenesisBlock(context, chainId, consensusType, signedConfigItems=[]): channel_group=channelConfig) configEnvelope = common_dot_configtx_pb2.ConfigEnvelope(config=config) - envelope = createConfigTxEnvelope(chainId=chainId, config_envelope=configEnvelope) + envelope = createEnvelopeForMsg(directory=directory, chainId=chainId, nodeAdminTuple=nodeAdminTuple, msg=configEnvelope, typeAsString="CONFIG") blockData = common_dot_common_pb2.BlockData(data=[envelope.SerializeToString()]) # Spoke with kostas, for orderer in general @@ -1025,3 +1039,8 @@ def getArgsFromContextForUser(context, userName): args.append(arg) return args + +def getChannelIdFromConfigUpdateEnvelope(config_update_envelope): + config_update = common_dot_configtx_pb2.ConfigUpdate() + config_update.ParseFromString(config_update_envelope.config_update) + return config_update diff --git a/bddtests/steps/docgen.py b/bddtests/steps/docgen.py index 9299dde48be..1ebc1a47e05 100644 --- a/bddtests/steps/docgen.py +++ b/bddtests/steps/docgen.py @@ -173,7 +173,7 @@ def afterScenarioAdvice(self, joinpoint): main = env.get_template("html/main.html").render(header=header, body=self.output.getvalue()) (fileName, fileExists) = self.contextHelper.getTmpPathForName("scenario", extension="html") with open(fileName, 'w') as f: - f.write(main) + f.write(main.encode("utf-8")) self._writeNetworkJson() return joinpoint.proceed() diff --git a/bddtests/steps/orderer_util.py b/bddtests/steps/orderer_util.py index 5c04ae93b6a..4a66dd85084 100644 --- a/bddtests/steps/orderer_util.py +++ b/bddtests/steps/orderer_util.py @@ -21,6 +21,7 @@ from common import common_pb2 import bdd_test_util +import bootstrap_util from grpc.beta import implementations from grpc.framework.interfaces.face.face import AbortionError @@ -100,8 +101,11 @@ def handleNetworkError(self, networkError): class DeliverStreamHelper(StreamHelper): - def __init__(self, ordererStub, timeout = 110): + def __init__(self, ordererStub, entity, directory, nodeAdminTuple, timeout = 110): StreamHelper.__init__(self) + self.nodeAdminTuple = nodeAdminTuple + self.directory = directory + self.entity = entity # Set the UpdateMessage and start the stream sendGenerator = self.createSendGenerator(timeout) self.replyGenerator = ordererStub.Deliver(sendGenerator, timeout + 1) @@ -114,19 +118,12 @@ def createSeekInfo(self, chainID, start = 'Oldest', end = 'Newest', behavior = ) print("SeekInfo = {0}".format(seekInfo)) print("") - return common_pb2.Envelope( - payload = common_pb2.Payload( - header = common_pb2.Header( - channel_header = common_pb2.ChannelHeader( channel_id = chainID ).SerializeToString(), - signature_header = common_pb2.SignatureHeader().SerializeToString(), - ), - data = seekInfo.SerializeToString(), - ).SerializeToString(), - ) + return seekInfo def seekToRange(self, chainID = TEST_CHAIN_ID, start = 'Oldest', end = 'Newest'): seekInfo = self.createSeekInfo(start = start, end = end, chainID = chainID) - self.sendQueue.put(seekInfo) + envelope = bootstrap_util.createEnvelopeForMsg(directory=self.directory, chainId=chainID, msg=seekInfo, typeAsString="DELIVER_SEEK_INFO", nodeAdminTuple=self.nodeAdminTuple) + self.sendQueue.put(envelope) def getBlocks(self): blocks = [] @@ -148,8 +145,9 @@ def getBlocks(self): class UserRegistration: - def __init__(self, userName): + def __init__(self, userName, directory): self.userName= userName + self.directory = directory self.tags = {} # Dictionary of composeService->atomic broadcast grpc Stub self.atomicBroadcastStubsDict = {} @@ -163,10 +161,12 @@ def closeStreams(self): for compose_service, deliverStreamHelper in self.abDeliversStreamHelperDict.iteritems(): deliverStreamHelper.sendQueue.put(None) - def connectToDeliverFunction(self, context, composeService, timeout=1): + def connectToDeliverFunction(self, context, composeService, cert, nodeAdminTuple, timeout=1): 'Connect to the deliver function and drain messages to associated orderer queue' assert not composeService in self.abDeliversStreamHelperDict, "Already connected to deliver stream on {0}".format(composeService) - streamHelper = DeliverStreamHelper(self.getABStubForComposeService(context, composeService)) + streamHelper = DeliverStreamHelper(directory=self.directory, + ordererStub=self.getABStubForComposeService(context, composeService), + entity=self, nodeAdminTuple=nodeAdminTuple) self.abDeliversStreamHelperDict[composeService] = streamHelper return streamHelper diff --git a/bddtests/templates/html/graph.html b/bddtests/templates/html/graph.html index 81a26ec2da5..54f7050cb72 100644 --- a/bddtests/templates/html/graph.html +++ b/bddtests/templates/html/graph.html @@ -12,7 +12,7 @@
- +