コード例 #1
0
ファイル: test.py プロジェクト: cianx/sawtooth-core
    def setUp(self):
        self.dir = tempfile.mkdtemp()
        self.block_db = NativeLmdbDatabase(
            os.path.join(self.dir, 'block.lmdb'),
            BlockStore.create_index_configuration())
        self.block_store = BlockStore(self.block_db)
        self.block_manager = BlockManager()
        self.block_manager.add_commit_store(self.block_store)
        self.gossip = MockGossip()
        self.completer = Completer(
            block_manager=self.block_manager,
            transaction_committed=self.block_store.has_transaction,
            get_committed_batch_by_id=self.block_store.get_batch,
            get_committed_batch_by_txn_id=(
                self.block_store.get_batch_by_transaction
            ),
            get_chain_head=lambda: self.block_store.chain_head,
            gossip=self.gossip)
        self.completer.set_on_block_received(self._on_block_received)
        self.completer.set_on_batch_received(self._on_batch_received)
        self._has_block_value = True

        context = create_context('secp256k1')
        private_key = context.new_random_private_key()
        crypto_factory = CryptoFactory(context)
        self.signer = crypto_factory.new_signer(private_key)

        self.blocks = []
        self.batches = []
コード例 #2
0
    def __init__(self, delegate, args):
        super(IntKeyWorkload, self).__init__(delegate, args)
        self._auth_info = args.auth_info
        self._urls = []
        self._pending_batches = {}
        self._lock = threading.Lock()
        self._delegate = delegate
        self._deps = {}
        context = create_context('secp256k1')
        crypto_factory = CryptoFactory(context=context)
        if args.key_file is not None:
            try:
                with open(args.key_file, 'r') as infile:
                    signing_key = infile.read().strip()
                private_key = Secp256k1PrivateKey.from_hex(signing_key)

                self._signer = crypto_factory.new_signer(
                    private_key=private_key)
            except ParseError as pe:
                raise IntKeyCliException(str(pe))
            except IOError as ioe:
                raise IntKeyCliException(str(ioe))
        else:
            self._signer = crypto_factory.new_signer(
                context.new_random_private_key())
コード例 #3
0
ファイル: sawset.py プロジェクト: jjason/sawtooth-core
def _read_signer(key_filename):
    """Reads the given file as a hex key.

    Args:
        key_filename: The filename where the key is stored. If None,
            defaults to the default key for the current user.

    Returns:
        Signer: the signer

    Raises:
        CliException: If unable to read the file.
    """
    filename = key_filename
    if filename is None:
        filename = os.path.join(os.path.expanduser('~'),
                                '.sawtooth',
                                'keys',
                                getpass.getuser() + '.priv')

    try:
        with open(filename, 'r') as key_file:
            signing_key = key_file.read().strip()
    except IOError as e:
        raise CliException('Unable to read key file: {}'.format(str(e)))

    try:
        private_key = Secp256k1PrivateKey.from_hex(signing_key)
    except ParseError as e:
        raise CliException('Unable to read key in file: {}'.format(str(e)))

    context = create_context('secp256k1')
    crypto_factory = CryptoFactory(context)
    return crypto_factory.new_signer(private_key)
コード例 #4
0
def do_populate(batches, keys):
    context = create_context('secp256k1')
    private_key = context.new_random_private_key()
    crypto_factory = CryptoFactory(context)
    signer = crypto_factory.new_signer(private_key)

    total_txn_count = 0
    txns = []
    for i in range(0, len(keys)):
        name = list(keys)[i]
        txn = create_intkey_transaction(
            verb='set',
            name=name,
            value=random.randint(9000, 100000),
            deps=[],
            signer=signer)
        total_txn_count += 1
        txns.append(txn)
        # Establish the signature of the txn associated with the word
        # so we can create good dependencies later
        keys[name] = txn.header_signature

    batch = create_batch(
        transactions=txns,
        signer=signer)

    batches.append(batch)
コード例 #5
0
ファイル: tests.py プロジェクト: jjason/sawtooth-core
 def setUp(self):
     context = create_context('secp256k1')
     crypto_factory = CryptoFactory(context)
     private_key = context.new_random_private_key()
     self.signer = crypto_factory.new_signer(private_key)
     self._identity_view_factory = MockIdentityViewFactory()
     self.permissions = {}
     self._identity_cache = IdentityCache(
         self._identity_view_factory)
     self.permission_verifier = \
         PermissionVerifier(
             permissions=self.permissions,
             current_root_func=self._current_root_func,
             identity_cache=self._identity_cache)
コード例 #6
0
    def __init__(self, with_genesis=True):
        self.block_sender = MockBlockSender()
        self.batch_sender = MockBatchSender()
        self.dir = tempfile.mkdtemp()
        self.block_db = NativeLmdbDatabase(
            os.path.join(self.dir, 'block.lmdb'),
            BlockStore.create_index_configuration())
        self.block_store = BlockStore(self.block_db)
        self.block_cache = BlockCache(self.block_store)
        self.state_db = NativeLmdbDatabase(
            os.path.join(self.dir, "merkle.lmdb"),
            MerkleDatabase.create_index_configuration())

        self.state_view_factory = NativeStateViewFactory(self.state_db)

        self.block_manager = BlockManager()
        self.block_manager.add_commit_store(self.block_store)

        context = create_context('secp256k1')
        private_key = context.new_random_private_key()
        crypto_factory = CryptoFactory(context)
        self.signer = crypto_factory.new_signer(private_key)

        identity_private_key = context.new_random_private_key()
        self.identity_signer = crypto_factory.new_signer(identity_private_key)
        chain_head = None
        if with_genesis:
            self.genesis_block = self.generate_genesis_block()
            chain_head = self.genesis_block
            self.block_manager.put([chain_head.block])
            self.block_manager.persist(
                chain_head.block.header_signature,
                "commit_store")

        self.block_publisher = BlockPublisher(
            block_manager=self.block_manager,
            transaction_executor=MockTransactionExecutor(),
            transaction_committed=self.block_store.has_transaction,
            batch_committed=self.block_store.has_batch,
            state_view_factory=self.state_view_factory,
            block_sender=self.block_sender,
            batch_sender=self.block_sender,
            chain_head=chain_head.block,
            identity_signer=self.identity_signer,
            data_dir=None,
            config_dir=None,
            permission_verifier=MockPermissionVerifier(),
            batch_observers=[])
コード例 #7
0
    def __init__(self, base_url, keyfile, wait=None):
        """
        Member variables:
            _base_url
            _private_key
            _public_key
            _transaction_family
            _family_version
            _wait
        """
        self._base_url = base_url

        try:
            with open(keyfile) as fd:
                private_key_str = fd.read().strip()
        except OSError as err:
            raise IOError("Failed to read keys: {}.".format(str(err)))

        try:
            private_key = Secp256k1PrivateKey.from_hex(private_key_str)
        except ParseError as e:
            raise BattleshipException(
                'Unable to load private key: {}'.format(str(e)))

        self._signer = CryptoFactory(
            create_context('secp256k1')).new_signer(private_key)

        self._transaction_family = "battleship"
        self._family_version = "1.0"
        self._wait = wait
コード例 #8
0
ファイル: test.py プロジェクト: Whiteblock/sawtooth-core
    def setUp(self):
        self.block_store = BlockStore(DictDatabase(
            indexes=BlockStore.create_index_configuration()))
        self.gossip = MockGossip()
        self.completer = Completer(self.block_store, self.gossip)
        self.completer._on_block_received = self._on_block_received
        self.completer._on_batch_received = self._on_batch_received
        self.completer._has_block = self._has_block
        self._has_block_value = True

        context = create_context('secp256k1')
        private_key = context.new_random_private_key()
        crypto_factory = CryptoFactory(context)
        self.signer = crypto_factory.new_signer(private_key)

        self.blocks = []
        self.batches = []
コード例 #9
0
    def __init__(self, with_genesis=True):
        self.block_sender = MockBlockSender()
        self.batch_sender = MockBatchSender()
        self.block_store = BlockStore(DictDatabase(
            indexes=BlockStore.create_index_configuration()))
        self.block_cache = BlockCache(self.block_store)
        self.state_db = {}

        # add the mock reference to the consensus
        consensus_setting_addr = SettingsView.setting_address(
            'sawtooth.consensus.algorithm')
        self.state_db[consensus_setting_addr] = _setting_entry(
            'sawtooth.consensus.algorithm', 'test_journal.mock_consensus')

        self.state_view_factory = MockStateViewFactory(self.state_db)
        context = create_context('secp256k1')
        private_key = context.new_random_private_key()
        crypto_factory = CryptoFactory(context)
        self.signer = crypto_factory.new_signer(private_key)

        identity_private_key = context.new_random_private_key()
        self.identity_signer = crypto_factory.new_signer(identity_private_key)
        chain_head = None
        if with_genesis:
            self.genesis_block = self.generate_genesis_block()
            self.set_chain_head(self.genesis_block)
            chain_head = self.genesis_block

        self.block_publisher = BlockPublisher(
            transaction_executor=MockTransactionExecutor(),
            block_cache=self.block_cache,
            state_view_factory=self.state_view_factory,
            settings_cache=SettingsCache(
                SettingsViewFactory(self.state_view_factory),
            ),
            block_sender=self.block_sender,
            batch_sender=self.block_sender,
            squash_handler=None,
            chain_head=chain_head,
            identity_signer=self.identity_signer,
            data_dir=None,
            config_dir=None,
            permission_verifier=MockPermissionVerifier(),
            check_publish_block_frequency=0.1,
            batch_observers=[])
コード例 #10
0
async def create_account(request):
    """Creates a new Account and corresponding authorization token"""
    required_fields = ['email', 'password']
    common.validate_fields(required_fields, request.json)

    private_key = request.app.config.CONTEXT.new_random_private_key()
    signer = CryptoFactory(request.app.config.CONTEXT).new_signer(private_key)
    public_key = signer.get_public_key().as_hex()

    auth_entry = _create_auth_dict(
        request, public_key, private_key.as_hex())
    await auth_query.create_auth_entry(request.app.config.DB_CONN, auth_entry)

    account = _create_account_dict(request.json, public_key)

    batches, batch_id = transaction_creation.create_account(
        txn_key=signer,
        batch_key=request.app.config.SIGNER,
        label=account.get('label'),
        description=account.get('description'))

    await messaging.send(
        request.app.config.VAL_CONN,
        request.app.config.TIMEOUT,
        batches)

    try:
        await messaging.check_batch_status(
            request.app.config.VAL_CONN, batch_id)
    except (ApiBadRequest, ApiInternalError) as err:
        await auth_query.remove_auth_entry(
            request.app.config.DB_CONN, request.json.get('email'))
        raise err

    token = common.generate_auth_token(
        request.app.config.SECRET_KEY,
        account.get('email'),
        public_key)

    return response.json(
        {
            'authorization': token,
            'account': account
        })
コード例 #11
0
def do_generate(args, batches, keys):
    context = create_context('secp256k1')
    private_key = context.new_random_private_key()
    crypto_factory = CryptoFactory(context)
    signer = crypto_factory.new_signer(private_key)

    start = time.time()
    total_txn_count = 0
    for i in range(0, args.count):
        txns = []
        for _ in range(0, random.randint(1, args.max_batch_size)):
            name = random.choice(list(keys))
            txn = create_intkey_transaction(
                verb=random.choice(['inc', 'dec']),
                name=name,
                value=random.randint(1, 10),
                deps=[keys[name]],
                signer=signer)
            total_txn_count += 1
            txns.append(txn)

        batch = create_batch(
            transactions=txns,
            signer=signer)

        batches.append(batch)

        if i % 100 == 0 and i != 0:
            stop = time.time()

            txn_count = 0
            for batch in batches[-100:]:
                txn_count += len(batch.transactions)

            fmt = 'batches {}, batch/sec: {:.2f}, txns: {}, txns/sec: {:.2f}'
            print(fmt.format(
                str(i),
                100 / (stop - start),
                str(total_txn_count),
                txn_count / (stop - start)))
            start = stop
コード例 #12
0
ファイル: test.py プロジェクト: jjason/sawtooth-core
    def test_authorization_challenge_submit_bad_signature(self):
        """
        Test the AuthorizationChallengeSubmitHandler returns an
        AuthorizationViolation and closes the connection if the signature
        is not verified.
        """
        context = create_context('secp256k1')
        private_key = context.new_random_private_key()
        crypto_factory = CryptoFactory(context)
        signer = crypto_factory.new_signer(private_key)

        payload = os.urandom(10)

        signature = signer.sign(payload)

        auth_challenge_submit = AuthorizationChallengeSubmit(
            public_key="other",
            signature=signature,
            roles=[RoleType.Value("NETWORK")])

        roles = {"network": AuthorizationType.TRUST}

        network = MockNetwork(
            roles,
            connection_status={
                "connection_id": ConnectionStatus.AUTH_CHALLENGE_REQUEST
            })
        permission_verifer = MockPermissionVerifier()
        gossip = MockGossip()
        handler = AuthorizationChallengeSubmitHandler(
            network, permission_verifer, gossip, {"connection_id": payload})
        handler_status = handler.handle(
            "connection_id",
            auth_challenge_submit.SerializeToString())
        self.assertEqual(handler_status.status, HandlerStatus.RETURN_AND_CLOSE)
        self.assertEqual(
            handler_status.message_type,
            validator_pb2.Message.AUTHORIZATION_VIOLATION)
コード例 #13
0
ファイル: keys.py プロジェクト: Whiteblock/sawtooth-core
def load_identity_signer(key_dir, key_name):
    """Loads a private key from the key directory, based on a validator's
    identity.

    Args:
        key_dir (str): The path to the key directory.
        key_name (str): The name of the key to load.

    Returns:
        Signer: the cryptographic signer for the key
    """
    key_path = os.path.join(key_dir, '{}.priv'.format(key_name))

    if not os.path.exists(key_path):
        raise LocalConfigurationError(
            "No such signing key file: {}".format(key_path))
    if not os.access(key_path, os.R_OK):
        raise LocalConfigurationError(
            "Key file is not readable: {}".format(key_path))

    LOGGER.info('Loading signing key: %s', key_path)
    try:
        with open(key_path, 'r') as key_file:
            private_key_str = key_file.read().strip()
    except IOError as e:
        raise LocalConfigurationError(
            "Could not load key file: {}".format(str(e)))

    try:
        private_key = Secp256k1PrivateKey.from_hex(private_key_str)
    except signing.ParseError as e:
        raise LocalConfigurationError(
            "Invalid key in file {}: {}".format(key_path, str(e)))

    context = signing.create_context('secp256k1')
    crypto_factory = CryptoFactory(context)
    return crypto_factory.new_signer(private_key)
コード例 #14
0
ファイル: tests.py プロジェクト: Whiteblock/sawtooth-core
def create_chain(num=10):
    context = create_context('secp256k1')
    private_key = context.new_random_private_key()
    crypto_factory = CryptoFactory(context)
    signer = crypto_factory.new_signer(private_key)

    counter = 1
    previous_block_id = "0000000000000000"
    blocks = []
    while counter <= num:
        current_block_id = uuid4().hex
        txns = [
            t[0]
            for t in [
                create_transaction(
                    payload=uuid4().hex.encode(), signer=signer)
                for _ in range(20)
            ]
        ]

        txn_ids = [t.header_signature for t in txns]
        batch = create_batch(
            transactions=txns,
            signer=signer)

        blk_w = create_block(
            counter,
            previous_block_id,
            current_block_id,
            batches=[batch])
        blocks.append((current_block_id, blk_w, txn_ids))

        counter += 1
        previous_block_id = current_block_id

    return blocks
コード例 #15
0
ファイル: intkey_client.py プロジェクト: cianx/sawtooth-core
    def __init__(self, url, keyfile=None):
        self.url = url

        if keyfile is not None:
            try:
                with open(keyfile) as fd:
                    private_key_str = fd.read().strip()
                    fd.close()
            except OSError as err:
                raise IntkeyClientException(
                    'Failed to read private key: {}'.format(str(err)))

            try:
                private_key = Secp256k1PrivateKey.from_hex(private_key_str)
            except ParseError as e:
                raise IntkeyClientException(
                    'Unable to load private key: {}'.format(str(e)))

            self._signer = CryptoFactory(
                create_context('secp256k1')).new_signer(private_key)
コード例 #16
0
    def __init__(self, file_name):
        """

        Args:
            file_name (str): The yaml filename and path.
            scheduler (scheduler.Scheduler): Any Scheduler implementaion
            context_manager (context_manager.ContextManager): The context
                manager holding state for this scheduler.
        """
        self._context = create_context('secp256k1')
        self._crypto_factory = CryptoFactory(self._context)
        self._yaml_file_name = file_name
        self._counter = itertools.count(0)
        self._referenced_txns_in_other_batches = {}
        self._batch_id_by_txn_id = {}
        self._txn_execution = {}

        self._batch_results = {}
        self._batches = []

        self._create_batches()
コード例 #17
0
    def __init__(self, name, rest_endpoint):
        """
        Args:
            name (str): An identifier for this Transactor
            rest_endpoint (str): The rest api that this Transactor will
                communicate with.
        """

        self.name = name
        self._rest_endpoint = rest_endpoint \
            if rest_endpoint.startswith("http://") \
            else "http://{}".format(rest_endpoint)
        with open('/root/.sawtooth/keys/{}.priv'.format(name)) as priv_file:
            private_key = Secp256k1PrivateKey.from_hex(
                priv_file.read().strip('\n'))
        self._signer = CryptoFactory(create_context('secp256k1')) \
            .new_signer(private_key)
        self._factories = {}
        self._client = RestClient(url=self._rest_endpoint)

        self._add_transaction_family_factory(Families.INTKEY)
        self._add_transaction_family_factory(Families.XO)
コード例 #18
0
ファイル: xo_client.py プロジェクト: Whiteblock/sawtooth-core
    def __init__(self, base_url, keyfile=None):

        self._base_url = base_url

        if keyfile is None:
            self._signer = None
            return

        try:
            with open(keyfile) as fd:
                private_key_str = fd.read().strip()
        except OSError as err:
            raise XoException(
                'Failed to read private key {}: {}'.format(
                    keyfile, str(err)))

        try:
            private_key = Secp256k1PrivateKey.from_hex(private_key_str)
        except ParseError as e:
            raise XoException(
                'Unable to load private key: {}'.format(str(e)))

        self._signer = CryptoFactory(create_context('secp256k1')) \
            .new_signer(private_key)
コード例 #19
0
ファイル: code_smell_client.py プロジェクト: obahy/Susereum
class CodeSmellClient:
    """
    construct and send code smell transaction.
    """
    def __init__(self, base_url, work_path, keyfile=None):
        self._base_url = base_url
        self._work_path = work_path

        if keyfile is None:
            self._signer = None
            return

        try:
            with open(keyfile) as fileptr:
                private_key_str = fileptr.read().strip()
        except OSError as err:
            raise CodeSmellException(
                'Failed to read private key {}: {}'.format(keyfile, str(err)))

        try:
            private_key = Secp256k1PrivateKey.from_hex(private_key_str)
        except ParseError as error:
            raise CodeSmellException('Unable to load private key: {}'.format(
                str(error)))

        self._signer = CryptoFactory(
            create_context('secp256k1')).new_signer(private_key)

    def default(self, repo_id=None):
        """
        load a defautl code smell configuration
        """

        #identify code_smell family configuration file
        conf_file = self._work_path + '/etc/.suse'
        response = ""

        #get date
        txn_date = _get_date()
        #return txn_date

        if os.path.isfile(conf_file):
            try:
                with open(conf_file) as config:
                    raw_config = config.read()
            except IOError as error:
                raise CodeSmellException(
                    "Unable to load code smell family configuration file: {}".
                    format(error))

            #load toml config into a dict
            parsed_toml_config = toml.loads(raw_config)

            #get default code smells
            code_smells_config = parsed_toml_config['code_smells']
            """traverse dict and process each code smell
                nested for loop to procces level two dict."""
            for code_smells in code_smells_config.values():
                for name, metric in code_smells.items():
                    #send trasaction
                    response = self._send_code_smell_txn(
                        txn_type='code_smell',
                        txn_id=name,
                        data=str(metric[0]),  ## TODO: add weigth value
                        state='create',
                        date=txn_date)

            code_smells_config = parsed_toml_config['vote_setting']
            """traverse dict and process each code smell
                nested for loop to procces level two dict."""
            for name, metric in code_smells_config.items():
                #send transaction
                response = self._send_code_smell_txn(txn_type='code_smell',
                                                     txn_id=name,
                                                     data=str(metric),
                                                     state='create',
                                                     date=txn_date)
        else:
            raise CodeSmellException(
                "Configuration File {} does not exists".format(conf_file))

        #send configuration file to all peers
        self._publish_config(conf_file=conf_file)

        #send new config to github
        suse_config = _get_suse_config(conf_file)
        self._send_git_request(suse_config, repo_id)

        return response

    def list(self, txn_type=None, active=None):
        """
        list all transactions.

        Args:
            type (str), asset that we want to list (code smells, proposals, votes)
        """
        #pull all transactions of code smell family
        result = self._send_request("transactions")

        transactions = {}
        try:
            proposal_info = " "
            encoded_entries = yaml.safe_load(result)["data"]
            if txn_type is None:
                for entry in encoded_entries:
                    transactions[entry["header_signature"]] = base64.b64decode(
                        entry["payload"])
            else:
                for entry in encoded_entries:
                    #if the transaction does not have the expected format ignore it
                    try:
                        transaction_type = base64.b64decode(
                            entry["payload"]).decode().split(',')[0]
                        if transaction_type == txn_type:
                            if txn_type == "proposal" and active is not None:
                                status = base64.b64decode(
                                    entry["payload"]).decode().split(',')[3]
                                if status == "active":
                                    transactions[entry[
                                        "header_signature"]] = base64.b64decode(
                                            entry["payload"])
                                    p_date = base64.b64decode(
                                        entry["payload"]).decode().split(
                                            ',')[4]
                                    proposal_info = entry[
                                        "header_signature"] + " " + p_date
                                break
                            else:
                                transactions[entry[
                                    "header_signature"]] = base64.b64decode(
                                        entry["payload"])
                    except:
                        pass
            if proposal_info != " ":
                return proposal_info
            else:
                return transactions
        except BaseException:
            return None

    def show(self, address):
        """
        list a specific transaction, based on its address

        Args:
            address (str), transaction's address
        """
        result = self._send_request("transactions/{}".format(address))

        transactions = {}
        try:
            encoded_entries = yaml.safe_load(result)["data"]
            transactions["payload"] = base64.b64decode(
                encoded_entries["payload"])
            transactions["header_signature"] = encoded_entries[
                "header_signature"]
            return transactions
        except BaseException:
            return None

    def propose(self, code_smells):
        """
        propose new metrics for the code smell families
        the function assumes that all code smells have been updated even if they don't

        Args:
            code_smells (dict), dictionary of code smells and metrics
        """
        #get code smell family address prefix
        code_smell_prefix = self._get_prefix()

        #check for an active proposal, transactions are return in sequential order.
        proposal_result = self._send_request(
            "state?address={}".format(code_smell_prefix))
        encoded_entries = yaml.safe_load(proposal_result)["data"]
        print(encoded_entries)
        try:
            for entry in encoded_entries:
                print(base64.b64decode(entry["data"]).decode().split(',')[0])
                #look for the first proposal transactiosn
                if base64.b64decode(
                        entry["data"]).decode().split(',')[0] == "proposal":
                    last_proposal = base64.b64decode(
                        entry["data"]).decode().split(',')
                    break
            print(last_proposal)
        #try:
        #if last_proposal[3] == "active":
        #    return "Invalid Operation, another proposal is Active"
        except BaseException:
            pass

        #get date
        propose_date = _get_date()

        #send transaction
        response = self._send_code_smell_txn(
            txn_id=_sha512(str(code_smells).encode('utf-8'))[0:6],
            txn_type='proposal',
            data=str(code_smells).replace(",", ";"),
            state='active',
            date=propose_date)

        return response

    def update_proposal(self, proposal_id, state, repo_id):
        """
        update proposal state

        Args:
            proposal_id (str), proposal ID
            state (Str), new proposal ID
        """
        proposal = self.show(proposal_id)

        if state == 1:
            state = "Accepted"
        else:
            state = "Rejected"

        self._update_proposal(proposal, state, repo_id)

    def _update_proposal(self, proposal, state, repo_id):
        """
        update proposal, update state.
        proposal state 1 = accepeted, 0 = rejected

        Args:
            proposal (dict), proposal data
            sate (str), new proposal's state
        """
        conf_file = self._work_path + 'etc/.suse'
        txn_date = _get_date()
        proposal = proposal["payload"].decode().split(',')

        response = self._send_code_smell_txn(txn_id=proposal[1],
                                             txn_type='proposal',
                                             data=proposal[2],
                                             state=str(state),
                                             date=txn_date)

        print(response)

        if state == "Accepted":
            #update suse configuration file
            self._update_suse_file(proposal)

            #send new config to github
            suse_config = _get_suse_config(conf_file)
            self._send_git_request(suse_config, repo_id)

    def _send_git_request(self, toml_config, repo_id=None):
        """
        send new code smell configuration to github

        Args:
            toml_config (dict): code smells to send
        """
        wrapper_json = {}
        wrapper_json["sender"] = "Sawtooth"
        wrapper_json["repo"] = repo_id
        wrapper_json["suse_file"] = toml_config
        data = json.dumps(wrapper_json)
        requests.post('http://129.108.7.2:3000', data=data)

    def _update_suse_file(self, proposal):
        """
        update code smell configuration metrics, after the proposal is accepted
        the configuration file needs to be updated.

        Args:
            toml_config (dict), current configuration
            proposal (str), proposal that contains new configuration
        """
        #get proposal payload
        proposal_payload = yaml.safe_load(proposal[2].replace(";", ","))

        #identify code_smell family configuration file
        conf_file = self._work_path + '/etc/.suse'

        print(self._work_path)

        #get current config
        suse_config = _get_suse_config(conf_file)
        """
        start by traversing the proposal,
        get the code smell and the metric
        """
        try:
            for proposal_key, proposal_metric in proposal_payload.items():
                tmp_type = ""
                """
                we don't know where on the toml file is the code smell,
                traverse the toml dictionary looking for the same code smell.
                """
                for code_type in suse_config["code_smells"]:
                    """
                    once you found the code smell, break the loop and return
                    a pseudo location
                    """
                    if proposal_key in suse_config["code_smells"][
                            code_type].keys():
                        tmp_type = code_type
                        break
                #update code smell metric
                if proposal_key == "CommentsToCodeRatioLower" or proposal_key == "CommentsToCodeRatioUpper":
                    suse_config["code_smells"][tmp_type][proposal_key][
                        0] = float(proposal_metric)
                else:
                    suse_config["code_smells"][tmp_type][proposal_key][
                        0] = int(proposal_metric)

            #save new configuration
            try:
                with open(conf_file, 'w+') as config:
                    toml.dump(suse_config, config)
                #self._send_git_request(toml_config)
            except IOError as error:
                raise CodeSmellException(
                    "Unable to open configuration file {}".format(error))

            #publish new configuration file to all peers
            self._publish_config(conf_file=conf_file)
        except:
            raise CodeSmellException("Incorrect proposal format")

    def check_votes(self, proposal_id):
        """
        review the votes of a proposal

        Args:
            proposal_id (str), proposal id
        """
        #print(self._base_url)
        result = self._send_request("transactions/{}".format(proposal_id))
        #print (proposal_id)
        #print ("print"+result)
        encoded_result = yaml.safe_load(result)["data"]
        proposal = base64.b64decode(
            encoded_result["payload"]).decode().split(',')
        proposal_id = proposal[1]
        transactions = self.list(txn_type='vote')
        votes = []
        if not transactions:
            return ""
        for vote in transactions:
            #for all votes of proposal
            if transactions[vote].decode().split(',')[2] == proposal_id:
                votes.append(int(transactions[vote].decode().split(',')[3]))
        return votes

    def vote(self, proposal_id, vote):
        """
        vote to accept or reject a proposal

        Args:
            proposal_id (str), id of proposal
            vote (int), value of vote 1=accept, 0=reject
        """

        #verify active proposal
        result = self._send_request("transactions/{}".format(proposal_id))
        encoded_result = yaml.safe_load(result)["data"]
        proposal = base64.b64decode(
            encoded_result["payload"]).decode().split(',')
        if proposal[3] != 'active':
            return "Proposal not active"

        #The condition to only one vote will be handle from the GUI.
        #leaving this logic for future reference
        #verify double voting
        # proposal_id = proposal[1]
        # result = self._send_request("transactions")
        # encoded_entries = yaml.safe_load(result)["data"]
        # for entry in encoded_entries:
        #     transaction_type = base64.b64decode(entry["payload"]).decode().split(',')[0]
        #     if transaction_type == 'vote':
        #         if entry['header']['signer_public_key'] == self._signer.get_public_key().as_hex():
        #             return ("User already submitted a vote")
        txn_date = _get_date()

        #active proposal, record vote
        response = self._send_code_smell_txn(txn_id=str(
            random.randrange(1, 99999)),
                                             txn_type='vote',
                                             data=proposal[1],
                                             state=str(vote),
                                             date=txn_date)

        return response

    def _publish_config(self, conf_file=None):
        """
        function to send an update configuration transaction to the chain
        after the code smell configuration is updated all peers in the network
        must update the local configuration file.

        Args:
            config (dictionary), code smell configuration
        """
        #read .suse configuration file
        suse_config = _get_suse_config(conf_file)

        #get current time
        txn_date = _get_date()

        self._send_code_smell_txn(txn_id=str(random.randrange(1, 99999)),
                                  txn_type='config',
                                  data=str(suse_config).replace(",", ";"),
                                  state='update',
                                  date=txn_date)

    def _get_prefix(self):
        """
        get code smell family address prefix
        """
        return _sha512('code-smell'.encode('utf-8'))[0:6]

    def _get_address(self, transaction_id):
        """
        get transaction address

        Args:
            id (str): trasaction id
        """
        code_smell_prefix = self._get_prefix()
        code_smell_address = _sha512(transaction_id.encode('utf-8'))[0:64]
        return code_smell_prefix + code_smell_address

    def _send_request(self,
                      suffix,
                      data=None,
                      content_type=None,
                      auth_user=None,
                      auth_password=None):
        """
        send request to code smell processor
        the transaction will be validate by the processor of each family.
        """
        if self._base_url.startswith("http://"):
            url = "{}/{}".format(self._base_url, suffix)
        else:
            url = "http://{}/{}".format(self._base_url, suffix)

        headers = {}
        if auth_user is not None:
            auth_string = "{}:{}".format(auth_user, auth_password)
            b64_string = b64encode(auth_string.encode()).decode()
            auth_header = 'Basic {}'.format(b64_string)
            headers['authorization'] = auth_header

        if content_type is not None:
            headers['Content-Type'] = content_type

        try:
            if data is not None:
                result = requests.post(url, headers=headers, data=data)
            else:
                result = requests.get(url, headers=headers)

            if result.status_code == 404:
                raise CodeSmellException("No such transaction")
            elif not result.ok:
                raise CodeSmellException("Error {}:{}".format(
                    result.status_code, result.reason))

        except requests.ConnectionError as err:
            raise CodeSmellException('Failed to connect to {}:{}'.format(
                url, str(err)))

        except BaseException as err:
            raise CodeSmellException(err)

        return result.text

    def _send_code_smell_txn(self,
                             txn_type=None,
                             txn_id=None,
                             data=None,
                             state=None,
                             date=None):
        """
        serialize payload and create header transaction

        Args:
            type (str):    type of transaction
            id (str):      asset id, will depend on type of transaction
            data (object): transaction data
            state (str):   all transactions must have a state
            wait (int):    delay to process transactions
        """
        #serialization is just a delimited utf-8 encoded strings
        if txn_type in ('proposal', 'config', 'code_smell', 'vote'):
            payload = ",".join([txn_type, txn_id, data, state,
                                str(date)]).encode()
        else:
            payload = ",".join([txn_type, txn_id, data, state]).encode()

        #pprint("payload: {}".format(payload))

        #construct the address
        address = self._get_address(txn_id)

        #construct header`
        header = TransactionHeader(
            signer_public_key=self._signer.get_public_key().as_hex(),
            family_name="code-smell",
            family_version="0.1",
            inputs=[address],
            outputs=[address],
            dependencies=[],
            payload_sha512=_sha512(payload),
            batcher_public_key=self._signer.get_public_key().as_hex(),
            nonce=hex(random.randint(0, 2**64))).SerializeToString()

        signature = self._signer.sign(header)

        #create transaction
        transaction = Transaction(header=header,
                                  payload=payload,
                                  header_signature=signature)

        #create batch list, suserum policy: one transaction per batch
        batch_list = self._create_batch_list([transaction])

        return self._send_request("batches", batch_list.SerializeToString(),
                                  'application/octet-stream')

    def _create_batch_list(self, transactions):
        """
        Create the list of batches that the client will send to the REST API

        Args:
            transactions (transaction): transaction(s) included in the batch

        Returns:
            BatchList: a list of batches to send to the REST API
        """
        transaction_signatures = [t.header_signature for t in transactions]

        header = BatchHeader(
            signer_public_key=self._signer.get_public_key().as_hex(),
            transaction_ids=transaction_signatures).SerializeToString()

        signature = self._signer.sign(header)

        batch = Batch(header=header,
                      transactions=transactions,
                      header_signature=signature)

        return BatchList(batches=[batch])
