Esempio n. 1
0
    def is_valid(self):
        """ Check whether block is fully valid according to block rules.

        Includes checking for no double spend, that all transactions are valid, that all header fields are correctly
        computed, etc.

        Returns:
            bool, str: True if block is valid, False otherwise plus an error or success message.
        """

        chain = blockchain.chain  # This object of type Blockchain may be useful

        # (checks that apply to all blocks)

        #[test_rejects_invalid_merkle]
        #Check if the current block's merkle root is the same as the calculated mr
        if self.merkle != self.calculate_merkle_root():
            return False, "Merkle root failed to match"

        #[test_rejects_invalid_hash]
        #Check if the current block's hash is the same as the calculated hash of the block
        if self.hash != self.calculate_hash():
            return False, "Hash failed to match"

        #[test_rejects_too_many_txs]
        #Check to see if the current block meets the transaction limit
        if len(self.transactions) > 900:
            return False, "Too many transactions"

        # (checks that apply to genesis block)

        #[test_invalid_genesis]
        #Chek if the current block is genesis or not
        if self.is_genesis is True:

            #Make sure that this is a valid genesis block
            #Check that it is at height 0 and that the parent hash is genesis
            if self.height != 0 or self.parent_hash != "genesis":
                return False, "Invalid genesis"

        # (checks that apply only to non-genesis blocks)
        # Check that parent exists (you may find chain.blocks helpful) [test_nonexistent_parent]
        # On failure: return False, "Nonexistent parent"

        # (checks that apply only to non-genesis blocks)
        if self.is_genesis is False:

            #[test_nonexistent_parent]
            #Check that the parent block is in the current chain
            if self.parent_hash not in chain.blocks:
                return False, "Nonexistent parent"

            #[test_bad_height]
            #Check if the space between the current block and parent block is 1
            if (self.height - chain.blocks[self.parent_hash].height) != 1:
                return False, "Invalid height"

            #[test_bad_timestamp]
            #Check that the timestamp on the block and parent block are the same
            if self.timestamp != chain.blocks[self.parent_hash].timestamp:
                return False, "Invalid timestamp"

            #[test_bad_seal]
            #Check that the seal is valid
            if not self.seal_is_valid():
                return False, "Invalid seal"

            #[test_malformed_txs]
            #get each transaction in the block
            for i in self.transactions:
                #Check if the transaction is valid
                if not i.is_valid():
                    return False, "Malformed transaction included"

            #initiate lists for later checks
            l = []
            output = []

            # Check that for every transaction
            for tx in self.transactions:
                #create a list of transactions
                l.append(tx)

                #[test_double_tx_inclusion_same_chain]
                #check that the transaction hash is not already presenet in the chain
                if tx.hash in chain.blocks_containing_tx:
                    return False, "Double transaction inclusion"

                #[test_double_tx_inclusion_same_block]
                #Check that the transaction doesnt appear twice in the same block
                if self.transactions.count(tx) != 1:
                    return False, "Double transaction inclusion"

                #for money creation test
                in_total = 0

                # get the input ref for each tx
                for input_ref in tx.input_refs:

                    # Split the input ref into the hash and transaction position
                    h, pos = input_ref.split(':')
                    #convert position to int for later use
                    pos = int(pos)

                    #[test_failed_input_lookup]
                    #Create a list of transaction hashes in the block
                    tx_h = [tx.hash for tx in self.transactions]

                    #Check if the input ref hash is in the chain
                    if h not in chain.all_transactions:
                        #If input ref hash is not in the chan, check if its in the block
                        if h not in tx_h:
                            return False, "Required output not found"

                    #Check if the input ref hash is in the chain
                    if h in chain.all_transactions:
                        #create variable with list of transaction from input ref hash
                        input_tx = chain.all_transactions[h]

                    #Check if the input ref hash is not in the chain
                    else:
                        #Get each transaction in the block
                        for input_trans in self.transactions:
                            #if the input ref hash is equal to the hash of a transaction in the block
                            if h == input_trans.hash:
                                #if true, set the input tx var to the transaction from the block and exit
                                input_tx = input_trans
                                break

                    #Get the number of outputs in the transaction
                    output_num = len(input_tx.outputs)

                    #check if the
                    if pos >= output_num:
                        return False, "Required output not found"

                    #[test_user_consistency]
                    # Get user who received transaction input
                    rec = input_tx.outputs[pos].receiver

                    # list of users the sent transaction
                    send = [user.sender for user in tx.outputs]

                    # Get user in send list
                    for user in send:
                        #check if user is the reciever
                        if user != rec:
                            return False, "User inconsistencies"

                    #[test_doublespent_input_same_chain]
                    #Check if trans input ref has been spent elsewhere in the chain
                    if input_ref in chain.blocks_spending_input:

                        #get a list of blocks to check
                        blks = chain.get_chain_ending_with(self.parent_hash)

                        #get a list of blocks where the input ref was spent
                        spend = chain.blocks_spending_input[input_ref]

                        #check if the block the input ref was spent on was spent elsewhere on the chain
                        if nonempty_intersection(blks, spend):
                            return False, "Double-spent input"

                    #[test_doublespent_input_same_block]
                    #compile tx inputs on block
                    b_inputs = []
                    for trans in self.transactions:
                        #for each tx in block
                        for tx_input_ref in trans.input_refs:
                            #for each inport ref in the tx, add to list
                            b_inputs.append(tx_input_ref)

                    # check if the input was already spent on the block
                    if b_inputs.count(input_ref) != 1:
                        return False, "Double-spent input"

                    #[test_input_txs_on_chain]
                    #check if the transaction is on the current blockchain

                    if h in chain.blocks_containing_tx:
                        #create list of blocks in question and blocks that contain the input transaction
                        blks = chain.get_chain_ending_with(self.parent_hash)
                        b_w_h = chain.blocks_containing_tx[h]

                        #check if the input trans is in both lists
                        if not nonempty_intersection(blks, b_w_h):
                            #check if the input transaction is not in the transactions on block
                            if h not in tx_h:
                                return False, "Input transaction not found"
#FIX THIS
#[test_input_txs_in_block]
#if the input ref hash is not on the chain, check if its in the current block

                    elif h in tx_h:
                        break
                    else:
                        return False, "Input transaction not found"

                    #for money creation test
                    in_total += input_tx.outputs[pos].amount

                #[test_user_consistency]
                #create a list of senders of transaxctions
                send = []
                for user in tx.outputs:
                    send.append(user.sender)

                #check if there is only one sender
                if len(set(send)) > 1:
                    return False, "User inconsistencies"

                #[test_no_money_creation]
                #create a list of transactions to calculate amount
                out_total = []
                for output in tx.outputs:
                    out_total.append(output.amount)

                #get the total output amount
                out_total = sum(out_total)

                #check if the output value is greater than the input value
                if in_total < out_total:
                    return False, "Creating money"

        return True, "All checks passed"
