Example #1
0
def is_valid_batch(batch):
    # validate batch signature
    header = BatchHeader()
    header.ParseFromString(batch.header)

    context = create_context('secp256k1')
    public_key = Secp256k1PublicKey.from_hex(header.signer_public_key)
    if not context.verify(batch.header_signature, batch.header, public_key):
        LOGGER.debug("batch failed signature validation: %s",
                     batch.header_signature)
        return False

    # validate all transactions in batch
    for txn in batch.transactions:
        if not is_valid_transaction(txn):
            return False

        txn_header = TransactionHeader()
        txn_header.ParseFromString(txn.header)
        if txn_header.batcher_public_key != header.signer_public_key:
            LOGGER.debug(
                "txn batcher public_key does not match signer"
                "public_key for batch: %s txn: %s", batch.header_signature,
                txn.header_signature)
            return False

    return True
Example #2
0
    def handle(self, connection_id, message_content):
        batch_header = BatchHeader()
        for batch in message_content.batches:
            batch_header.ParseFromString(batch.header)
            if batch_header.signer_public_key == self._whitelist_public_key:
                # There is a whitelisted batch, so allow it to continue
                return HandlerResult(status=HandlerStatus.PASS)

            batch_header.Clear()

        if self._is_batch_pool_full():
            if not self._applying_backpressure:
                self._applying_backpressure = True
                LOGGER.info(
                    'Applying back pressure on client submitted batches')

            self._batches_rejected_count.inc()
            self._batches_rejected_gauge.set_value(
                self._batches_rejected_gauge.get_value() + 1)

            response = ClientBatchSubmitResponse(
                status=ClientBatchSubmitResponse.QUEUE_FULL)
            return HandlerResult(
                status=HandlerStatus.RETURN,
                message_out=response,
                message_type=Message.CLIENT_BATCH_SUBMIT_RESPONSE
            )

        if self._applying_backpressure:
            self._applying_backpressure = False
            self._batches_rejected_gauge.set_value(0)
            LOGGER.info('Ending back pressure on client submitted batches')

        return HandlerResult(status=HandlerStatus.PASS)
Example #3
0
    def is_batch_signer_authorized(self,
                                   batch,
                                   state_root=None,
                                   from_state=False):
        """ Check the batch signing key against the allowed transactor
            permissions. The roles being checked are the following, from first
            to last:
                "transactor.batch_signer"
                "transactor"
                "default"

            The first role that is set will be the one used to enforce if the
            batch signer is allowed.

            Args:
                batch (Batch): The batch that is being verified.
                state_root(string): The state root of the previous block. If
                    this is None, the current state root hash will be
                    retrieved.
                from_state (bool): Whether the identity value should be read
                    directly from state, instead of using the cached values.
                    This should be used when the state_root passed is not from
                    the current chain head.

        """
        if state_root is None:
            state_root = self._current_root_func()
            LOGGER.debug("authorized Chain head is %s.", state_root)
            if state_root == INIT_ROOT_KEY:
                LOGGER.debug("Chain head is not set yet. Permit all.")
                return True

        self._cache.update_view(state_root)

        header = BatchHeader()
        header.ParseFromString(batch.header)

        role = self._cache.get_role("transactor.batch_signer", state_root,
                                    from_state)

        if role is None:
            role = self._cache.get_role("transactor", state_root, from_state)

        if role is None:
            policy_name = "default"
        else:
            policy_name = role.policy_name

        policy = self._cache.get_policy(policy_name, state_root, from_state)
        if policy is None:
            allowed = True
        else:
            allowed = self._allowed(header.signer_public_key, policy)

        if allowed:
            return self.is_transaction_signer_authorized(
                batch.transactions, state_root, from_state)
        LOGGER.debug("Batch Signer: %s is not permitted.",
                     header.signer_public_key)
        return False