コード例 #20
0
class SimpleWalletClient(object):
    '''Client simple wallet class.

    This supports deposit, withdraw, transfer, and balance functions.
    '''
    def __init__(self, baseUrl, keyFile=None):
        '''Initialize the client class.

           This is mainly getting the key pair and computing the address.
        '''

        self._baseUrl = baseUrl

        if keyFile is None:
            self._signer = None
            return

        try:
            with open(keyFile) as fd:
                privateKeyStr = fd.read().strip()
        except OSError as err:
            raise Exception('Failed to read private key {}: {}'.format(
                keyFile, str(err)))

        try:
            privateKey = Secp256k1PrivateKey.from_hex(privateKeyStr)
        except ParseError as err:
            raise Exception('Failed to load private key: {}'.format(str(err)))

        self._signer = CryptoFactory(create_context('secp256k1')) \
            .new_signer(privateKey)

        self._publicKey = self._signer.get_public_key().as_hex()

        self._address = _hash(FAMILY_NAME.encode('utf-8'))[0:6] + \
            _hash(self._publicKey.encode('utf-8'))[0:64]

    # For each valid cli command in _cli.py file,
    # add methods to:
    # 1. Do any additional handling, if required
    # 2. Create a transaction and a batch
    # 2. Send to rest-api
    def deposit(self, value):
        return self._wrap_and_send("deposit", value)

    def withdraw(self, value):
        try:
            retValue = self._wrap_and_send("withdraw", value)
        except Exception:
            raise Exception('Encountered an error during withdrawal')
        return retValue

    def make_driver(self, value):
        try:
            retValue = self._wrap_and_send("makeDriver", value)
        except Exception:
            raise Exception('Encountered an error during make driver')
        return retValue

    def transfer(self, value, clientToKey):
        try:
            with open(clientToKey) as fd:
                publicKeyStr = fd.read().strip()
            retValue = self._wrap_and_send("transfer", value, publicKeyStr)
        except OSError as err:
            raise Exception('Failed to read public key {}: {}'.format(
                clientToKey, str(err)))
        except Exception as err:
            raise Exception('Encountered an error during transfer', err)
        return retValue

    def balance(self):
        result = self._send_to_restapi("state/{}".format(self._address))
        try:
            return base64.b64decode(yaml.safe_load(result)["data"])

        except BaseException:
            return None

    def _send_to_restapi(self, suffix, data=None, contentType=None):
        '''Send a REST command to the Validator via the REST API.'''

        if self._baseUrl.startswith("http://"):
            url = "{}/{}".format(self._baseUrl, suffix)
        else:
            url = "http://{}/{}".format(self._baseUrl, suffix)

        headers = {}

        if contentType is not None:
            headers['Content-Type'] = contentType

        try:
            if data is not None:
                result = requests.post(url, headers=headers, data=data)
            else:
                result = requests.get(url, headers=headers)

            if not result.ok:
                raise Exception("Error {}: {}".format(result.status_code,
                                                      result.reason))

        except requests.ConnectionError as err:
            raise Exception('Failed to connect to {}: {}'.format(
                url, str(err)))

        except BaseException as err:
            raise Exception(err)

        return result.text

    def _wrap_and_send(self, action, *values):
        '''Create a transaction, then wrap it in a batch.     
                                                              
           Even single transactions must be wrapped into a batch.
        '''

        # Generate a csv utf-8 encoded string as payload
        rawPayload = action

        for val in values:
            rawPayload = ",".join([rawPayload, str(val)])

        payload = rawPayload.encode()

        # Construct the address where we'll store our state
        address = self._address
        inputAddressList = [address]
        outputAddressList = [address]

        if "transfer" == action:
            toAddress = _hash(FAMILY_NAME.encode('utf-8'))[0:6] + \
            _hash(values[1].encode('utf-8'))[0:64]
            inputAddressList.append(toAddress)
            outputAddressList.append(toAddress)

        # Create a TransactionHeader
        header = TransactionHeader(
            signer_public_key=self._publicKey,
            family_name=FAMILY_NAME,
            family_version="1.0",
            inputs=inputAddressList,
            outputs=outputAddressList,
            dependencies=[],
            payload_sha512=_hash(payload),
            batcher_public_key=self._publicKey,
            nonce=random.random().hex().encode()).SerializeToString()

        # Create a Transaction from the header and payload above
        transaction = Transaction(header=header,
                                  payload=payload,
                                  header_signature=self._signer.sign(header))

        transactionList = [transaction]

        # Create a BatchHeader from transactionList above
        header = BatchHeader(
            signer_public_key=self._publicKey,
            transaction_ids=[txn.header_signature
                             for txn in transactionList]).SerializeToString()

        #Create Batch using the BatchHeader and transactionList above
        batch = Batch(header=header,
                      transactions=transactionList,
                      header_signature=self._signer.sign(header))

        #Create a Batch List from Batch above
        batch_list = BatchList(batches=[batch])

        # Send batch_list to rest-api
        return self._send_to_restapi("batches", batch_list.SerializeToString(),
                                     'application/octet-stream')
    def test_block_publisher_doesnt_finalize_block(
            self,
            mock_utils,
            mock_validator_registry_view,
            mock_consensus_state,
            mock_poet_enclave_factory,
            mock_consensus_state_store,
            mock_poet_key_state_store,
            mock_signup_info,
            mock_wait_certificate,
            mock_poet_settings_view,
            mock_block_wrapper):
        """ Test verifies that PoET Block Publisher doesn't finalize
            a candidate block that doesn't have a valid wait certificate.
        """

        # create a mock_validator_registry_view with
        # get_validator_info that does nothing
        mock_validator_registry_view.return_value.get_validator_info. \
            return_value = \
            ValidatorInfo(
                name='validator_001',
                id='validator_deadbeef',
                signup_info=SignUpInfo(
                    poet_public_key='00112233445566778899aabbccddeeff'))

        # create a mock_wait_certificate that pretends to fail
        mock_wait_certificate.create_wait_certificate.side_effect = \
            ValueError('Unit test fake failure')

        # create a mock_consensus_state that returns a mock with
        # the following settings:
        mock_state = MockConsensusState().create_mock_consensus_state()

        mock_consensus_state.consensus_state_for_block_id.return_value = \
            mock_state

        # create mock_batch_publisher
        context = create_context('secp256k1')
        private_key = context.new_random_private_key()
        crypto_factory = CryptoFactory(context)
        signer = crypto_factory.new_signer(private_key)
        mock_batch_publisher = mock.Mock(
            identity_signer=signer)

        mock_block_cache = mock.MagicMock()
        mock_state_view_factory = mock.Mock()

        # create mock_block_header with the following fields
        mock_block = mock.Mock(identifier='0123456789abcdefedcba9876543210')
        mock_block.header.signer_public_key = \
            '90834587139405781349807435098745'
        mock_block.header.previous_block_id = '2'
        mock_block.header.block_num = 1
        mock_block.header.state_root_hash = '6'
        mock_block.header.batch_ids = '4'

        # check test
        with mock.patch('sawtooth_poet.poet_consensus.poet_block_publisher.'
                        'LOGGER') as mock_logger:
            block_publisher = \
                poet_block_publisher.PoetBlockPublisher(
                    block_cache=mock_block_cache,
                    state_view_factory=mock_state_view_factory,
                    batch_publisher=mock_batch_publisher,
                    data_dir=self._temp_dir,
                    config_dir=self._temp_dir,
                    validator_id='validator_deadbeef')

            with mock.patch('sawtooth_poet.poet_consensus.'
                            'poet_block_publisher.json') as _:
                self.assertFalse(
                    block_publisher.finalize_block(
                        block_header=mock_block.header))

            # Could be a hack, but verify that the appropriate log message is
            # generated - so we at least have some faith that the failure was
            # because of what we are testing and not something else.  I know
            # that this is fragile if the log message is changed, so would
            # accept any suggestions on a better way to verify that the
            # function fails for the reason we expect.

            (message, *_), _ = mock_logger.error.call_args
            self.assertTrue('Failed to create wait certificate: '
                            in message)
コード例 #22
0
import agpayload_pb2
import enums_pb2
from hashlib import sha512
from sawtooth_sdk.protobuf.transaction_pb2 import TransactionHeader
from sawtooth_sdk.protobuf.transaction_pb2 import Transaction
from sawtooth_sdk.protobuf.batch_pb2 import BatchHeader,Batch,BatchList
from sawtooth_signing import create_context
from sawtooth_signing import CryptoFactory
import urllib.request
from urllib.error import HTTPError
import addresser


context = create_context('secp256k1')
private_key = context.new_random_private_key()
signer = CryptoFactory(context).new_signer(private_key)
public_key = signer.get_public_key().as_hex()
payload = agpayload_pb2.Realpayload()
payload.Action = agpayload_pb2.action.Value('register_farmer')
payload.reg_far.aadhar_card = 'dfv98fsdff98s83'
payload.reg_far.timestamp = 12242343
payload.reg_far.full_name  = 'Bro Code'
payload.reg_far.otp = 1234
payload.reg_far.State = enums_pb2.state.Value('Gujarat')
payload.reg_far.pincode = 123456
payload.reg_far.mobilenumber = 9999999999
payload.reg_far.district = 'sachin'
input = [addresser.get_farmer_address(public_key),addresser.get_otp_address(9999999999,1234)]

print(input)
payload_bytes = payload.SerializeToString()
コード例 #23
0
 def __init__(self, validator_url):
     self._connection = Connection(validator_url)
     self._context = create_context('secp256k1')
     self._crypto_factory = CryptoFactory(self._context)
     self._batch_signer = self._crypto_factory.new_signer(
         self._context.new_random_private_key())
コード例 #24
0
class BattleshipClient:

    def __init__(self, base_url, keyfile, wait=None):
        """
        Member variables:
            _base_url
            _private_key
            _public_key
            _transaction_family
            _family_version
            _wait
        """
        self._base_url = base_url

        try:
            with open(keyfile) as fd:
                private_key_str = fd.read().strip()
        except OSError as err:
            raise IOError("Failed to read keys: {}.".format(str(err)))

        try:
            private_key = Secp256k1PrivateKey.from_hex(private_key_str)
        except ParseError as e:
            raise BattleshipException(
                'Unable to load private key: {}'.format(str(e)))

        self._signer = CryptoFactory(
            create_context('secp256k1')).new_signer(private_key)

        self._transaction_family = "battleship"
        self._family_version = "1.0"
        self._wait = wait

    def _send_battleship_txn(self, update):
        """The client needs to have the same
            defaults as the Transaction subclass
            before it is signed inside sendtxn
        """
        if 'Name' not in update:
            raise BattleshipException('Game name required')
        if 'Action' not in update:
            update['Action'] = None
        if 'Ships' not in update:
            update['Ships'] = None
        if update['Action'] == 'JOIN':
            if 'Board' not in update:
                update['Board'] = None
        if update['Action'] == 'FIRE':
            if 'Column' not in update:
                update['Column'] = None
            if 'Row' not in update:
                update['Row'] = None

        payload = json.dumps(update).encode()
        address = self._get_address(update['Name'])

        header = TransactionHeader(
            signer_public_key=self._signer.get_public_key().as_hex(),
            family_name=self._transaction_family,
            family_version=self._family_version,
            inputs=[address],
            outputs=[address],
            dependencies=[],
            payload_sha512=self._sha512(payload),
            batcher_public_key=self.signer.get_public_key().as_hex(),
            nonce=hex(random.randint(0, 2**64))
        ).SerializeToString()

        signature = self._signer.sign(header)

        transaction = Transaction(
            header=header,
            payload=payload,
            header_signature=signature
        )

        batch_list = self._create_batch_list([transaction])
        batch_id = batch_list.batches[0].header_signature

        if self._wait and self._wait > 0:
            wait_time = 0
            start_time = time.time()
            response = self._send_request(
                "batches", batch_list.SerializeToString(),
                'application/octet-stream'
            )
            while wait_time < self._wait:
                status = self._get_status(
                    batch_id,
                    self._wait - int(wait_time)
                )
                wait_time = time.time() - start_time

                if status != 'PENDING':
                    return response

            return response

        return self._send_request(
            "batches", batch_list.SerializeToString(),
            'application/octet-stream')

    def create(self, name, ships):
        """ Create battleship game
        """
        update = {
            'Action': 'CREATE',
            'Name': name,
            'Ships': ships
        }

        return self._send_battleship_txn(update)

    def join(self, name, board):
        """ User joins battleship game
        """
        update = {
            'Action': 'JOIN',
            'Name': name,
            'Board': board
        }

        return self._send_battleship_txn(update)

    def fire(self, name, column, row, reveal_space, reveal_nonce):
        """ Fire at (column, row)
        """
        update = {
            'Action': 'FIRE',
            'Name': name,
            'Column': column,
            'Row': row
        }

        if reveal_space is not None:
            update['RevealSpace'] = reveal_space

        if reveal_nonce is not None:
            update['RevealNonce'] = reveal_nonce

        return self._send_battleship_txn(update)

    def list_games(self, auth_user=None, auth_password=None):
        prefix = self._get_prefix()

        result = self._send_request(
            "state?address={}".format(prefix),
            auth_user=auth_user,
            auth_password=auth_password
        )

        try:
            encoded_entries = yaml.safe_load(result)["data"]

            ret = {}
            for entry in encoded_entries:
                d = json.loads(b64decode(entry["data"]).decode())
                for k, v in d.items():
                    ret[k] = v

            return ret

        except BaseException:
            return None

    def _sha512(self, data):
        return hashlib.sha512(data).hexdigest()

    def _get_prefix(self):
        return self._sha512(self._transaction_family.encode('utf-8'))[0:6]

    def _get_address(self, name):
        prefix = self._get_prefix()
        game_address = self._sha512(name.encode('utf-8'))[0:64]
        return prefix + game_address

    def _create_batch_list(self, transactions):
        transaction_signatures = [t.header_signature for t in transactions]

        header = BatchHeader(
            signer_public_key=self._signer.get_public_key().as_hex(),
            transaction_ids=transaction_signatures
        ).SerializeToString()

        signature = self._signer.sign(header)

        batch = Batch(
            header=header,
            transactions=transactions,
            header_signature=signature
        )
        return BatchList(batches=[batch])

    def _get_status(self, batch_id, wait):
        try:
            result = self._send_request(
                'batch_statuses?id={}&wait={}'.format(batch_id, wait))
            return yaml.safe_load(result)['data'][0]['status']
        except BaseException as err:
            raise BattleshipException(err)

    def _send_request(
            self, suffix, data=None,
            content_type=None, name=None, auth_user=None, auth_password=None):
        if self._base_url.startswith("http://"):
            url = "{}/{}".format(self._base_url, suffix)
        else:
            url = "http://{}/{}".format(self._base_url, suffix)

        headers = {}
        if auth_user is not None:
            auth_string = "{}:{}".format(auth_user, auth_password)
            b64_string = b64encode(auth_string.encode()).decode()
            auth_header = 'Basic {}'.format(b64_string)
            headers['Authorization'] = auth_header

        if content_type is not None:
            headers['Content-Type'] = content_type

        try:
            if data is not None:
                result = requests.post(url, headers=headers, data=data)
            else:
                result = requests.get(url, headers=headers)

            if result.status_code == 404:
                raise BattleshipException("No such game: {}".format(name))

            elif not result.ok:
                raise BattleshipException("Error {}: {}".format(
                    result.status_code, result.reason))

        except BaseException as err:
            raise BattleshipException(err)

        return result.text
コード例 #25
0
ファイル: tests.py プロジェクト: Whiteblock/sawtooth-core
 def setUp(self):
     self._temp_dir = tempfile.mkdtemp()
     context = create_context('secp256k1')
     private_key = context.new_random_private_key()
     crypto_factory = CryptoFactory(context)
     self._signer = crypto_factory.new_signer(private_key)
コード例 #26
0
ファイル: intkey_client.py プロジェクト: cianx/sawtooth-core
class IntkeyClient:
    def __init__(self, url, keyfile=None):
        self.url = url

        if keyfile is not None:
            try:
                with open(keyfile) as fd:
                    private_key_str = fd.read().strip()
                    fd.close()
            except OSError as err:
                raise IntkeyClientException(
                    'Failed to read private key: {}'.format(str(err)))

            try:
                private_key = Secp256k1PrivateKey.from_hex(private_key_str)
            except ParseError as e:
                raise IntkeyClientException(
                    'Unable to load private key: {}'.format(str(e)))

            self._signer = CryptoFactory(
                create_context('secp256k1')).new_signer(private_key)

    def set(self, name, value, wait=None):
        return self._send_transaction('set', name, value, wait=wait)

    def inc(self, name, value, wait=None):
        return self._send_transaction('inc', name, value, wait=wait)

    def dec(self, name, value, wait=None):
        return self._send_transaction('dec', name, value, wait=wait)

    def list(self):
        result = self._send_request(
            "state?address={}".format(
                self._get_prefix()))

        try:
            encoded_entries = yaml.safe_load(result)["data"]

            return [
                cbor.loads(base64.b64decode(entry["data"]))
                for entry in encoded_entries
            ]

        except BaseException:
            return None

    def show(self, name):
        address = self._get_address(name)

        result = self._send_request("state/{}".format(address), name=name,)

        try:
            return cbor.loads(
                base64.b64decode(
                    yaml.safe_load(result)["data"]))[name]

        except BaseException:
            return None

    def _get_status(self, batch_id, wait):
        try:
            result = self._send_request(
                'batch_statuses?id={}&wait={}'.format(batch_id, wait),)
            return yaml.safe_load(result)['data'][0]['status']
        except BaseException as err:
            raise IntkeyClientException(err)

    def _get_prefix(self):
        return _sha512('intkey'.encode('utf-8'))[0:6]

    def _get_address(self, name):
        prefix = self._get_prefix()
        game_address = _sha512(name.encode('utf-8'))[64:]
        return prefix + game_address

    def _send_request(self, suffix, data=None, content_type=None, name=None):
        if self.url.startswith("http://"):
            url = "{}/{}".format(self.url, suffix)
        else:
            url = "http://{}/{}".format(self.url, suffix)

        headers = {}

        if content_type is not None:
            headers['Content-Type'] = content_type

        try:
            if data is not None:
                result = requests.post(url, headers=headers, data=data)
            else:
                result = requests.get(url, headers=headers)

            if result.status_code == 404:
                raise IntkeyClientException("No such key: {}".format(name))

            elif not result.ok:
                raise IntkeyClientException("Error {}: {}".format(
                    result.status_code, result.reason))

        except requests.ConnectionError as err:
            raise IntkeyClientException(
                'Failed to connect to REST API: {}'.format(err))

        except BaseException as err:
            raise IntkeyClientException(err)

        return result.text

    def _send_transaction(self, verb, name, value, wait=None):
        payload = cbor.dumps({
            'Verb': verb,
            'Name': name,
            'Value': value,
        })

        # Construct the address
        address = self._get_address(name)

        header = TransactionHeader(
            signer_public_key=self._signer.get_public_key().as_hex(),
            family_name="intkey",
            family_version="1.0",
            inputs=[address],
            outputs=[address],
            dependencies=[],
            payload_sha512=_sha512(payload),
            batcher_public_key=self._signer.get_public_key().as_hex(),
            nonce=hex(random.randint(0, 2**64))
        ).SerializeToString()

        signature = self._signer.sign(header)

        transaction = Transaction(
            header=header,
            payload=payload,
            header_signature=signature
        )

        batch_list = self._create_batch_list([transaction])
        batch_id = batch_list.batches[0].header_signature

        if wait and wait > 0:
            wait_time = 0
            start_time = time.time()
            response = self._send_request(
                "batches", batch_list.SerializeToString(),
                'application/octet-stream',
            )
            while wait_time < wait:
                status = self._get_status(
                    batch_id,
                    wait - int(wait_time),
                )
                wait_time = time.time() - start_time

                if status != 'PENDING':
                    return response

            return response

        return self._send_request(
            "batches", batch_list.SerializeToString(),
            'application/octet-stream',
        )

    def _create_batch_list(self, transactions):
        transaction_signatures = [t.header_signature for t in transactions]

        header = BatchHeader(
            signer_public_key=self._signer.get_public_key().as_hex(),
            transaction_ids=transaction_signatures
        ).SerializeToString()

        signature = self._signer.sign(header)

        batch = Batch(
            header=header,
            transactions=transactions,
            header_signature=signature)
        return BatchList(batches=[batch])
