Exemplo n.º 1
0
    def validate(self, bigchain):
        """Validate a block.

        Args:
            bigchain (Bigchain): an instantiated bigchaindb.Bigchain object.

        Returns:
            block (Block): The block as a `Block` object if it is valid.
                           Else it raises an appropriate exception describing
                           the reason of invalidity.

        Raises:
            OperationError: if a non-federation node signed the block.
        """

        # First, make sure this node hasn't already voted on this block
        if bigchain.has_previous_vote(self.id, self.voters):
            return self

        # Check if the block was created by a federation node
        possible_voters = (bigchain.nodes_except_me + [bigchain.me])
        if self.node_pubkey not in possible_voters:
            raise OperationError('Only federation nodes can create blocks')

        if not self.is_signature_valid():
            raise InvalidSignature('Block signature invalid')

        # Finally: Tentative assumption that every blockchain will want to
        # validate all transactions in each block
        for tx in self.transactions:
            # NOTE: If a transaction is not valid, `is_valid` will throw an
            #       an exception and block validation will be canceled.
            bigchain.validate_transaction(tx)

        return self
Exemplo n.º 2
0
    def from_dict(cls, block_body):
        block = block_body['block']
        block_serialized = serialize(block)
        block_id = hash_data(block_serialized)
        verifying_key = VerifyingKey(block['node_pubkey'])

        try:
            signature = block_body['signature']
        except KeyError:
            signature = None

        if block_id != block_body['id']:
            raise InvalidHash()

        if signature is not None:
            # NOTE: CC throws a `ValueError` on some wrong signatures
            #       https://github.com/bigchaindb/cryptoconditions/issues/27
            try:
                signature_valid = verifying_key\
                        .verify(block_serialized.encode(), signature)
            except ValueError:
                signature_valid = False
            if signature_valid is False:
                raise InvalidSignature('Invalid block signature')

        transactions = [
            Transaction.from_dict(tx) for tx in block['transactions']
        ]

        return cls(transactions, block['node_pubkey'], block['timestamp'],
                   block['voters'], signature)
Exemplo n.º 3
0
    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
Exemplo n.º 4
0
    def from_dict(cls, ffill):
        """Transforms a Python dictionary to a Fulfillment object.

            Note:
                Optionally, this method can also serialize a Cryptoconditions-
                Fulfillment that is not yet signed.

            Args:
                ffill (dict): The Fulfillment to be transformed.

            Returns:
                :class:`~bigchaindb.common.transaction.Fulfillment`

            Raises:
                InvalidSignature: If a Fulfillment's URI couldn't be parsed.
        """
        try:
            fulfillment = CCFulfillment.from_uri(ffill['fulfillment'])
        except ValueError:
            # TODO FOR CC: Throw an `InvalidSignature` error in this case.
            raise InvalidSignature("Fulfillment URI couldn't been parsed")
        except TypeError:
            # NOTE: See comment about this special case in
            #       `Fulfillment.to_dict`
            fulfillment = CCFulfillment.from_dict(ffill['fulfillment'])
        input_ = TransactionLink.from_dict(ffill['input'])
        return cls(fulfillment, ffill['owners_before'], input_)
Exemplo n.º 5
0
    def from_dict(cls, data):
        """Transforms a Python dictionary to an Input object.

            Note:
                Optionally, this method can also serialize a Cryptoconditions-
                Fulfillment that is not yet signed.

            Args:
                data (dict): The Input to be transformed.

            Returns:
                :class:`~bigchaindb.common.transaction.Input`

            Raises:
                InvalidSignature: If an Input's URI couldn't be parsed.
        """
        fulfillment = data['fulfillment']
        if not isinstance(fulfillment, (Fulfillment, type(None))):
            try:
                fulfillment = Fulfillment.from_uri(data['fulfillment'])
            except ASN1DecodeError:
                # TODO Remove as it is legacy code, and simply fall back on
                # ASN1DecodeError
                raise InvalidSignature("Fulfillment URI couldn't been parsed")
            except TypeError:
                # NOTE: See comment about this special case in
                #       `Input.to_dict`
                fulfillment = _fulfillment_from_details(data['fulfillment'])
        fulfills = TransactionLink.from_dict(data['fulfills'])
        return cls(fulfillment, data['owners_before'], fulfills)
    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