Esempio n. 2
0
    def is_valid(self):
        """ Check whether block is fully valid according to block rules.

        Includes checking for no double spend, that all transactions are valid, that all header fields are correctly
        computed, etc.

        Returns:
            bool, str: True if block is valid, False otherwise plus an error or success message.
        """

        chain = blockchain.chain  # This object of type Blockchain may be useful

        # Placeholder for (1a)

        # (checks that apply to all blocks)
        # Check that Merkle root calculation is consistent with transactions in block (use the calculate_merkle_root function) [test_rejects_invalid_merkle]
        # On failure: return False, "Merkle root failed to match"
        if not self.merkle == self.calculate_merkle_root():
            return False, "Merkle root failed to match"

        # Check that block.hash is correctly calculated [test_rejects_invalid_hash]
        # On failure: return False, "Hash failed to match"
        if not self.hash == self.calculate_hash():
            return False, "Hash failed to match"

        # Check that there are at most 900 transactions in the block [test_rejects_too_many_txs]
        # On failure: return False, "Too many transactions"
        if len(self.transactions) > 900:
            return False, "Too many transactions"

        # (checks that apply to genesis block)
        # Check that height is 0 and parent_hash is "genesis" [test_invalid_genesis]
        # On failure: return False, "Invalid genesis"
        if self.is_genesis:
            if self.height != 0 or self.parent_hash != 'genesis' or self.hash != self.calculate_hash(
            ):
                return False, "Invalid genesis"

        # (checks that apply only to non-genesis blocks)
        else:
            # Check that parent exists (you may find chain.blocks helpful) [test_nonexistent_parent]
            # On failure: return False, "Nonexistent parent"
            if self.parent_hash not in chain.blocks.keys():
                return False, "Nonexistent parent"

            # Check that height is correct w.r.t. parent height [test_bad_height]
            # On failure: return False, "Invalid height"
            parent_block = chain.blocks[self.parent_hash]
            if self.height != (parent_block.height + 1):
                return False, "Invalid height"

            # Check that timestamp is non-decreasing [test_bad_timestamp]
            # On failure: return False, "Invalid timestamp"
            if self.timestamp < parent_block.timestamp:
                return False, "Invalid timestamp"

            # Check that seal is correctly computed and satisfies "target" requirements; use the provided seal_is_valid method [test_bad_seal]
            # On failure: return False, "Invalid seal"
            if not self.seal_is_valid():
                return False, "Invalid seal"

            # Check that all transactions within are valid (use tx.is_valid) [test_malformed_txs]
            # On failure: return False, "Malformed transaction included"
            for tx in self.transactions:
                if not tx.is_valid():
                    return False, "Malformed transaction included"

            # Check that for every transaction
            for tx in self.transactions:
                # the transaction has not already been included on a block on the same blockchain as this block [test_double_tx_inclusion_same_chain]
                # (or twice in this block; you will have to check this manually) [test_double_tx_inclusion_same_block]
                # (you may find chain.get_chain_ending_with and chain.blocks_containing_tx and util.nonempty_intersection useful)
                # On failure: return False, "Double transaction inclusion"

                # [test_double_tx_inclusion_same_block]
                tx_hashes = [t.hash for t in self.transactions]
                if len(set(tx_hashes)) != len(tx_hashes):
                    return False, "Double transaction inclusion"

                # [test_double_tx_inclusion_same_chain]
                block = self
                while block.parent_hash != "genesis":
                    block = chain.blocks[block.parent_hash]
                    if tx.hash in [t.hash for t in block.transactions]:
                        return False, "Double transaction inclusion"

                # for every input ref in the tx
                for input_ref in tx.input_refs:
                    # (you may find the string split method for parsing the input into its components)
                    tx_id = input_ref.split(":")[0]
                    output_idx = int(input_ref.split(":")[1])
                    # each input_ref is valid (aka corresponding transaction can be looked up in its holding transaction) [test_failed_input_lookup]
                    # (you may find chain.all_transactions useful here)
                    # On failure: return False, "Required output not found"
                    tx_in_same_block = tx_id in tx_hashes

                    if (not tx_in_same_block
                            and tx_id not in chain.all_transactions):
                        return False, "Required output not found"
                    else:
                        """
                        find target transaction.
                        - from previous block: `chain.all_transactions[tx_id]`
                        - from the same block: `[t for t in self.transactions if t.hash == tx_id][0]`
                        """
                        if tx_id not in chain.all_transactions.keys():
                            target_transaction = [
                                t for t in self.transactions if t.hash == tx_id
                            ][0]
                        else:
                            target_transaction = chain.all_transactions[tx_id]
                        # output_idx overflow:
                        output_idx_overflow = (output_idx + 1) > len(
                            target_transaction.outputs)
                        if output_idx_overflow:
                            return False, "Required output not found"
                    # every input was sent to the same user (would normally carry a signature from this user; we leave this out for simplicity) [test_user_consistency]
                    # On failure: return False, "User inconsistencies"
                    previous_output_transaction = target_transaction.outputs[
                        output_idx]
                    this_input_name = previous_output_transaction.receiver
                    this_outputs_names = set([t.sender for t in tx.outputs])
                    if this_input_name not in this_outputs_names or len(
                            this_outputs_names) > 1:
                        return False, "User inconsistencies"
                    this_inputs_names = set([
                        target_transaction.outputs[out_id].receiver for out_id
                        in map(lambda x: int(x.split(":")[1]), tx.input_refs)
                    ])
                    if len(this_inputs_names) > 1:
                        return False, "User inconsistencies"

                    # no input_ref has been spent in a previous block on this chain [test_doublespent_input_same_chain]
                    # (or in this block; you will have to check this manually) [test_doublespent_input_same_block]
                    # (you may find nonempty_intersection and chain.blocks_spending_input helpful here)
                    # On failure: return False, "Double-spent input"
                    if input_ref in chain.blocks_spending_input:
                        """
                        double spend on same chain.
                        """
                        having_this_tx_blocks = list(
                            map(lambda x: chain.blocks[x],
                                chain.blocks_spending_input[input_ref]))
                        max_height = max(
                            map(lambda x: x.height, having_this_tx_blocks))
                        if self.height > max_height:
                            return False, "Double-spent input"
                    else:
                        """
                        double spend on same block.
                        """
                        init_input_ref = []
                        for i in self.transactions:
                            if nonempty_intersection(init_input_ref,
                                                     i.input_refs):
                                return False, "Double-spent input"
                            else:
                                init_input_ref.extend(i.input_refs)

                    # each input_ref points to a transaction on the same blockchain as this block [test_input_txs_on_chain]
                    # (or in this block; you will have to check this manually) [test_input_txs_in_block]
                    # (you may find chain.blocks_containing_tx.get and nonempty_intersection as above helpful)
                    # On failure: return False, "Input transaction not found"
                    if tx_id in list(map(lambda x: x.hash, self.transactions)):
                        pass
                    elif tx_id in chain.all_transactions.keys():
                        """
                        test_input_txs_on_chain
                        """
                        contain_this_tx_blocks = list(
                            map(lambda x: chain.blocks[x],
                                chain.blocks_containing_tx[tx_id]))
                        max_height = max(
                            map(lambda x: x.height, contain_this_tx_blocks))
                        if self.height <= max_height:
                            return False, "Input transaction not found"

                # for every output in the tx
                # every output was sent from the same user (would normally carry a signature from this user; we leave this out for simplicity)
                # (this MUST be the same user as the outputs are locked to above) [test_user_consistency]
                # On failure: return False, "User inconsistencies"
                # the sum of the input values is at least the sum of the output values (no money created out of thin air) [test_no_money_creation]
                # On failure: return False, "Creating money"
                for input_ref in tx.input_refs:
                    tx_id = input_ref.split(":")[0]
                    output_idx = int(input_ref.split(":")[1])
                    if tx_id not in chain.all_transactions.keys():
                        target_transaction = [
                            t for t in self.transactions if t.hash == tx_id
                        ][0]
                    else:
                        target_transaction = chain.all_transactions[tx_id]
                    previous_output_transaction = target_transaction.outputs[
                        output_idx]
                    sender_name = previous_output_transaction.receiver
                    money_upper_bound = previous_output_transaction.amount
                    current_transaction_outputs = tx.outputs
                    if sum(
                            map(
                                lambda x: x.amount
                                if x.sender == sender_name else 0,
                                current_transaction_outputs)
                    ) > money_upper_bound:
                        return False, "Creating money"

        return True, "All checks passed"