コード例 #27
0
ファイル: xo_client.py プロジェクト: hardice501/hardice
class XoClient:
    def __init__(self, base_url, keyfile=None):

        self._base_url = base_url

        if keyfile is None:
            self._signer = None
            return

        try:
            with open(keyfile) as fd:
                private_key_str = fd.read().strip()
        except OSError as err:
            raise XoException('Failed to read private key {}: {}'.format(
                keyfile, str(err)))

        try:
            private_key = Secp256k1PrivateKey.from_hex(private_key_str)
        except ParseError as e:
            raise XoException('Unable to load private key: {}'.format(str(e)))

        self._signer = CryptoFactory(create_context('secp256k1')) \
            .new_signer(private_key)

    def create(self, name, wait=None, auth_user=None, auth_password=None):
        return self._send_xo_txn(name,
                                 "create",
                                 wait=wait,
                                 auth_user=auth_user,
                                 auth_password=auth_password)

    def delete(self, name, wait=None, auth_user=None, auth_password=None):
        return self._send_xo_txn(name,
                                 "delete",
                                 wait=wait,
                                 auth_user=auth_user,
                                 auth_password=auth_password)

    def take(self, name, space, wait=None, auth_user=None, auth_password=None):
        return self._send_xo_txn(name,
                                 "take",
                                 space,
                                 wait=wait,
                                 auth_user=auth_user,
                                 auth_password=auth_password)

    def list(self, auth_user=None, auth_password=None):
        xo_prefix = self._get_prefix()

        result = self._send_request("state?address={}".format(xo_prefix),
                                    auth_user=auth_user,
                                    auth_password=auth_password)

        try:
            encoded_entries = yaml.safe_load(result)["data"]

            return [
                base64.b64decode(entry["data"]) for entry in encoded_entries
            ]

        except BaseException:
            return None

    def show(self, name, auth_user=None, auth_password=None):
        address = self._get_address(name)

        result = self._send_request("state/{}".format(address),
                                    name=name,
                                    auth_user=auth_user,
                                    auth_password=auth_password)
        try:
            return base64.b64decode(yaml.safe_load(result)["data"])

        except BaseException:
            return None

    def _get_status(self, batch_id, wait, auth_user=None, auth_password=None):
        try:
            result = self._send_request('batch_statuses?id={}&wait={}'.format(
                batch_id, wait),
                                        auth_user=auth_user,
                                        auth_password=auth_password)
            return yaml.safe_load(result)['data'][0]['status']
        except BaseException as err:
            raise XoException(err)

    def _get_prefix(self):
        return _sha512('xo'.encode('utf-8'))[0:6]

    def _get_address(self, name):
        xo_prefix = self._get_prefix()
        game_address = _sha512(name.encode('utf-8'))[0:64]
        return xo_prefix + game_address

    def _send_request(self,
                      suffix,
                      data=None,
                      content_type=None,
                      name=None,
                      auth_user=None,
                      auth_password=None):
        if self._base_url.startswith("http://"):
            url = "{}/{}".format(self._base_url, suffix)
        else:
            url = "http://{}/{}".format(self._base_url, suffix)

        headers = {}
        if auth_user is not None:
            auth_string = "{}:{}".format(auth_user, auth_password)
            b64_string = b64encode(auth_string.encode()).decode()
            auth_header = 'Basic {}'.format(b64_string)
            headers['Authorization'] = auth_header

        if content_type is not None:
            headers['Content-Type'] = content_type

        try:
            if data is not None:
                result = requests.post(url, headers=headers, data=data)
            else:
                result = requests.get(url, headers=headers)

            if result.status_code == 404:
                raise XoException("No such game: {}".format(name))

            if not result.ok:
                raise XoException("Error {}: {}".format(
                    result.status_code, result.reason))

        except requests.ConnectionError as err:
            raise XoException('Failed to connect to {}: {}'.format(
                url, str(err)))

        except BaseException as err:
            raise XoException(err)

        return result.text

    def _send_xo_txn(self,
                     name,
                     action,
                     space="",
                     wait=None,
                     auth_user=None,
                     auth_password=None):
        # Serialization is just a delimited utf-8 encoded string
        payload = ",".join([name, action, str(space)]).encode()

        # Construct the address
        address = self._get_address(name)

        header = TransactionHeader(
            signer_public_key=self._signer.get_public_key().as_hex(),
            family_name="xo",
            family_version="1.0",
            inputs=[address],
            outputs=[address],
            dependencies=[],
            payload_sha512=_sha512(payload),
            batcher_public_key=self._signer.get_public_key().as_hex(),
            nonce=hex(random.randint(0, 2**64))).SerializeToString()

        signature = self._signer.sign(header)

        transaction = Transaction(header=header,
                                  payload=payload,
                                  header_signature=signature)

        batch_list = self._create_batch_list([transaction])
        batch_id = batch_list.batches[0].header_signature

        if wait and wait > 0:
            wait_time = 0
            start_time = time.time()
            response = self._send_request("batches",
                                          batch_list.SerializeToString(),
                                          'application/octet-stream',
                                          auth_user=auth_user,
                                          auth_password=auth_password)
            while wait_time < wait:
                status = self._get_status(batch_id,
                                          wait - int(wait_time),
                                          auth_user=auth_user,
                                          auth_password=auth_password)
                wait_time = time.time() - start_time

                if status != 'PENDING':
                    return response

            return response

        return self._send_request("batches",
                                  batch_list.SerializeToString(),
                                  'application/octet-stream',
                                  auth_user=auth_user,
                                  auth_password=auth_password)

    def _create_batch_list(self, transactions):
        transaction_signatures = [t.header_signature for t in transactions]

        header = BatchHeader(
            signer_public_key=self._signer.get_public_key().as_hex(),
            transaction_ids=transaction_signatures).SerializeToString()

        signature = self._signer.sign(header)

        batch = Batch(header=header,
                      transactions=transactions,
                      header_signature=signature)
        return BatchList(batches=[batch])
コード例 #28
0
BIDS_TABLE = FAMILY_NAME + BIDDING_ENTRY_TABLE + BIDS_TABLE[:58]

ITEMS_TABLE = FAMILY_NAME + BIDDING_ENTRY_TABLE + ITEMS_TABLE[:58]

base_url = "http://rest-api:8008"
import optparse
import argparse
FAMILY_NAME = hashlib.sha256("bidding".encode()).hexdigest()[:6]
parser = optparse.OptionParser()
parser.add_option('-U', '--url', action="store", dest="url", default="spam")
namespace = ""

context = create_context('secp256k1')

private_key = context.new_random_private_key()
signer = CryptoFactory(context).new_signer(private_key)

public_key = signer.get_public_key().as_hex()


def hash(name, n=0):
    if (n == 0):
        return hashlib.sha512(name.encode()).hexdigest()
    else:

        return hashlib.sha512(name.encode()).hexdigest()[:n]


def showitems():
    result = send_to_rest_api("state/{}".format(ITEMS_TABLE))
    try:
コード例 #29
0
class TransferClient:

    def __init__(self, base_url , keyfile = None):

        self._base_url = base_url

        if keyfile is None:
            self._signer = None
            return

        try:
            with open(keyfile) as f:
                private_key_str = f.read().strip()
        except OSError as err:
            raise TransferException('Failed to read private key {} : {}'.format(keyfile , str(err)))

        try:
            private_key = Secp256k1PrivateKey.from_hex(private_key_str)
        except ParseError as e:
            raise TransferException('Failed to load private key : {}'.format(str(err)))

        self._signer = CryptoFactory(create_context('secp256k1')).new_signer(private_key)


    def createBox(self, medicineName, medicineID, units, wait = None, auth_user = None, auth_password = None):
        boxID = ''.join(random.sample('0123456789', 5))
        return self._send_transfer_txn(
                        medicineName,
                        medicineID,
                        units,
                        '',
                        '',
                        boxID,
                        self._signer.get_public_key().as_hex(),
                        '',
                        '',
                        '',
                        'createBox',
                        wait,
                        auth_user,
                        auth_password
                        )
    
    
    def updateBox(self, medicineName, medicineID, units, boxID, wait = None, auth_user = None, auth_password = None):
        return self._send_transfer_txn(
                        medicineName,
                        medicineID,
                        units,
                        '',
                        '',
                        boxID,
                        self._signer.get_public_key().as_hex(),
                        '',
                        '',
                        '',
                        'updateBox',
                        wait,
                        auth_user,
                        auth_password
                        )
    
    
    def createShipment(self, boxIDArray, origin, destination, wait = None, auth_user = None, auth_password = None):
        shipmentID = ''.join(random.sample('0123456789', 5))
        shipmentStatus = 'CREATED'
        return self._send_transfer_txn(
                        '',
                        '',
                        '',
                        origin,
                        destination,
                        '',
                        self._signer.get_public_key().as_hex(),
                        shipmentID,
                        boxIDArray,
                        shipmentStatus,
                        'createShipment',
                        wait,
                        auth_user,
                        auth_password            
                        )
    

    def updateShipmentStatus(self, shipmentID, shipmentStatus, wait = None, auth_user = None, auth_password = None):
        return self._send_transfer_txn(
                        '',
                        '',
                        '',
                        '',
                        '',
                        '',
                        self._signer.get_public_key().as_hex(),
                        shipmentID,
                        '',
                        shipmentStatus,
                        'updateShipmentStatus',
                        wait,
                        auth_user,
                        auth_password
                        )
    

    def deleteShipment(self, shipmentID, wait = None, auth_user = None, auth_password = None):
        return self._send_transfer_txn(
                        '',
                        '',
                        '',
                        '',
                        '',
                        '',
                        self._signer.get_public_key().as_hex(),
                        shipmentID,
                        '',
                        '',
                        'deleteShipment',
                        wait,
                        auth_user,
                        auth_password
        )


    def list(self, auth_user=None, auth_password=None):
        transfer_prefix = self._get_prefix()

        result = self._send_request(
            "state?address={}".format(transfer_prefix),
            auth_user=auth_user,
            auth_password=auth_password)

        try:
            encoded_entries = yaml.safe_load(result)["data"]

            return [
                base64.b64decode(entry["data"]) for entry in encoded_entries
            ]

        except BaseException:
            return None


    def show(self, name, auth_user=None, auth_password=None):
        address = self._get_address(name)

        result = self._send_request(
            "state/{}".format(address),
            name=name,
            auth_user=auth_user,
            auth_password=auth_password)
        try:
            return base64.b64decode(yaml.safe_load(result)["data"])

        except BaseException:
            return None


    def _get_status(self, batch_id, wait, auth_user=None, auth_password=None):
        try:
            result = self._send_request(
                'batch_statuses?id={}&wait={}'.format(batch_id, wait),
                auth_user=auth_user,
                auth_password=auth_password)
            return yaml.safe_load(result)['data'][0]['status']
        except BaseException as err:
            raise TransferException(err)


    def _get_prefix(self):
        return(_sha512('transfer'.encode('utf-8'))[0:6])


    def _get_address(self, name):
        transfer_prefix = self._get_prefix()
        transfer_address = _sha512(name.encode('utf-8'))[0:64]
        return(transfer_prefix + transfer_address)


    def _send_request(self,
                      suffix,
                      data=None,
                      content_type=None,
                      name=None,
                      auth_user=None,
                      auth_password=None):
        if self._base_url.startswith("http://"):
            url = "{}/{}".format(self._base_url, suffix)
        else:
            url = "http://{}/{}".format(self._base_url, suffix)

        headers = {}
        if auth_user is not None:
            auth_string = "{}:{}".format(auth_user, auth_password)
            b64_string = b64encode(auth_string.encode()).decode()
            auth_header = 'Basic {}'.format(b64_string)
            headers['Authorization'] = auth_header

        if content_type is not None:
            headers['Content-Type'] = content_type

        try:
            if data is not None:
                result = requests.post(url, headers=headers, data=data)
            else:
                result = requests.get(url, headers=headers)

            if result.status_code == 404:
                raise TransferException("No such transfers: {}".format(name))

            if not result.ok:
                raise TransferException("Error {}: {}".format(result.status_code, result.reason))

        except requests.ConnectionError as err:
            raise TransferException(
                'Failed to connect to {}: {}'.format(url, str(err)))

        except BaseException as err:
            raise TransferException(err)

        return(result.text)
    

    def _send_transfer_txn(self,
                        medicineName,
                        medicineID,
                        units,
                        origin,
                        destination,
                        boxID,
                        logisticsID,
                        shipmentID,
                        boxIDArray,
                        shipmentStatus,
                        action,
                        wait = None,
                        auth_user = None,
                        auth_password =None):

        payload = ",".join([medicineName, str(medicineID), str(units), origin, destination, str(boxID), str(logisticsID), str(shipmentID), str(boxIDArray), shipmentStatus, action]).encode()

        addresss = self._get_address(str(shipmentID))
        addressb = self._get_address(str(boxID))

        if(boxID is None):
            address = self._get_address(str(shipmentID))
        else:
            address = self._get_address(str(boxID))
        

        med_address = _make_medicine_address(medicineName)

        header = TransactionHeader(
            signer_public_key=self._signer.get_public_key().as_hex(),
            family_name="transfer",
            family_version="1.0",
            inputs=[addresss, addressb, address, med_address],
            outputs=[addresss, addressb, address, med_address],
            dependencies=[],
            payload_sha512=_sha512(payload),
            batcher_public_key=self._signer.get_public_key().as_hex(),
            nonce=hex(random.randint(0, 2**64))
        ).SerializeToString()

        signature = self._signer.sign(header)

        transaction = Transaction(
            header=header,
            payload=payload,
            header_signature=signature
        )

        batch_list = self._create_batch_list([transaction])
        batch_id = batch_list.batches[0].header_signature

        if wait and wait > 0:
            wait_time = 0
            start_time = time.time()
            response = self._send_request(
                "batches", batch_list.SerializeToString(),
                'application/octet-stream',
                auth_user=auth_user,
                auth_password=auth_password)
            while wait_time < wait:
                status = self._get_status(
                    batch_id,
                    wait - int(wait_time),
                    auth_user=auth_user,
                    auth_password=auth_password)
                wait_time = time.time() - start_time

                if status != 'PENDING':
                    return response

            return response

        return self._send_request(
            "batches", batch_list.SerializeToString(),
            'application/octet-stream',
            auth_user=auth_user,
            auth_password=auth_password)


    def _create_batch_list(self, transactions):
        transaction_signatures = [t.header_signature for t in transactions]

        header = BatchHeader(
            signer_public_key=self._signer.get_public_key().as_hex(),
            transaction_ids=transaction_signatures
        ).SerializeToString()

        signature = self._signer.sign(header)

        batch = Batch(
            header=header,
            transactions=transactions,
            header_signature=signature)
        return BatchList(batches=[batch])
コード例 #30
0
class IoTClient:
    def __init__(self, url, keyfile=None):
        self.url = url

        if keyfile is not None:
            try:
                with open(keyfile) as fd:
                    private_key_str = fd.read().strip()
                    fd.close()
            except OSError as err:
                raise IoTException('Failed to read private key: {}'.format(
                    str(err)))
            try:
                private_key = Secp256k1PrivateKey.from_hex(private_key_str)
            except ParseError as e:
                raise IoTException('Unable to load private key: {}'.format(
                    str(e)))

            self._signer = CryptoFactory(
                create_context('secp256k1')).new_signer(private_key)

    def send(self, path):
        #get user public, we will use as ID
        device_id = self._signer.get_public_key().as_hex()[:4]
        #get image metadata
        metadata = _get_metadata(path)
        #get timestamp
        timestamp = _get_date()
        if metadata is None:
            return "Unable to open Image"
        return self._send_transaction(device_id, metadata, timestamp)

    def list(self):
        result = self._send_request("state?address={}".format(
            self._get_prefix()))

        try:
            encoded_entries = yaml.safe_load(result)["data"]

            return [
                cbor.loads(base64.b64decode(entry["data"]))
                for entry in encoded_entries
            ]
        except BaseException:
            return None

    def _get_prefix(self):
        return _sha512('iot-tp'.encode('utf-8'))[0:6]

    def _get_address(self, metadata):
        prefix = self._get_prefix()
        txn_address = _sha512(yaml.dump(metadata).encode('utf-8'))[64:]
        return prefix + txn_address

    def _send_request(self, suffix, data=None, content_type=None, name=None):
        if self.url.startswith("http://"):
            url = "{}/{}".format(self.url, suffix)
        else:
            url = "http://{}/{}".format(self.url, suffix)

        headers = {}

        if content_type is not None:
            headers['Content-Type'] = content_type

        try:
            if data is not None:
                result = requests.post(url, headers=headers, data=data)
            else:
                result = requests.get(url, headers=headers)

            if result.status_code == 4004:
                raise IoTClient("No such key: {}".format(name))
            elif not result.ok:
                raise IoTClient("Error {}: {}".format(result.status_code,
                                                      result.reason))
        except requests.ConnectionError as err:
            raise IoTClient('Failed to connect to REST API: {}'.format(err))
        except BaseException as err:
            raise IoTClient(err)

        return result.text

    def _send_transaction(self, device_id, metadata, timestamp):
        payload = cbor.dumps({
            'device_id': device_id,
            'metadata': metadata,
            'timestamp': timestamp,
        })

        address = self._get_address(metadata)

        header = TransactionHeader(
            signer_public_key=self._signer.get_public_key().as_hex(),
            family_name="iot-tp",
            family_version="1.0",
            inputs=[address],
            outputs=[address],
            dependencies=[],
            payload_sha512=_sha512(payload),
            batcher_public_key=self._signer.get_public_key().as_hex(),
            nonce=hex(random.randint(0, 2**64))).SerializeToString()

        signature = self._signer.sign(header)

        transaction = Transaction(header=header,
                                  payload=payload,
                                  header_signature=signature)

        batch_list = self._create_batch_list([transaction])
        batch_id = batch_list.batches[0].header_signature

        return self._send_request(
            "batches",
            batch_list.SerializeToString(),
            'application/octet-stream',
        )

    def _create_batch_list(self, transactions):
        transaction_signatures = [t.header_signature for t in transactions]

        header = BatchHeader(
            signer_public_key=self._signer.get_public_key().as_hex(),
            transaction_ids=transaction_signatures).SerializeToString()

        signature = self._signer.sign(header)

        batch = Batch(header=header,
                      transactions=transactions,
                      header_signature=signature)

        return BatchList(batches=[batch])
コード例 #31
0
class BgtClient:
    def __init__(self, url, keyfile=None):
        self.url = url

        if keyfile is not None:
            try:
                with open(keyfile) as fd:
                    private_key_str = fd.read().strip()
                    fd.close()
            except OSError as err:
                raise BgtClientException(
                    'Failed to read private key: {}'.format(str(err)))

            try:
                private_key = Secp256k1PrivateKey.from_hex(private_key_str)
            except ParseError as e:
                raise BgtClientException(
                    'Unable to load private key: {}'.format(str(e)))

            self._signer = CryptoFactory(
                create_context('secp256k1')).new_signer(private_key)

    def set(self, name, value, wait=None):
        return self._send_transaction('set', name, value, to=None, wait=wait)

    def inc(self, name, value, wait=None):
        return self._send_transaction('inc', name, value, to=None, wait=wait)

    def dec(self, name, value, wait=None):
        return self._send_transaction('dec', name, value, to=None, wait=wait)

    def trans(self, name, value, to, wait=None):
        return self._send_transaction('trans', name, value, to=to, wait=wait)

    def list(self):
        result = self._send_request(
            "state?address={}".format(
                self._get_prefix()))

        try:
            encoded_entries = yaml.safe_load(result)["data"]

            return [
                cbor.loads(base64.b64decode(entry["data"]))
                for entry in encoded_entries
            ]

        except BaseException:
            return None

    def show(self, name):
        address = self._get_address(name)

        result = self._send_request("state/{}".format(address), name=name,)

        try:
            return cbor.loads(base64.b64decode(yaml.safe_load(result)["data"]))[name]

        except BaseException:
            return None

    def _get_status(self, batch_id, wait):
        try:
            result = self._send_request(
                'batch_statuses?id={}&wait={}'.format(batch_id, wait),)
            return yaml.safe_load(result)['data'][0]['status']
        except BaseException as err:
            raise BgtClientException(err)

    def _get_prefix(self):
        return _sha512('bgt'.encode('utf-8'))[0:6]

    def _get_address(self, name):
        prefix = self._get_prefix()
        game_address = _sha512(name.encode('utf-8'))[64:]
        return prefix + game_address

    def _send_request(self, suffix, data=None, content_type=None, name=None):
        if self.url.startswith("http://"):
            url = "{}/{}".format(self.url, suffix)
        else:
            url = "http://{}/{}".format(self.url, suffix)

        headers = {}

        if content_type is not None:
            headers['Content-Type'] = content_type

        try:
            if data is not None:
                result = requests.post(url, headers=headers, data=data)
            else:
                result = requests.get(url, headers=headers)

            if result.status_code == 404:
                raise BgtClientException("No such key: {}".format(name))

            elif not result.ok:
                raise BgtClientException("Error {}: {}".format(
                    result.status_code, result.reason))

        except requests.ConnectionError as err:
            raise BgtClientException(
                'Failed to connect to REST API: {}'.format(err))

        except BaseException as err:
            raise BgtClientException(err)

        return result.text

    def _send_transaction(self, verb, name, value, to=None, wait=None):
        val = {
            'Verb': verb,
            'Name': name,
            'Value': value,
        }
        if to is not None:
            val['To'] = to

        payload = cbor.dumps(val)

        # Construct the address
        address = self._get_address(name)
        inputs = [address]
        outputs = [address]
        if to is not None:
            address_to = self._get_address(to)
            inputs.append(address_to)
            outputs.append(address_to)

        header = TransactionHeader(
            signer_public_key=self._signer.get_public_key().as_hex(),
            family_name=FAMILY_NAME,
            family_version=FAMILY_VERSION,
            inputs=inputs,
            outputs=outputs,
            dependencies=[],
            payload_sha512=_sha512(payload),
            batcher_public_key=self._signer.get_public_key().as_hex(),
            nonce=hex(random.randint(0, 2**64))
        ).SerializeToString()

        signature = self._signer.sign(header)

        transaction = Transaction(
            header=header,
            payload=payload,
            header_signature=signature
        )

        batch_list = self._create_batch_list([transaction])
        batch_id = batch_list.batches[0].header_signature

        if wait and wait > 0:
            wait_time = 0
            start_time = time.time()
            response = self._send_request(
                "batches", batch_list.SerializeToString(),
                'application/octet-stream',
            )
            while wait_time < wait:
                status = self._get_status(
                    batch_id,
                    wait - int(wait_time),
                )
                wait_time = time.time() - start_time

                if status != 'PENDING':
                    return response

            return response

        return self._send_request(
            "batches", batch_list.SerializeToString(),
            'application/octet-stream',
        )

    def _create_batch_list(self, transactions):
        transaction_signatures = [t.header_signature for t in transactions]

        header = BatchHeader(
            signer_public_key=self._signer.get_public_key().as_hex(),
            transaction_ids=transaction_signatures
        ).SerializeToString()

        signature = self._signer.sign(header)

        batch = Batch(
            header=header,
            transactions=transactions,
            header_signature=signature,
            timestamp=int(time.time()))
        return BatchList(batches=[batch])
