def add_batch(self, batch, state_hash=None, required=False): with self._condition: if self._final: raise SchedulerError('Invalid attempt to add batch to ' 'finalized scheduler; batch: {}' .format(batch.header_signature)) if not self._batches: self._least_batch_id_wo_results = batch.header_signature preserve = required if not required: # If this is the first non-required batch, it is preserved for # the schedule to be completed (i.e. no empty schedules in the # event of unschedule_incomplete_batches being called before # the first batch is completed). preserve = _first( filterfalse(lambda sb: sb.required, self._batches_by_id.values())) is None self._batches.append(batch) self._batches_by_id[batch.header_signature] = \ _AnnotatedBatch(batch, required=required, preserve=preserve) for txn in batch.transactions: self._batches_by_txn_id[txn.header_signature] = batch self._txns_available.append(txn) self._transactions[txn.header_signature] = txn if state_hash is not None: b_id = batch.header_signature self._batches_with_state_hash[b_id] = state_hash # For dependency handling: First, we determine our dependencies # based on the current state of the predecessor tree. Second, # we update the predecessor tree with reader and writer # information based on input and outputs. for txn in batch.transactions: header = TransactionHeader() header.ParseFromString(txn.header) # Calculate predecessors (transaction ids which must come # prior to the current transaction). predecessors = self._find_input_dependencies(header.inputs) predecessors.extend( self._find_output_dependencies(header.outputs)) txn_id = txn.header_signature # Update our internal state with the computed predecessors. self._txn_predecessors[txn_id] = set(predecessors) # Update the predecessor tree. # # Order of reader/writer operations is relevant. A writer # may overshadow a reader. For example, if the transaction # has the same input/output address, the end result will be # this writer (txn.header_signature) stored at the address of # the predecessor tree. The reader information will have been # discarded. Write operations to partial addresses will also # overshadow entire parts of the predecessor tree. # # Thus, the order here (inputs then outputs) will cause the # minimal amount of relevant information to be stored in the # predecessor tree, with duplicate information being # automatically discarded by the set_writer() call. for address in header.inputs: self._predecessor_tree.add_reader( address, txn_id) for address in header.outputs: self._predecessor_tree.set_writer( address, txn_id) self._condition.notify_all()
def _txn_header(self, txn): txn_hdr = TransactionHeader() txn_hdr.ParseFromString(txn.header) return txn_hdr
def _get_dependencies(self, transaction): header = TransactionHeader() header.ParseFromString(transaction.header) return list(header.dependencies)
def is_transaction_signer_authorized(self, transactions, state_root, from_state): """ Check the transaction signing key against the allowed transactor permissions. The roles being checked are the following, from first to last: "transactor.transaction_signer.<TP_Name>" "transactor.transaction_signer" "transactor" "default" The first role that is set will be the one used to enforce if the transaction signer is allowed. Args: transactions (List of Transactions): The transactions that are 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. """ role = None if role is None: role = self._cache.get_role("transactor.transaction_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) family_roles = {} for transaction in transactions: header = TransactionHeader() header.ParseFromString(transaction.header) family_policy = None if header.family_name not in family_roles: role = self._cache.get_role( "transactor.transaction_signer." + header.family_name, state_root, from_state) if role is not None: family_policy = self._cache.get_policy( role.policy_name, state_root, from_state) family_roles[header.family_name] = family_policy else: family_policy = family_roles[header.family_name] if family_policy is not None: if not self._allowed(header.signer_public_key, family_policy): LOGGER.debug("Transaction Signer: %s is not permitted.", header.signer_public_key) return False else: if policy is not None: if not self._allowed(header.signer_public_key, policy): LOGGER.debug( "Transaction Signer: %s is not permitted.", header.signer_public_key) return False return True
def is_transaction_signer_authorized(self, transactions, state_root): """ Check the transaction signing key against the allowed transactor permissions. The roles being checked are the following, from first to last: "transactor.transaction_signer.<TP_Name>" "transactor.transaction_signer" "transactor" "default" The first role that is set will be the one used to enforce if the transaction signer is allowed. Args: transactions (List of Transactions): The transactions that are being verified. identity_view (IdentityView): The IdentityView that should be used to verify the transactions. """ role = None if role is None: role = self._cache.get_role("transactor.transaction_signer", state_root) if role is None: role = self._cache.get_role("transactor", state_root) if role is None: policy_name = "default" else: policy_name = role.policy_name policy = self._cache.get_policy(policy_name, state_root) family_roles = {} for transaction in transactions: header = TransactionHeader() header.ParseFromString(transaction.header) family_policy = None if header.family_name not in family_roles: role = self._cache.get_role( "transactor.transaction_signer." + header.family_name, state_root) if role is not None: family_policy = self._cache.get_policy( role.policy_name, state_root) family_roles[header.family_name] = family_policy else: family_policy = family_roles[header.family_name] if family_policy is not None: if not self._allowed(header.signer_public_key, family_policy): LOGGER.debug("Transaction Signer: %s is not permitted.", header.signer_public_key) return False else: if policy is not None: if not self._allowed(header.signer_public_key, policy): LOGGER.debug( "Transaction Signer: %s is not permitted.", header.signer_public_key) return False return True