Esempio n. 3
0
    def is_valid(self):
        """ Check whether block is fully valid according to block rules.

        Includes checking for no double spend, that all transactions are valid, that all header fields are correctly
        computed, etc.

        Returns:
            bool, str: True if block is valid, False otherwise plus an error or success message.
        """

        chain = blockchain.chain  # This object of type Blockchain may be useful

        all_blocks = chain.get_chain_ending_with(self.hash)
        # print(all_blocks)
        # Placeholder for (1a)

        # (checks that apply to all blocks)
        # Check that Merkle root calculation is consistent with transactions in block (use the calculate_merkle_root function) [test_rejects_invalid_merkle]
        # On failure: return False, "Merkle root failed to match"

        if self.merkle != self.calculate_merkle_root():
            return False, "Merkle root failed to match"

        # Check that block.hash is correctly calculated [test_rejects_invalid_hash]
        # On failure: return False, "Hash failed to match"

        if self.hash != self.calculate_hash():
            return False, "Hash failed to match"

        # Check that there are at most 900 transactions in the block [test_rejects_too_many_txs]
        # On failure: return False, "Too many transactions"

        if len(self.transactions) > 900:
            return False, "Too many transactions"

        # (checks that apply to genesis block)
        # Check that height is 0 and parent_hash is "genesis" [test_invalid_genesis]
        # On failure: return False, "Invalid genesis"

        if self.is_genesis:
            if (self.height != 0 or self.parent_hash != "genesis"):
                return False, "Invalid genesis"

        else:
            # (checks that apply only to non-genesis blocks)

            # Check that parent exists (you may find chain.blocks helpful) [test_nonexistent_parent]
            # On failure: return False, "Nonexistent parent"
            if self.parent_hash not in chain.blocks:
                return False, "Nonexistent parent"
            else:
                parent = chain.blocks[self.parent_hash]

                # Check that height is correct w.r.t. parent height [test_bad_height]
                # On failure: return False, "Invalid height"
                if self.height != parent.height + 1:
                    return False, "Invalid height"

                # Check that timestamp is non-decreasing [test_bad_timestamp]
                # On failure: return False, "Invalid timestamp"
                if self.timestamp < parent.timestamp:
                    return False, "Invalid timestamp"

            # Check that seal is correctly computed and satisfies "target" requirements; use the provided seal_is_valid method [test_bad_seal]
            # On failure: return False, "Invalid seal"
            if not self.seal_is_valid():
                return False, "Invalid seal"

            # Check that all transactions within are valid (use tx.is_valid) [test_malformed_txs]
            # On failure: return False, "Malformed transaction included"
            transactions = {}
            parent_chain = chain.get_chain_ending_with(self.parent_hash)
            for i, tx in enumerate(self.transactions):
                h = tx.hash
                transactions[h] = i

            for tx in self.transactions:
                if not tx.is_valid():
                    return False, "Malformed transaction included"

            # Check that for every transaction
            # the transaction has not already been included on a block on the same blockchain as this block [test_double_tx_inclusion_same_chain]
            # (or twice in this block; you will have to check this manually) [test_double_tx_inclusion_same_block]
            # (you may find chain.get_chain_ending_with and chain.blocks_containing_tx and util.nonempty_intersection useful)
            # On failure: return False, "Double transaction inclusion"

            if len(transactions) != len(self.transactions):
                return False, "Double transaction inclusion"

            for tx in self.transactions:
                copy_list = chain.blocks_containing_tx.get(tx.hash, [])
                if nonempty_intersection(parent_chain, copy_list):
                    return False, "Double transaction inclusion"

                # for every input ref in the tx
                # (you may find the string split method for parsing the input into its components)

                # each input_ref is valid (aka corresponding transaction can be looked up in its holding transaction) [test_failed_input_lookup]
                # (you may find chain.all_transactions useful here)
                # On failure: return False, "Required output not found"
            block_inputs = []
            for tx in self.transactions:
                total_input = 0
                for r in tx.input_refs:
                    split = r.split(':')
                    h = split[0]
                    i = int(split[1])

                    if h not in chain.all_transactions and h not in transactions:
                        return False, "Required output not found"

                    if h in chain.all_transactions:
                        input_txs = chain.all_transactions[h]
                    else:
                        input_txs = self.transactions[transactions[h]]

                    if len(input_txs.outputs) - 1 < i:
                        return False, "Required output not found"

                    # every input was sent to the same user (would normally carry a signature from this user; we leave this out for simplicity) [test_user_consistency]
                    # On failure: return False, "User inconsistencies"
                    receiver = input_txs.outputs[i].receiver
                    senders = []

                    for user in tx.outputs:
                        senders.append(user.sender)

                    for sender in senders:
                        if sender != receiver:
                            return False, "User inconsistencies"

                    # no input_ref has been spent in a previous block on this chain [test_doublespent_input_same_chain]
                    # (or in this block; you will have to check this manually) [test_doublespent_input_same_block]
                    # (you may find nonempty_intersection and chain.blocks_spending_input helpful here)
                    # On failure: return False, "Double-spent input"

                    spend = chain.blocks_spending_input.get(r, [])
                    parent_chain = chain.get_chain_ending_with(
                        self.parent_hash)
                    if len(spend) >= 1 and nonempty_intersection(
                            parent_chain, spend):
                        return False, "Double-spent input"
                    if r in block_inputs:
                        return False, "Double-spent input"
                    else:
                        block_inputs.append(r)

                    # each input_ref points to a transaction on the same blockchain as this block [test_input_txs_on_chain]
                    # (or in this block; you will have to check this manually) [test_input_txs_in_block]
                    # (you may find chain.blocks_containing_tx.get and nonempty_intersection as above helpful)
                    # On failure: return False, "Input transaction not found"

                    blocks_with_transaction = chain.blocks_containing_tx.get(
                        h, [])
                    if h not in transactions and not (nonempty_intersection(
                            blocks_with_transaction, parent_chain)):
                        return False, "Input transaction not found"

                # for every output in the tx
                # every output was sent from the same user (would normally carry a signature from this user; we leave this out for simplicity)
                # (this MUST be the same user as the outputs are locked to above) [test_user_consistency]
                # On failure: return False, "User inconsistencies"
                # the sum of the input values is at least the sum of the output values (no money created out of thin air) [test_no_money_creation]
                # On failure: return False, "Creating money"
            for tx in self.transactions:
                total_input = 0
                total_output = 0
                for output in tx.outputs:
                    total_output += output.amount

                for input_ref in tx.input_refs:
                    split = input_ref.split(':')
                    h = split[0]
                    i = int(split[1])
                    input_transaction = chain.all_transactions[
                        h] if h in chain.all_transactions else self.transactions[
                            transactions[h]]
                total_input += input_transaction.outputs[i].amount
                if total_input < total_output:
                    return False, "Creating money"
        return True, "All checks passed"