Example #4
0
def is_valid_batch(batch):
    # batch structure verification
    header = BatchHeader()
    header.ParseFromString(batch.header)

    # check whether a batch has duplicate transactions
    if len(header.transaction_ids) != len(set(header.transaction_ids)):
        LOGGER.debug("Batch has duplicate transactions. Dropping batch: %s",
                     batch.header_signature)
        return False

    # validate the transaction_ids field in batch header contains a list of
    # transaction header_signatures and must be the same order as the
    # transactions field
    if len(batch.transactions) > len(header.transaction_ids):
        LOGGER.debug("Batch has extra transactions. Dropping batch: %s",
                     batch.header_signature)
        return False
    if len(batch.transactions) < len(header.transaction_ids):
        LOGGER.debug("Batch lacks transactions. Dropping batch: %s",
                     batch.header_signature)
        return False

    for header_txn_id, txn in zip(header.transaction_ids, batch.transactions):
        if header_txn_id != txn.header_signature:
            LOGGER.debug(
                "The header.transaction_ids does not match the "
                "order of transactions in the batch: %s txn: %s",
                batch.header_signature, header_txn_id)
            return False

    return True
Example #5
0
    def _create_batches(self,
                        batch_count,
                        txn_count,
                        valid_batch=True,
                        valid_txn=True,
                        valid_structure=True,
                        valid_batcher=True):

        batch_list = []

        for i in range(batch_count):
            txn_list = self._create_transactions(txn_count, valid_txn,
                                                 valid_batcher)
            txn_sig_list = [txn.header_signature for txn in txn_list]
            if not valid_structure:
                txn_sig_list.pop()

            batch_header = BatchHeader(signer_pubkey=self.public_key)
            batch_header.transaction_ids.extend(txn_sig_list)

            header_bytes = batch_header.SerializeToString()

            if valid_batch:
                signature = signing.sign(header_bytes, self.private_key)
            else:
                signature = "bad_signature"

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

            batch_list.append(batch)

        return batch_list
Example #6
0
def is_valid_batch(batch):
    # validate batch signature
    header = BatchHeader()
    header.ParseFromString(batch.header)

    if not signing.verify(batch.header, batch.header_signature,
                          header.signer_public_key):
        LOGGER.debug("batch failed signature validation: %s",
                     batch.header_signature)
        return False

    # validate all transactions in batch
    for txn in batch.transactions:
        if not is_valid_transaction(txn):
            return False

        txn_header = TransactionHeader()
        txn_header.ParseFromString(txn.header)
        if txn_header.batcher_public_key != header.signer_public_key:
            LOGGER.debug(
                "txn batcher public_key does not match signer"
                "public_key for batch: %s txn: %s", batch.header_signature,
                txn.header_signature)
            return False

    return True
Example #7
0
    def _generate_batch(self, payload):
        payload_encoded = payload.encode('utf-8')
        hasher = hashlib.sha512()
        hasher.update(payload_encoded)

        header = TransactionHeader()
        header.batcher_pubkey = self.public_key
        # txn.dependencies not yet
        header.family_name = 'test'
        header.family_version = '1'
        header.nonce = _generate_id(16)
        header.payload_encoding = "text"
        header.payload_sha512 = hasher.hexdigest().encode()
        header.signer_pubkey = self.public_key

        txn = Transaction()
        header_bytes = header.SerializeToString()
        txn.header = header_bytes
        txn.header_signature = signing.sign(header_bytes, self.signing_key)
        txn.payload = payload_encoded

        batch_header = BatchHeader()
        batch_header.signer_pubkey = self.public_key
        batch_header.transaction_ids.extend([txn.header_signature])

        batch = Batch()
        header_bytes = batch_header.SerializeToString()
        batch.header = header_bytes
        batch.header_signature = signing.sign(header_bytes, self.signing_key)
        batch.transactions.extend([txn])
        return batch
Example #8
0
def validate_batch(batch):
    # validate batch signature
    header = BatchHeader()
    header.ParseFromString(batch.header)
    valid = signing.verify(batch.header, batch.header_signature,
                           header.signer_pubkey)

    if not valid:
        LOGGER.debug("batch failed signature validation: %s",
                     batch.header_signature)

    # validate all transactions in batch
    total = len(batch.transactions)
    index = 0
    while valid and index < total:
        txn = batch.transactions[index]
        valid = validate_transaction(txn)
        if valid:
            txn_header = TransactionHeader()
            txn_header.ParseFromString(txn.header)
            if txn_header.batcher_pubkey != header.signer_pubkey:
                LOGGER.debug(
                    "txn batcher pubkey does not match signer"
                    "pubkey for batch: %s txn: %s", batch.header_signature,
                    txn.header_signature)
                valid = False
        index += 1

    return valid