コード例 #32
0
class SchedulerTester(object):
    """ The canonical form of the yaml is:
      -  <------------------------------------------ batch start
        state_hash: string. Optional. No default.
        - <----------------------------------------- transaction start
          inputs: list of string. Required.
            - ....
          outputs: list of string. Required.
            - ....
          addresses_to_set: list of dict. Optional.
            - string <address>: Optional bytes <value>
          addresses_to_delete: list of str. Optional
            - string <address>
          valid: boolean. Optional. Defaults to True
          dependencies: list of string. Optional. Defaults to empty list.
            - ..... string. No default. If a dependency is the same
                            string as a 'name' for another txn, that
                            txn's signature will be used for the
                            actual Transaction's dependency. If the
                            string is not an 'name' of another txn, if
                            it is longer than 20 characters it will be
                            used as if is is the actual
                            Transaction.header_signature for the
                            dependency. If not, it will be
                            disregarded.
          name: string. Optional. No default.
    """
    def __init__(self, file_name):
        """

        Args:
            file_name (str): The yaml filename and path.
            scheduler (scheduler.Scheduler): Any Scheduler implementaion
            context_manager (context_manager.ContextManager): The context
                manager holding state for this scheduler.
        """
        self._context = create_context('secp256k1')
        self._crypto_factory = CryptoFactory(self._context)
        self._yaml_file_name = file_name
        self._counter = itertools.count(0)
        self._referenced_txns_in_other_batches = {}
        self._batch_id_by_txn_id = {}
        self._txn_execution = {}

        self._batch_results = {}
        self._batches = []

        self._create_batches()

    @property
    def batch_results(self):
        """The batch results calculated from the yaml file.

        Returns:
            (dict): Computed from the yaml file, a dictionary with
                batch signature keys and BatchExecutionResult values.
        """
        return self._batch_results

    def run_scheduler(self,
                      scheduler,
                      context_manager,
                      validation_state_hash=None,
                      txns_executed_fifo=True):
        """Add all the batches to the scheduler in order and then run through
        the txns in the scheduler, calling next_transaction() after each
        transaction_execution_result is set.

        Args:
            scheduler (scheduler.Scheduler): Any implementation of the
                Scheduler abstract base class.
            context_manager (context_manager.ContextManager): The context
                manager is needed to store state based on the yaml file.
            validation_state_hash (str): Used in cases where the yaml
                represents a single block of valid batches, and the
                state hash is not in the yaml file. This state hash is added
                to the last batch in the scheduler.

        Returns batch_results (list of tuples): A list of tuples of
            batch signature, BatchExecutionResult pairs.
        """

        for i, batch in enumerate(self._batches):
            if i == len(self._batches) - 1 and \
                    validation_state_hash is not None:
                s_h = validation_state_hash
            else:
                s_h = self._batch_results[batch.header_signature].state_hash
            scheduler.add_batch(batch=batch, state_hash=s_h)

        scheduler.finalize()
        txns_to_process = deque()

        txn_context_by_txn_id = self._compute_transaction_execution_context()

        transactions_to_assert_state = {}
        while not scheduler.complete(block=False):
            stop = False
            while not stop:
                try:
                    txn_info = scheduler.next_transaction()
                except StopIteration:
                    break
                if txn_info is not None:
                    txns_to_process.append(txn_info)
                    LOGGER.debug("Transaction %s scheduled",
                                 txn_info.txn.header_signature[:16])
                else:
                    stop = True
            try:
                if txns_executed_fifo:
                    t_info = txns_to_process.popleft()
                else:
                    t_info = txns_to_process.pop()
            except IndexError:
                # No new txn was returned from next_transaction so
                # check again if complete.
                continue

            inputs, outputs = self._get_inputs_outputs(t_info.txn)

            c_id = context_manager.create_context(
                state_hash=t_info.state_hash,
                base_contexts=t_info.base_context_ids,
                inputs=inputs,
                outputs=outputs)

            t_id = t_info.txn.header_signature

            if t_id in txn_context_by_txn_id:
                state_up_to_now = txn_context_by_txn_id[t_id].state
                txn_context = txn_context_by_txn_id[t_id]
                inputs, _ = self._get_inputs_outputs(txn_context.txn)
                addresses = [input for input in inputs if len(input) == 70]
                state_found = context_manager.get(context_id=c_id,
                                                  address_list=addresses)

                LOGGER.debug(
                    "Transaction Id %s, Batch %s, Txn %s, "
                    "Context_id %s, Base Contexts %s", t_id[:16],
                    txn_context.batch_num, txn_context.txn_num, c_id,
                    t_info.base_context_ids)

                state_to_assert = [(add, state_up_to_now.get(add))
                                   for add, _ in state_found]
                transactions_to_assert_state[t_id] = (txn_context, state_found,
                                                      state_to_assert)

            validity, address_values, deletes = self._txn_execution[
                t_info.txn.header_signature]

            context_manager.set(context_id=c_id,
                                address_value_list=address_values)

            context_manager.delete(context_id=c_id, address_list=deletes)
            LOGGER.debug("Transaction %s is %s", t_id[:16],
                         'valid' if validity else 'invalid')
            scheduler.set_transaction_execution_result(
                txn_signature=t_info.txn.header_signature,
                is_valid=validity,
                context_id=c_id)

        batch_ids = [b.header_signature for b in self._batches]
        batch_results = [(b_id, scheduler.get_batch_execution_result(b_id))
                         for b_id in batch_ids]

        return batch_results, transactions_to_assert_state

    def run_scheduler_alternating(self,
                                  scheduler,
                                  context_manager,
                                  validation_state_hash=None,
                                  txns_executed_fifo=True):
        batches = deque()
        batches.extend(self._batches)

        txns_to_process = deque()

        txn_context_by_txn_id = self._compute_transaction_execution_context()

        transactions_to_assert_state = {}
        while not scheduler.complete(block=False):
            stop = False
            while not stop:
                try:
                    txn_info = scheduler.next_transaction()
                except StopIteration:
                    stop = True

                if txn_info is not None:
                    txns_to_process.append(txn_info)
                    LOGGER.debug("Transaction %s scheduled",
                                 txn_info.txn.header_signature[:16])
                else:
                    stop = True

            try:
                scheduler.add_batch(batches.popleft())
            except IndexError:
                scheduler.finalize()

            try:
                if txns_executed_fifo:
                    t_info = txns_to_process.popleft()
                else:
                    t_info = txns_to_process.pop()
            except IndexError:
                # No new txn was returned from next_transaction so
                # check again if complete.
                continue

            inputs, outputs = self._get_inputs_outputs(t_info.txn)

            c_id = context_manager.create_context(
                state_hash=t_info.state_hash,
                base_contexts=t_info.base_context_ids,
                inputs=inputs,
                outputs=outputs)

            t_id = t_info.txn.header_signature

            if t_id in txn_context_by_txn_id:
                state_up_to_now = txn_context_by_txn_id[t_id].state
                txn_context = txn_context_by_txn_id[t_id]
                inputs, _ = self._get_inputs_outputs(txn_context.txn)
                addresses = [input for input in inputs if len(input) == 70]
                state_found = context_manager.get(context_id=c_id,
                                                  address_list=addresses)

                LOGGER.debug(
                    "Transaction Id %s, Batch %s, Txn %s, "
                    "Context_id %s, Base Contexts %s", t_id[:16],
                    txn_context.batch_num, txn_context.txn_num, c_id,
                    t_info.base_context_ids)

                state_to_assert = [(add, state_up_to_now.get(add))
                                   for add, _ in state_found]
                transactions_to_assert_state[t_id] = (txn_context, state_found,
                                                      state_to_assert)

            validity, address_values, deletes = self._txn_execution[
                t_info.txn.header_signature]

            context_manager.set(context_id=c_id,
                                address_value_list=address_values)
            context_manager.delete(context_id=c_id, address_list=deletes)
            LOGGER.debug("Transaction %s is %s", t_id[:16],
                         'valid' if validity else 'invalid')
            scheduler.set_transaction_execution_result(
                txn_signature=t_info.txn.header_signature,
                is_valid=validity,
                context_id=c_id)

        batch_ids = [b.header_signature for b in self._batches]
        batch_results = [(b_id, scheduler.get_batch_execution_result(b_id))
                         for b_id in batch_ids]

        return batch_results, transactions_to_assert_state

    def compute_state_hashes_wo_scheduler(self, base_dir):
        """Creates a state hash from the state updates from each txn in a
        valid batch.

        Returns state_hashes (list of str): The merkle roots from state
            changes in 1 or more blocks in the yaml file.

        """

        database = NativeLmdbDatabase(os.path.join(
            base_dir, 'compute_state_hashes_wo_scheduler.lmdb'),
                                      _size=10 * 1024 * 1024)

        tree = MerkleDatabase(database=database)
        state_hashes = []
        updates = {}
        for batch in self._batches:
            b_id = batch.header_signature
            result = self._batch_results[b_id]
            if result.is_valid:
                for txn in batch.transactions:
                    txn_id = txn.header_signature
                    _, address_values, deletes = self._txn_execution[txn_id]
                    batch_updates = {}
                    for pair in address_values:
                        batch_updates.update({a: pair[a] for a in pair.keys()})

                    # since this is entirely serial, any overwrite
                    # of an address is expected and desirable.
                    updates.update(batch_updates)

                    for address in deletes:
                        if address in updates:
                            del updates[address]

            # This handles yaml files that have state roots in them
            if result.state_hash is not None:
                s_h = tree.update(set_items=updates, virtual=False)
                tree.set_merkle_root(merkle_root=s_h)
                state_hashes.append(s_h)
        if not state_hashes:
            state_hashes.append(tree.update(set_items=updates))
        return state_hashes

    def _compute_transaction_execution_context(self):
        """Compute the serial state for each txn in the yaml file up to and
        including the invalid txn in each invalid batch.

        Notes:
            The TransactionExecutionContext for a txn will contain the
            state applied serially up to that point for each valid batch and
            then for invalid batches up to the invalid txn.

        Returns:
            dict: The transaction id to the TransactionExecutionContext
        """
        transaction_contexts = {}
        state_up_to_now = {}

        for batch_num, batch in enumerate(self._batches):
            partial_batch_transaction_contexts = {}
            partial_batch_state_up_to_now = state_up_to_now.copy()
            for txn_num, txn in enumerate(batch.transactions):
                t_id = txn.header_signature
                is_valid, address_values, deletes = self._txn_execution[t_id]
                partial_batch_transaction_contexts[t_id] = \
                    TransactionExecutionContext(
                        txn=txn,
                        txn_num=txn_num + 1,
                        batch_num=batch_num + 1,
                        state=partial_batch_state_up_to_now.copy())

                for item in address_values:
                    partial_batch_state_up_to_now.update(item)
                for address in deletes:
                    if address in partial_batch_state_up_to_now:
                        partial_batch_state_up_to_now[address] = None
                if not is_valid:
                    break
            batch_id = batch.header_signature
            batch_is_valid = self._batch_results[batch_id].is_valid

            if batch_is_valid:
                transaction_contexts.update(partial_batch_transaction_contexts)
                state_up_to_now.update(partial_batch_state_up_to_now)

        return transaction_contexts

    def _address(self, add, require_full=False):
        if ':sha' not in add and ',' not in add:
            return add

        if ',' in add:
            return binascii.hexlify(bytearray([int(i)
                                               for i in add.split(',')]))

        parts = add.split(':')
        if len(parts) == 3 and parts[2] == 'sha':
            # eg. 'yy:aaabbbb:sha'
            namespace = hashlib.sha512(parts[0].encode()).hexdigest()[:6]
            address = namespace + hashlib.sha512(
                parts[1].encode()).hexdigest()[:64]
        elif len(parts) == 3 and not require_full:
            # eg. 'a:sha:56'
            length = min(int(parts[2]), 70)
            address = hashlib.sha512(parts[0].encode()).hexdigest()[:length]
        elif len(parts) == 2:
            # eg. 'aaabbbb:sha'
            intermediate = parts[0]
            address = hashlib.sha512(intermediate.encode()).hexdigest()[:70]
        else:
            raise ValueError("Address specified by {} could "
                             "not be formed".format(add))
        return address

    def _get_inputs_outputs(self, txn):
        """Similarly to the TransactionExecutor, deserialize the inputs and
         outputs.

         Notes:
             The SchedulerTester has the inputs and outputs from the yaml file
             that it used to create the transaction, but it seems less
             error-prone to recreate the behavior of the TransactionExecutor.

        Args:
            txn (sawtooth_validator.protobuf.transaction_pb2.Transaction)

        Returns (tuple): (inputs, outputs)

        """

        header = transaction_pb2.TransactionHeader()
        header.ParseFromString(txn.header)

        return list(header.inputs), list(header.outputs)

    def _bytes_if_none(self, value):
        if value is None:
            value = uuid.uuid4().hex.encode()
        return value

    def _yaml_from_file(self):
        with open(self._yaml_file_name, 'r') as infile:
            test_yaml = yaml.safe_load(infile)
        return test_yaml

    def _contains_and_not_none(self, key, obj):
        return key in obj and obj[key] is not None

    def _process_batches(self, yaml_batches, signer):
        batches = []
        b_results = {}
        for batch in yaml_batches:
            batch_state_root = None
            if self._contains_and_not_none('state_hash', batch):
                batch_state_root = batch['state_hash']

            txn_processing_result = self._process_txns(
                batch=batch,
                previous_batch_results=b_results.copy(),
                signer=signer)
            txns, batch_is_valid = txn_processing_result
            batch_real = create_batch(transactions=txns, signer=signer)
            for txn in txns:
                txn_id = txn.header_signature
                batch_id = batch_real.header_signature
                self._batch_id_by_txn_id[txn_id] = batch_id

            b_results[batch_real.header_signature] = BatchExecutionResult(
                is_valid=batch_is_valid, state_hash=batch_state_root)
            batches.append(batch_real)
        return batches, b_results

    def _dependencies_are_valid(self, dependencies, previous_batch_results):
        for dep in dependencies:
            if dep in self._batch_id_by_txn_id:
                batch_id = self._batch_id_by_txn_id[dep]
                dep_result = previous_batch_results[batch_id]
                if not dep_result.is_valid:
                    return False
        return True

    def _process_txns(self, batch, previous_batch_results, signer):
        txns = []
        referenced_txns = {}
        execution = {}
        batch_is_valid = True
        for transaction in batch:
            is_valid = True
            addresses_to_set = []
            addresses_to_delete = []
            inputs = transaction['inputs']
            outputs = transaction['outputs']
            inputs_real = [self._address(a) for a in inputs]
            outputs_real = [self._address(a) for a in outputs]
            if self._contains_and_not_none('addresses_to_set', transaction):
                addresses_to_set = [{
                    self._address(a, require_full=True):
                    self._bytes_if_none(d[a])
                    for a in d
                } for d in transaction['addresses_to_set']]
            if self._contains_and_not_none('addresses_to_delete', transaction):
                addresses_to_delete = [
                    self._address(a, require_full=True)
                    for a in transaction['addresses_to_delete']
                ]

            if self._contains_and_not_none('dependencies', transaction):
                if any([
                        a not in self._referenced_txns_in_other_batches
                        and len(a) <= 20 for a in transaction['dependencies']
                ]):
                    # This txn has a dependency with a txn signature that is
                    # not known about,
                    return None

                dependencies = [
                    self._referenced_txns_in_other_batches[a]
                    if a in self._referenced_txns_in_other_batches else a
                    for a in transaction['dependencies']
                ]
                dependencies = [a for a in dependencies if len(a) > 20]
            else:
                dependencies = []

            deps_valid = self._dependencies_are_valid(dependencies,
                                                      previous_batch_results)

            if self._contains_and_not_none('valid', transaction):
                is_valid = bool(transaction['valid'])

            if not is_valid or not deps_valid:
                batch_is_valid = False

            txn, _ = create_transaction(payload=uuid.uuid4().hex.encode(),
                                        dependencies=dependencies,
                                        inputs=inputs_real,
                                        outputs=outputs_real,
                                        signer=signer)

            if self._contains_and_not_none('name', transaction):
                referenced_txns[transaction['name']] = txn.header_signature

            execution[txn.header_signature] = (is_valid, addresses_to_set,
                                               addresses_to_delete)
            txns.append(txn)

        self._txn_execution.update(execution)
        self._referenced_txns_in_other_batches.update(referenced_txns)
        return txns, batch_is_valid

    def _create_batches(self):
        test_yaml = self._yaml_from_file()
        private_key = self._context.new_random_private_key()
        signer = self._crypto_factory.new_signer(private_key)

        batches, batch_results = self._process_batches(yaml_batches=test_yaml,
                                                       signer=signer)

        self._batch_results = batch_results
        self._batches = batches
コード例 #33
0
    def test_no_validator_registry(
            self, mock_utils, mock_validator_registry_view,
            mock_consensus_state, mock_poet_enclave_factory,
            mock_consensus_state_store, mock_poet_key_state_store,
            mock_signup_info, mock_poet_settings_view, mock_block_wrapper):
        """ Test verifies that PoET Block Publisher fails
        if a validator doesn't have any signup info
        in the validator registry (the validator is not listed
        in the validator registry)
        """

        # create a mock_validator_registry_view that throws KeyError
        mock_validator_registry_view.return_value.get_validator_info. \
            side_effect = KeyError('Non-existent validator')

        # create a mock_wait_certificate that does nothing in check_valid
        mock_wait_certificate = mock.Mock()
        mock_wait_certificate.check_valid.return_value = None

        mock_utils.deserialize_wait_certificate.return_value = \
            mock_wait_certificate

        # create a mock_consensus_state that returns a mock with
        # the following settings:
        mock_state = MockConsensusState.create_mock_consensus_state()

        mock_consensus_state.consensus_state_for_block_id.return_value = \
            mock_state

        mock_poet_key_state_store.return_value = \
            _MockPoetKeyStateStore(active_key=None)

        # create mock_signup_info
        mock_signup_info.create_signup_info.return_value = \
            mock.Mock(
                poet_public_key='poet public key',
                proof_data='proof data',
                anti_sybil_id='anti-sybil ID',
                sealed_signup_data='sealed signup data')
        mock_signup_info.block_id_to_nonce.return_value = 'nonce'

        # create mock_batch_publisher
        context = create_context('secp256k1')
        private_key = context.new_random_private_key()
        crypto_factory = CryptoFactory(context)
        signer = crypto_factory.new_signer(private_key)
        mock_batch_publisher = mock.Mock(identity_signer=signer)

        mock_block_cache = mock.MagicMock()
        mock_state_view_factory = mock.Mock()

        # create mock_block_header with the following fields
        mock_block = mock.Mock(identifier='0123456789abcdefedcba9876543210')
        mock_block.header.signer_public_key = \
            '90834587139405781349807435098745'
        mock_block.header.previous_block_id = '2'
        mock_block.header.block_num = 1
        mock_block.header.state_root_hash = '6'
        mock_block.header.batch_ids = '4'

        # check test
        block_publisher = \
            poet_block_publisher.PoetBlockPublisher(
                block_cache=mock_block_cache,
                state_view_factory=mock_state_view_factory,
                batch_publisher=mock_batch_publisher,
                data_dir=self._temp_dir,
                config_dir=self._temp_dir,
                validator_id='validator_deadbeef')

        self.assertFalse(
            block_publisher.initialize_block(block_header=mock_block.header))

        # check that batch publisher was called to send out
        # the txn header and txn for the validator registry update
        self.assertTrue(mock_batch_publisher.send.called)
コード例 #34
0
ファイル: main.py プロジェクト: rachelye1/ICTDResearch
class SawtoothClient(object):
    def __init__(self, url, keyfile=None):
        self.base_url = url

        if keyfile is not None:
            with open(keyfile) as fd:
                private_key_str = fd.read().strip()
                fd.close()

            sawtooth_signing_key = Secp256k1PrivateKey.from_hex(
                private_key_str)

            self._signer = CryptoFactory(
                create_context('secp256k1')).new_signer(sawtooth_signing_key)

    def add_net(self, network_id, payload, wait=None):
        address = make_network_address(network_id)
        return self._send_transaction(ActionTypes.ADD_NET.value,
                                      payload, [address],
                                      wait=wait)

    def _send_transaction(self, action, action_payload, addresses, wait=None):
        payload = cbor.dumps({'action': action, 'payload': action_payload})

        header = TransactionHeader(
            signer_public_key=self._signer.get_public_key().as_hex(),
            family_name="billing-crdt",
            family_version="0.0.1",
            inputs=addresses,
            outputs=addresses,
            dependencies=[],
            payload_sha512=self._sha512(payload),
            batcher_public_key=self._signer.get_public_key().as_hex(),
            nonce=self._nonce()).SerializeToString()

        signature = self._signer.sign(header)

        transaction = Transaction(header=header,
                                  payload=payload,
                                  header_signature=signature)

        batch_list = self._create_batch_list([transaction])
        batch_id = batch_list.batches[0].header_signature

        if wait and wait > 0:
            wait_time = 0
            start_time = time.time()
            response = self._send_request(
                "batches",
                batch_list.SerializeToString(),
                'application/octet-stream',
            )
            while wait_time < wait:
                status = self._get_status(
                    batch_id,
                    wait - int(wait_time),
                )
                wait_time = time.time() - start_time

                if status != 'PENDING':
                    return response

            return response

        return self._send_request(
            "batches",
            batch_list.SerializeToString(),
            'application/octet-stream',
        )

    def _send_request(self, suffix, data=None, content_type=None, name=None):
        url = "{}/{}".format(self.base_url, suffix)
        headers = {}
        if content_type is not None:
            headers['Content-Type'] = content_type

        try:
            if data is not None:
                result = requests.post(url, headers=headers, data=data)
            else:
                result = requests.get(url, headers=headers)

            if not result.ok:
                raise CrdtClientException(
                    "Error url={} name={} - {}: {}".format(
                        suffix, name, result.status_code, result.reason))

        except requests.ConnectionError as err:
            raise CrdtClientException(
                'Failed to connect to REST API: {}'.format(err))

        except BaseException as err:
            raise CrdtClientException(err)

        return result.text

    def _create_batch_list(self, transactions):
        transaction_signatures = [t.header_signature for t in transactions]

        header = BatchHeader(
            signer_public_key=self._signer.get_public_key().as_hex(),
            transaction_ids=transaction_signatures).SerializeToString()

        signature = self._signer.sign(header)

        batch = Batch(header=header,
                      transactions=transactions,
                      header_signature=signature)
        return BatchList(batches=[batch])

    @staticmethod
    def _sha512(data):
        return hashlib.sha512(data).hexdigest()

    @staticmethod
    def _nonce():
        return time.time().hex().encode()
コード例 #35
0
class CarLoggerClient(object):
    '''Client car logger class.

    This supports create, add, delete, history functions.
    '''
    def __init__(self, baseUrl, private_key=None, vin=''):
        '''Initialize the client class.

           This is mainly getting the key pair and computing the address.
        '''

        self._baseUrl = baseUrl

        try:
            privateKey = Secp256k1PrivateKey.from_hex(private_key)
        except ParseError as err:
            raise Exception('Failed to load private key: {}'.format(str(err)))

        self._signer = CryptoFactory(create_context('secp256k1')) \
            .new_signer(privateKey)

        self._publicKey = self._signer.get_public_key().as_hex()
        self.VIN = vin
        self._address = _hash(FAMILY_NAME.encode('utf-8'))[0:6] + \
            _hash(self.VIN.encode('utf-8'))[0:64]

    # For each valid cli command in _cli.py file,
    # add methods to:
    # 1. Do any additional handling, if required
    # 2. Create a transaction and a batch
    # 2. Send to rest-api

    def create(self, VIN, keyfile, work_date, brand, model, description):
        return self._wrap_and_send("create", VIN, keyfile, work_date, brand,
                                   model, description)

    def add(self, VIN, keyfile, work_date, work, km_status, description):
        return self._wrap_and_send("add", VIN, keyfile, work_date, work,
                                   km_status, description)

    def delete(self, VIN, keyfile, work_date, work, km_status, description):
        return self._wrap_and_send("delete", VIN, keyfile, work_date, work,
                                   km_status, description)

    def history(self):
        result = self._send_to_restapi("state/{}".format(self._address))
        try:
            return base64.b64decode(yaml.safe_load(result)["data"])

        except BaseException:
            return None

    def _send_to_restapi(self, suffix, data=None, contentType=None):
        '''Send a REST command to the Validator via the REST API.'''

        if self._baseUrl.startswith("http://"):
            url = "{}/{}".format(self._baseUrl, suffix)
        else:
            url = "http://{}/{}".format(self._baseUrl, suffix)

        headers = {}

        if contentType is not None:
            headers['Content-Type'] = contentType

        try:
            if data is not None:
                result = requests.post(url, headers=headers, data=data)
            else:
                result = requests.get(url, headers=headers)

            if not result.ok:
                raise Exception("Error {}: {}".format(result.status_code,
                                                      result.reason))

        except requests.ConnectionError as err:
            raise Exception('Failed to connect to {}: {}'.format(
                url, str(err)))

        except BaseException as err:
            raise Exception(err)

        return result.text

    def _wrap_and_send(self, action, *values):
        '''Create a transaction, then wrap it in a batch.
           Even single transactions must be wrapped into a batch.
        '''

        # Generate a csv utf-8 encoded string as payload
        rawPayload = action

        for val in values:
            rawPayload = ",".join([rawPayload, str(val)])

        payload = rawPayload.encode()

        # Construct the address where we'll store our state
        address = self._address
        inputAddressList = [address]
        outputAddressList = [address]

        # Create a TransactionHeader
        header = TransactionHeader(
            signer_public_key=self._publicKey,
            family_name=FAMILY_NAME,
            family_version="1.0",
            inputs=inputAddressList,
            outputs=outputAddressList,
            dependencies=[],
            payload_sha512=_hash(payload),
            batcher_public_key=self._publicKey,
            nonce=random.random().hex().encode()).SerializeToString()

        # Create a Transaction from the header and payload above
        transaction = Transaction(header=header,
                                  payload=payload,
                                  header_signature=self._signer.sign(header))

        transactionList = [transaction]

        # Create a BatchHeader from transactionList above
        header = BatchHeader(
            signer_public_key=self._publicKey,
            transaction_ids=[txn.header_signature
                             for txn in transactionList]).SerializeToString()

        # Create Batch using the BatchHeader and transactionList above
        batch = Batch(header=header,
                      transactions=transactionList,
                      header_signature=self._signer.sign(header))

        # Create a Batch List from Batch above
        batch_list = BatchList(batches=[batch])

        # Send batch_list to rest-api
        return self._send_to_restapi("batches", batch_list.SerializeToString(),
                                     'application/octet-stream')
