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)