Esempio n. 4
0
    def is_valid(self):
        """ Check whether block is fully valid according to block rules.

        Includes checking for no double spend, that all transactions are valid, that all header fields are correctly
        computed, etc.

        Returns:
            bool, str: True if block is valid, False otherwise plus an error or success message.
        """

        chain = blockchain.chain  # This object of type Blockchain may be useful

        # Placeholder for (1a)

        # (checks that apply to all blocks)
        # Check that Merkle root calculation is consistent with transactions in block (use the calculate_merkle_root function) [test_rejects_invalid_merkle]
        # On failure: return False, "Merkle root failed to match"
        if not self.merkle == self.calculate_merkle_root():
            return False, "Merkle root failed to match"

        # Check that block.hash is correctly calculated [test_rejects_invalid_hash]
        # On failure: return False, "Hash failed to match"
        if not self.hash == self.calculate_hash():
            return False, "Hash failed to match"

        # Check that there are at most 900 transactions in the block [test_rejects_too_many_txs]
        # On failure: return False, "Too many transactions"
        if len(self.transactions) > 900:
            return False, "Too many transactions"

        # (checks that apply to genesis block)
        if self.is_genesis:
            # Check that height is 0 and parent_hash is "genesis" [test_invalid_genesis]
            # On failure: return False, "Invalid genesis"
            if not (self.parent_hash == "genesis" and self.height == 0):
                return False, "Invalid genesis"

        # (checks that apply only to non-genesis blocks)
        else:
            # Check that parent exists (you may find chain.blocks helpful) [test_nonexistent_parent]
            # On failure: return False, "Nonexistent parent"
            if not self.parent_hash in chain.blocks:
                return False, "Nonexistent parent"

            # Check that height is correct w.r.t. parent height [test_bad_height]
            # On failure: return False, "Invalid height"
            if not self.height == (chain.blocks[self.parent_hash].height + 1):
                return False, "Invalid height"

            # Check that timestamp is non-decreasing [test_bad_timestamp]
            # On failure: return False, "Invalid timestamp"
            if not self.timestamp >= chain.blocks[self.parent_hash].timestamp:
                return False, "Invalid timestamp"

            # Check that seal is correctly computed and satisfies "target" requirements; use the provided is_valid_seal method [test_bad_seal]
            # On failure: return False, "Invalid seal"
            if not self.seal_is_valid():
                return False, "Invalid seal"

            # Check that all transactions within are valid (use tx.is_valid) [test_malformed_txs]
            # On failure: return False, "Malformed transaction included"
            for tx in self.transactions:
                if not tx.is_valid():
                    return False, "Malformed transaction included"

            # Check that for every transaction
            if not len(list(set(self.transactions))) == len(self.transactions):
                return False, "Double transaction inclusion"

            d_ir = {}
            t_hash = [t.hash for t in self.transactions]
            for tx in self.transactions:

                # the transaction has not already been included on a block on the same blockchain as this block [test_double_tx_inclusion_same_chain]
                # (or twice in this block; you will have to check this manually) [test_double_tx_inclusion_same_block]
                # (you may find chain.get_chain_ending_with and chain.blocks_containing_tx and util.nonempty_intersection useful)
                if tx.hash in chain.blocks_containing_tx:
                    for hash in chain.blocks_containing_tx[tx.hash]:
                        if hash in chain.get_chain_ending_with(
                                self.parent_hash) and not hash == self.hash:
                            return False, "Double transaction inclusion"

                # for every input ref in the tx
                sum_in = 0
                sum_out = 0
                op_sender = None
                for ir in tx.input_refs:

                    # (you may find the string split method for parsing the input into its components)
                    tx_hash, value = ir.split(":")
                    value = int(value)

                    # each input_ref is valid (aka corresponding transaction can be looked up in its holding transaction) [test_failed_input_lookup]
                    # (you may find chain.all_transactions useful here)
                    # On failure: return False, "Required output not found"
                    if not tx_hash in chain.all_transactions or value + 1 > len(
                            chain.all_transactions[tx_hash].outputs):
                        return False, "Required output not found"

                    # every input was sent to the same user (would normally carry a signature from this user; we leave this out for simplicity) [test_user_consistency]
                    # On failure: return False, "User inconsistencies"
                    if not op_sender:
                        op_sender = chain.all_transactions[tx_hash].outputs[
                            value].receiver
                    elif not op_sender == chain.all_transactions[
                            tx_hash].outputs[value].receiver:
                        return False, "User inconsistencies"

                    # no input_ref has been spent in a previous block on this chain [test_doublespent_input_same_chain]
                    # (or in this block; you will have to check this manually) [test_doublespent_input_same_block]
                    # (you may find nonempty_intersection and chain.blocks_spending_input helpful here)
                    # On failure: return False, "Double-spent input"
                    if ir in chain.blocks_spending_input and nonempty_intersection(
                            chain.blocks_spending_input[ir],
                            chain.get_chain_ending_with(
                                self.parent_hash)) or ir in d_ir:
                        return False, "Double-spent input"
                    d_ir[ir] = True

                    # each input_ref points to a transaction on the same blockchain as this block [test_input_txs_on_chain]
                    # (or in this block; you will have to check this manually) [test_input_txs_in_block]
                    # (you may find chain.blocks_containing_tx.get and nonempty_intersection as above helpful)
                    # On failure: return False, "Input transaction not found"
                    if not (tx_hash in t_hash or nonempty_intersection(
                            chain.get_chain_ending_with(self.parent_hash),
                            chain.blocks_containing_tx[tx_hash])):
                        return False, "Input transaction not found"

                    sum_in += chain.all_transactions[tx_hash].outputs[
                        value].amount

                # for every output in the tx
                for op in tx.outputs:

                    # every output was sent from the same user (would normally carry a signature from this user; we leave this out for simplicity)
                    # (this MUST be the same user as the outputs are locked to above) [test_user_consistency]
                    # On failure: return False, "User inconsistencies"
                    if not op.sender == op_sender:
                        return False, "User inconsistencies"

                    sum_out += op.amount

                # the sum of the input values is at least the sum of the output values (no money created out of thin air) [test_no_money_creation]
                # On failure: return False, "Creating money"
                if sum_in < sum_out:
                    return False, "Creating money"

        return True, "All checks passed"