Exemplo n.º 7
0
    def validate_transfer_inputs(self, bigchain, current_transactions=[]):
        # store the inputs so that we can check if the asset ids match
        input_txs = []
        input_conditions = []
        for input_ in self.inputs:
            input_txid = input_.fulfills.txid
            input_tx = bigchain.get_transaction(input_txid)

            if input_tx is None:
                for ctxn in current_transactions:
                    if ctxn.id == input_txid:
                        input_tx = ctxn

            if input_tx is None:
                raise InputDoesNotExist(
                    "input `{}` doesn't exist".format(input_txid))

            spent = bigchain.get_spent(input_txid, input_.fulfills.output,
                                       current_transactions)
            if spent:
                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 = self.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 True
Exemplo n.º 8
0
    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
Exemplo n.º 9
0
    def from_dict(cls, block_body):
        """Transform a Python dictionary to a Block object.

        Args:
            block_body (dict): A block dictionary to be transformed.

        Returns:
            :class:`~Block`

        Raises:
            InvalidHash: If the block's id is not corresponding to its
                data.
            InvalidSignature: If the block's signature is not corresponding
                to it's data or `node_pubkey`.
        """
        # TODO: Reuse `is_signature_valid` method here.
        block = block_body['block']
        block_serialized = serialize(block)
        block_id = hash_data(block_serialized)
        public_key = PublicKey(block['node_pubkey'])

        try:
            signature = block_body['signature']
        except KeyError:
            signature = None

        if block_id != block_body['id']:
            raise InvalidHash()

        if signature is not None:
            # NOTE: CC throws a `ValueError` on some wrong signatures
            #       https://github.com/bigchaindb/cryptoconditions/issues/27
            try:
                signature_valid = public_key\
                        .verify(block_serialized.encode(), signature)
            except ValueError:
                signature_valid = False
            if signature_valid is False:
                raise InvalidSignature('Invalid block signature')

        transactions = [
            Transaction.from_dict(tx) for tx in block['transactions']
        ]

        return cls(transactions, block['node_pubkey'], block['timestamp'],
                   block['voters'], signature)
Exemplo n.º 10
0
    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 if the block was created by a federation node
        if self.node_pubkey not in bigchain.federation:
            raise SybilError('Only federation nodes can create blocks')

        # Check that the signature is valid
        if not self.is_signature_valid():
            raise InvalidSignature('Invalid block signature')
Exemplo n.º 11
0
    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')
Exemplo n.º 12
0
    def _validate_block(self, bigchain):
        """Validate the Block without validating the transactions.

        Args:
            bigchain (:class:`~bigchaindb.Bigchain`): An instantiated Bigchain
                object.

        Raises:
            OperationError: If a non-federation node signed the Block.
            InvalidSignature: If a Block's signature is invalid.
        """
        # Check if the block was created by a federation node
        possible_voters = (bigchain.nodes_except_me + [bigchain.me])
        if self.node_pubkey not in possible_voters:
            raise OperationError('Only federation nodes can create blocks')

        # Check that the signature is valid
        if not self.is_signature_valid():
            raise InvalidSignature('Invalid block signature')
Exemplo n.º 13
0
    def validate(self, bigchain):
        """Validate a transaction.

        Args:
            bigchain (Bigchain): an instantiated bigchaindb.Bigchain object.

        Returns:
            The transaction (Transaction) if the transaction is valid else it
            raises an exception describing the reason why the transaction is
            invalid.

        Raises:
            OperationError: if the transaction operation is not supported
            TransactionDoesNotExist: if the input of the transaction is not
                                     found
            TransactionNotInValidBlock: if the input of the transaction is not
                                        in a valid block
            TransactionOwnerError: if the new transaction is using an input it
                                   doesn't own
            DoubleSpend: if the transaction is a double spend
            InvalidHash: if the hash of the transaction is wrong
            InvalidSignature: if the signature of the transaction is wrong
        """
        if len(self.inputs) == 0:
            raise ValueError('Transaction contains no inputs')

        input_conditions = []
        inputs_defined = all([input_.fulfills for input_ in self.inputs])

        # validate amounts
        if any(output.amount < 1 for output in self.outputs):
            raise AmountError('`amount` needs to be greater than zero')

        if self.operation in (Transaction.CREATE, Transaction.GENESIS):
            # validate asset
            if self.asset['data'] is not None and not isinstance(
                    self.asset['data'], dict):
                raise TypeError(('`asset.data` must be a dict instance or '
                                 'None for `CREATE` transactions'))
            # validate inputs
            if inputs_defined:
                raise ValueError('A CREATE operation has no inputs')
        elif self.operation == Transaction.TRANSFER:
            # validate asset
            if not isinstance(self.asset['id'], str):
                raise ValueError(('`asset.id` must be a string for '
                                  '`TRANSFER` transations'))
            # check inputs
            if not inputs_defined:
                raise ValueError('Only `CREATE` transactions can have null '
                                 'inputs')

            # 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:
                    raise TransactionDoesNotExist(
                        "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)
                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)
                if output.amount < 1:
                    raise AmountError('`amount` needs to be greater than zero')

            # 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'))

            # validate the amounts
            for output in self.outputs:
                if output.amount < 1:
                    raise AmountError('`amount` needs to be greater than zero')

            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))

        else:
            allowed_operations = ', '.join(Transaction.ALLOWED_OPERATIONS)
            raise TypeError('`operation`: `{}` must be either {}.'.format(
                self.operation, allowed_operations))

        if not self.inputs_valid(input_conditions):
            raise InvalidSignature('Transaction signature is invalid.')

        return self