コード例 #36
0
    def test_block_publisher_doesnt_claim_readiness(
            self, mock_utils, mock_validator_registry_view,
            mock_consensus_state, mock_poet_enclave_factory,
            mock_consensus_state_store, mock_poet_key_state_store,
            mock_signup_info, mock_wait_time, mock_poet_settings_view,
            mock_block_wrapper):
        """ Test verifies that PoET Block Publisher doesn't
         claims readiness if the wait timer hasn't expired
        """

        # create a mock_validator_registry_view with
        # get_validator_info that does nothing
        mock_validator_registry_view.return_value.get_validator_info. \
            return_value = \
            ValidatorInfo(
                name='validator_001',
                id='validator_deadbeef',
                signup_info=SignUpInfo(
                    poet_public_key='00112233445566778899aabbccddeeff'))

        # create a mock_consensus_state that returns a mock with
        # the following settings:
        mock_state = MockConsensusState.create_mock_consensus_state()

        mock_consensus_state.consensus_state_for_block_id.return_value = \
            mock_state

        mock_consensus_state_store.return_value.__getitem__.return_value = \
            mock_consensus_state

        # Create mock key state
        mock_poet_key_state_store.return_value.__getitem__.return_value = \
            mock.Mock(
                sealed_signup_data='sealed signup data',
                has_been_refreshed=False)

        # create mock_signup_info
        mock_signup_info.unseal_signup_data.return_value = \
            '00112233445566778899aabbccddeeff'

        # create mock_batch_publisher
        context = create_context('secp256k1')
        private_key = context.new_random_private_key()
        crypto_factory = CryptoFactory(context)
        signer = crypto_factory.new_signer(private_key)

        mock_batch_publisher = mock.Mock(identity_signer=signer)

        mock_block_cache = mock.MagicMock()
        mock_state_view_factory = mock.Mock()

        # create mock_block_header with the following fields
        mock_block = mock.Mock(identifier='0123456789abcdefedcba9876543210')
        mock_block.header.signer_public_key = \
            '90834587139405781349807435098745'
        mock_block.header.previous_block_id = '2'
        mock_block.header.block_num = 1
        mock_block.header.state_root_hash = '6'
        mock_block.header.batch_ids = '4'

        # create a mock_wait_timer that hasn't expired yet
        my_wait_time = mock.Mock()
        my_wait_time.has_expired.return_value = False

        mock_wait_time.create_wait_timer.return_value = my_wait_time

        # create mock_poet_enclave_module
        mock_poet_enclave_module = mock.Mock()
        mock_poet_enclave_module.return_value = \
            mock_poet_enclave_factory.get_poet_enclave_module.return_value

        # check test
        block_publisher = \
            poet_block_publisher.PoetBlockPublisher(
                block_cache=mock_block_cache,
                state_view_factory=mock_state_view_factory,
                batch_publisher=mock_batch_publisher,
                data_dir=self._temp_dir,
                config_dir=self._temp_dir,
                validator_id='validator_deadbeef')

        # check initialize_block() first to set wait_timer
        self.assertTrue(
            block_publisher.initialize_block(block_header=mock_block.header))

        # check that block_publisher only claims readiness
        # when the wait_timer has expired
        self.assertFalse(
            block_publisher.check_publish_block(
                block_header=mock_block.header))
コード例 #37
0
    def test_z_policy(self, mock_utils, mock_validator_registry_view,
                      mock_consensus_state, mock_poet_enclave_factory,
                      mock_consensus_state_store, mock_poet_key_state_store,
                      mock_signup_info, mock_poet_settings_view,
                      mock_block_wrapper):
        """ Z Policy: Test verifies that PoET Block Publisher fails
        if a validator attempts to claim more blocks frequently than is allowed
        """

        # create a mock_validator_registry_view with
        # get_validator_info that does nothing
        mock_validator_registry_view.return_value.get_validator_info. \
            return_value = \
            ValidatorInfo(
                name='validator_001',
                id='validator_deadbeef',
                signup_info=SignUpInfo(
                    poet_public_key='00112233445566778899aabbccddeeff'))

        # create a mock_wait_certificate that does nothing in check_valid
        mock_wait_certificate = mock.Mock()
        mock_wait_certificate.check_valid.return_value = None

        mock_utils.deserialize_wait_certificate.return_value = \
            mock_wait_certificate

        # create a mock_consensus_state that returns a mock with
        # the following settings:
        mock_state = MockConsensusState.create_mock_consensus_state(
            claiming_too_frequently=True)

        mock_consensus_state.consensus_state_for_block_id.return_value = \
            mock_state

        mock_consensus_state_store.return_value.__getitem__.return_value = \
            mock_consensus_state

        # Create mock key state
        mock_poet_key_state_store.return_value.__getitem__.return_value = \
            mock.Mock(
                sealed_signup_data='sealed signup data',
                has_been_refreshed=False)

        # create mock_signup_info
        mock_signup_info.unseal_signup_data.return_value = \
            '00112233445566778899aabbccddeeff'

        # create mock_batch_publisher
        context = create_context('secp256k1')
        private_key = context.new_random_private_key()
        crypto_factory = CryptoFactory(context)
        signer = crypto_factory.new_signer(private_key)

        mock_batch_publisher = mock.Mock(identity_signer=signer)

        mock_block_cache = mock.MagicMock()
        mock_state_view_factory = mock.Mock()

        # create mock_block_header with the following fields
        mock_block = mock.Mock(identifier='0123456789abcdefedcba9876543210')
        mock_block.header.signer_public_key = \
            '90834587139405781349807435098745'
        mock_block.header.previous_block_id = '2'
        mock_block.header.block_num = 1
        mock_block.header.state_root_hash = '6'
        mock_block.header.batch_ids = '4'

        # check test
        with mock.patch('sawtooth_poet.poet_consensus.poet_block_publisher.'
                        'LOGGER') as mock_logger:
            block_publisher = \
                poet_block_publisher.PoetBlockPublisher(
                    block_cache=mock_block_cache,
                    state_view_factory=mock_state_view_factory,
                    batch_publisher=mock_batch_publisher,
                    data_dir=self._temp_dir,
                    config_dir=self._temp_dir,
                    validator_id='validator_deadbeef')

            self.assertFalse(
                block_publisher.initialize_block(
                    block_header=mock_block.header))

            # Could be a hack, but verify that the appropriate log message is
            # generated - so we at least have some faith that the failure was
            # because of what we are testing and not something else.  I know
            # that this is fragile if the log message is changed, so would
            # accept any suggestions on a better way to verify that the
            # function fails for the reason we expect.

            (message, *_), _ = mock_logger.info.call_args
            self.assertTrue('is claiming blocks too ' 'frequently' in message)
コード例 #38
0
class CapBACClient:
    def __init__(self, url, keyfile=None):
        self.url = url

        if keyfile is not None:
            try:
                with open(keyfile) as fd:
                    private_key_str = fd.read().strip()
                    fd.close()
            except OSError as err:
                raise CapBACClientException(
                    'Failed to read private key: {}'.format(str(err)))

            try:
                private_key = Secp256k1PrivateKey.from_hex(private_key_str)
            except ParseError as e:
                raise CapBACClientException(
                    'Unable to load private key: {}'.format(str(e)))

            self._signer = CryptoFactory(
                create_context('secp256k1')).new_signer(private_key)

    # For each valid cli commands in _cli.py file
    # Add methods to:
    # 1. Do any additional handling, if required
    # 2. Create a transaction and a batch
    # 2. Send to rest-api

    def issue(self, token, is_root):

        try:
            token = json.loads(token)
        except:
            raise CapBACClientException('Invalid token: serialization failed')

        return self.issue_from_dict(token, is_root)

    def issue_from_dict(self,token, is_root):

        # check the formal validity of the incomplete token
        subset = set(CAPABILITY_FORMAT) - {'II','SI','VR'}
        if is_root: subset -= {'IC','SU'}

        _check_format(token,'capabiliy token',CAPABILITY_FORMAT,subset)

        for access_right in token['AR']:
            _check_format(access_right,'capability token: access right',ACCESS_RIGHT_FORMAT)

        # time interval logical check
        try:
            not_before = int(token['NB'])
            not_after  = int(token['NA'])
        except:
            raise CapBACClientException('Invalid capability: timestamp not a number')

        if not_before > not_after:
            raise CapBACClientException("Invalid capability: incorrect time interval")

        now = int(time.time())
        if now > not_after:
            raise CapBACClientException("Capability already expired")

        if is_root:
            token['IC'] = None
            token['SU'] = self._signer.get_public_key().as_hex()

        # add signature
        token= self.sign_dict(token)

        # now the token is complete

        payload = cbor.dumps({
            'AC': "issue",
            'OB': token
        })

        return self._send_transaction(payload, token['DE'])

    def revoke(self, token):

        try:
            token = json.loads(token)
        except:
            raise CapBACClientException('Invalid revocation token: serialization failed')

        return self.revoke_from_dict(token)

    def revoke_from_dict(self, token):

        # check the formal validity of the incomplete revocation token
        subset = set(REVOCATION_FORMAT) - {'II','SI','VR'}

        _check_format(token,'revocation token',REVOCATION_FORMAT,subset)

        # add signature
        token = self.sign_dict(token)

        # now the revocation token is complete

        payload = cbor.dumps({
            'AC': "revoke",
            'OB': token
        })

        return self._send_transaction(payload, token['DE'])

    def list(self,device):

        if len(device) > MAX_URI_LENGTH:
            raise CapBACClientException(
                'Invalid URI: max length exceeded, should be less than {}'
                .format(MAX_URI_LENGTH))

        result = self._send_request(
            "state?address={}".format(
                self._get_address(device)))

        try:
            encoded_entries = yaml.safe_load(result)["data"]

            data_list = [
                cbor.loads(base64.b64decode(entry["data"]))
                for entry in encoded_entries
            ]

            return json.dumps({
                x:y[x] for y in data_list for x in y
            }, indent=4, sort_keys=True)

        except BaseException:
            return None

    def validate(self,token):

        try:
            token = json.loads(token)
        except:
            raise CapBACClientException('Invalid access token: serialization failed')

        return self.validate_from_dict(token)

    def validate_from_dict(self,token):

        _check_format(token,"access token",VALIDATION_FORMAT)

        # state retrival
        device = token['DE']
        result = self._send_request(
            "state?address={}".format(
                self._get_address(device)))

        try:
            encoded_entries = yaml.safe_load(result)["data"]

            data_list =  [
                cbor.loads(base64.b64decode(entry["data"]))
                for entry in encoded_entries
            ]

            state = {x:y[x] for y in data_list for x in y}

        except BaseException:
            return None

        LOGGER.info('checking authorization')
        # check authorization
        capability = token['IC']

        if capability not in state:
            return False

        LOGGER.info('checking delegation chain')
        # delegation chain check
        now = int(time.time())
        resource = token['RE']
        action = token['AC']

        current_token = state[capability]
        parent = current_token['IC']
        while parent != None:
            if parent not in state:
                raise BaseException
            parent_token = state[parent]

            # check time interval
            if now >= int(parent_token['NA']):
                return False
            if now < int(parent_token['NB']):
                return False

            # check access rights
            if resource not in parent_token["AR"]:
                return False
            if action not in parent_token["AR"][resource]:
                return False

            # next
            current_token = parent_token
            parent = current_token['IC']

        LOGGER.info('checking signature')
        # check signature
        signature = token.pop('SI')
        if not create_context('secp256k1').verify(
            signature,
            str(cbor.dumps(token,sort_keys=True)).encode('utf-8'),
            Secp256k1PublicKey.from_hex(state[capability]['SU'])
            ):
            return False

        return True

    def sign(self, token):

        try:
            token = json.loads(token)
        except:
            raise CapBACClientException('Invalid token: serialization failed')

        token = self.sign_dict(token)
        return json.dumps(token)

    def sign_dict(self, token):

        # add version
        token['VR'] = FAMILY_VERSION

        # add issue time
        now = int(time.time())
        token['II'] = str(now)

        # add signature
        token_serialized = str(cbor.dumps(token,sort_keys=True)).encode('utf-8')
        token['SI'] = self._signer.sign(token_serialized)

        return token

    def _get_prefix(self):
        return _sha512(FAMILY_NAME.encode('utf-8'))[0:6]

    def _get_address(self, device):
        prefix = self._get_prefix()
        device_address = _sha512(device.encode('utf-8'))[64:]
        return prefix + device_address

    def _send_request(self,
                      suffix,
                      data=None,
                      contentType=None):
        if self.url.startswith("http://"):
            url = "{}/{}".format(self.url, suffix)
        else:
            url = "http://{}/{}".format(self.url, suffix)

        headers = {}

        if contentType is not None:
            headers['Content-Type'] = contentType

        try:
            if data is not None:
                result = requests.post(url, headers=headers, data=data)
            else:
                result = requests.get(url, headers=headers)

            if not result.ok:
                raise CapBACClientException("Error {}: {}".format(
                    result.status_code, result.reason))

        except requests.ConnectionError as err:
            raise CapBACClientException(
                'Failed to connect to {}: {}'.format(url, str(err)))

        except BaseException as err:
            raise CapBACClientException(err)

        return result.text

    def _send_transaction(self, payload, device):

        # Get the unique address for the device's tokens
        address = self._get_address(device)

        header = TransactionHeader(
            signer_public_key=self._signer.get_public_key().as_hex(),
            family_name=FAMILY_NAME,
            family_version=FAMILY_VERSION,
            inputs=[address],
            outputs=[address],
            dependencies=[],
            payload_sha512=_sha512(payload),
            batcher_public_key=self._signer.get_public_key().as_hex(),
            nonce=time.time().hex().encode()
        ).SerializeToString()

        signature = self._signer.sign(header)

        transaction = Transaction(
            header=header,
            payload=payload,
            header_signature=signature
        )

        batch_list = self._create_batch_list([transaction])

        return self._send_request(
            "batches", batch_list.SerializeToString(),
            'application/octet-stream'
        )

    def _create_batch_list(self, transactions):
        transaction_signatures = [t.header_signature for t in transactions]

        header = BatchHeader(
            signer_public_key=self._signer.get_public_key().as_hex(),
            transaction_ids=transaction_signatures
        ).SerializeToString()

        signature = self._signer.sign(header)

        batch = Batch(
            header=header,
            transactions=transactions,
            header_signature=signature)
        return BatchList(batches=[batch])
コード例 #39
0
ファイル: sawtooth.py プロジェクト: dyne/petition-tp-python
class SawtoothHelper:
    def __init__(self, base_url, validator_url=None, pk=None, context=None):
        self.base_url = base_url
        self.validator_url = validator_url if validator_url else f"{base_url}:4004"
        self.context = context if context else create_context("secp256k1")
        self.pk = pk if pk else self.context.new_random_private_key()
        self.signer = CryptoFactory(self.context).new_signer(self.pk)
        self.family_name = "DECODE_PETITION"
        self.family_version = "1.0"

    @property
    def private_key(self):
        return self.pk.secp256k1_private_key.serialize()

    def set_url(self, url):
        self.base_url = url

    def create_transaction(self, payload, family_name, family_version,
                           address):
        payload_bytes = cbor2.dumps(payload)

        txn_header = TransactionHeader(
            batcher_public_key=self.signer.get_public_key().as_hex(),
            inputs=[address],
            outputs=[address],
            dependencies=[],
            family_name=family_name,
            family_version=family_version,
            nonce=hex(randint(0, 2**64)),
            payload_sha512=sha512(payload_bytes).hexdigest(),
            signer_public_key=self.signer.get_public_key().as_hex(),
        ).SerializeToString()

        txn = Transaction(
            header=txn_header,
            header_signature=self.signer.sign(txn_header),
            payload=payload_bytes,
        )

        return [txn]

    def create_batch(self, transactions):
        batch_header = BatchHeader(
            signer_public_key=self.signer.get_public_key().as_hex(),
            transaction_ids=[txn.header_signature for txn in transactions],
        ).SerializeToString()

        batch = Batch(
            header=batch_header,
            header_signature=self.signer.sign(batch_header),
            transactions=transactions,
        )

        return BatchList(batches=[batch]).SerializeToString()

    def get_state(self, payload, address):
        petition_address = self.generate_address(self.family_name, payload)
        r = requests.get(f"{address}/state?address={petition_address}")
        return r.json()

    def get_batches(self, payload, address):
        state = self.get_state(payload, address)
        r = requests.get(f"{address}/blocks/{state['head']}")
        batches = r.json()["data"]["batches"]
        return batches

    def _post(self, payload, family_name, family_version, address):
        transactions = self.create_transaction(payload, family_name,
                                               family_version, address)
        batches = self.create_batch(transactions)
        response = requests.post(
            f"{self.base_url}",
            data=batches,
            headers={"Content-Type": "application/octet-stream"},
        )
        return response.json()

    def post(self, payload):
        address = self.generate_address(self.family_name, payload)
        return self._post(payload, self.family_name, self.family_version,
                          address)

    @staticmethod
    def generate_address(family_name, payload):
        namespace = sha512(family_name.encode("utf-8")).hexdigest()[0:6]
        petition = sha512(
            payload["petition_id"].encode("utf-8")).hexdigest()[-64:]
        return namespace + petition
コード例 #40
0
    def test_signup_info_not_committed_within_allowed_delay(
            self,
            mock_utils,
            mock_validator_registry_view,
            mock_consensus_state,
            mock_poet_enclave_factory,
            mock_consensus_state_store,
            mock_poet_key_state_store,
            mock_signup_info,
            mock_poet_settings_view,
            mock_block_wrapper):
        """ Test verifies that PoET Block Publisher fails if
        a validator's signup info was not committed to
        the block chain within the allowed configured delay
        """

        # create a mock_validator_registry_view with
        # get_validator_info that does nothing
        mock_validator_registry_view.return_value.get_validator_info. \
            return_value = \
            ValidatorInfo(
                name='validator_001',
                id='validator_deadbeef',
                signup_info=SignUpInfo(
                    poet_public_key='00112233445566778899aabbccddeeff',
                    nonce='nonce'))

        # create a mock_wait_certificate that does nothing in check_valid
        mock_wait_certificate = mock.Mock()
        mock_wait_certificate.check_valid.return_value = None

        mock_utils.deserialize_wait_certificate.return_value = \
            mock_wait_certificate

        # create a mock_consensus_state that returns a mock with
        # the following settings:
        mock_state = MockConsensusState.create_mock_consensus_state(
            committed_too_late=True)
        mock_consensus_state.consensus_state_for_block_id.return_value = \
            mock_state

        mock_consensus_state_store.return_value.__getitem__.return_value = \
            mock_consensus_state

        # Create mock key state
        mock_poet_key_state_store.return_value.__getitem__.return_value = \
            mock.Mock(
                sealed_signup_data='sealed signup data',
                has_been_refreshed=False)

        # create mock_signup_info
        mock_signup_info.create_signup_info.return_value = \
            mock.Mock(
                poet_public_key='poet public key',
                proof_data='proof data',
                anti_sybil_id='anti-sybil ID',
                sealed_signup_data='sealed signup data')
        mock_signup_info.block_id_to_nonce.return_value = 'nonce'
        mock_signup_info.unseal_signup_data.return_value = \
            '00112233445566778899aabbccddeeff'

        # create mock_batch_publisher
        context = create_context('secp256k1')
        private_key = context.new_random_private_key()
        crypto_factory = CryptoFactory(context)
        signer = crypto_factory.new_signer(private_key)

        mock_batch_publisher = mock.Mock(identity_signer=signer)

        mock_block_cache = mock.MagicMock()
        mock_state_view_factory = mock.Mock()

        # create mock_block_header with the following fields
        mock_block = mock.Mock(identifier='0123456789abcdefedcba9876543210')
        mock_block.header.signer_public_key = \
            '90834587139405781349807435098745'
        mock_block.header.previous_block_id = '2'
        mock_block.header.block_num = 1
        mock_block.header.state_root_hash = '6'
        mock_block.header.batch_ids = '4'

        # check test
        with mock.patch('sawtooth_poet.poet_consensus.poet_block_publisher.'
                        'LOGGER') as mock_logger:
            block_publisher = \
                poet_block_publisher.PoetBlockPublisher(
                    block_cache=mock_block_cache,
                    state_view_factory=mock_state_view_factory,
                    batch_publisher=mock_batch_publisher,
                    data_dir=self._temp_dir,
                    config_dir=self._temp_dir,
                    validator_id='validator_deadbeef')

            self.assertFalse(
                block_publisher.initialize_block(
                    block_header=mock_block.header))

            # Could be a hack, but verify that the appropriate log message is
            # generated - so we at least have some faith that the failure was
            # because of what we are testing and not something else.  I know
            # that this is fragile if the log message is changed, so would
            # accept any suggestions on a better way to verify that the
            # function fails for the reason we expect.
            self.assertTrue(
                any(
                    'Validator signup information not committed in a timely '
                    'manner.' in call[0][0] for call in
                    mock_logger.info.call_args_list))

            # check that create.signup_info() was called to create
            # the validator registry payload with new set of keys
            self.assertTrue(mock_signup_info.create_signup_info.called)
コード例 #41
0
ファイル: keygen.py プロジェクト: nankedr/RepMag
import os
from sawtooth_signing import create_context
from sawtooth_signing import CryptoFactory
from sawtooth_signing.secp256k1 import Secp256k1PrivateKey

if not os.path.exists('userskey'):
    context = create_context('secp256k1')
    with open('userskey', 'w') as f:
        for i in range(0, 100):
            private_key = context.new_random_private_key()
            print(private_key.as_hex())
            f.write(private_key.as_hex() + '\n')

with open('userskey', 'r') as f:
    signer_list = [line.rstrip('\n') for line in f.readlines()]

print(signer_list)

if not os.path.exists('users_pub_key'):
    context = create_context('secp256k1')
    with open('users_pub_key', 'w') as f:
        for key in signer_list:
            pub_key = CryptoFactory(context).new_signer(
                Secp256k1PrivateKey.from_hex(key)).get_public_key().as_hex()
            f.write(pub_key + ' ' + '1' + '\n')
コード例 #42
0
    def test_z_policy(
            self,
            mock_utils,
            mock_validator_registry_view,
            mock_consensus_state,
            mock_poet_enclave_factory,
            mock_consensus_state_store,
            mock_poet_key_state_store,
            mock_signup_info,
            mock_poet_settings_view,
            mock_block_wrapper):
        """ Z Policy: Test verifies that PoET Block Publisher fails
        if a validator attempts to claim more blocks frequently than is allowed
        """

        # create a mock_validator_registry_view with
        # get_validator_info that does nothing
        mock_validator_registry_view.return_value.get_validator_info. \
            return_value = \
            ValidatorInfo(
                name='validator_001',
                id='validator_deadbeef',
                signup_info=SignUpInfo(
                    poet_public_key='00112233445566778899aabbccddeeff'))

        # create a mock_wait_certificate that does nothing in check_valid
        mock_wait_certificate = mock.Mock()
        mock_wait_certificate.check_valid.return_value = None

        mock_utils.deserialize_wait_certificate.return_value = \
            mock_wait_certificate

        # create a mock_consensus_state that returns a mock with
        # the following settings:
        mock_state = MockConsensusState.create_mock_consensus_state(
            claiming_too_frequently=True)

        mock_consensus_state.consensus_state_for_block_id.return_value = \
            mock_state

        mock_consensus_state_store.return_value.__getitem__.return_value = \
            mock_consensus_state

        # Create mock key state
        mock_poet_key_state_store.return_value.__getitem__.return_value = \
            mock.Mock(
                sealed_signup_data='sealed signup data',
                has_been_refreshed=False)

        # create mock_signup_info
        mock_signup_info.unseal_signup_data.return_value = \
            '00112233445566778899aabbccddeeff'

        # create mock_batch_publisher
        context = create_context('secp256k1')
        private_key = context.new_random_private_key()
        crypto_factory = CryptoFactory(context)
        signer = crypto_factory.new_signer(private_key)

        mock_batch_publisher = mock.Mock(identity_signer=signer)

        mock_block_cache = mock.MagicMock()
        mock_state_view_factory = mock.Mock()

        # create mock_block_header with the following fields
        mock_block = mock.Mock(identifier='0123456789abcdefedcba9876543210')
        mock_block.header.signer_public_key = \
            '90834587139405781349807435098745'
        mock_block.header.previous_block_id = '2'
        mock_block.header.block_num = 1
        mock_block.header.state_root_hash = '6'
        mock_block.header.batch_ids = '4'

        # check test
        with mock.patch('sawtooth_poet.poet_consensus.poet_block_publisher.'
                        'LOGGER') as mock_logger:
            block_publisher = \
                poet_block_publisher.PoetBlockPublisher(
                    block_cache=mock_block_cache,
                    state_view_factory=mock_state_view_factory,
                    batch_publisher=mock_batch_publisher,
                    data_dir=self._temp_dir,
                    config_dir=self._temp_dir,
                    validator_id='validator_deadbeef')

            self.assertFalse(
                block_publisher.initialize_block(
                    block_header=mock_block.header))

            # Could be a hack, but verify that the appropriate log message is
            # generated - so we at least have some faith that the failure was
            # because of what we are testing and not something else.  I know
            # that this is fragile if the log message is changed, so would
            # accept any suggestions on a better way to verify that the
            # function fails for the reason we expect.

            (message, *_), _ = mock_logger.info.call_args
            self.assertTrue('is claiming blocks too '
                            'frequently' in message)