Esempio n. 5
0
    def is_valid(self):
        """ Check whether block is fully valid according to block rules.

        Includes checking for no double spend, that all transactions are valid, that all header fields are correctly
        computed, etc.

        Returns:
            bool, str: True if block is valid, False otherwise plus an error or success message.
        """

        chain = blockchain.chain  # This object of type Blockchain may be useful

        # Placeholder for (1a)

        # (checks that apply to all blocks)
        # Check that Merkle root calculation is consistent with transactions in block (use the calculate_merkle_root function) [test_rejects_invalid_merkle]
        # On failure: return False, "Merkle root failed to match"
        if not self.merkle == self.calculate_merkle_root():
            return (False, "Merkle root failed to match")

        # Check that block.hash is correctly calculated [test_rejects_invalid_hash]
        # On failure: return False, "Hash failed to match"
        if not self.hash == self.calculate_hash():
            return (False, "Hash failed to match")

        # Check that there are at most 900 transactions in the block [test_rejects_too_many_txs]
        # On failure: return False, "Too many transactions"
        if len(self.transactions) > 900:
            return (False, "Too many transactions")

        # (checks that apply to genesis block)
        if self.is_genesis:
            # Check that height is 0 and parent_hash is "genesis" [test_invalid_genesis]
            # On failure: return False, "Invalid genesis"
            if self.height != 0 or self.parent_hash != "genesis":
                return (False, "Invalid genesis")

        # (checks that apply only to non-genesis blocks)
        if not self.is_genesis:
            # Check that parent exists (you may find chain.blocks helpful) [test_nonexistent_parent]
            # On failure: return False, "Nonexistent parent"
            if not (self.parent_hash in chain.blocks):
                return (False, "Nonexistent parent")

            # Check that height is correct w.r.t. parent height [test_bad_height]
            # On failure: return False, "Invalid height"
            parent = chain.blocks.get(self.parent_hash)
            if self.height != parent.height + 1:
                return (False, "Invalid height")

            # Check that timestamp is non-decreasing [test_bad_timestamp]
            # On failure: return False, "Invalid timestamp"
            if self.timestamp < parent.timestamp:
                return (False, "Invalid timestamp")

            # Check that seal is correctly computed and satisfies "target" requirements; use the provided is_valid_seal method [test_bad_seal]
            # On failure: return False, "Invalid seal"
            if not self.seal_is_valid():
                return (False, "Invalid seal")

            # Check that all transactions within are valid (use tx.is_valid) [test_malformed_txs]
            # On failure: return False, "Malformed transaction included"
            total_input_amount = 0
            for tx in self.transactions:
                if not tx.is_valid():
                    return (False, "Malformed transaction included")

            # Check that for every transaction
            # the transaction has not already been included on a block on the same blockchain as this block [test_double_tx_inclusion_same_chain]
            # (or twice in this block; you will have to check this manually) [test_double_tx_inclusion_same_block]
            # (you may find chain.get_chain_ending_with and chain.blocks_containing_tx and util.nonempty_intersection useful)
                if self.transactions.count(tx) > 1:
                    return (False, "Double transaction inclusion")
                for block2 in chain.get_chain_ending_with(self.parent_hash):
                    if nonempty_intersection(
                            self.transactions,
                            chain.blocks.get(block2).transactions):
                        return (False, "Double transaction inclusion")

                # for every input ref in the tx
                receiver = None
                for index, input_ref in enumerate(tx.input_refs):
                    # (you may find the string split method for parsing the input into its components)
                    (tx_id, input_loc) = input_ref.split(":")

                    # each input_ref is valid (aka corresponding transaction can be looked up in its holding transaction) [test_failed_input_lookup]
                    # (you may find chain.all_transactions useful here)
                    # On failure: return False, "Required output not found"
                    input_loc = int(input_loc)
                    found = False
                    input_tx = None
                    for tx2 in self.transactions:
                        if tx_id == tx2.hash:
                            found = True
                            input_tx = tx2.outputs[input_loc]
                    if len(chain.all_transactions) < input_loc and not found:
                        return (False, "Required output not found")
                    if tx_id not in chain.all_transactions and not found:
                        return (False, "Required output not found")

                    # every input was sent to the same user (would normally carry a signature from this user; we leave this out for simplicity) [test_user_consistency]
                    # On failure: return False, "User inconsistencies"
                    if not input_tx:
                        input_tx = chain.all_transactions.get(
                            tx_id).outputs[input_loc]
                    if receiver == None:
                        receiver = input_tx.receiver
                    elif receiver != input_tx.receiver:
                        return (False, "User inconsistencies")

                    # Check that there is no wrong users
                    for tx2 in tx.outputs:
                        if tx2.sender != receiver:
                            return (False, "User inconsistencies")

                    total_input_amount += input_tx.amount
                    # no input_ref has been spent in a previous block on this chain [test_doublespent_input_same_chain]
                    # (or in this block; you will have to check this manually) [test_doublespent_input_same_block]
                    # (you may find nonempty_intersection and chain.blocks_spending_input helpful here)
                    # On failure: return False, "Double-spent input"
                    block_aux = chain.blocks.get(self.parent_hash)
                    while not block_aux.is_genesis:
                        for tx2 in block_aux.transactions:
                            if input_ref in tx2.input_refs:
                                return (False, "Double-spent input")
                        block_aux = chain.blocks.get(block_aux.parent_hash)

                    count = 0
                    for tx2 in self.transactions:
                        for ir in tx2.input_refs:
                            if input_ref == ir:
                                count += 1
                            if count > 1:
                                return (False, "Double-spent input")

                    # each input_ref points to a transaction on the same blockchain as this block [test_input_txs_on_chain]
                    # (or in this block; you will have to check this manually) [test_input_txs_in_block]
                    # (you may find chain.blocks_containing_tx.get and nonempty_intersection as above helpful)
                    # On failure: return False, "Input transaction not found"
                    block_aux = chain.blocks.get(self.parent_hash)
                    input_found = False
                    while True:
                        for tx2 in block_aux.transactions:
                            if tx_id == tx2.hash:
                                input_found = True
                                break
                        if block_aux.is_genesis:
                            break
                        block_aux = chain.blocks.get(block_aux.parent_hash)

                    for tx2 in self.transactions:
                        if tx_id == tx2.hash:
                            input_found = True
                            break

                    if not input_found:
                        return (False, "Input transaction not found")

                # for every output in the tx
                sender = tx.outputs[0].sender
                total_output_amount = 0
                for output in tx.outputs:
                    # every output was sent from the same user (would normally carry a signature from this user; we leave this out for simplicity)
                    # (this MUST be the same user as the outputs are locked to above) [test_user_consistency]
                    # On failure: return False, "User inconsistencies"
                    total_output_amount += output.amount
                    if output.sender != sender:
                        return (False, "User inconsistencies")
                # the sum of the input values is at least the sum of the output values (no money created out of thin air) [test_no_money_creation]
                # On failure: return False, "Creating money"
                if total_output_amount > total_input_amount:
                    return (False, "Creating money")

        return True, "All checks passed"