Example #9
0
    def _create_batches(self, batch_count, txn_count,
                        missing_dep=False):

        batch_list = []

        for i in range(batch_count):
            txn_list = self._create_transactions(txn_count,
                                                 missing_dep=missing_dep)
            txn_sig_list = [txn.header_signature for txn in txn_list]

            batch_header = BatchHeader(signer_pubkey=self.public_key)
            batch_header.transaction_ids.extend(txn_sig_list)

            header_bytes = batch_header.SerializeToString()


            signature = signing.sign(
                header_bytes,
                self.private_key)

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

            batch_list.append(batch)

        return batch_list
def is_batch_signer_authorized(batch, allowed_pubkeys):
    header = BatchHeader()
    header.ParseFromString(batch.header)
    if header.signer_pubkey not in allowed_pubkeys:
        LOGGER.info("Batch was signed by an unauthorized signing key %s",
                    header.signer_pubkey)
        return False
    return True
Example #11
0
def _make_mock_batch(self, batch_id='batch_id'):
    txn = _make_mock_transaction(batch_id)

    header = BatchHeader(signer_pubkey='pubkey',
                         transaction_ids=[txn.header_signature])

    return Batch(header=header.SerializeToString(),
                 header_signature=batch_id,
                 transactions=[txn])
Example #12
0
def make_mock_batch(base_id='id'):
    batch_id = 'b-' + base_id
    txn = _make_mock_transaction(base_id)

    header = BatchHeader(signer_public_key='public_key-' + base_id,
                         transaction_ids=[txn.header_signature])

    return Batch(header=header.SerializeToString(),
                 header_signature=batch_id,
                 transactions=[txn])
Example #13
0
def make_mock_batch(base_id='id'):
    batch_id = 'a' * (128 - len(base_id)) + base_id
    txn = _make_mock_transaction(base_id)

    signer_public_key = b'public_key' + bytes(base_id, 'utf-8')

    header = BatchHeader(signer_public_key=signer_public_key.hex(),
                         transaction_ids=[txn.header_signature])

    return Batch(header=header.SerializeToString(),
                 header_signature=batch_id,
                 transactions=[txn])
    def is_batch_signer_authorized(self, batch, state_root=None):
        """ Check the batch signing key against the allowed transactor
            permissions. The roles being checked are the following, from first
            to last:
                "transactor.batch_signer"
                "transactor"
                "default"

            The first role that is set will be the one used to enforce if the
            batch signer is allowed.

            Args:
                batch (Batch): The batch that is being verified.
                state_root(string): The state root of the previous block. If
                    this is None, the current state root hash will be
                    retrieved.
        """
        if state_root is None:
            state_root = self._current_root_func()
            if state_root == INIT_ROOT_KEY:
                LOGGER.debug("Chain head is not set yet. Permit all.")
                return True

        identity_view = \
            self._identity_view_factory.create_identity_view(state_root)

        header = BatchHeader()
        header.ParseFromString(batch.header)

        role = \
            identity_view.get_role("transactor.batch_signer")

        if role is None:
            role = identity_view.get_role("transactor")

        if role is None:
            policy_name = "default"
        else:
            policy_name = role.policy_name

        policy = identity_view.get_policy(policy_name)
        if policy is None:
            allowed = True
        else:
            allowed = self._allowed(header.signer_pubkey, policy)

        if allowed:
            return self.is_transaction_signer_authorized(
                batch.transactions, identity_view)
        LOGGER.debug("Batch Signer: %s is not permitted.",
                     header.signer_pubkey)
        return False