コード例 #43
0
class SchedulerTester(object):
    """ The canonical form of the yaml is:
      -  <------------------------------------------ batch start
        state_hash: string. Optional. No default.
        - <----------------------------------------- transaction start
          inputs: list of string. Required.
            - ....
          outputs: list of string. Required.
            - ....
          addresses_to_set: list of dict. Optional.
            - string <address>: Optional bytes <value>
          addresses_to_delete: list of str. Optional
            - string <address>
          valid: boolean. Optional. Defaults to True
          dependencies: list of string. Optional. Defaults to empty list.
            - ..... string. No default. If a dependency is the same
                            string as a 'name' for another txn, that
                            txn's signature will be used for the
                            actual Transaction's dependency. If the
                            string is not an 'name' of another txn, if
                            it is longer than 20 characters it will be
                            used as if is is the actual
                            Transaction.header_signature for the
                            dependency. If not, it will be
                            disregarded.
          name: string. Optional. No default.
    """

    def __init__(self, file_name):
        """

        Args:
            file_name (str): The yaml filename and path.
            scheduler (scheduler.Scheduler): Any Scheduler implementaion
            context_manager (context_manager.ContextManager): The context
                manager holding state for this scheduler.
        """
        self._context = create_context('secp256k1')
        self._crypto_factory = CryptoFactory(self._context)
        self._yaml_file_name = file_name
        self._counter = itertools.count(0)
        self._referenced_txns_in_other_batches = {}
        self._batch_id_by_txn_id = {}
        self._txn_execution = {}

        self._batch_results = {}
        self._batches = []

        self._create_batches()

    @property
    def batch_results(self):
        """The batch results calculated from the yaml file.

        Returns:
            (dict): Computed from the yaml file, a dictionary with
                batch signature keys and BatchExecutionResult values.
        """
        return self._batch_results

    def run_scheduler(self,
                      scheduler,
                      context_manager,
                      validation_state_hash=None,
                      txns_executed_fifo=True):
        """Add all the batches to the scheduler in order and then run through
        the txns in the scheduler, calling next_transaction() after each
        transaction_execution_result is set.

        Args:
            scheduler (scheduler.Scheduler): Any implementation of the
                Scheduler abstract base class.
            context_manager (context_manager.ContextManager): The context
                manager is needed to store state based on the yaml file.
            validation_state_hash (str): Used in cases where the yaml
                represents a single block of valid batches, and the
                state hash is not in the yaml file. This state hash is added
                to the last batch in the scheduler.

        Returns batch_results (list of tuples): A list of tuples of
            batch signature, BatchExecutionResult pairs.
        """

        for i, batch in enumerate(self._batches):
            if i == len(self._batches) - 1 and \
                    validation_state_hash is not None:
                s_h = validation_state_hash
            else:
                s_h = self._batch_results[batch.header_signature].state_hash
            scheduler.add_batch(batch=batch, state_hash=s_h)

        scheduler.finalize()
        txns_to_process = deque()

        txn_context_by_txn_id = self._compute_transaction_execution_context()

        transactions_to_assert_state = {}
        while not scheduler.complete(block=False):
            stop = False
            while not stop:
                try:
                    txn_info = scheduler.next_transaction()
                except StopIteration:
                    break
                if txn_info is not None:
                    txns_to_process.append(txn_info)
                    LOGGER.debug("Transaction %s scheduled",
                                 txn_info.txn.header_signature[:16])
                else:
                    stop = True
            try:
                if txns_executed_fifo:
                    t_info = txns_to_process.popleft()
                else:
                    t_info = txns_to_process.pop()
            except IndexError:
                # No new txn was returned from next_transaction so
                # check again if complete.
                continue

            inputs, outputs = self._get_inputs_outputs(t_info.txn)

            c_id = context_manager.create_context(
                state_hash=t_info.state_hash,
                base_contexts=t_info.base_context_ids,
                inputs=inputs,
                outputs=outputs)

            t_id = t_info.txn.header_signature

            if t_id in txn_context_by_txn_id:
                state_up_to_now = txn_context_by_txn_id[t_id].state
                txn_context = txn_context_by_txn_id[t_id]
                inputs, _ = self._get_inputs_outputs(txn_context.txn)
                addresses = [input for input in inputs if len(input) == 70]
                state_found = context_manager.get(
                    context_id=c_id,
                    address_list=addresses)

                LOGGER.debug("Transaction Id %s, Batch %s, Txn %s, "
                             "Context_id %s, Base Contexts %s",
                             t_id[:16],
                             txn_context.batch_num,
                             txn_context.txn_num,
                             c_id,
                             t_info.base_context_ids)

                state_to_assert = [(add, state_up_to_now.get(add))
                                   for add, _ in state_found]
                transactions_to_assert_state[t_id] = (txn_context,
                                                      state_found,
                                                      state_to_assert)

            validity, address_values, deletes = self._txn_execution[
                t_info.txn.header_signature]

            context_manager.set(
                context_id=c_id,
                address_value_list=address_values)

            context_manager.delete(
                context_id=c_id,
                address_list=deletes)
            LOGGER.debug("Transaction %s is %s",
                         t_id[:16],
                         'valid' if validity else 'invalid')
            scheduler.set_transaction_execution_result(
                txn_signature=t_info.txn.header_signature,
                is_valid=validity,
                context_id=c_id)

        batch_ids = [b.header_signature for b in self._batches]
        batch_results = [
            (b_id, scheduler.get_batch_execution_result(b_id))
            for b_id in batch_ids]

        return batch_results, transactions_to_assert_state

    def run_scheduler_alternating(self, scheduler, context_manager,
                                  validation_state_hash=None,
                                  txns_executed_fifo=True):
        batches = deque()
        batches.extend(self._batches)

        txns_to_process = deque()

        txn_context_by_txn_id = self._compute_transaction_execution_context()

        transactions_to_assert_state = {}
        while not scheduler.complete(block=False):
            stop = False
            while not stop:
                try:
                    txn_info = scheduler.next_transaction()
                except StopIteration:
                    stop = True

                if txn_info is not None:
                    txns_to_process.append(txn_info)
                    LOGGER.debug("Transaction %s scheduled",
                                 txn_info.txn.header_signature[:16])
                else:
                    stop = True

            try:
                scheduler.add_batch(batches.popleft())
            except IndexError:
                scheduler.finalize()

            try:
                if txns_executed_fifo:
                    t_info = txns_to_process.popleft()
                else:
                    t_info = txns_to_process.pop()
            except IndexError:
                # No new txn was returned from next_transaction so
                # check again if complete.
                continue

            inputs, outputs = self._get_inputs_outputs(t_info.txn)

            c_id = context_manager.create_context(
                state_hash=t_info.state_hash,
                base_contexts=t_info.base_context_ids,
                inputs=inputs,
                outputs=outputs)

            t_id = t_info.txn.header_signature

            if t_id in txn_context_by_txn_id:
                state_up_to_now = txn_context_by_txn_id[t_id].state
                txn_context = txn_context_by_txn_id[t_id]
                inputs, _ = self._get_inputs_outputs(txn_context.txn)
                addresses = [input for input in inputs if len(input) == 70]
                state_found = context_manager.get(
                    context_id=c_id,
                    address_list=addresses)

                LOGGER.debug("Transaction Id %s, Batch %s, Txn %s, "
                             "Context_id %s, Base Contexts %s",
                             t_id[:16],
                             txn_context.batch_num,
                             txn_context.txn_num,
                             c_id,
                             t_info.base_context_ids)

                state_to_assert = [(add, state_up_to_now.get(add))
                                   for add, _ in state_found]
                transactions_to_assert_state[t_id] = (txn_context,
                                                      state_found,
                                                      state_to_assert)

            validity, address_values, deletes = self._txn_execution[
                t_info.txn.header_signature]

            context_manager.set(
                context_id=c_id,
                address_value_list=address_values)
            context_manager.delete(
                context_id=c_id,
                address_list=deletes)
            LOGGER.debug("Transaction %s is %s",
                         t_id[:16],
                         'valid' if validity else 'invalid')
            scheduler.set_transaction_execution_result(
                txn_signature=t_info.txn.header_signature,
                is_valid=validity,
                context_id=c_id)

        batch_ids = [b.header_signature for b in self._batches]
        batch_results = [
            (b_id, scheduler.get_batch_execution_result(b_id))
            for b_id in batch_ids]

        return batch_results, transactions_to_assert_state

    def compute_state_hashes_wo_scheduler(self, base_dir):
        """Creates a state hash from the state updates from each txn in a
        valid batch.

        Returns state_hashes (list of str): The merkle roots from state
            changes in 1 or more blocks in the yaml file.

        """

        database = NativeLmdbDatabase(
            os.path.join(base_dir, 'compute_state_hashes_wo_scheduler.lmdb'),
            indexes=MerkleDatabase.create_index_configuration(),
            _size=10 * 1024 * 1024)

        tree = MerkleDatabase(database=database)
        state_hashes = []
        updates = {}
        for batch in self._batches:
            b_id = batch.header_signature
            result = self._batch_results[b_id]
            if result.is_valid:
                for txn in batch.transactions:
                    txn_id = txn.header_signature
                    _, address_values, deletes = self._txn_execution[txn_id]
                    batch_updates = {}
                    for pair in address_values:
                        batch_updates.update({a: pair[a] for a in pair.keys()})

                    # since this is entirely serial, any overwrite
                    # of an address is expected and desirable.
                    updates.update(batch_updates)

                    for address in deletes:
                        if address in updates:
                            del updates[address]

            # This handles yaml files that have state roots in them
            if result.state_hash is not None:
                s_h = tree.update(set_items=updates, virtual=False)
                tree.set_merkle_root(merkle_root=s_h)
                state_hashes.append(s_h)
        if not state_hashes:
            state_hashes.append(tree.update(set_items=updates))
        return state_hashes

    def _compute_transaction_execution_context(self):
        """Compute the serial state for each txn in the yaml file up to and
        including the invalid txn in each invalid batch.

        Notes:
            The TransactionExecutionContext for a txn will contain the
            state applied serially up to that point for each valid batch and
            then for invalid batches up to the invalid txn.

        Returns:
            dict: The transaction id to the TransactionExecutionContext
        """
        transaction_contexts = {}
        state_up_to_now = {}

        for batch_num, batch in enumerate(self._batches):
            partial_batch_transaction_contexts = {}
            partial_batch_state_up_to_now = state_up_to_now.copy()
            for txn_num, txn in enumerate(batch.transactions):
                t_id = txn.header_signature
                is_valid, address_values, deletes = self._txn_execution[t_id]
                partial_batch_transaction_contexts[t_id] = \
                    TransactionExecutionContext(
                        txn=txn,
                        txn_num=txn_num + 1,
                        batch_num=batch_num + 1,
                        state=partial_batch_state_up_to_now.copy())

                for item in address_values:
                    partial_batch_state_up_to_now.update(item)
                for address in deletes:
                    if address in partial_batch_state_up_to_now:
                        partial_batch_state_up_to_now[address] = None
                if not is_valid:
                    break
            batch_id = batch.header_signature
            batch_is_valid = self._batch_results[batch_id].is_valid

            if batch_is_valid:
                transaction_contexts.update(partial_batch_transaction_contexts)
                state_up_to_now.update(partial_batch_state_up_to_now)

        return transaction_contexts

    def _address(self, add, require_full=False):
        if ':sha' not in add and ',' not in add:
            return add

        if ',' in add:
            return binascii.hexlify(bytearray(
                [int(i) for i in add.split(',')]))

        parts = add.split(':')
        if len(parts) == 3 and parts[2] == 'sha':
            # eg. 'yy:aaabbbb:sha'
            namespace = hashlib.sha512(parts[0].encode()).hexdigest()[:6]
            address = namespace + hashlib.sha512(
                parts[1].encode()).hexdigest()[:64]
        elif len(parts) == 3 and not require_full:
            # eg. 'a:sha:56'
            length = min(int(parts[2]), 70)
            address = hashlib.sha512(parts[0].encode()).hexdigest()[:length]
        elif len(parts) == 2:
            # eg. 'aaabbbb:sha'
            intermediate = parts[0]
            address = hashlib.sha512(intermediate.encode()).hexdigest()[:70]
        else:
            raise ValueError("Address specified by {} could "
                             "not be formed".format(add))
        return address

    def _get_inputs_outputs(self, txn):
        """Similarly to the TransactionExecutor, deserialize the inputs and
         outputs.

         Notes:
             The SchedulerTester has the inputs and outputs from the yaml file
             that it used to create the transaction, but it seems less
             error-prone to recreate the behavior of the TransactionExecutor.

        Args:
            txn (sawtooth_validator.protobuf.transaction_pb2.Transaction)

        Returns (tuple): (inputs, outputs)

        """

        header = transaction_pb2.TransactionHeader()
        header.ParseFromString(txn.header)

        return list(header.inputs), list(header.outputs)

    def _bytes_if_none(self, value):
        if value is None:
            value = uuid.uuid4().hex.encode()
        return value

    def _yaml_from_file(self):
        with open(self._yaml_file_name, 'r') as infile:
            test_yaml = yaml.safe_load(infile)
        return test_yaml

    def _contains_and_not_none(self, key, obj):
        return key in obj and obj[key] is not None

    def _process_batches(self, yaml_batches, signer):
        batches = []
        b_results = {}
        for batch in yaml_batches:
            batch_state_root = None
            if self._contains_and_not_none('state_hash', batch):
                batch_state_root = batch['state_hash']

            txn_processing_result = self._process_txns(
                batch=batch,
                previous_batch_results=b_results.copy(),
                signer=signer)
            txns, batch_is_valid = txn_processing_result
            batch_real = create_batch(
                transactions=txns,
                signer=signer)
            for txn in txns:
                txn_id = txn.header_signature
                batch_id = batch_real.header_signature
                self._batch_id_by_txn_id[txn_id] = batch_id

            b_results[batch_real.header_signature] = BatchExecutionResult(
                is_valid=batch_is_valid,
                state_hash=batch_state_root)
            batches.append(batch_real)
        return batches, b_results

    def _dependencies_are_valid(self, dependencies, previous_batch_results):
        for dep in dependencies:
            if dep in self._batch_id_by_txn_id:
                batch_id = self._batch_id_by_txn_id[dep]
                dep_result = previous_batch_results[batch_id]
                if not dep_result.is_valid:
                    return False
        return True

    def _process_txns(self, batch, previous_batch_results, signer):
        txns = []
        referenced_txns = {}
        execution = {}
        batch_is_valid = True
        for transaction in batch:
            is_valid = True
            addresses_to_set = []
            addresses_to_delete = []
            inputs = transaction['inputs']
            outputs = transaction['outputs']
            inputs_real = [self._address(a) for a in inputs]
            outputs_real = [self._address(a) for a in outputs]
            if self._contains_and_not_none('addresses_to_set', transaction):
                addresses_to_set = [{
                    self._address(a, require_full=True): self._bytes_if_none(
                        d[a])
                    for a in d
                } for d in transaction['addresses_to_set']]
            if self._contains_and_not_none('addresses_to_delete', transaction):
                addresses_to_delete = [
                    self._address(a, require_full=True)
                    for a in transaction['addresses_to_delete']
                ]

            if self._contains_and_not_none('dependencies', transaction):
                if any([
                        a not in self._referenced_txns_in_other_batches
                        and len(a) <= 20 for a in transaction['dependencies']
                ]):
                    # This txn has a dependency with a txn signature that is
                    # not known about,
                    return None

                dependencies = [
                    self._referenced_txns_in_other_batches[a]
                    if a in self._referenced_txns_in_other_batches else a
                    for a in transaction['dependencies']
                ]
                dependencies = [a for a in dependencies if len(a) > 20]
            else:
                dependencies = []

            deps_valid = self._dependencies_are_valid(
                dependencies,
                previous_batch_results)

            if self._contains_and_not_none('valid', transaction):
                is_valid = bool(transaction['valid'])

            if not is_valid or not deps_valid:
                batch_is_valid = False

            txn, _ = create_transaction(
                payload=uuid.uuid4().hex.encode(),
                dependencies=dependencies,
                inputs=inputs_real,
                outputs=outputs_real,
                signer=signer)

            if self._contains_and_not_none('name', transaction):
                referenced_txns[transaction['name']] = txn.header_signature

            execution[txn.header_signature] = (is_valid,
                                               addresses_to_set,
                                               addresses_to_delete)
            txns.append(txn)

        self._txn_execution.update(execution)
        self._referenced_txns_in_other_batches.update(referenced_txns)
        return txns, batch_is_valid

    def _create_batches(self):
        test_yaml = self._yaml_from_file()
        private_key = self._context.new_random_private_key()
        signer = self._crypto_factory.new_signer(private_key)

        batches, batch_results = self._process_batches(
            yaml_batches=test_yaml,
            signer=signer)

        self._batch_results = batch_results
        self._batches = batches
コード例 #44
0
    def test_no_validator_registry(
            self,
            mock_utils,
            mock_validator_registry_view,
            mock_consensus_state,
            mock_poet_enclave_factory,
            mock_consensus_state_store,
            mock_poet_key_state_store,
            mock_signup_info,
            mock_poet_settings_view,
            mock_block_wrapper):
        """ Test verifies that PoET Block Publisher fails
        if a validator doesn't have any signup info
        in the validator registry (the validator is not listed
        in the validator registry)
        """

        # create a mock_validator_registry_view that throws KeyError
        mock_validator_registry_view.return_value.get_validator_info. \
            side_effect = KeyError('Non-existent validator')

        # create a mock_wait_certificate that does nothing in check_valid
        mock_wait_certificate = mock.Mock()
        mock_wait_certificate.check_valid.return_value = None

        mock_utils.deserialize_wait_certificate.return_value = \
            mock_wait_certificate

        # create a mock_consensus_state that returns a mock with
        # the following settings:
        mock_state = MockConsensusState.create_mock_consensus_state()

        mock_consensus_state.consensus_state_for_block_id.return_value = \
            mock_state

        mock_poet_key_state_store.return_value = \
            _MockPoetKeyStateStore(active_key=None)

        # create mock_signup_info
        mock_signup_info.create_signup_info.return_value = \
            mock.Mock(
                poet_public_key='poet public key',
                proof_data='proof data',
                anti_sybil_id='anti-sybil ID',
                sealed_signup_data='sealed signup data')
        mock_signup_info.block_id_to_nonce.return_value = 'nonce'

        # create mock_batch_publisher
        context = create_context('secp256k1')
        private_key = context.new_random_private_key()
        crypto_factory = CryptoFactory(context)
        signer = crypto_factory.new_signer(private_key)
        mock_batch_publisher = mock.Mock(
            identity_signer=signer)

        mock_block_cache = mock.MagicMock()
        mock_state_view_factory = mock.Mock()

        # create mock_block_header with the following fields
        mock_block = mock.Mock(identifier='0123456789abcdefedcba9876543210')
        mock_block.header.signer_public_key = \
            '90834587139405781349807435098745'
        mock_block.header.previous_block_id = '2'
        mock_block.header.block_num = 1
        mock_block.header.state_root_hash = '6'
        mock_block.header.batch_ids = '4'

        # check test
        block_publisher = \
            poet_block_publisher.PoetBlockPublisher(
                block_cache=mock_block_cache,
                state_view_factory=mock_state_view_factory,
                batch_publisher=mock_batch_publisher,
                data_dir=self._temp_dir,
                config_dir=self._temp_dir,
                validator_id='validator_deadbeef')

        self.assertFalse(
            block_publisher.initialize_block(
                block_header=mock_block.header))

        # check that batch publisher was called to send out
        # the txn header and txn for the validator registry update
        self.assertTrue(mock_batch_publisher.send.called)
コード例 #45
0
class Messenger(object):
    def __init__(self, validator_url):
        self._connection = Connection(validator_url)
        self._context = create_context('secp256k1')
        self._crypto_factory = CryptoFactory(self._context)
        self._batch_signer = self._crypto_factory.new_signer(
            self._context.new_random_private_key())

    def open_validator_connection(self):
        self._connection.open()

    def close_validator_connection(self):
        self._connection.close()

    def get_new_key_pair(self):
        private_key = self._context.new_random_private_key()
        public_key = self._context.get_public_key(private_key)
        return public_key.as_hex(), private_key.as_hex()

    async def send_create_agent_transaction(self,
                                            private_key,
                                            name,
                                            timestamp):
        transaction_signer = self._crypto_factory.new_signer(
            secp256k1.Secp256k1PrivateKey.from_hex(private_key))

        batch = make_create_agent_transaction(
            transaction_signer=transaction_signer,
            batch_signer=self._batch_signer,
            name=name,
            timestamp=timestamp)
        await self._send_and_wait_for_commit(batch)

    async def send_create_record_transaction(self,
                                             private_key,
                                             device,
                                             seq, ts, ddata, dsize, dhash,
                                             record_id,
                                             timestamp):
        transaction_signer = self._crypto_factory.new_signer(
            secp256k1.Secp256k1PrivateKey.from_hex(private_key))

        batch = make_create_record_transaction(
            transaction_signer=transaction_signer,
            batch_signer=self._batch_signer,
            seq=seq,
            ts=ts,
            device=device,
            ddata=ddata,
            dsize=dsize,
            dhash=dhash,
            record_id=record_id,
            timestamp=timestamp)
        await self._send_and_wait_for_commit(batch)

    async def send_transfer_record_transaction(self,
                                               private_key,
                                               receiving_agent,
                                               record_id,
                                               timestamp):
        transaction_signer = self._crypto_factory.new_signer(
            secp256k1.Secp256k1PrivateKey.from_hex(private_key))

        batch = make_transfer_record_transaction(
            transaction_signer=transaction_signer,
            batch_signer=self._batch_signer,
            receiving_agent=receiving_agent,
            record_id=record_id,
            timestamp=timestamp)
        await self._send_and_wait_for_commit(batch)

    async def send_update_record_transaction(self,
                                             private_key,
                                             device,
                                   seq, ts, ddata, dsize, dhash,
                                             record_id,
                                             timestamp):
        transaction_signer = self._crypto_factory.new_signer(
            secp256k1.Secp256k1PrivateKey.from_hex(private_key))
        batch = make_update_record_transaction(
            transaction_signer=transaction_signer,
            batch_signer=self._batch_signer,
            seq=seq,
            ts=ts,
            device=device,
            ddata=ddata,
            dsize=dsize,
            dhash=dhash,
            record_id=record_id,
            timestamp=timestamp)
        await self._send_and_wait_for_commit(batch)

    async def _send_and_wait_for_commit(self, batch):
        # Send transaction to validator
        submit_request = client_batch_submit_pb2.ClientBatchSubmitRequest(
            batches=[batch])
        await self._connection.send(
            validator_pb2.Message.CLIENT_BATCH_SUBMIT_REQUEST,
            submit_request.SerializeToString())

        # Send status request to validator
        batch_id = batch.header_signature
        status_request = client_batch_submit_pb2.ClientBatchStatusRequest(
            batch_ids=[batch_id], wait=True)
        validator_response = await self._connection.send(
            validator_pb2.Message.CLIENT_BATCH_STATUS_REQUEST,
            status_request.SerializeToString())

        # Parse response
        status_response = client_batch_submit_pb2.ClientBatchStatusResponse()
        status_response.ParseFromString(validator_response.content)
        status = status_response.batch_statuses[0].status
        if status == client_batch_submit_pb2.ClientBatchStatus.INVALID:
            error = status_response.batch_statuses[0].invalid_transactions[0]
            raise ApiBadRequest(error.message)
        elif status == client_batch_submit_pb2.ClientBatchStatus.PENDING:
            raise ApiInternalError('Transaction submitted but timed out')
        elif status == client_batch_submit_pb2.ClientBatchStatus.UNKNOWN:
            raise ApiInternalError('Something went wrong. Try again later')
コード例 #46
0
class Transactor:
    def __init__(self, name, rest_endpoint):
        """
        Args:
            name (str): An identifier for this Transactor
            rest_endpoint (str): The rest api that this Transactor will
                communicate with.
        """

        self.name = name
        self._rest_endpoint = rest_endpoint \
            if rest_endpoint.startswith("http://") \
            else "http://{}".format(rest_endpoint)
        with open('/root/.sawtooth/keys/{}.priv'.format(name)) as priv_file:
            private_key = Secp256k1PrivateKey.from_hex(
                priv_file.read().strip('\n'))
        self._signer = CryptoFactory(create_context('secp256k1')) \
            .new_signer(private_key)
        self._factories = {}
        self._client = RestClient(url=self._rest_endpoint)

        self._add_transaction_family_factory(Families.INTKEY)
        self._add_transaction_family_factory(Families.XO)

    @property
    def public_key(self):
        return self._signer.get_public_key().as_hex()

    def _add_transaction_family_factory(self, family_name):
        """Add a MessageFactory for the specified family.

        Args:
            family_name (Families): One of the Enum values representing
                transaction families.
        """

        family_config = FAMILY_CONFIG[family_name]
        self._factories[family_name] = MessageFactory(
            family_name=family_config['family_name'],
            family_version=family_config['family_version'],
            namespace=family_config['namespace'],
            signer=self._signer)

    def create_txn(self, family_name, batcher=None):
        unique_value = uuid4().hex[:20]
        encoder = TRANSACTION_ENCODER[family_name]['encoder']
        payload = encoder(
            TRANSACTION_ENCODER[family_name]['payload_func'](unique_value))

        address = TRANSACTION_ENCODER[family_name]['address_func'](
            unique_value)

        return self._factories[family_name].create_transaction(
            payload=payload,
            inputs=[address],
            outputs=[address],
            deps=[],
            batcher=batcher)

    def create_batch(self, family_name, count=1):
        transactions = [self.create_txn(family_name) for _ in range(count)]
        return self.batch_transactions(family_name, transactions=transactions)

    def batch_transactions(self, family_name, transactions):
        return self._factories[family_name].create_batch(
            transactions=transactions)

    def send(self, family_name, transactions=None):
        if not transactions:
            batch_list = self.create_batch(family_name)
        else:
            batch_list = self.batch_transactions(family_name=family_name,
                                                 transactions=transactions)

        self._client.send_batches(batch_list=batch_list)

    def set_public_key_for_role(self, policy, role, permit_keys, deny_keys):
        permits = ["PERMIT_KEY {}".format(key) for key in permit_keys]
        denies = ["DENY_KEY {}".format(key) for key in deny_keys]
        self._run_identity_commands(policy, role, denies + permits)

    def _run_identity_commands(self, policy, role, rules):
        subprocess.run([
            'sawtooth', 'identity', 'policy', 'create', '-k',
            '/root/.sawtooth/keys/{}.priv'.format(self.name), '--wait', '15',
            '--url', self._rest_endpoint, policy, *rules
        ],
                       check=True)
        subprocess.run([
            'sawtooth', 'identity', 'role', 'create', '-k',
            '/root/.sawtooth/keys/{}.priv'.format(self.name), '--wait', '15',
            '--url', self._rest_endpoint, role, policy
        ],
                       check=True)