Esempio n. 6
0
    def is_valid(self):
        """ Check whether block is fully valid according to block rules.

        Includes checking for no double spend, that all transactions are valid, that all header fields are correctly
        computed, etc.

        Returns:
            bool, str: True if block is valid, False otherwise plus an error or success message.
        """

        chain = blockchain.chain  # This object of type Blockchain may be useful

        # Placeholder for (1a)

        # (checks that apply to all blocks)
        # Check that Merkle root calculation is consistent with transactions in block (use the calculate_merkle_root function) [test_rejects_invalid_merkle]
        # On failure: return False, "Merkle root failed to match"
        if self.calculate_merkle_root() != self.merkle:
            return False, "Merkle root failed to match"
        # Check that block.hash is correctly calculated [test_rejects_invalid_hash]
        # On failure: return False, "Hash failed to match"
        if self.calculate_hash() != self.hash:
            return False, "Hash failed to match"
        # Check that there are at most 900 transactions in the block [test_rejects_too_many_txs]
        # On failure: return False, "Too many transactions"
        if len(self.transactions) > 900:
            return False, "Too many transactions"
        # (checks that apply to genesis block)
        # Check that height is 0 and parent_hash is "genesis" [test_invalid_genesis]
        # On failure: return False, "Invalid genesis"
        if self.is_genesis:
            if self.height != 0 or self.parent_hash != 'genesis' or self.hash != self.calculate_hash(
            ):
                return False, "Invalid genesis"
        # (checks that apply only to non-genesis blocks)
        if not self.is_genesis:
            # Check that parent exists (you may find chain.blocks helpful) [test_nonexistent_parent]
            # On failure: return False, "Nonexistent parent"
            if not self.parent_hash in chain.blocks.keys():
                return False, "Nonexistent parent"
            # Check that height is correct w.r.t. parent height [test_bad_height]
            # On failure: return False, "Invalid height"
            if self.height != chain.blocks[self.parent_hash].height + 1:
                return False, "Invalid height"
            # Check that timestamp is non-decreasing [test_bad_timestamp]
            # On failure: return False, "Invalid timestamp"
            if self.timestamp < chain.blocks[self.parent_hash].timestamp:
                return False, "Invalid timestamp"
            # Check that seal is correctly computed and satisfies "target" requirements; use the provided seal_is_valid method [test_bad_seal]
            # On failure: return False, "Invalid seal"
            if not self.seal_is_valid():
                return False, "Invalid seal"
            # Check that all transactions within are valid (use tx.is_valid) [test_malformed_txs]
            # On failure: return False, "Malformed transaction included"
            for transaction in self.transactions:
                if not transaction.is_valid():
                    return False, "Malformed transaction included"
            # Check that for every transaction
            txs = {}
            inputs_spent = []
            for transaction in self.transactions:
                txid = None
                # the transaction has not already been included on a block on the same blockchain as this block [test_double_tx_inclusion_same_chain]
                # (or twice in this block; you will have to check this manually) [test_double_tx_inclusion_same_block]
                # (you may find chain.get_chain_ending_with and chain.blocks_containing_tx and util.nonempty_intersection useful)
                # On failure: return False, "Double transaction inclusion"

                if transaction.hash in txs or nonempty_intersection(
                        chain.get_chain_ending_with(self.parent_hash),
                        chain.blocks_containing_tx.get(transaction.hash, [])):
                    return False, "Double transaction inclusion"

                # for every input ref in the tx
                for input_ref in transaction.input_refs:
                    input_tx, output_tx = input_ref.split(":")
                    output_tx = int(output_tx)
                    # (you may find the string split method for parsing the input into its components)

                    # each input_ref is valid (aka corresponding transaction can be looked up in its holding transaction) [test_failed_input_lookup]
                    # (you may find chain.all_transactions useful here)
                    # On failure: return False, "Required output not found"
                    if input_tx in txs:
                        target = txs[input_tx]
                    elif input_tx in chain.all_transactions:
                        target = chain.all_transactions[input_tx]
                    else:
                        return False, "Required output not found"

                    if output_tx + 1 > len(target.outputs):
                        return False, "Required output not found"

                    # every input was sent to the same user (would normally carry a signature from this user; we leave this out for simplicity) [test_user_consistency]
                    # On failure: return False, "User inconsistencies"
                    outputs = target.outputs[output_tx]
                    total_in = 0
                    total_in += outputs.amount
                    if txid == None:
                        txid = outputs.receiver
                    else:
                        if outputs.receiver != txid:
                            return False, "User inconsistencies"
                    # no input_ref has been spent in a previous block on this chain [test_doublespent_input_same_chain]
                    # (or in this block; you will have to check this manually) [test_doublespent_input_same_block]
                    # (you may find nonempty_intersection and chain.blocks_spending_input helpful here)
                    # On failure: return False, "Double-spent input"
                    if input_ref in inputs_spent or nonempty_intersection(
                            chain.get_chain_ending_with(self.parent_hash),
                            chain.blocks_spending_input.get(input_ref, [])):
                        return False, "Double-spent input"

                    # each input_ref points to a transaction on the same blockchain as this block [test_input_txs_on_chain]
                    # (or in this block; you will have to check this manually) [test_input_txs]
                    # (you may find chain.blocks_containing_tx.get and nonempty_intersection as above helpful)
                    # On failure: return False, "Input transaction not found"
                    if input_tx in txs or nonempty_intersection(
                            chain.get_chain_ending_with(self.parent_hash),
                            chain.blocks_containing_tx.get(input_tx, [])):
                        inputs_spent.append(input_ref)
                        continue
                    else:
                        return False, "Input transaction not found"
                # for every output in the tx
                total_out = 0
                for output in transaction.outputs:
                    # every output was sent from the same user (would normally carry a signature from this user; we leave this out for simplicity)
                    # (this MUST be the same user as the outputs are locked to above) [test_user_consistency]
                    # On failure: return False, "User inconsistencies"
                    if (output.sender != txid):
                        return False, "User inconsistencies"
                    total_out += output.amount
                # the sum of the input values is at least the sum of the output values (no money created out of thin air) [test_no_money_creation]
                # On failure: return False, "Creating money"
                if total_out > total_in:
                    return False, "Creating money"
                txs[transaction.hash] = transaction

        return True, "All checks passed"