Exemplo n.º 14
0
    def validate(self, bigchain):
        """Validate a transaction.

        Args:
            bigchain (Bigchain): an instantiated bigchaindb.Bigchain object.

        Returns:
            The transaction (Transaction) if the transaction is valid else it
            raises an exception describing the reason why the transaction is
            invalid.

        Raises:
            OperationError: if the transaction operation is not supported
            TransactionDoesNotExist: if the input of the transaction is not
                                     found
            TransactionOwnerError: if the new transaction is using an input it
                                   doesn't own
            DoubleSpend: if the transaction is a double spend
            InvalidHash: if the hash of the transaction is wrong
            InvalidSignature: if the signature of the transaction is wrong
        """
        if len(self.fulfillments) == 0:
            raise ValueError('Transaction contains no fulfillments')

        input_conditions = []
        inputs_defined = all([ffill.tx_input for ffill in self.fulfillments])

        if self.operation in (Transaction.CREATE, Transaction.GENESIS):
            # validate inputs
            if inputs_defined:
                raise ValueError('A CREATE operation has no inputs')
            # validate asset
            self.asset._validate_asset()
        elif self.operation == Transaction.TRANSFER:
            if not inputs_defined:
                raise ValueError('Only `CREATE` transactions can have null '
                                 'inputs')
            # check inputs
            # store the inputs so that we can check if the asset ids match
            input_txs = []
            for ffill in self.fulfillments:
                input_txid = ffill.tx_input.txid
                input_cid = ffill.tx_input.cid
                input_tx, status = bigchain.\
                    get_transaction(input_txid, include_status=True)

                if input_tx is None:
                    raise TransactionDoesNotExist(
                        "input `{}` doesn't exist".format(input_txid))

                if status != bigchain.TX_VALID:
                    raise FulfillmentNotInValidBlock(
                        'input `{}` does not exist in a valid block'.format(
                            input_txid))

                spent = bigchain.get_spent(input_txid, ffill.tx_input.cid)
                if spent and spent.id != self.id:
                    raise DoubleSpend(
                        'input `{}` was already spent'.format(input_txid))

                input_conditions.append(input_tx.conditions[input_cid])
                input_txs.append(input_tx)

            # validate asset id
            asset_id = Asset.get_asset_id(input_txs)
            if asset_id != self.asset.data_id:
                raise AssetIdMismatch(
                    'The asset id of the input does not match the asset id of the transaction'
                )
        else:
            allowed_operations = ', '.join(Transaction.ALLOWED_OPERATIONS)
            raise TypeError('`operation`: `{}` must be either {}.'.format(
                self.operation, allowed_operations))

        if not self.fulfillments_valid(input_conditions):
            raise InvalidSignature()
        else:
            return self