コード例 #47
0
ファイル: client.py プロジェクト: AIrenzhi/python-tp-examples
class SimpleTestClient:

    def __init__(self, baseUrl):
        self._baseUrl = baseUrl
        privateKey = Secp256k1PrivateKey.from_hex(privateKeyStr)
        self._signer = CryptoFactory(create_context('secp256k1')) \
            .new_signer(privateKey)
        self._publicKey = self._signer.get_public_key().as_hex()
        self.publicKey = self._signer.get_public_key().as_hex()

        self._address = _hash(FAMILY_NAME.encode('utf-8'))[0:6]
                        # _hash(self._publicKey.encode('utf-8'))[0:64]


    def wrap_and_send(self, data_dict):
        # rawPayload = action
        # for val in values:
        #     rawPayload = ",".join([rawPayload, str(val)])

        payload = json.dumps(data_dict).encode()

        address = self._address
        inputAddressList = [address]
        outputAddressList = [address]

        header = TransactionHeader(
            signer_public_key=self._publicKey,
            family_name=FAMILY_NAME,
            family_version="1.0",
            inputs=inputAddressList,
            outputs=outputAddressList,
            dependencies=[],
            payload_sha512=_hash(payload),
            batcher_public_key=self._publicKey,
            nonce=time.time().hex().encode()
        ).SerializeToString()

        transaction = Transaction(
            header=header,
            payload=payload,
            header_signature=self._signer.sign(header)
        )

        transactionList = [transaction]

        header = BatchHeader(
            signer_public_key=self._publicKey,
            transaction_ids=[txn.header_signature for txn in transactionList]
        ).SerializeToString()

        batch = Batch(
            header=header,
            transactions=transactionList,
            header_signature=self._signer.sign(header))

        batch_list = BatchList(batches=[batch])
        return self._send_to_restapi(
            "batches",
            batch_list.SerializeToString(),
            'application/octet-stream')

    def _send_to_restapi(self,
                      suffix,
                      data=None,
                      contentType=None):
        if self._baseUrl.startswith("http://"):
            url = "{}/{}".format(self._baseUrl, suffix)
        else:
            url = "http://{}/{}".format(self._baseUrl, suffix)

        headers = {}

        if contentType is not None:
            headers['Content-Type'] = contentType

        try:
            if data is not None:
                result = requests.post(url, headers=headers, data=data)
            else:
                result = requests.get(url, headers=headers)

            if not result.ok:
                print('服务器错误')

        except requests.ConnectionError as err:
            print('连接失败',err)
            # raise SimpleWalletException(
            #     'Failed to connect to {}: {}'.format(url, str(err)))

        except BaseException as err:
            # raise SimpleWalletException(err)
            print(err)
        return result.text


    def get_state(self):
        result = self._send_to_restapi(
            "state/{}".format(self._address))
        print(result)
        try:
            return base64.b64decode(yaml.safe_load(result)["data"])
        except BaseException:
            return None

    def get_block(self):
        result = requests.get(self._baseUrl+'/blocks')
        datas = result.json()['data']
        for data in datas:
            # print(data)
            payload = data['batches'][0]['transactions'][0]['payload']
            # print(payload)
            p = base64.b64decode(payload.encode()).decode()
            try:
                print(json.loads(p))
            except:
                pass
コード例 #48
0
ファイル: client.py プロジェクト: Dzhan85/bchainca
class CaClient:
    def __init__(self, base_url, keyfile=None):

        self._base_url = base_url

        if keyfile is None:
            self._signer = None
            return

        try:
            with open(keyfile) as fd:
                private_key_str = fd.read().strip()
        except OSError as err:
            raise XoException(
                'Failed to read private key {}: {}'.format(
                    keyfile, str(err)))

        try:
            private_key = Secp256k1PrivateKey.from_hex(private_key_str)
        except ParseError as e:
            raise XoException(
                'Unable to load private key: {}'.format(str(e)))

        self._signer = CryptoFactory(create_context('secp256k1')) \
            .new_signer(private_key)

    def create(self, csr, wait=None, auth_user=None, auth_password=None):
        return self._send_ca_txn(
            "create",
            value=csr,
            wait=wait,
            auth_user=auth_user,
            auth_password=auth_password)

    def init(self, pkey, wait=None, auth_user=None, auth_password=None):
        return self._send_ca_txn(
            "init",
            value=pkey,
            wait=wait,
            auth_user=auth_user,
            auth_password=auth_password)

    def simple(self, data, wait=None, auth_user=None, auth_password=None):
        return self._send_simple_txn(
            value=data,
            wait=wait,
            auth_user=auth_user,
            auth_password=auth_password)

    def get(self, serial: str, wait=None, auth_user=None, auth_password=None):
        return self._send_ca_txn(
            "get",
            value=serial,
            wait=wait,
            auth_user=auth_user,
            auth_password=auth_password)

    def status(self, serial: str, wait=None, auth_user=None, auth_password=None):
        return self._send_ca_txn(
            "status",
            value=serial,
            wait=wait,
            auth_user=auth_user,
            auth_password=auth_password)

    def revoke(self, serial: str, wait=None, auth_user=None, auth_password=None):
        return self._send_ca_txn(
            "revoke",
            value=serial,
            wait=wait,
            auth_user=auth_user,
            auth_password=auth_password)

    def _get_status(self, batch_id, wait, auth_user=None, auth_password=None):
        try:
            result = self._send_request(
                'batch_statuses?id={}&wait={}'.format(batch_id, wait),
                auth_user=auth_user,
                auth_password=auth_password)
            return yaml.safe_load(result)['data'][0]['status']
        except BaseException as err:
            raise XoException(err)

    def _get_prefix(self):
        return _sha512('ca_1'.encode('utf-8'))[:6]

    def _get_address(self, name):
        xo_prefix = self._get_prefix()
        game_address = _sha512(name.encode('utf-8'))[:64]
        return xo_prefix + game_address

    def _get_simple_address(self, data):
        prefix = hashlib.sha512('simple'.encode('utf-8')).hexdigest()[:6]
        address = hashlib.sha512(data.encode('utf-8')).hexdigest()[:64]
        return prefix + address

    def _send_request(self,
                      suffix,
                      data=None,
                      content_type=None,
                      name=None,
                      auth_user=None,
                      auth_password=None):
        if self._base_url.startswith("http://"):
            url = "{}/{}".format(self._base_url, suffix)
        else:
            url = "http://{}/{}".format(self._base_url, suffix)

        headers = {}
        if auth_user is not None:
            auth_string = "{}:{}".format(auth_user, auth_password)
            b64_string = b64encode(auth_string.encode()).decode()
            auth_header = 'Basic {}'.format(b64_string)
            headers['Authorization'] = auth_header

        if content_type is not None:
            headers['Content-Type'] = content_type

        try:
            if data is not None:
                result = requests.post(url, headers=headers, data=data)
            else:
                result = requests.get(url, headers=headers)

            if result.status_code == 404:
                raise XoException("No such game: {}".format(name))

            elif not result.ok:
                raise XoException("Error {}: {}".format(
                    result.status_code, result.reason))

        except requests.ConnectionError as err:
            raise XoException(
                'Failed to connect to {}: {}'.format(url, str(err)))

        except BaseException as err:
            raise XoException(err)

        return result.text

    def _send_ca_txn(self,
                     action,
                     value="",
                     wait=None,
                     auth_user=None,
                     auth_password=None):
        # Serialization is just a delimited utf-8 encoded string
        payload = "|".join([action, datetime.datetime.utcnow().isoformat(), str(value)]).encode('utf-8')

        # Construct the address
        address = self._get_prefix()
        header = TransactionHeader(
            signer_public_key=self._signer.get_public_key().as_hex(),
            family_name="CA",
            family_version="1.0",
            inputs=[address],
            outputs=[address],
            dependencies=[],
            payload_sha512=_sha512(payload),
            batcher_public_key=self._signer.get_public_key().as_hex(),
            nonce=hex(random.randint(0, 2**64))
        ).SerializeToString()

        signature = self._signer.sign(header)

        transaction = Transaction(
            header=header,
            payload=payload,
            header_signature=signature
        )

        batch_list = self._create_batch_list([transaction])
        batch_id = batch_list.batches[0].header_signature

        if wait and wait > 0:
            wait_time = 0
            start_time = time.time()
            response = self._send_request(
                "batches", batch_list.SerializeToString(),
                'application/octet-stream',
                auth_user=auth_user,
                auth_password=auth_password)
            while wait_time < wait:
                status = self._get_status(
                    batch_id,
                    wait - int(wait_time),
                    auth_user=auth_user,
                    auth_password=auth_password)
                wait_time = time.time() - start_time

                if status != 'PENDING':
                    return response

            return response

        return self._send_request(
            "batches", batch_list.SerializeToString(),
            'application/octet-stream',
            auth_user=auth_user,
            auth_password=auth_password)

    def _send_simple_txn(self,
                         value="",
                         wait=None,
                         auth_user=None,
                         auth_password=None):
        # Serialization is just a delimited utf-8 encoded string
        payload = str(value).encode()

        # Construct the address
        address = self._get_simple_address('Simple Data Value 1')

        header = TransactionHeader(
            signer_public_key=self._signer.get_public_key().as_hex(),
            family_name='SIMPLE',
            family_version="1.0",
            inputs=[address],
            outputs=[address],
            dependencies=[],
            payload_sha512=_sha512(payload),
            batcher_public_key=self._signer.get_public_key().as_hex(),
            nonce=hex(random.randint(0, 2**64))
        ).SerializeToString()

        signature = self._signer.sign(header)

        transaction = Transaction(
            header=header,
            payload=payload,
            header_signature=signature
        )

        batch_list = self._create_batch_list([transaction])
        batch_id = batch_list.batches[0].header_signature

        if wait and wait > 0:
            wait_time = 0
            start_time = time.time()
            response = self._send_request(
                "batches", batch_list.SerializeToString(),
                'application/octet-stream',
                auth_user=auth_user,
                auth_password=auth_password)
            while wait_time < wait:
                status = self._get_status(
                    batch_id,
                    wait - int(wait_time),
                    auth_user=auth_user,
                    auth_password=auth_password)
                wait_time = time.time() - start_time

                if status != 'PENDING':
                    return response

            return response

        return self._send_request(
            "batches", batch_list.SerializeToString(),
            'application/octet-stream',
            auth_user=auth_user,
            auth_password=auth_password)

    def _create_batch_list(self, transactions):
        transaction_signatures = [t.header_signature for t in transactions]

        header = BatchHeader(
            signer_public_key=self._signer.get_public_key().as_hex(),
            transaction_ids=transaction_signatures
        ).SerializeToString()

        signature = self._signer.sign(header)

        batch = Batch(
            header=header,
            transactions=transactions,
            header_signature=signature)
        return BatchList(batches=[batch])

    def subscribe(self, event_name: str, is_write_to_file=False, file_name='certificate.pem'):
        subscription = EventSubscription(event_type="ca_1/{}".format(event_name))

        # Setup a connection to the validator
        ctx = zmq.Context()
        socket = ctx.socket(zmq.DEALER)
        socket.connect('tcp://127.0.0.1:4004')

        # Construct the request
        request = ClientEventsSubscribeRequest(
            subscriptions=[subscription]).SerializeToString()

        # Construct the message wrapper
        correlation_id = "123"  # This must be unique for all in-process requests
        msg = Message(
            correlation_id=correlation_id,
            message_type=Message.CLIENT_EVENTS_SUBSCRIBE_REQUEST,
            content=request)

        # Send the request
        socket.send_multipart([msg.SerializeToString()])

        # Receive the response
        resp = socket.recv_multipart()[-1]

        # Parse the message wrapper
        msg = Message()
        msg.ParseFromString(resp)

        # Validate the response type
        if msg.message_type != Message.CLIENT_EVENTS_SUBSCRIBE_RESPONSE:
            print("Unexpected message type")
            return

        # Parse the response
        response = ClientEventsSubscribeResponse()
        response.ParseFromString(msg.content)

        # Validate the response status
        if response.status != ClientEventsSubscribeResponse.OK:
            print("Subscription failed: {}".format(response.response_message))
            return

        resp = socket.recv_multipart()[-1]

        # Parse the message wrapper
        msg = Message()
        msg.ParseFromString(resp)

        # Validate the response type
        if msg.message_type != Message.CLIENT_EVENTS:
            print("Unexpected message type")
            return

        # Parse the response
        events = EventList()
        events.ParseFromString(msg.content)

        for event in events.events:
            if event.data is not None:
                if is_write_to_file:
                    write_to_file(file_name, event.data)
                else:
                    print(event.data)

        # Construct the request
        request = ClientEventsUnsubscribeRequest().SerializeToString()

        # Construct the message wrapper
        correlation_id = "124"  # This must be unique for all in-process requests
        msg = Message(
            correlation_id=correlation_id,
            message_type=Message.CLIENT_EVENTS_UNSUBSCRIBE_REQUEST,
            content=request)

        # Send the request
        socket.send_multipart([msg.SerializeToString()])

        # Receive the response
        resp = socket.recv_multipart()[-1]

        # Parse the message wrapper
        msg = Message()
        msg.ParseFromString(resp)

        # Validate the response type
        if msg.message_type != Message.CLIENT_EVENTS_UNSUBSCRIBE_RESPONSE:
            print("Unexpected message type")

        # Parse the response
        response = ClientEventsUnsubscribeResponse()
        response.ParseFromString(msg.content)

        # Validate the response status
        if response.status != ClientEventsUnsubscribeResponse.OK:
            print("Unsubscription failed: {}".format(response.response_message))

        # Close the connection to the validator
        socket.close()
    def test_block_publisher_finalize_block(
            self,
            mock_utils,
            mock_validator_registry_view,
            mock_consensus_state,
            mock_poet_enclave_factory,
            mock_consensus_state_store,
            mock_poet_key_state_store,
            mock_signup_info,
            mock_wait_certificate,
            mock_poet_settings_view,
            mock_block_wrapper):
        """ Test verifies that PoET Block Publisher finalizes the block,
            meaning that the candidate block is good and should be generated.
        """

        # create a mock_validator_registry_view with
        # get_validator_info that does nothing
        mock_validator_registry_view.return_value.get_validator_info. \
            return_value = \
            ValidatorInfo(
                name='validator_001',
                id='validator_deadbeef',
                signup_info=SignUpInfo(
                    poet_public_key='00112233445566778899aabbccddeeff'))

        # create a mock_wait_certificate that does nothing in check_valid
        my_wait_certificate = mock.Mock()
        my_wait_certificate.check_valid.return_value = None
        mock_wait_certificate.create_wait_certificate.return_value = \
            my_wait_certificate

        # create a mock_consensus_state that returns a mock with
        # the following settings:
        mock_state = MockConsensusState().create_mock_consensus_state()

        mock_consensus_state.consensus_state_for_block_id.return_value = \
            mock_state

        # create mock_batch_publisher
        context = create_context('secp256k1')
        private_key = context.new_random_private_key()
        crypto_factory = CryptoFactory(context)
        signer = crypto_factory.new_signer(private_key)
        mock_batch_publisher = mock.Mock(
            identity_signer=signer)

        mock_block_cache = mock.MagicMock()
        mock_state_view_factory = mock.Mock()

        # create mock_block_header with the following fields
        mock_block = mock.Mock(identifier='0123456789abcdefedcba9876543210')
        mock_block.header.signer_public_key = \
            '90834587139405781349807435098745'
        mock_block.header.previous_block_id = '2'
        mock_block.header.block_num = 1
        mock_block.header.state_root_hash = '6'
        mock_block.header.batch_ids = '4'

        # check test
        block_publisher = \
            poet_block_publisher.PoetBlockPublisher(
                block_cache=mock_block_cache,
                state_view_factory=mock_state_view_factory,
                batch_publisher=mock_batch_publisher,
                data_dir=self._temp_dir,
                config_dir=self._temp_dir,
                validator_id='validator_deadbeef')

        with mock.patch('sawtooth_poet.poet_consensus.'
                        'poet_block_publisher.json') as _:
            self.assertTrue(block_publisher.finalize_block(
                block_header=mock_block.header))
コード例 #50
0
 def get_new_signer(cls):
     context = create_context('secp256k1')
     return CryptoFactory(context).new_signer(
         context.new_random_private_key())
コード例 #51
0
class CCellularClient:
    def __init__(self, conf: DistributedManagerConfig):
        self.conf = conf
        self.url = conf.CLIENT_URL

        # Transaction batcher
        self.transaction_queue = queue.Queue()
        self.pending_transactions = []
        self.run_check = None
        self.transaction_batcher_thread = None
        self.last_batch_time = 0

        # Get the key from the local machine
        keyfile = conf.CLIENT_KEY_PATH

        # The signer requires a key from the local user/machine
        # See sawtooth documentation for producing a key
        if keyfile is not None:
            try:
                with open(keyfile) as fd:
                    private_key_str = fd.read().strip()
                    fd.close()
            except OSError as err:
                raise Exception('Failed to read private key at {}'.format(err))

            try:
                private_key = Secp256k1PrivateKey.from_hex(private_key_str)
            except ParseError as e:
                raise Exception(
                    'Unable to load the private key correctly {}'.format(
                        str(e)))

            self._signer = CryptoFactory(
                create_context('secp256k1')).new_signer(private_key)

        self.logger = None

    # Spawns a thread that handles the creation of transactions and batching
    # Run check function is used by the batcher to check if parent module is still running
    def start_batcher(self, run_check_function):
        if run_check_function is None:
            raise ValueError("Run check function must be specified")
        self.run_check = run_check_function

        self.transaction_batcher_thread = threading.Thread(
            target=self._transaction_batcher)
        self.transaction_batcher_thread.start()

    # Creates a transaction and sends to sawtooth validator
    def set_entry(self, entry: DatabaseEntry):
        self.log("Set entry called, queueing transaction")
        self.transaction_queue.put(('set', entry))

    # Get value of the entry corresponding to the key
    def get(self, key):
        self.log("Get entry called with key: " + str(key))
        address = make_ccellular_address(key)
        result = self._send_request("state/{}".format(address), name=key)
        if result != None:
            try:
                json_result = json.loads(result)
                data_response = json_result['data']
                b64data = yaml.safe_load(data_response)
                b64decoded = base64.b64decode(b64data)
                cbor_decoded = cbor.loads(b64decoded)
                return DatabaseEntry(cbor_decoded[key])
            except BaseException as e:
                print("Received a base exception:", e)
        return None

    # Will likely get all data, may need to be optimized
    def get_all(self):
        self.log("Getting all keys")
        prefix = get_prefix()  # For the transaction family
        result = self._send_request("state",
                                    name="GET_ALL_KEYS",
                                    params={"address": prefix})
        if result != None:
            try:
                self.log("json result: " + str(json.loads(result)))
                next_page = json.loads(result)['paging'].get('next')
                json_result_list = json.loads(result)['data']
                entry_key_set = set()
                for result in json_result_list:
                    data_response = result['data']
                    b64data = yaml.safe_load(data_response)
                    b64decoded = base64.b64decode(b64data)
                    cbor_decoded = cbor.loads(b64decoded)
                    entry_key_set.update(set(cbor_decoded.keys()))

                # Get paginated elements
                while next_page != None:
                    self.log("Getting paginated element")
                    result_obj = requests.get(next_page)
                    if result_obj != None:
                        if not result_obj.ok:
                            self.log("Error getting paginated list -- {}: {}".
                                     format(result_obj.status_code,
                                            result_obj.reason))
                            break

                        result = result_obj.text

                        next_page = json.loads(result)['paging'].get('next')
                        json_result_list = json.loads(result)['data']
                        self.log("json result (pag): " +
                                 str(json.loads(result)))
                        for result in json_result_list:
                            data_response = result['data']
                            b64data = yaml.safe_load(data_response)
                            b64decoded = base64.b64decode(b64data)
                            cbor_decoded = cbor.loads(b64decoded)
                            entry_key_set.update(set(cbor_decoded.keys()))

                return entry_key_set
            except BaseException as e:
                self.log("Received a base exception: " + str(e))
        return None

    # Processes available transactions into batches
    # Batch size and timeout can be configured
    def _transaction_batcher(self):
        self.log("Batcher thread entering")

        while self.run_check():
            # get any new transactions (up to batch size)
            while self.transaction_queue.qsize() > 0:
                # get the next pending transaction and add it to pending
                action, entry = self.transaction_queue.get()
                self._build_transaction(action, entry)

                # stop adding new messages if batch size is reached
                # TODO: possible overloading option?
                if len(self.pending_transactions) >= self.conf.BATCH_SIZE:
                    break

            # if there are no transactions, reset the batch timeout
            if len(self.pending_transactions) == 0:
                self.last_batch_time = time.time()

            # check for a new full size batch or a batch timeout with at least one transaction
            elif len(self.pending_transactions) >= self.conf.BATCH_SIZE or\
                     (time.time() - self.last_batch_time >= self.conf.BATCH_TIMEOUT and\
                     len(self.pending_transactions) > 0):

                self.log("Creating and sending new batch")
                if len(self.pending_transactions) >= self.conf.BATCH_SIZE:
                    self.log(" Batch size reached")
                else:
                    self.log(" Batch timeout exceeded, sending with {0}/{1}"\
                        .format(len(self.pending_transactions), self.conf.BATCH_SIZE))

                # build batch from available transactions
                batch_list = self._create_batch_list(self.pending_transactions)

                # continue and retry later if there is no batch to send
                if batch_list is None:
                    self.log("No batch list to send")
                    continue

                # clear the pending list of transactions
                self.pending_transactions = []

                # Send new batch (TODO save output?)
                self._send_request(
                    "batches",
                    batch_list.SerializeToString(),
                    'application/octet-stream',
                )

            # wait a little before checking again (for performance)
            time.sleep(self.conf.BATCH_CHECK_DELAY)

        self.log("Batcher thread exiting")
        self.transaction_batcher_thread = None

    # Builds a transaction from the provided info and adds to pending
    def _build_transaction(self, action, entry):
        payload = build_payload(action, entry)
        address = make_ccellular_address(entry.key())

        header = TransactionHeader(
            signer_public_key=self._signer.get_public_key().as_hex(),
            family_name=self.conf.FAMILY_NAME,
            family_version=self.conf.FAMILY_VERSION,
            inputs=[address],
            outputs=[address],
            dependencies=[],
            payload_sha512=_sha512(payload),
            batcher_public_key=self._signer.get_public_key().as_hex(),
            nonce=hex(random.randint(0, 2**64))).SerializeToString()

        signature = self._signer.sign(header)

        transaction = Transaction(header=header,
                                  payload=payload,
                                  header_signature=signature)

        self.pending_transactions.append(transaction)

    # Creates a transaction batch of one or more transactions
    # All transactions must be included in a batch
    def _create_batch_list(self, transactions):
        if len(transactions) < 1:
            self.log(
                "Attempting to create batch with no transactions, ignoring")
            return None

        transaction_signatures = [t.header_signature for t in transactions]

        header = BatchHeader(
            signer_public_key=self._signer.get_public_key().as_hex(),
            transaction_ids=transaction_signatures).SerializeToString()

        signature = self._signer.sign(header)

        batch = Batch(header=header,
                      transactions=transactions,
                      header_signature=signature)
        return BatchList(batches=[batch])

    # Sends the request to the validator
    def _send_request(self,
                      suffix,
                      data=None,
                      content_type=None,
                      name=None,
                      params={}):
        if self.url.startswith("http://"):
            url = "{}/{}".format(self.url, suffix)
        else:
            url = "http://{}/{}".format(self.url, suffix)
        headers = {}

        if content_type is not None:
            headers['Content-Type'] = content_type

        try:
            if data is not None:
                result = requests.post(url, headers=headers, data=data)
            else:
                result = requests.get(url, headers=headers, params=params)

            if result.status_code == 404:
                self.log("No such Key Exists: {}".format(name))
                return None

            if not result.ok:
                raise Exception("Error {}: {}".format(result.status_code,
                                                      result.reason))

        except requests.ConnectionError as err:
            raise Exception(
                "Failed to connect to the REST API services : {}".format(err))

        except BaseException as err:
            raise Exception("Failed {}".format(err))

        return result.text

    def log(self, message):
        if self.logger:
            self.logger("(Client) " + message)
