def validate(self, bigchain, current_transactions=[]): """Validate transaction spend Args: bigchain (BigchainDB): an instantiated bigchaindb.BigchainDB object. Returns: The transaction (Transaction) if the transaction is valid else it raises an exception describing the reason why the transaction is invalid. Raises: ValidationError: If the transaction is invalid """ input_conditions = [] if self.operation == Transaction.CREATE: duplicates = any(txn for txn in current_transactions if txn.id == self.id) if bigchain.is_committed(self.id) or duplicates: raise DuplicateTransaction( 'transaction `{}` already exists'.format(self.id)) if not self.inputs_valid(input_conditions): raise InvalidSignature('Transaction signature is invalid.') elif self.operation == Transaction.TRANSFER: self.validate_transfer_inputs(bigchain, current_transactions) return self
def validate(self, bigchain, current_transactions=[]): """Validate election transaction For more details refer BEP-21: https://github.com/bigchaindb/BEPs/tree/master/21 NOTE: * A valid election is initiated by an existing validator. * A valid election is one where voters are validators and votes are alloacted according to the voting power of each validator node. Args: bigchain (BigchainDB): an instantiated bigchaindb.lib.BigchainDB object. Returns: ValidatorElection object Raises: ValidationError: If the election is invalid """ input_conditions = [] duplicates = any(txn for txn in current_transactions if txn.id == self.id) if bigchain.get_transaction(self.id) or duplicates: raise DuplicateTransaction( 'transaction `{}` already exists'.format(self.id)) if not self.inputs_valid(input_conditions): raise InvalidSignature('Transaction signature is invalid.') current_validators = self.get_validators(bigchain) # NOTE: Proposer should be a single node if len(self.inputs) != 1 or len(self.inputs[0].owners_before) != 1: raise MultipleInputsError( '`tx_signers` must be a list instance of length one') # NOTE: change more than 1/3 of the current power is not allowed if self.asset['data']['power'] >= (1 / 3) * sum( current_validators.values()): raise InvalidPowerChange( '`power` change must be less than 1/3 of total power') # NOTE: Check if the proposer is a validator. [election_initiator_node_pub_key] = self.inputs[0].owners_before if election_initiator_node_pub_key not in current_validators.keys(): raise InvalidProposer( 'Public key is not a part of the validator set') # NOTE: Check if all validators have been assigned votes equal to their voting power if not self.is_same_topology(current_validators, self.outputs): raise UnequalValidatorSet( 'Validator set much be exactly same to the outputs of election' ) return self
def validate(self, bigchain, current_transactions=[]): """Validate election transaction NOTE: * A valid election is initiated by an existing validator. * A valid election is one where voters are validators and votes are allocated according to the voting power of each validator node. Args: :param bigchain: (BigchainDB) an instantiated bigchaindb.lib.BigchainDB object. :param current_transactions: (list) A list of transactions to be validated along with the election Returns: Election: a Election object or an object of the derived Election subclass. Raises: ValidationError: If the election is invalid """ input_conditions = [] duplicates = any(txn for txn in current_transactions if txn.id == self.id) if bigchain.is_committed(self.id) or duplicates: raise DuplicateTransaction( 'transaction `{}` already exists'.format(self.id)) if not self.inputs_valid(input_conditions): raise InvalidSignature('Transaction signature is invalid.') current_validators = self.get_validators(bigchain) # NOTE: Proposer should be a single node if len(self.inputs) != 1 or len(self.inputs[0].owners_before) != 1: raise MultipleInputsError( '`tx_signers` must be a list instance of length one') # NOTE: Check if the proposer is a validator. [election_initiator_node_pub_key] = self.inputs[0].owners_before if election_initiator_node_pub_key not in current_validators.keys(): raise InvalidProposer( 'Public key is not a part of the validator set') # NOTE: Check if all validators have been assigned votes equal to their voting power if not self.is_same_topology(current_validators, self.outputs): raise UnequalValidatorSet( 'Validator set much be exactly same to the outputs of election' ) return self
def _validate_block_transactions(self, bigchain): """Validate Block transactions. Args: bigchain (Bigchain): an instantiated bigchaindb.Bigchain object. Raises: ValidationError: If an invalid transaction is found """ txids = [tx.id for tx in self.transactions] if len(txids) != len(set(txids)): raise DuplicateTransaction('Block has duplicate transaction') for tx in self.transactions: # If a transaction is not valid, `validate_transactions` will # throw an an exception and block validation will be canceled. bigchain.validate_transaction(tx)
def _validate_block(self, bigchain): """Validate the Block without validating the transactions. Args: bigchain (:class:`~bigchaindb.Bigchain`): An instantiated Bigchain object. Raises: ValidationError: If there is a problem with the block """ # Check that the signature is valid if not self.is_signature_valid(): raise InvalidSignature('Invalid block signature') # Check that the block contains no duplicated transactions txids = [tx.id for tx in self.transactions] if len(txids) != len(set(txids)): raise DuplicateTransaction('Block has duplicate transaction')
def validate(self, bigchain, current_transactions=[]): """Validate transaction spend Args: bigchain (BigchainDB): an instantiated bigchaindb.tendermint.BigchainDB object. Returns: The transaction (Transaction) if the transaction is valid else it raises an exception describing the reason why the transaction is invalid. Raises: ValidationError: If the transaction is invalid """ input_conditions = [] if self.operation == Transaction.CREATE: duplicates = any(txn for txn in current_transactions if txn.id == self.id) if bigchain.get_transaction(self.to_dict()['id']) or duplicates: raise DuplicateTransaction( 'transaction `{}` already exists'.format(self.id)) elif self.operation == Transaction.TRANSFER: # store the inputs so that we can check if the asset ids match input_txs = [] for input_ in self.inputs: input_txid = input_.fulfills.txid input_tx, status = bigchain.\ get_transaction(input_txid, include_status=True) if input_tx is None: for ctxn in current_transactions: # assume that the status as valid for previously validated # transactions in current round if ctxn.id == input_txid: input_tx = ctxn status = bigchain.TX_VALID if input_tx is None: raise InputDoesNotExist( "input `{}` doesn't exist".format(input_txid)) if status != bigchain.TX_VALID: raise TransactionNotInValidBlock( 'input `{}` does not exist in a valid block'.format( input_txid)) spent = bigchain.get_spent(input_txid, input_.fulfills.output, current_transactions) if spent and spent.id != self.id: raise DoubleSpend( 'input `{}` was already spent'.format(input_txid)) output = input_tx.outputs[input_.fulfills.output] input_conditions.append(output) input_txs.append(input_tx) # Validate that all inputs are distinct links = [i.fulfills.to_uri() for i in self.inputs] if len(links) != len(set(links)): raise DoubleSpend('tx "{}" spends inputs twice'.format( self.id)) # validate asset id asset_id = Transaction.get_asset_id(input_txs) if asset_id != self.asset['id']: raise AssetIdMismatch(('The asset id of the input does not' ' match the asset id of the' ' transaction')) input_amount = sum([ input_condition.amount for input_condition in input_conditions ]) output_amount = sum( [output_condition.amount for output_condition in self.outputs]) if output_amount != input_amount: raise AmountError( ('The amount used in the inputs `{}`' ' needs to be same as the amount used' ' in the outputs `{}`').format(input_amount, output_amount)) if not self.inputs_valid(input_conditions): raise InvalidSignature('Transaction signature is invalid.') return self