Esempio n. 7
0
    def is_valid(self):
        """ Check whether block is fully valid according to block rules.

        Includes checking for no double spend, that all transactions are valid, that all header fields are correctly
        computed, etc.

        Returns:
            bool, str: True if block is valid, False otherwise plus an error or success message.
        """

        chain = blockchain.chaindb.chain  # This object of type Blockchain may be useful

        # Solution for (1a)

        # (checks that apply to all blocks)
        # Check that Merkle root calculation is consistent with transactions in block (use the calculate_merkle_root function) [test_rejects_invalid_merkle]
        if not (self.merkle == self.calculate_merkle_root()):
            return False, "Merkle root failed to match"
        # Check that block.hash is correctly calculated [test_rejects_invalid_hash]
        if not (self.hash == self.calculate_hash()):
            return False, "Hash failed to match"
        # Check that there are at most 900 transactions in the block [test_rejects_too_many_txs]
        if len(self.transactions) > 900:
            return False, "Too many transactions"

        # (checks that apply to genesis block)
        if self.is_genesis:
            # Check that height is 0 and parent_hash is "genesis" [test_invalid_genesis]
            if not (self.height == 0):
                return False, "Invalid genesis"
            if not (self.parent_hash == "genesis"):
                return False, "Invalid genesis"

        # (checks that apply only to non-genesis blocks)
        if not self.is_genesis:
            # Check that parent exists [test_nonexistent_parent]
            if not self.parent_hash in chain.blocks:
                return False, "Nonexistent parent"
            parent_block = chain.blocks[self.parent_hash]
            # Check that height is correct w.r.t. parent height [test_bad_height]
            if not (self.height == parent_block.height + 1):
                return False, "Invalid height"
            # Check that timestamp is non-decreasing [test_bad_timestamp]
            if self.timestamp < parent_block.timestamp:
                return False, "Invalid timestamp"
            # Check that seal is correctly computed and satisfies "target" requirements [test_bad_seal]
            if not self.seal_is_valid():
                return False, "Invalid seal"
            # Check that all transactions within are valid (use tx.is_valid) [test_malformed_txs]
            for tx in self.transactions:
                if not tx.is_valid():
                    return False, "Malformed transaction included"

            # Check that for every transaction
            txs_in_block = {}
            inputs_spent_in_block = []
            blocks_in_chain = chain.get_chain_ending_with(self.parent_hash)
            for tx in self.transactions:
                user_transacting = None
                # the transaction has not already been included on a block on the same blockchain as this block [test_double_tx_inclusion_same_chain]
                if nonempty_intersection(
                        blocks_in_chain,
                        chain.blocks_containing_tx.get(tx.hash, [])):
                    return False, "Double transaction inclusion"
                # (or twice in this block; you will have to check this manually) [test_double_tx_inclusion_same_block]
                if tx.hash in txs_in_block:
                    return False, "Double transaction inclusion"
                # for every input ref in the tx
                total_amount_input = 0
                for input_ref in tx.input_refs:
                    input_tx_hash = input_ref.split(":")[0]
                    input_index = int(input_ref.split(":")[1])

                    # each input_ref is valid (aka can be looked up in its holding transaction) [test_failed_input_lookup]
                    if input_tx_hash in txs_in_block:
                        candidate_tx = txs_in_block[input_tx_hash]
                    elif input_tx_hash in chain.all_transactions:
                        candidate_tx = chain.all_transactions[input_tx_hash]
                    else:
                        return False, "Required output not found"
                    if not input_index < len(candidate_tx.outputs):
                        return False, "Required output not found"
                    output_for_input = candidate_tx.outputs[input_index]
                    total_amount_input += output_for_input.amount

                    # every input was sent to the same user (would normally carry a signature from this user; we leave this out for simplicity) [test_user_consistency]
                    if user_transacting == None:
                        user_transacting = output_for_input.receiver
                    else:
                        if not output_for_input.receiver == user_transacting:
                            return False, "User inconsistencies"

                    # no input_ref has been spent in a previous block on this chain [test_doublespent_input_same_chain]
                    if nonempty_intersection(
                            blocks_in_chain,
                            chain.blocks_spending_input.get(input_ref, [])):
                        return False, "Double-spent input"
                    # (or in this block; you will have to check this manually) [test_doublespent_input_same_block]
                    if input_ref in inputs_spent_in_block:
                        return False, "Double-spent input"
                    # each input_ref points to a transaction on the same blockchain as this block [test_input_txs_on_chain]
                    if nonempty_intersection(
                            blocks_in_chain,
                            chain.blocks_containing_tx.get(input_tx_hash, [])):
                        inputs_spent_in_block.append(input_ref)
                        continue
                    # (or in this block; you will have to check this manually) [test_input_txs_in_block]
                    if input_tx_hash in txs_in_block:
                        inputs_spent_in_block.append(input_ref)
                        continue
                    return False, "Input transaction not found"

                total_amount_output = 0
                for output in tx.outputs:
                    # every output was sent from the same user (would normally carry a signature from this user; we leave this out for simplicity)
                    # (this MUST be the same user as the outputs are locked to above) [test_user_consistency]
                    if (output.sender != user_transacting):
                        return False, "User inconsistencies"
                    total_amount_output += output.amount
                # the sum of the input values is at least the sum of the output values (no money created out of thin air) [test_no_money_creation]
                if total_amount_output > total_amount_input:
                    return False, "Creating money"
                txs_in_block[tx.hash] = tx
        return True, "All checks passed"

        # Placeholder for (1a)
        return True, "All checks passed"