コード例 #52
0
ファイル: main.py プロジェクト: weihanx42/sawtooth-healthcare
def load_config(appl):  # pylint: disable=too-many-branches
    appl.config.update(DEFAULT_CONFIG)
    config_file_path = os.path.join(
        os.path.dirname(os.path.dirname(os.path.realpath(__file__))),
        'config.py')
    try:
        appl.config.from_pyfile(config_file_path)
    except FileNotFoundError:
        LOGGER.warning("No config file provided")

    # CLI Options will override config file options
    opts = parse_args(sys.argv[1:])

    if opts.host is not None:
        appl.config.HOST = opts.host
    if opts.port is not None:
        appl.config.PORT = opts.port
    if opts.timeout is not None:
        appl.config.TIMEOUT = opts.timeout

    if opts.validator is not None:
        appl.config.VALIDATOR_URL = opts.validator
    # if opts.db_host is not None:
    #     app.config.DB_HOST = opts.db_host
    # if opts.db_port is not None:
    #     app.config.DB_PORT = opts.db_port
    # if opts.db_name is not None:
    #     app.config.DB_NAME = opts.db_name

    if opts.debug is not None:
        appl.config.DEBUG = opts.debug

    if opts.secret_key is not None:
        appl.config.SECRET_KEY = opts.secret_key
    if appl.config.SECRET_KEY is None:
        LOGGER.exception("API secret key was not provided")
        sys.exit(1)

    if opts.aes_key is not None:
        appl.config.AES_KEY = opts.aes_key
    if appl.config.AES_KEY is None:
        LOGGER.exception("AES key was not provided")
        sys.exit(1)

    if opts.batcher_private_key is not None:
        appl.config.BATCHER_PRIVATE_KEY = opts.batcher_private_key
    if appl.config.BATCHER_PRIVATE_KEY is None:
        LOGGER.exception("Batcher private key was not provided")
        sys.exit(1)

    if opts.batcher_private_key_file_name_clinic is not None:
        appl.config.BATCHER_PRIVATE_KEY_FILE_NAME_CLINIC = opts.batcher_private_key_file_name_clinic
    if opts.batcher_private_key_file_name_doctor is not None:
        appl.config.BATCHER_PRIVATE_KEY_FILE_NAME_DOCTOR = opts.batcher_private_key_file_name_doctor
    if opts.batcher_private_key_file_name_patient is not None:
        appl.config.BATCHER_PRIVATE_KEY_FILE_NAME_PATIENT = opts.batcher_private_key_file_name_patient
    if opts.batcher_private_key_file_name_lab is not None:
        appl.config.BATCHER_PRIVATE_KEY_FILE_NAME_LAB = opts.batcher_private_key_file_name_lab
    if opts.batcher_private_key_file_name_insurance is not None:
        appl.config.BATCHER_PRIVATE_KEY_FILE_NAME_INSURANCE = opts.batcher_private_key_file_name_insurance

    if appl.config.BATCHER_PRIVATE_KEY_FILE_NAME_CLINIC is None:
        LOGGER.exception(
            "Batcher private key file name for Clinic entity was not provided")
        sys.exit(1)
    if appl.config.BATCHER_PRIVATE_KEY_FILE_NAME_DOCTOR is None:
        LOGGER.exception(
            "Batcher private key file name for Doctor entity was not provided")
        sys.exit(1)
    if appl.config.BATCHER_PRIVATE_KEY_FILE_NAME_PATIENT is None:
        LOGGER.exception(
            "Batcher private key file name for Patient entity was not provided"
        )
        sys.exit(1)
    if appl.config.BATCHER_PRIVATE_KEY_FILE_NAME_LAB is None:
        LOGGER.exception(
            "Batcher private key file name for Lab entity was not provided")
        sys.exit(1)
    if appl.config.BATCHER_PRIVATE_KEY_FILE_NAME_INSURANCE is None:
        LOGGER.exception(
            "Batcher private key file name for Insurance entity was not provided"
        )
        sys.exit(1)

    try:
        private_key_file_name_clinic = get_keyfile(
            appl.config.BATCHER_PRIVATE_KEY_FILE_NAME_CLINIC)
        clinic_private_key = get_signer_from_file(private_key_file_name_clinic)
        private_key_file_name_doctor = get_keyfile(
            appl.config.BATCHER_PRIVATE_KEY_FILE_NAME_DOCTOR)
        doctor_private_key = get_signer_from_file(private_key_file_name_doctor)
        private_key_file_name_patient = get_keyfile(
            appl.config.BATCHER_PRIVATE_KEY_FILE_NAME_PATIENT)
        patient_private_key = get_signer_from_file(
            private_key_file_name_patient)
        private_key_file_name_lab = get_keyfile(
            appl.config.BATCHER_PRIVATE_KEY_FILE_NAME_LAB)
        lab_private_key = get_signer_from_file(private_key_file_name_lab)
        private_key_file_name_insurance = get_keyfile(
            appl.config.BATCHER_PRIVATE_KEY_FILE_NAME_INSURANCE)
        insurance_private_key = get_signer_from_file(
            private_key_file_name_insurance)

        # private_key = Secp256k1PrivateKey.from_hex(
        #     app.config.BATCHER_PRIVATE_KEY)
    except ParseError as err:
        LOGGER.exception('Unable to load private key: %s', str(err))
        sys.exit(1)
    appl.config.CONTEXT = create_context('secp256k1')
    appl.config.SIGNER_CLINIC = CryptoFactory(
        appl.config.CONTEXT).new_signer(clinic_private_key)
    appl.config.SIGNER_DOCTOR = CryptoFactory(
        appl.config.CONTEXT).new_signer(doctor_private_key)
    appl.config.SIGNER_PATIENT = CryptoFactory(
        appl.config.CONTEXT).new_signer(patient_private_key)
    appl.config.SIGNER_LAB = CryptoFactory(
        appl.config.CONTEXT).new_signer(lab_private_key)
    appl.config.SIGNER_INSURANCE = CryptoFactory(
        appl.config.CONTEXT).new_signer(insurance_private_key)
コード例 #53
0
class Transactor(object):
    def __init__(self, name, rest_endpoint):
        """
        Args:
            name (str): An identifier for this Transactor
            rest_endpoint (str): The rest api that this Transactor will
                communicate with.
        """

        self.name = name
        self._rest_endpoint = rest_endpoint \
            if rest_endpoint.startswith("http://") \
            else "http://{}".format(rest_endpoint)
        with open('/root/.sawtooth/keys/{}.priv'.format(name)) as priv_file:
            private_key = Secp256k1PrivateKey.from_hex(
                priv_file.read().strip('\n'))
        self._signer = CryptoFactory(create_context('secp256k1')) \
            .new_signer(private_key)
        self._factories = {}
        self._client = RestClient(url=self._rest_endpoint)

        self._add_transaction_family_factory(Families.INTKEY)
        self._add_transaction_family_factory(Families.XO)

    @property
    def public_key(self):
        return self._signer.get_public_key().as_hex()

    def _add_transaction_family_factory(self, family_name):
        """Add a MessageFactory for the specified family.

        Args:
            family_name (Families): One of the Enum values representing
                transaction families.
        """

        family_config = FAMILY_CONFIG[family_name]
        self._factories[family_name] = MessageFactory(
            family_name=family_config['family_name'],
            family_version=family_config['family_version'],
            namespace=family_config['namespace'],
            signer=self._signer)

    def create_txn(self, family_name, batcher=None):
        unique_value = uuid4().hex[:20]
        encoder = TRANSACTION_ENCODER[family_name]['encoder']
        payload = encoder(
            TRANSACTION_ENCODER[family_name]['payload_func'](unique_value))

        address = TRANSACTION_ENCODER[family_name]['address_func'](
            unique_value)

        return self._factories[family_name].create_transaction(
            payload=payload,
            inputs=[address],
            outputs=[address],
            deps=[],
            batcher=batcher)

    def create_batch(self, family_name, count=1):
        transactions = [self.create_txn(family_name) for _ in range(count)]
        return self.batch_transactions(family_name, transactions=transactions)

    def batch_transactions(self, family_name, transactions):
        return self._factories[family_name].create_batch(
            transactions=transactions)

    def send(self, family_name, transactions=None):
        if not transactions:
            batch_list = self.create_batch(family_name)
        else:
            batch_list = self.batch_transactions(
                family_name=family_name,
                transactions=transactions)

        self._client.send_batches(batch_list=batch_list)

    def set_public_key_for_role(self, policy, role, permit_keys, deny_keys):
        permits = ["PERMIT_KEY {}".format(key) for key in permit_keys]
        denies = ["DENY_KEY {}".format(key) for key in deny_keys]
        self._run_identity_commands(policy, role, denies + permits)

    def _run_identity_commands(self, policy, role, rules):
        subprocess.run(
            ['sawtooth', 'identity', 'policy', 'create',
             '-k', '/root/.sawtooth/keys/{}.priv'.format(self.name),
             '--wait', '15',
             '--url', self._rest_endpoint, policy, *rules],
            check=True)
        subprocess.run(
            ['sawtooth', 'identity', 'role', 'create',
             '-k', '/root/.sawtooth/keys/{}.priv'.format(self.name),
             '--wait', '15',
             '--url', self._rest_endpoint, role, policy],
            check=True)
コード例 #54
0
def get_signer():
    context = create_context('secp256k1')
    private_key = context.new_random_private_key()
    crypto_factory = CryptoFactory(context)
    return crypto_factory.new_signer(private_key)
コード例 #55
0
class SupplierBatch:
    def __init__(self, base_url, keyfile=None):

        self._base_url = base_url

        if keyfile is None:
            self._signer = None
            return

        try:
            with open(keyfile) as fd:
                private_key_str = fd.read().strip()
        except OSError as err:
            raise SupplierException(
                'Failed to read private key {}: {}'.format(
                    keyfile, str(err)))

        try:
            private_key = Secp256k1PrivateKey.from_hex(private_key_str)
        except ParseError as e:
            raise SupplierException(
                'Unable to load private key: {}'.format(str(e)))

        self._signer = CryptoFactory(create_context('secp256k1')) \
            .new_signer(private_key)

        
    def create(self,supplier_id,short_id,supplier_name,passwd,supplier_url, auth_user=None, auth_password=None):
        return self.create_supplier_transaction(supplier_id,short_id,supplier_name,passwd,supplier_url, "create",
                                 auth_user=auth_user,
                                 auth_password=auth_password)

   
        
    def add_part(self,supplier_id,part_id):
        return self.create_supplier_transaction(supplier_id,"","","","","AddPart",part_id)

        
    def list_supplier(self, auth_user=None, auth_password=None):
        supplier_prefix = self._get_prefix()

        result = self._send_request(
            "state?address={}".format(supplier_prefix),
            auth_user=auth_user,
            auth_password=auth_password
        )

        try:
            encoded_entries = yaml.safe_load(result)["data"]

            return [
                base64.b64decode(entry["data"]) for entry in encoded_entries
            ]

        except BaseException:
            return None

        
    def retrieve_supplier(self, supplier_id, auth_user=None, auth_password=None):
        address = self._get_address(supplier_id)

        result = self._send_request("state/{}".format(address), supplier_id=supplier_id,
                                    auth_user=auth_user,
                                    auth_password=auth_password)
        try:
            return base64.b64decode(yaml.safe_load(result)["data"])

        except BaseException:
            return None


    def _get_status(self, batch_id, wait, auth_user=None, auth_password=None):
        try:
            result = self._send_request(
                'batch_statuses?id={}&wait={}'.format(batch_id, wait),
                auth_user=auth_user,
                auth_password=auth_password)
            return yaml.safe_load(result)['data'][0]['status']
        except BaseException as err:
            raise SupplierException(err)

    def _get_prefix(self):
        return _sha512('supplier'.encode('utf-8'))[0:6]

    def _get_address(self, supplier_id):
        supplier_prefix = self._get_prefix()
        address = _sha512(supplier_id.encode('utf-8'))[0:64]
        return supplier_prefix + address
    
    
    def _send_request(
            self, suffix, data=None,
            content_type=None, supplier_id=None, auth_user=None, auth_password=None):
        if self._base_url.startswith("http://"):
            url = "{}/{}".format(self._base_url, suffix)
        else:
            url = "http://{}/{}".format(self._base_url, suffix)

        headers = {}
        if auth_user is not None:
            auth_string = "{}:{}".format(auth_user, auth_password)
            b64_string = b64encode(auth_string.encode()).decode()
            auth_header = 'Basic {}'.format(b64_string)
            headers['Authorization'] = auth_header

        if content_type is not None:
            headers['Content-Type'] = content_type

        try:
            if data is not None:
                result = requests.post(url, headers=headers, data=data)
            else:
                result = requests.get(url, headers=headers)

            if result.status_code == 404:
                raise SupplierException("No such supplier: {}".format(supplier_id))

            elif not result.ok:
                raise SupplierException("Error {}: {}".format(
                    result.status_code, result.reason))

        except BaseException as err:
            raise SupplierException(err)

        return result.text

    
    def create_supplier_transaction(self, supplier_id,short_id="",supplier_name="",passwd="",supplier_url="", action="",part_id="",
                     auth_user=None, auth_password=None):
        
        payload = ",".join([supplier_id,str(short_id),str(supplier_name),str(passwd),str(supplier_url), action,str(part_id)]).encode()

        # Construct the address
        address = self._get_address(supplier_id)

        header = TransactionHeader(
            signer_pubkey=self._signer.get_public_key().as_hex(),
            family_name="supplier",
            family_version="1.0",
            inputs=[address],
            outputs=[address],
            dependencies=[],
            payload_encoding="csv-utf8",
            payload_sha512=_sha512(payload),
            batcher_pubkey=self._signer.get_public_key().as_hex(),
            nonce=time.time().hex().encode()
        ).SerializeToString()

        signature = self._signer.sign(header)

        transaction = Transaction(
            header=header,
            payload=payload,
            header_signature=signature
        )

        batch_list = self._create_batch_list([transaction])
        batch_id = batch_list.batches[0].header_signature
        
        return self._send_request(
            "batches", batch_list.SerializeToString(),
            'application/octet-stream',
            auth_user=auth_user,
            auth_password=auth_password
        )

    
    def _create_batch_list(self, transactions):
        transaction_signatures = [t.header_signature for t in transactions]

        header = BatchHeader(
            signer_public_key=self._signer.get_public_key().as_hex(),
            transaction_ids=transaction_signatures
        ).SerializeToString()

        signature = self._signer.sign(header)

        batch = Batch(
            header=header,
            transactions=transactions,
            header_signature=signature
        )
        return BatchList(batches=[batch])
コード例 #56
0
def make_key():
    context = create_context('secp256k1')
    private_key = context.new_random_private_key()
    signer = CryptoFactory(context).new_signer(private_key)
    return signer
コード例 #57
0
ファイル: xo_client.py プロジェクト: Whiteblock/sawtooth-core
class XoClient:
    def __init__(self, base_url, keyfile=None):

        self._base_url = base_url

        if keyfile is None:
            self._signer = None
            return

        try:
            with open(keyfile) as fd:
                private_key_str = fd.read().strip()
        except OSError as err:
            raise XoException(
                'Failed to read private key {}: {}'.format(
                    keyfile, str(err)))

        try:
            private_key = Secp256k1PrivateKey.from_hex(private_key_str)
        except ParseError as e:
            raise XoException(
                'Unable to load private key: {}'.format(str(e)))

        self._signer = CryptoFactory(create_context('secp256k1')) \
            .new_signer(private_key)

    def create(self, name, wait=None, auth_user=None, auth_password=None):
        return self._send_xo_txn(
            name,
            "create",
            wait=wait,
            auth_user=auth_user,
            auth_password=auth_password)

    def delete(self, name, wait=None, auth_user=None, auth_password=None):
        return self._send_xo_txn(
            name,
            "delete",
            wait=wait,
            auth_user=auth_user,
            auth_password=auth_password)

    def take(self, name, space, wait=None, auth_user=None, auth_password=None):
        return self._send_xo_txn(
            name,
            "take",
            space,
            wait=wait,
            auth_user=auth_user,
            auth_password=auth_password)

    def list(self, auth_user=None, auth_password=None):
        xo_prefix = self._get_prefix()

        result = self._send_request(
            "state?address={}".format(xo_prefix),
            auth_user=auth_user,
            auth_password=auth_password)

        try:
            encoded_entries = yaml.safe_load(result)["data"]

            return [
                base64.b64decode(entry["data"]) for entry in encoded_entries
            ]

        except BaseException:
            return None

    def show(self, name, auth_user=None, auth_password=None):
        address = self._get_address(name)

        result = self._send_request(
            "state/{}".format(address),
            name=name,
            auth_user=auth_user,
            auth_password=auth_password)
        try:
            return base64.b64decode(yaml.safe_load(result)["data"])

        except BaseException:
            return None

    def _get_status(self, batch_id, wait, auth_user=None, auth_password=None):
        try:
            result = self._send_request(
                'batch_statuses?id={}&wait={}'.format(batch_id, wait),
                auth_user=auth_user,
                auth_password=auth_password)
            return yaml.safe_load(result)['data'][0]['status']
        except BaseException as err:
            raise XoException(err)

    def _get_prefix(self):
        return _sha512('xo'.encode('utf-8'))[0:6]

    def _get_address(self, name):
        xo_prefix = self._get_prefix()
        game_address = _sha512(name.encode('utf-8'))[0:64]
        return xo_prefix + game_address

    def _send_request(self,
                      suffix,
                      data=None,
                      content_type=None,
                      name=None,
                      auth_user=None,
                      auth_password=None):
        if self._base_url.startswith("http://"):
            url = "{}/{}".format(self._base_url, suffix)
        else:
            url = "http://{}/{}".format(self._base_url, suffix)

        headers = {}
        if auth_user is not None:
            auth_string = "{}:{}".format(auth_user, auth_password)
            b64_string = b64encode(auth_string.encode()).decode()
            auth_header = 'Basic {}'.format(b64_string)
            headers['Authorization'] = auth_header

        if content_type is not None:
            headers['Content-Type'] = content_type

        try:
            if data is not None:
                result = requests.post(url, headers=headers, data=data)
            else:
                result = requests.get(url, headers=headers)

            if result.status_code == 404:
                raise XoException("No such game: {}".format(name))

            elif not result.ok:
                raise XoException("Error {}: {}".format(
                    result.status_code, result.reason))

        except requests.ConnectionError as err:
            raise XoException(
                'Failed to connect to {}: {}'.format(url, str(err)))

        except BaseException as err:
            raise XoException(err)

        return result.text

    def _send_xo_txn(self,
                     name,
                     action,
                     space="",
                     wait=None,
                     auth_user=None,
                     auth_password=None):
        # Serialization is just a delimited utf-8 encoded string
        payload = ",".join([name, action, str(space)]).encode()

        # Construct the address
        address = self._get_address(name)

        header = TransactionHeader(
            signer_public_key=self._signer.get_public_key().as_hex(),
            family_name="xo",
            family_version="1.0",
            inputs=[address],
            outputs=[address],
            dependencies=[],
            payload_sha512=_sha512(payload),
            batcher_public_key=self._signer.get_public_key().as_hex(),
            nonce=time.time().hex().encode()
        ).SerializeToString()

        signature = self._signer.sign(header)

        transaction = Transaction(
            header=header,
            payload=payload,
            header_signature=signature
        )

        batch_list = self._create_batch_list([transaction])
        batch_id = batch_list.batches[0].header_signature

        if wait and wait > 0:
            wait_time = 0
            start_time = time.time()
            response = self._send_request(
                "batches", batch_list.SerializeToString(),
                'application/octet-stream',
                auth_user=auth_user,
                auth_password=auth_password)
            while wait_time < wait:
                status = self._get_status(
                    batch_id,
                    wait - int(wait_time),
                    auth_user=auth_user,
                    auth_password=auth_password)
                wait_time = time.time() - start_time

                if status != 'PENDING':
                    return response

            return response

        return self._send_request(
            "batches", batch_list.SerializeToString(),
            'application/octet-stream',
            auth_user=auth_user,
            auth_password=auth_password)

    def _create_batch_list(self, transactions):
        transaction_signatures = [t.header_signature for t in transactions]

        header = BatchHeader(
            signer_public_key=self._signer.get_public_key().as_hex(),
            transaction_ids=transaction_signatures
        ).SerializeToString()

        signature = self._signer.sign(header)

        batch = Batch(
            header=header,
            transactions=transactions,
            header_signature=signature)
        return BatchList(batches=[batch])
コード例 #58
0
def test_verification(benchmark):
    context = create_context("secp256k1")
    factory = CryptoFactory(context)
    pub_key1 = Secp256k1PublicKey.from_hex(KEY1_PUB_HEX)
    result = benchmark(context.verify, MSG1_KEY1_SIG, MSG1.encode(), pub_key1)
    assert result == True
コード例 #59
0
    def test_block_publisher_doesnt_claim_readiness(
            self,
            mock_utils,
            mock_validator_registry_view,
            mock_consensus_state,
            mock_poet_enclave_factory,
            mock_consensus_state_store,
            mock_poet_key_state_store,
            mock_signup_info,
            mock_wait_time,
            mock_poet_settings_view,
            mock_block_wrapper):
        """ Test verifies that PoET Block Publisher doesn't
         claims readiness if the wait timer hasn't expired
        """

        # create a mock_validator_registry_view with
        # get_validator_info that does nothing
        mock_validator_registry_view.return_value.get_validator_info. \
            return_value = \
            ValidatorInfo(
                name='validator_001',
                id='validator_deadbeef',
                signup_info=SignUpInfo(
                    poet_public_key='00112233445566778899aabbccddeeff'))

        # create a mock_consensus_state that returns a mock with
        # the following settings:
        mock_state = MockConsensusState.create_mock_consensus_state()

        mock_consensus_state.consensus_state_for_block_id.return_value = \
            mock_state

        mock_consensus_state_store.return_value.__getitem__.return_value = \
            mock_consensus_state

        # Create mock key state
        mock_poet_key_state_store.return_value.__getitem__.return_value = \
            mock.Mock(
                sealed_signup_data='sealed signup data',
                has_been_refreshed=False)

        # create mock_signup_info
        mock_signup_info.unseal_signup_data.return_value = \
            '00112233445566778899aabbccddeeff'

        # create mock_batch_publisher
        context = create_context('secp256k1')
        private_key = context.new_random_private_key()
        crypto_factory = CryptoFactory(context)
        signer = crypto_factory.new_signer(private_key)

        mock_batch_publisher = mock.Mock(identity_signer=signer)

        mock_block_cache = mock.MagicMock()
        mock_state_view_factory = mock.Mock()

        # create mock_block_header with the following fields
        mock_block = mock.Mock(identifier='0123456789abcdefedcba9876543210')
        mock_block.header.signer_public_key = \
            '90834587139405781349807435098745'
        mock_block.header.previous_block_id = '2'
        mock_block.header.block_num = 1
        mock_block.header.state_root_hash = '6'
        mock_block.header.batch_ids = '4'

        # create a mock_wait_timer that hasn't expired yet
        my_wait_time = mock.Mock()
        my_wait_time.has_expired.return_value = False

        mock_wait_time.create_wait_timer.return_value = my_wait_time

        # create mock_poet_enclave_module
        mock_poet_enclave_module = mock.Mock()
        mock_poet_enclave_module.return_value = \
            mock_poet_enclave_factory.get_poet_enclave_module.return_value

        # check test
        block_publisher = \
            poet_block_publisher.PoetBlockPublisher(
                block_cache=mock_block_cache,
                state_view_factory=mock_state_view_factory,
                batch_publisher=mock_batch_publisher,
                data_dir=self._temp_dir,
                config_dir=self._temp_dir,
                validator_id='validator_deadbeef')

        # check initialize_block() first to set wait_timer
        self.assertTrue(
            block_publisher.initialize_block(
                block_header=mock_block.header))

        # check that block_publisher only claims readiness
        # when the wait_timer has expired
        self.assertFalse(
            block_publisher.check_publish_block(
                block_header=mock_block.header))
コード例 #60
0
    def test_signup_info_not_committed_within_allowed_delay(
            self, mock_utils, mock_validator_registry_view,
            mock_consensus_state, mock_poet_enclave_factory,
            mock_consensus_state_store, mock_poet_key_state_store,
            mock_signup_info, mock_poet_settings_view, mock_block_wrapper):
        """ Test verifies that PoET Block Publisher fails if
        a validator's signup info was not committed to
        the block chain within the allowed configured delay
        """

        # create a mock_validator_registry_view with
        # get_validator_info that does nothing
        mock_validator_registry_view.return_value.get_validator_info. \
            return_value = \
            ValidatorInfo(
                name='validator_001',
                id='validator_deadbeef',
                signup_info=SignUpInfo(
                    poet_public_key='00112233445566778899aabbccddeeff',
                    nonce='nonce'))

        # create a mock_wait_certificate that does nothing in check_valid
        mock_wait_certificate = mock.Mock()
        mock_wait_certificate.check_valid.return_value = None

        mock_utils.deserialize_wait_certificate.return_value = \
            mock_wait_certificate

        # create a mock_consensus_state that returns a mock with
        # the following settings:
        mock_state = MockConsensusState.create_mock_consensus_state(
            committed_too_late=True)
        mock_consensus_state.consensus_state_for_block_id.return_value = \
            mock_state

        mock_consensus_state_store.return_value.__getitem__.return_value = \
            mock_consensus_state

        # Create mock key state
        mock_poet_key_state_store.return_value.__getitem__.return_value = \
            mock.Mock(
                sealed_signup_data='sealed signup data',
                has_been_refreshed=False)

        # create mock_signup_info
        mock_signup_info.create_signup_info.return_value = \
            mock.Mock(
                poet_public_key='poet public key',
                proof_data='proof data',
                anti_sybil_id='anti-sybil ID',
                sealed_signup_data='sealed signup data')
        mock_signup_info.block_id_to_nonce.return_value = 'nonce'
        mock_signup_info.unseal_signup_data.return_value = \
            '00112233445566778899aabbccddeeff'

        # create mock_batch_publisher
        context = create_context('secp256k1')
        private_key = context.new_random_private_key()
        crypto_factory = CryptoFactory(context)
        signer = crypto_factory.new_signer(private_key)

        mock_batch_publisher = mock.Mock(identity_signer=signer)

        mock_block_cache = mock.MagicMock()
        mock_state_view_factory = mock.Mock()

        # create mock_block_header with the following fields
        mock_block = mock.Mock(identifier='0123456789abcdefedcba9876543210')
        mock_block.header.signer_public_key = \
            '90834587139405781349807435098745'
        mock_block.header.previous_block_id = '2'
        mock_block.header.block_num = 1
        mock_block.header.state_root_hash = '6'
        mock_block.header.batch_ids = '4'

        # check test
        with mock.patch('sawtooth_poet.poet_consensus.poet_block_publisher.'
                        'LOGGER') as mock_logger:
            block_publisher = \
                poet_block_publisher.PoetBlockPublisher(
                    block_cache=mock_block_cache,
                    state_view_factory=mock_state_view_factory,
                    batch_publisher=mock_batch_publisher,
                    data_dir=self._temp_dir,
                    config_dir=self._temp_dir,
                    validator_id='validator_deadbeef')

            self.assertFalse(
                block_publisher.initialize_block(
                    block_header=mock_block.header))

            # Could be a hack, but verify that the appropriate log message is
            # generated - so we at least have some faith that the failure was
            # because of what we are testing and not something else.  I know
            # that this is fragile if the log message is changed, so would
            # accept any suggestions on a better way to verify that the
            # function fails for the reason we expect.
            self.assertTrue(
                any('Validator signup information not committed in a timely '
                    'manner.' in call[0][0]
                    for call in mock_logger.info.call_args_list))

            # check that create.signup_info() was called to create
            # the validator registry payload with new set of keys
            self.assertTrue(mock_signup_info.create_signup_info.called)