Example #15
0
def create_batch(transactions, signer):
    transaction_signatures = [t.header_signature for t in transactions]

    header = BatchHeader(signer_public_key=signer.get_public_key().as_hex(),
                         transaction_ids=transaction_signatures)

    header_bytes = header.SerializeToString()

    signature = signer.sign(header_bytes)

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

    return batch
    def _generate_batch(self, txn_count=2, missing_deps=False, txns=None):
        if txns is None:
            txns = []

        if txn_count != 0:
            txns += [
                self.generate_transaction('txn_' + str(i))
                for i in range(txn_count)
            ]

        if missing_deps:
            target_txn = txns[-1]
            txn_missing_deps = self.generate_transaction(
                payload='this one has a missing dependency',
                deps=[target_txn.header_signature])
            # replace the targeted txn with the missing deps txn
            txns[-1] = txn_missing_deps

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

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

        return batch
    def create_batch(self, block_info):
        payload = BlockInfoTxn(block=block_info).SerializeToString()
        public_key = self._signer.get_public_key().as_hex()
        header = TransactionHeader(
            signer_public_key=public_key,
            family_name=FAMILY_NAME,
            family_version=FAMILY_VERSION,
            inputs=[CONFIG_ADDRESS, BLOCK_INFO_NAMESPACE],
            outputs=[CONFIG_ADDRESS, BLOCK_INFO_NAMESPACE],
            dependencies=[],
            payload_sha512=hashlib.sha512(payload).hexdigest(),
            batcher_public_key=public_key,
        ).SerializeToString()

        transaction_signature = self._signer.sign(header)

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

        header = BatchHeader(
            signer_public_key=public_key,
            transaction_ids=[transaction_signature],
        ).SerializeToString()

        batch_signature = self._signer.sign(header)

        return Batch(
            header=header,
            transactions=[transaction],
            header_signature=batch_signature,
        )
Example #18
0
    def get_batch_by_transaction(self, transaction_id):
        """
        Check to see if the requested transaction_id is in the current chain.
        If so, find the batch that has the transaction referenced by the
        transaction_id and return the batch. This is done by finding the block
        and searching for the batch.

        :param transaction_id (string): The id of the transaction that is being
            requested.
        :return:
        The batch that has the transaction.
        """
        block = self.get_block_by_transaction_id(transaction_id)
        # Find batch in block
        for batch in block.batches:
            batch_header = BatchHeader()
            batch_header.ParseFromString(batch.header)
            if transaction_id in batch_header.transaction_ids:
                return batch
    def _generate_batch_from_payload(self, payload):
        txn = self.generate_transaction(payload)

        batch_header = BatchHeader(
            signer_public_key=self.signer.get_public_key().as_hex(),
            transaction_ids=[txn.header_signature]).SerializeToString()

        batch = Batch(header=batch_header,
                      header_signature=self.signer.sign(batch_header),
                      transactions=[txn])
        return batch
def validate_batch(batch):
    # validate batch signature
    header = BatchHeader()
    header.ParseFromString(batch.header)
    valid = signing.verify(batch.header, batch.header_signature,
                           header.signer_pubkey)

    # validate all transactions in batch
    total = len(batch.transactions)
    index = 0
    while valid and index < total:
        txn = batch.transactions[index]
        valid = validate_transaction(txn)
        if valid:
            txn_header = TransactionHeader()
            txn_header.ParseFromString(txn.header)
            if txn_header.batcher_pubkey != header.signer_pubkey:
                valid = False
        index += 1

    return valid
    def _generate_batch_from_payload(self, payload):
        txn = self.generate_transaction(payload)

        batch_header = BatchHeader(signer_pubkey=self.public_key,
                                   transaction_ids=[txn.header_signature
                                                    ]).SerializeToString()

        batch = Batch(header=batch_header,
                      header_signature=self._signed_header(batch_header),
                      transactions=[txn])
        LOGGER.debug("Generated %s", dumps_batch(batch))
        return batch
    def check_off_chain_batch_roles(self, batch):
        """ Check the batch signing key against the allowed off-chain
            transactor permissions. The roles being checked are the following,
            from first to last:
                "transactor.batch_signer"
                "transactor"

            The first role that is set will be the one used to enforce if the
            batch signer is allowed.

            Args:
                batch (Batch): The batch that is being verified.
                state_root(string): The state root of the previous block. If
                    this is None, the current state root hash will be
                    retrieved.

        """
        if self._permissions is None:
            return True
        header = BatchHeader()
        header.ParseFromString(batch.header)
        policy = None
        if "transactor.batch_signer" in self._permissions:
            policy = self._permissions["transactor.batch_signer"]

        elif "transactor" in self._permissions:
            policy = self._permissions["transactor"]

        allowed = True
        if policy is not None:
            allowed = self._allowed(header.signer_public_key, policy)

        if allowed:
            return self.check_off_chain_transaction_roles(batch.transactions)

        LOGGER.debug(
            "Batch Signer: %s is not permitted by local"
            " configuration.", header.signer_public_key)
        return False