Exemplo n.º 15
0
    def validate(self, bigchain):
        """Validate transaction spend

        Args:
            bigchain (Bigchain): an instantiated bigchaindb.Bigchain 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.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:
                    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)
                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
Exemplo n.º 16
0
    def validate(self, bigchain):
        """Validate a transaction.

        Args:
            bigchain (Bigchain): an instantiated bigchaindb.Bigchain object.

        Returns:
            The transaction (Transaction) if the transaction is valid else it
            raises an exception describing the reason why the transaction is
            invalid.

        Raises:
            OperationError: if the transaction operation is not supported
            TransactionDoesNotExist: if the input of the transaction is not
                                     found
            TransactionOwnerError: if the new transaction is using an input it
                                   doesn't own
            DoubleSpend: if the transaction is a double spend
            InvalidHash: if the hash of the transaction is wrong
            InvalidSignature: if the signature of the transaction is wrong
        """
        # print(self.operation)
        if self.operation == Transaction.METADATA:
            return self
        if len(
                self.fulfillments
        ) == 0 and self.operation != Transaction.CONTRACT and self.operation != Transaction.INTERIM:
            # print(self.id)
            print('Transaction contains no fulfillments')
            raise ValueError('Transaction contains no fulfillments')
        # print("3")
        # print("self::",self)
        if len(
                self.conditions
        ) == 0 and self.operation != Transaction.CONTRACT and self.operation != Transaction.INTERIM:
            print('Transaction contains no conditions')
            raise ValueError('Transaction contains no conditions')

        input_conditions = []
        inputs_defined = all([ffill.tx_input for ffill in self.fulfillments])
        # print("4",inputs_defined)
        if self.operation in (Transaction.CREATE, Transaction.GENESIS):
            # print("5")
            # validate inputs
            if inputs_defined:
                raise ValueError('A CREATE operation has no inputs')
            # validate asset
            self.asset._validate_asset()
        elif self.operation in (Transaction.CONTRACT, Transaction.INTERIM):
            pass
        elif self.operation == Transaction.TRANSFER:
            if not inputs_defined:
                raise ValueError('Only `CREATE` transactions can have null '
                                 'inputs')
            # print("6")
            # check inputs
            # store the inputs so that we can check if the asset ids match
            input_txs = []
            for ffill in self.fulfillments:
                input_txid = ffill.tx_input.txid
                input_cid = ffill.tx_input.cid
                input_tx, status = bigchain.\
                    get_transaction(input_txid, include_status=True)

                if input_tx is None:
                    raise TransactionDoesNotExist(
                        "input `{}` doesn't exist".format(input_txid))

                if status != bigchain.TX_VALID:
                    raise FulfillmentNotInValidBlock(
                        'input `{}` does not exist in a valid block'.format(
                            input_txid))

                spent = bigchain.get_spent(input_txid, ffill.tx_input.cid)
                if spent and spent.id != self.id:
                    raise DoubleSpend(
                        'input `{}` was already spent'.format(input_txid))

                input_conditions.append(input_tx.conditions[input_cid])
                input_txs.append(input_tx)

            # validate asset id
            asset_id = Asset.get_asset_id(input_txs)
            if asset_id != self.asset.data_id:
                raise AssetIdMismatch(
                    'The asset id of the input does not match the asset id of the transaction'
                )
        else:
            allowed_operations = ', '.join(Transaction.ALLOWED_OPERATIONS)
            raise TypeError('`operation`: `{}` must be either {}.'.format(
                self.operation, allowed_operations))

        # print("validate in=2========",self.operation)
        if self.operation in (Transaction.CONTRACT):
            # validate contract signature
            # 1.validate the contract users signture
            # print("7")
            ContractBody = deepcopy(self.Contract["ContractBody"])
            contract_owners = ContractBody["ContractOwners"]
            contract_signatures = ContractBody["ContractSignatures"]
            ContractBody["ContractSignatures"] = None
            detail_serialized = serialize(ContractBody)
            if contract_owners != None and contract_signatures != None:
                if len(contract_owners) < len(contract_signatures):
                    raise MutilContractOwner
                for index, contract_sign in enumerate(contract_signatures):
                    owner_pubkey = contract_owners[index]
                    signature = contract_sign["Signature"]
                    if not self.is_signature_valid(detail_serialized,
                                                   owner_pubkey, signature):
                        print("Invalid contract Signature")
                        raise InvalidSignature()
                return self
            else:
                # TODO 2.validate the contract votes?
                return self

        # print("validate in=3========",self.operation,"==",self.version)
        if self.version == 2:
            # 1.validate the nodes signature
            voters = self.Relation["Voters"]
            votes = self.Relation["Votes"]
            # print("taskid 146 --- ",self.Relation["TaskId"])
            # tx_dict = deepcopy(self.to_dict())
            # tx_dict["transaction"].pop('Relation')
            # tx_dict["transaction"].pop('Contract')
            # detail_serialized = serialize(tx_dict)

            if len(voters) < len(votes):
                raise MutilcontractNode

            for index, vote in enumerate(votes):
                # print(index)
                owner_pubkey = voters[index]
                signature = vote["Signature"]
                detail_serialized = self.id
                print(detail_serialized)
                # print(owner_pubkey)
                # print(signature)
                if not self.is_signature_valid(detail_serialized, owner_pubkey,
                                               signature):
                    print("Invalid vote Signature")
                    raise InvalidSignature()
            return self

        if not self.fulfillments_valid(input_conditions):
            raise InvalidSignature()
        else:
            return self