github.com/muhammedhassanm/blockchain@v0.0.0-20200120143007-697261defd4d/sawtooth-core-master/consensus/poet/cli/sawtooth_poet_cli/registration.py (about) 1 # Copyright 2017 Intel Corporation 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 from hashlib import sha512 16 from hashlib import sha256 17 import os 18 import time 19 20 from sawtooth_poet_cli import config 21 from sawtooth_poet_cli.exceptions import CliException 22 from sawtooth_poet_cli.poet_enclave_module_wrapper import \ 23 PoetEnclaveModuleWrapper 24 from sawtooth_poet.poet_consensus.signup_info import SignupInfo 25 from sawtooth_poet.poet_consensus.poet_key_state_store \ 26 import PoetKeyState 27 from sawtooth_poet.poet_consensus.poet_key_state_store \ 28 import PoetKeyStateStore 29 import sawtooth_poet_common.protobuf.validator_registry_pb2 as vr_pb 30 31 from sawtooth_signing import create_context 32 from sawtooth_signing import CryptoFactory 33 from sawtooth_signing import ParseError 34 from sawtooth_signing.secp256k1 import Secp256k1PrivateKey 35 36 from sawtooth_validator.journal.block_wrapper import NULL_BLOCK_IDENTIFIER 37 from sawtooth_validator.state.settings_view import SettingsView 38 39 try: 40 import sawtooth_validator.protobuf.transaction_pb2 as txn_pb 41 import sawtooth_validator.protobuf.batch_pb2 as batch_pb 42 except ImportError: 43 import sawtooth_sdk.protobuf.transaction_pb2 as txn_pb 44 import sawtooth_sdk.protobuf.batch_pb2 as batch_pb 45 46 47 VR_NAMESPACE = sha256('validator_registry'.encode()).hexdigest()[0:6] 48 VALIDATOR_MAP_ADDRESS = \ 49 VR_NAMESPACE + sha256('validator_map'.encode()).hexdigest() 50 51 52 def add_registration_parser(subparsers, parent_parser): 53 """Add argument parser arguments for the `poet registration` 54 subcommand 55 """ 56 description = 'Provides a subcommand for creating PoET registration' 57 58 parser = subparsers.add_parser( 59 'registration', 60 help=description, 61 description=description + '.') 62 63 registration_sub = parser.add_subparsers( 64 title='subcommands', dest='subcommand') 65 registration_sub.required = True 66 67 add_create_parser(registration_sub, parent_parser) 68 69 70 def add_create_parser(subparsers, parent_parser): 71 """Add argument parser arguments for the `poet registration create` 72 subcommand. 73 """ 74 description = \ 75 'Creates a batch to enroll a validator in the validator registry' 76 77 parser = subparsers.add_parser( 78 'create', 79 help=description, 80 description=description + '.') 81 82 parser.add_argument( 83 '--enclave-module', 84 default='simulator', 85 choices=['simulator', 'sgx'], 86 type=str, 87 help='configure the enclave module to use') 88 89 parser.add_argument( 90 '-k', '--key', 91 type=str, 92 help='identify file containing transaction signing key') 93 94 parser.add_argument( 95 '-o', '--output', 96 default='poet-genesis.batch', 97 type=str, 98 help='change default output file name for resulting batches') 99 100 parser.add_argument( 101 '-b', '--block', 102 default=NULL_BLOCK_IDENTIFIER, 103 type=str, 104 help='specify the most recent block identifier to use as ' 105 'a sign-up nonce') 106 107 108 def do_registration(args): 109 if args.subcommand == 'create': 110 do_create(args) 111 else: 112 raise AssertionError('Invalid command: {}'.format(args.subcommand)) 113 114 115 def do_create(args): 116 """Executes the `poet registration` subcommand. 117 118 This command generates a validator registry transaction and saves it to a 119 file, whose location is determined by the args. The signup data, generated 120 by the selected enclave, is also stored in a well-known location. 121 """ 122 signer = _read_signer(args.key) 123 public_key = signer.get_public_key().as_hex() 124 125 public_key_hash = sha256(public_key.encode()).hexdigest() 126 nonce = SignupInfo.block_id_to_nonce(args.block) 127 with PoetEnclaveModuleWrapper( 128 enclave_module=args.enclave_module, 129 config_dir=config.get_config_dir(), 130 data_dir=config.get_data_dir()) as poet_enclave_module: 131 signup_info = SignupInfo.create_signup_info( 132 poet_enclave_module=poet_enclave_module, 133 originator_public_key_hash=public_key_hash, 134 nonce=nonce) 135 136 print( 137 'Writing key state for PoET public key: {}...{}'.format( 138 signup_info.poet_public_key[:8], 139 signup_info.poet_public_key[-8:])) 140 141 # Store the newly-created PoET key state, associating it with its 142 # corresponding public key 143 poet_key_state_store = \ 144 PoetKeyStateStore( 145 data_dir=config.get_data_dir(), 146 validator_id=public_key) 147 poet_key_state_store[signup_info.poet_public_key] = \ 148 PoetKeyState( 149 sealed_signup_data=signup_info.sealed_signup_data, 150 has_been_refreshed=False, 151 signup_nonce=nonce) 152 153 # Create the validator registry payload 154 payload = \ 155 vr_pb.ValidatorRegistryPayload( 156 verb='register', 157 name='validator-{}'.format(public_key[:8]), 158 id=public_key, 159 signup_info=vr_pb.SignUpInfo( 160 poet_public_key=signup_info.poet_public_key, 161 proof_data=signup_info.proof_data, 162 anti_sybil_id=signup_info.anti_sybil_id, 163 nonce=SignupInfo.block_id_to_nonce(args.block))) 164 serialized = payload.SerializeToString() 165 166 # Create the address that will be used to look up this validator 167 # registry transaction. Seems like a potential for refactoring.. 168 validator_entry_address = \ 169 VR_NAMESPACE + sha256(public_key.encode()).hexdigest() 170 171 # Create a transaction header and transaction for the validator 172 # registry update amd then hand it off to the batch publisher to 173 # send out. 174 output_addresses = [validator_entry_address, VALIDATOR_MAP_ADDRESS] 175 input_addresses = \ 176 output_addresses + \ 177 [SettingsView.setting_address('sawtooth.poet.report_public_key_pem'), 178 SettingsView.setting_address('sawtooth.poet.' 179 'valid_enclave_measurements'), 180 SettingsView.setting_address('sawtooth.poet.valid_enclave_basenames')] 181 182 header = \ 183 txn_pb.TransactionHeader( 184 signer_public_key=public_key, 185 family_name='sawtooth_validator_registry', 186 family_version='1.0', 187 inputs=input_addresses, 188 outputs=output_addresses, 189 dependencies=[], 190 payload_sha512=sha512(serialized).hexdigest(), 191 batcher_public_key=public_key, 192 nonce=time.time().hex().encode()).SerializeToString() 193 signature = signer.sign(header) 194 195 transaction = \ 196 txn_pb.Transaction( 197 header=header, 198 payload=serialized, 199 header_signature=signature) 200 201 batch = _create_batch(signer, [transaction]) 202 batch_list = batch_pb.BatchList(batches=[batch]) 203 try: 204 print('Generating {}'.format(args.output)) 205 with open(args.output, 'wb') as batch_file: 206 batch_file.write(batch_list.SerializeToString()) 207 except IOError as e: 208 raise CliException('Unable to write to batch file: {}'.format(str(e))) 209 210 211 def _create_batch(signer, transactions): 212 """Creates a batch from a list of transactions and a signer, and signs 213 the resulting batch with the given signing key. 214 215 Args: 216 signer (:obj:`Signer`): Cryptographic signer to sign the batch 217 transactions (list of `Transaction`): The transactions to add to the 218 batch. 219 220 Returns: 221 `Batch`: The constructed and signed batch. 222 """ 223 txn_ids = [txn.header_signature for txn in transactions] 224 batch_header = batch_pb.BatchHeader( 225 signer_public_key=signer.get_public_key().as_hex(), 226 transaction_ids=txn_ids).SerializeToString() 227 228 return batch_pb.Batch( 229 header=batch_header, 230 header_signature=signer.sign(batch_header), 231 transactions=transactions) 232 233 234 def _read_signer(key_filename): 235 """Reads the given file as a hex key. 236 237 Args: 238 key_filename: The filename where the key is stored. If None, 239 defaults to the default key for the current user. 240 241 Returns: 242 Signer: the signer 243 244 Raises: 245 CliException: If unable to read the file. 246 """ 247 filename = key_filename 248 if filename is None: 249 filename = os.path.join(config.get_key_dir(), 'validator.priv') 250 251 try: 252 with open(filename, 'r') as key_file: 253 signing_key = key_file.read().strip() 254 except IOError as e: 255 raise CliException('Unable to read key file: {}'.format(str(e))) 256 257 try: 258 private_key = Secp256k1PrivateKey.from_hex(signing_key) 259 except ParseError as e: 260 raise CliException('Unable to read key in file: {}'.format(str(e))) 261 262 context = create_context('secp256k1') 263 crypto_factory = CryptoFactory(context) 264 return crypto_factory.new_signer(private_key)