Example #23
0
    def _create_batches(self, batch_count, txn_count):

        batch_list = []

        for _ in range(batch_count):
            txn_list = self._create_transactions(txn_count)
            txn_sig_list = [txn.header_signature for txn in txn_list]

            batch_header = BatchHeader(
                signer_public_key=self.signer.get_public_key().as_hex())
            batch_header.transaction_ids.extend(txn_sig_list)

            header_bytes = batch_header.SerializeToString()

            signature = self.signer.sign(header_bytes)

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

            batch_list.append(batch)

        return batch_list
    def send(self, transactions):
        """ Package up transactions into a batch and send them to the
        network via the provided batch_sender.
        :param transactions: list of transactions to package and broadcast.
        :return: None
        """
        txn_signatures = [txn.header_signature for txn in transactions]
        header = BatchHeader(
            signer_pubkey=self._identity_public_key,
            transaction_ids=txn_signatures).SerializeToString()

        signature = signing.sign(header, self._identity_signing_key)
        batch = Batch(header=header,
                      transactions=transactions,
                      header_signature=signature)

        self._batch_sender.send(batch)
Example #25
0
def create_batch(signer, triples):
    transactions = [
        create_transaction(signer, verb, name, value)
        for verb, name, value in triples
    ]

    txn_signatures = [txn.header_signature for txn in transactions]

    header = BatchHeader(signer_public_key=signer.get_public_key().as_hex(),
                         transaction_ids=txn_signatures).SerializeToString()

    signature = signer.sign(header)

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

    batch_list = BatchList(batches=[batch])

    return batch_list.SerializeToString()
Example #26
0
def _create_batch(signer, transactions):
    """Creates a batch from a list of transactions and a public key, and signs
    the resulting batch with the given signing key.

    Args:
        signer (:obj:`Signer`): The cryptographic signer
        transactions (list of `Transaction`): The transactions to add to the
            batch.

    Returns:
        `Batch`: The constructed and signed batch.
    """
    txn_ids = [txn.header_signature for txn in transactions]
    batch_header = BatchHeader(
        signer_public_key=signer.get_public_key().as_hex(),
        transaction_ids=txn_ids).SerializeToString()

    return Batch(header=batch_header,
                 header_signature=signer.sign(batch_header),
                 transactions=transactions,
                 timestamp=int(time.time()))
Example #27
0
    def is_batch_signer_authorized(self, batch, state_root=None):
        """ Check the batch signing key against the allowed transactor
            permissions. The roles being checked are the following, from first
            to last:
                "transactor.batch_signer"
                "transactor"
                "default"

            The first role that is set will be the one used to enforce if the
            batch signer is allowed.

            Args:
                batch (Batch): The batch that is being verified.
                state_root(string): The state root of the previous block; if
                    this is specified, do not read cached values. If this is
                    None, the current state root hash and cached values will be
                    used.

        """
        if state_root is None:
            state_root_func = self._current_root_func
            from_state = False
            if not self._chain_head_set:
                if self._current_root_func() == INIT_ROOT_KEY:
                    if not self._log_guard.chain_head_not_yet_set:
                        LOGGER.debug("Chain head is not set yet. Permit all.")
                        self._log_guard.chain_head_not_yet_set = True
                    return True
                self._chain_head_set = True
        else:

            def state_root_func():
                return state_root

            from_state = True

        self._cache.update_view(state_root_func())

        header = BatchHeader()
        header.ParseFromString(batch.header)

        role = self._cache.get_role("transactor.batch_signer", state_root_func,
                                    from_state)

        if role is None:
            role = self._cache.get_role("transactor", state_root_func,
                                        from_state)

        if role is None:
            policy_name = "default"
        else:
            policy_name = role.policy_name

        policy = self._cache.get_policy(policy_name, state_root_func,
                                        from_state)
        if policy is None:
            allowed = True
        else:
            allowed = self._allowed(header.signer_public_key, policy)

        if allowed:
            return self.is_transaction_signer_authorized(
                batch.transactions, state_root_func, from_state)
        LOGGER.debug("Batch Signer: %s is not permitted.",
                     header.signer_public_key)
        return False