Esempio n. 8
0
    def is_valid(self):
        """ Check whether block is fully valid according to block rules.

        Includes checking for no double spend, that all transactions are valid, that all header fields are correctly
        computed, etc.

        Returns:
            bool, str: True if block is valid, False otherwise plus an error or success message.
        """

        chain = blockchain.chain  # This object of type Blockchain may be useful

        # Placeholder for (1a)

        # (checks that apply to all blocks)
        # Check that Merkle root calculation is consistent with transactions in block (use the calculate_merkle_root function) [test_rejects_invalid_merkle]
        # On failure: return False, "Merkle root failed to match"
        if self.calculate_merkle_root() != self.merkle:
            return False, "Merkle root failed to match"

        # Check that block.hash is correctly calculated [test_rejects_invalid_hash]
        # On failure: return False, "Hash failed to match"
        if self.hash != self.calculate_hash():
            return False, "Hash failed to match"

        # Check that there are at most 900 transactions in the block [test_rejects_too_many_txs]
        # On failure: return False, "Too many transactions"

        if len(self.transactions) > 900:
            return False, "Too many transactions"

        # (checks that apply to genesis block)
        # Check that height is 0 and parent_hash is "genesis" [test_invalid_genesis]
        # On failure: return False, "Invalid genesis"
        if self.is_genesis:
            if self.height != 0 or self.parent_hash != "genesis":
                return False, "Invalid genesis"

        # (checks that apply only to non-genesis blocks)
        else:
            # Check that parent exists (you may find chain.blocks helpful) [test_nonexistent_parent]
            # On failure: return False, "Nonexistent parent"
            if self.parent_hash not in chain.blocks:
                return False, "Nonexistent parent"

            # Check that height is correct w.r.t. parent height [test_bad_height]
            # On failure: return False, "Invalid height"

            if self.height != chain.blocks[self.parent_hash].height + 1:
                return False, "Invalid height"

            # Check that timestamp is non-decreasing [test_bad_timestamp]
            # On failure: return False, "Invalid timestamp"
            if self.timestamp < chain.blocks[self.parent_hash].timestamp:
                return False, "Invalid timestamp"

            # Check that seal is correctly computed and satisfies "target" requirements; use the provided seal_is_valid method [test_bad_seal]
            # On failure: return False, "Invalid seal"
            if not self.seal_is_valid():
                return False, "Invalid seal"

            # Check that all transactions within are valid (use tx.is_valid) [test_malformed_txs]
            # On failure: return False, "Malformed transaction included"
            for each_trans in self.transactions:
                if not each_trans.is_valid():
                    return False, "Malformed transaction included"

            # Check that for every transaction
            # the transaction has not already been included on a block on the same blockchain as this block [test_double_tx_inclusion_same_chain]
            # (or twice in this block; you will have to check this manually) [test_double_tx_inclusion_same_block]
            # (you may find chain.get_chain_ending_with and chain.blocks_containing_tx and util.nonempty_intersection useful)
            # On failure: return False, "Double transaction inclusion"
            trans_hash_list = []
            ref_list = []
            for each_trans in self.transactions:
                if each_trans.hash in chain.blocks_containing_tx:
                    if nonempty_intersection(
                            chain.blocks_containing_tx[each_trans.hash],
                            chain.get_chain_ending_with(self.parent_hash),
                    ):
                        return False, "Double transaction inclusion"

                if each_trans.hash in trans_hash_list:
                    return False, "Double transaction inclusion"
                trans_hash_list.append(each_trans.hash)

            # for every input ref in the tx
            # (you may find the string split method for parsing the input into its components)
            all_hash = []
            for each in self.transactions:
                all_hash.append(each.hash)

            for each_trans in self.transactions:

                flag = 0
                same_user = None
                inMoney = 0
                outMoney = 0
                for each_ref in each_trans.input_refs:
                    # each input_ref is valid (aka corresponding transaction can be looked up in its holding transaction) [test_failed_input_lookup]
                    # (you may find chain.all_transactions useful here)
                    # On failure: return False, "Required output not found"
                    ref_hash, ref_ind = each_ref.split(":")
                    temp_hash = None

                    for ele in self.transactions:
                        if ele.hash == ref_hash:
                            temp_hash = ele

                    if ref_hash not in all_hash:
                        if ref_hash not in chain.all_transactions:
                            return False, "Required output not found"
                        temp_hash = chain.all_transactions[ref_hash]

                    try:
                        flag = temp_hash.outputs[int(ref_ind)]
                    except:
                        return False, "Required output not found"

                    # every input was sent to the same user (would normally carry a signature from this user; we leave this out for simplicity) [test_user_consistency]
                    # On failure: return False, "User inconsistencies"

                    if same_user == None:
                        same_user = temp_hash.outputs[int(ref_ind)].receiver
                    elif same_user != temp_hash.outputs[int(ref_ind)].receiver:
                        return False, "User inconsistencies"

                    # no input_ref has been spent in a previous block on this chain [test_doublespent_input_same_chain]
                    # (or in this block; you will have to check this manually) [test_doublespent_input_same_block]
                    # (you may find nonempty_intersection and chain.blocks_spending_input helpful here)
                    # On failure: return False, "Double-spent input"
                    if ref_hash not in ref_list:
                        ref_list.append(ref_hash)
                    else:
                        return False, "Double-spent input"

                    if each_ref in chain.blocks_spending_input:
                        if nonempty_intersection(
                                chain.blocks_spending_input[each_ref],
                                chain.get_chain_ending_with(self.parent_hash),
                        ):
                            return False, "Double-spent input"

                    # each input_ref points to a transaction on the same blockchain as this block [test_input_txs_on_chain]
                    # (or in this block; you will have to check this manually) [test_input_txs_in_block]
                    # (you may find chain.blocks_containing_tx.get and nonempty_intersection as above helpful)
                    # On failure: return False, "Input transaction not found"
                    if ref_hash in chain.blocks_containing_tx:
                        if ref_hash not in all_hash and not nonempty_intersection(
                                chain.blocks_containing_tx[ref_hash],
                                chain.get_chain_ending_with(self.parent_hash),
                        ):
                            return False, "Input transaction not found"

                    # every output was sent from the same user (would normally carry a signature from this user; we leave this out for simplicity)
                    # (this MUST be the same user as the outputs are locked to above) [test_user_consistency]
                    # On failure: return False, "User inconsistencies"
                    for each_output in each_trans.outputs:
                        if same_user != each_output.sender:
                            return False, "User inconsistencies"
                        outMoney = outMoney + each_output.amount

                    # the sum of the input values is at least the sum of the output values (no money created out of thin air) [test_no_money_creation]
                    # On failure: return False, "Creating money"
                    inMoney = inMoney + temp_hash.outputs[int(ref_ind)].amount
                    if outMoney > inMoney:
                        return False, "Creating money"

        return True, "All checks passed"