Exemplo n.º 1
0
    def validate_chain(self, chain=''):
        '''
        Checks the chain for validity. Returns True on validation.
        '''
        num_of_indexes_at_0 = 0

        if not chain:
            chain = self.chainfile

        with open(chain, 'r') as f:
            for line in f:
                #print("VALIDATION OF NEXT BLOCK : ")
                #print()
                block_to_validate = json.loads(line)

                number_of_zeros = block_to_validate['num_zeros']
                nonce = block_to_validate['nonce']
                index = block_to_validate['index']
                previous_hash = block_to_validate['previous_hash']
                block_hash = block_to_validate['hash']
                timestamp = block_to_validate['timestamp']
                block_data = block_to_validate['data']

                #print("Validation : ",block_to_validate['data'])
                x = Block(index, timestamp, block_data, previous_hash, nonce,
                          number_of_zeros)
                calculated_hash = x.hash_block()
                '''
                sha = hashlib.sha256()
                sha.update(
                    str(index).encode('utf-8')
                    + str(timestamp).encode('utf-8')
                    + str(block_data).encode('utf-8')
                    + str(previous_hash).encode('utf-8')
                    + str(number_of_zeros).encode('utf-8')
                    + str(nonce).encode('utf-8')
                )
                calculated_hash = sha.hexdigest()
                '''
                if index == 0:
                    num_of_indexes_at_0 += 1
                else:
                    if block_hash != calculated_hash:
                        # print(block_hash,"    ",calculated_hash)
                        msg = 'Invalid Chain. Message has been changed'
                        raise ValueError(msg)
                    if not _hash == previous_hash:
                        msg = 'Incorrect hashes. Broken chain.'
                        raise ValueError(msg)

                _hash = block_to_validate['hash']
                _hash_to_validate = self._return_hash(previous_hash, nonce)
                self._validate_hash(_hash_to_validate, number_of_zeros)

        if num_of_indexes_at_0 > 1:
            msg = 'Multiple genesis blocks.'
            raise ValueError(msg)

        return True
Exemplo n.º 2
0
    def test_block_updateBlockchain(self):
        nodeA_chains = []  # has two blocks
        nodeB_chains = []  # has three blocks

        genesis_block = Block.create_genesis_block()
        second_block = Block.create_next_block(genesis_block)
        third_block = Block.create_next_block(second_block)

        genesis_block_dict = {
            "index": str(genesis_block.index),
            "timestamp": str(genesis_block.timestamp),
            "data": genesis_block.data,
            "hash": str(genesis_block.hash)
        }

        second_block_dict = {
            "index": str(second_block.index),
            "timestamp": str(second_block.timestamp),
            "data": second_block.data,
            "hash": str(second_block.hash)
        }

        third_block_dict = {
            "index": str(third_block.index),
            "timestamp": str(third_block.timestamp),
            "data": third_block.data,
            "hash": str(third_block.hash)
        }

        nodeA_chains.extend((genesis_block_dict, second_block_dict))

        nodeB_chains.extend(
            (genesis_block_dict, second_block_dict, third_block_dict))

        test_my_block = [genesis_block, second_block]
        test_peer_block = nodeB_chains
        test2_my_block = [genesis_block, second_block, third_block]
        test2_peer_block = nodeA_chains

        ret_chain = test2_my_block  # expected return from update_blockchain

        # assertion tests
        self.assertTrue(Test_compare.comp_list_of_block_obj( \
                self.block_helper._update_blockchain(test_my_block, test_peer_block), \
                ret_chain))

        self.assertTrue(Test_compare.comp_list_of_block_obj( \
                self.block_helper._update_blockchain(test2_my_block, test2_peer_block), \
                ret_chain))

        self.assertTrue(Test_compare.comp_list_of_block_obj( \
                self.block_helper._update_blockchain(test_peer_block, test_my_block, auto_update=True), \
                test_my_block))
    def _create_genesis_block(self):
        '''
        Creates the genesis block. Seperate routine due to the genesis block
            creation being a one-off event.
        '''
        b = Block(index=0,
            timestamp=str(datetime.datetime.now()),
            data='genesis block',
            previous_hash='0',
            nonce=1,
            num_zeros=0)

        self._write_to_chain(b.get_block_data())
        return
Exemplo n.º 4
0
    def test_syncBlocksHandler(self):
        # test data
        genesis_block = Block.create_genesis_block()
        second_block = Block.create_next_block(genesis_block)
        third_block = Block.create_next_block(second_block)

        mock_blockchain = [genesis_block, second_block, third_block]

        with patch("server.Server.block_helper.consensus", return_value=mock_blockchain), \
             patch("server.Server.blockchain", []) as mock_bc:

            # test method call
            Server.sync_blocks_handler()

            self.assertEqual(mock_bc, mock_blockchain)
Exemplo n.º 5
0
    def test_block_createBlock(self):
        with patch("resources.block.datetime") as mock_datetime:
            # test data
            mock_datetime.datetime.now.return_value = "NOW"
            genesis_block = Block.create_genesis_block()

            expected_result = Block(genesis_block.index + 1,
                                    "NOW",
                                    genesis_block.data,
                                    prev_hash=genesis_block.hash)

            # test
            test_result = self.block_helper.create_block(
                genesis_block.index + 1, "NOW", genesis_block.data,
                genesis_block.hash)

            boo_true = Test_compare.comp_list_of_block_obj([test_result],
                                                           [expected_result])
            self.assertTrue(boo_true)
Exemplo n.º 6
0
    def test_block_findOtherChains(self):

        test_peer_nodes = ['192.168.1.86:5000', '192.168.1.87:5000']

        test_get_ret_chain = []  # has two blocks

        genesis_block = Block.create_genesis_block()

        genesis_block_dict = {
            "index": str(genesis_block.index),
            "timestamp": str(genesis_block.timestamp),
            "data": str(genesis_block.data),
            "hash": genesis_block.hash
        }

        # need to create test dictionary data of the block object
        test_get_ret_chain.append(genesis_block_dict)

        second_block = Block.create_next_block(genesis_block)

        second_block_dict = {
            "index": str(second_block.index),
            "timestamp": str(second_block.timestamp),
            "data": str(second_block.data),
            "hash": second_block.hash
        }

        test_get_ret_chain.append(second_block_dict)

        test_get_ret_chain = json.dumps(test_get_ret_chain)

        chains = [
            json.loads(test_get_ret_chain),
            json.loads(test_get_ret_chain)
        ]  # technically using our previous dictionaries would work

        with patch('requests.get') as mock_get:
            mock_get.return_value.status_code = 200
            mock_get.return_value.content = test_get_ret_chain

            self.assertEqual(
                self.block_helper._find_other_chains(test_peer_nodes), chains)
Exemplo n.º 7
0
    def create_initial_block():
        b = Block(index=0, timestamp=str(datetime.datetime.now()),
            data='genesis block',
            previous_hash='0', nonce=1)

        return {'index':b.index,
            'timestamp':b.timestamp,
            'data':b.data,
            'nonce':b.nonce,
            'previous_hash':b.previous_hash,
            'hash':b.hash}
Exemplo n.º 8
0
    def test_block_createGenBlock(self):
        with patch("resources.block.datetime") as mock_datetime:
            # test data
            mock_datetime.datetime.now.return_value = "NOW"
            expected_result = Block.create_genesis_block()

            test_result = self.block_helper.create_gen_block()

            # test
            boo_true = Test_compare.comp_list_of_block_obj([test_result],
                                                           [expected_result])
            self.assertTrue(boo_true)
def mine():
    """Performs work. Becomes swoll. Miner gets rewarded.

    Raises
        ValueError : when `mine()` is called on an empty `blockchain`
    """
    MINER_REWARD = 1
    global this_nodes_transactions

    # verifies non-empty blockchain
    if not blockchain:
        msg = "Empty blockchain."
        raise ValueError(msg)
    # if not this_nodes_transactions:
    #     msg = "Empty transaction list."
    #     raise ValueError(msg)

    last_block = blockchain[len(blockchain) - 1]
    # perform proof of work function
    _previous_hash = last_block['hash']
    _nonce = proof_of_work(_previous_hash)
    # reward miner
    this_nodes_transactions.append({
        'from': 'network',
        'to': miner_address,
        'amount': MINER_REWARD
    })
    # generate new block's data, empty local transaction list
    _data = {'transactions': this_nodes_transactions}
    _index = int(last_block['index']) + 1
    _timestamp = str(datetime.datetime.now())
    mined_block = Block(index=_index,
                        timestamp=_timestamp,
                        data=_data,
                        previous_hash=_previous_hash,
                        nonce=_nonce)
    this_nodes_transactions = []

    mined_block_data = {
        'index': mined_block.index,
        'timestamp': mined_block.timestamp,
        'data': mined_block.data,
        'nonce': mined_block.nonce,
        'previous_hash': mined_block.previous_hash,
        'hash': mined_block.hash
    }
    blockchain.append(mined_block_data)

    # inform client of mining's completion
    mined = json.dumps(mined_block_data)
    print(mined + '\n')
    return mined
Exemplo n.º 10
0
    def create_new_block(self):
        '''
        Creates a block using the data in `self.data`.
        '''
        with open(self.chainfile, 'r') as f:
            previous_block = f.readlines()[-1]
            previous_block = json.loads(previous_block)
            f.close()

        index = previous_block['index'] + 1
        previous_hash = previous_block['hash']
        timestamp = str(datetime.datetime.now())
        nonce, number_of_leading_zeros = proof_of_work(previous_hash)
        self.block = Block(index=index,
                           timestamp=timestamp,
                           data=self.data,
                           previous_hash=previous_hash,
                           nonce=nonce,
                           num_zeros=number_of_leading_zeros)

        self._write_to_chain(self.block.get_block_data())
        self.data = " "
        return
Exemplo n.º 11
0
    def test_getBlocksHandler(self):
        # test data
        genesis_block = Block.create_genesis_block()

        genesis_block_dict = {
            "index": genesis_block.index,
            "timestamp": genesis_block.timestamp,
            "data": genesis_block.data,
            "hash": genesis_block.hash
        }

        mock_blockchain = [genesis_block]

        expected_result = json.dumps([genesis_block_dict])

        with patch("server.Server.blockchain", mock_blockchain):

            # test method call
            test_call_ret = Server.get_blocks_handler

            # comp_list_of_nodes will also work here
            self.assertEqual(json.loads(test_call_ret()),
                             json.loads(expected_result))
Exemplo n.º 12
0
class Blockchain:

    def __init__(self):
        # path to chain
        dir_path = os.path.dirname(os.path.realpath(__file__))
        self.chainfile = os.path.join(dir_path, 'chain', CHAIN_NAME)

        self._create_chain_if_not_exists()
        # create genesis block if chainfile is empty
        if os.stat(self.chainfile).st_size == 0:
            self._create_genesis_block()

        self.validate_chain()
        self.data = []


    def _create_chain_if_not_exists(self):
        if not os.path.isfile(self.chainfile):
            f = open(self.chainfile,'w')
            f.close()
        return


    def _create_genesis_block(self):
        '''
        Creates the genesis block. Seperate routine due to the genesis block
            creation being a one-off event.
        '''
        b = Block(index=0,
            timestamp=str(datetime.datetime.now()),
            data='genesis block',
            previous_hash='0',
            nonce=1,
            num_zeros=0)

        self._write_to_chain(b.get_block_data())
        return


    def _write_to_chain(self, block_dictionary):
        '''
        Writes a dictionary to json, appends the json to the blockchain text
            file.
        '''
        with open(self.chainfile, 'a') as f:
            f.write(json.dumps(block_dictionary) + '\n')
            f.close()
        return


    def create_new_block(self):
        '''
        Creates a block using the data in `self.data`.
        '''
        with open(self.chainfile, 'r') as f:
            previous_block = f.readlines()[-1]
            previous_block = json.loads(previous_block)
            f.close()

        index = previous_block['index'] + 1
        previous_hash = previous_block['hash']
        timestamp = str(datetime.datetime.now())
        nonce, number_of_leading_zeros = proof_of_work(previous_hash)

        self.block = Block(index=index,
            timestamp=timestamp,
            data=self.data,
            previous_hash=previous_hash,
            nonce=nonce,
            num_zeros=number_of_leading_zeros)

        self._write_to_chain(self.block.get_block_data())
        self.data = []
        return


    def add_data_to_block(self, new_data):
        '''
        Appends data to the newest block.
        '''
        self.data.append(str(new_data))


    def _return_hash(self, previous_hash, nonce):
        sha = hashlib.sha256()
        sha.update(
            str(previous_hash).encode('utf-8') +
            str(nonce).encode('utf-8')
            )
        return sha.hexdigest()


    def _validate_hash(self, _hash, num_zeros):
        if str(_hash[:num_zeros]) != "0" * num_zeros: # checks for leading zeros
            msg = 'Invalid chain.'
            raise ValueError(msg)
        else:
            return True


    def validate_chain(self, chain=''):
        '''
        Checks the chain for validity. Returns True on validation.
        '''
        num_of_indexes_at_0 = 0

        if not chain:
            chain = self.chainfile

        with open(chain, 'r') as f:
            for line in f:
                block_to_validate = json.loads(line)

                number_of_zeros = block_to_validate['num_zeros']
                nonce = block_to_validate['nonce']
                index = block_to_validate['index']
                previous_hash = block_to_validate['previous_hash']

                if index == 0:
                    num_of_indexes_at_0 += 1
                else:
                    if not _hash == previous_hash:
                        msg = 'Incorrect hashes. Broken chain.'
                        raise ValueError(msg)

                _hash = block_to_validate['hash']
                _hash_to_validate = self._return_hash(previous_hash, nonce)
                self._validate_hash(_hash_to_validate, number_of_zeros)

        if num_of_indexes_at_0 > 1:
            msg = 'Multiple genesis blocks.'
            raise ValueError(msg)

        return True
Exemplo n.º 13
0
    def test_block_consensus(self):
        test_peer_nodes = ['192.168.1.86:5000', '192.168.1.87:5000']
        ret = []
        nodeA_chains_dict = []  # has two blocks   format: [{dict}]
        nodeB_chains_dict = []  # has three blocks
        nodeC_chains_dict = [
        ]  # has one block    this is the same format returned from _find_other_chains

        genesis_block = Block.create_genesis_block()
        second_block = Block.create_next_block(genesis_block)
        third_block = Block.create_next_block(second_block)

        genesis_block_dict = {
            "index": str(genesis_block.index),
            "timestamp": str(genesis_block.timestamp),
            "data": genesis_block.data,
            "hash": str(genesis_block.hash)
        }

        second_block_dict = {
            "index": str(second_block.index),
            "timestamp": str(second_block.timestamp),
            "data": second_block.data,
            "hash": str(second_block.hash)
        }

        third_block_dict = {
            "index": str(third_block.index),
            "timestamp": str(third_block.timestamp),
            "data": third_block.data,
            "hash": str(third_block.hash)
        }

        nodeA_chains_dict.extend((genesis_block_dict, second_block_dict))

        nodeB_chains_dict.extend(
            (genesis_block_dict, second_block_dict, third_block_dict))

        nodeC_chains_dict.append(genesis_block_dict)

        ret.extend(
            (nodeA_chains_dict,
             nodeB_chains_dict))  # what is returned from _find_other_chains

        ret_chain = [genesis_block, second_block, third_block
                     ]  # expended returned chain output from consensus

        # need to create test data for when two coins are mined almost simoutaneously, in which case, we take the earlier stamped coin
        time_early = datetime.datetime.now()
        time_late = datetime.datetime.now()

        trans_network = {
            "timestamp": "NOW",
            "from": "network",
            "to": "random",
            "amount": 1
        }
        trans_no_network = {
            "timestamp": "NOW",
            "from": "random",
            "to": "random",
            "amount": 1
        }
        data_mine = {"proof-of-work": 36, "transactions": [trans_network]}
        data_not_mine = {
            "proof-of-work": 36,
            "transactions": [trans_no_network]
        }
        data_no_trans = {"proof-of-work": None, "transactions": None}

        # testing blocks
        block_early = {
            "index": 1,
            "timestamp": time_early,
            "data": dict(data_mine),
            "hash": "random-hash-bc-it-doesnt-matter-for-this-test"
        }
        block_late = {
            "index": 1,
            "timestamp": time_late,
            "data": dict(data_mine),
            "hash": "random-hash-bc-it-doesnt-matter-for-this-test"
        }

        block_early_obj = Block(block_early['index'],
                                block_early['timestamp'],
                                block_early['data'],
                                current_hash=block_late['hash'])

        ret2 = [[genesis_block_dict, block_early]]

        # tests for when my chain is either shorter or longer than peer's, in which we return the longest
        with patch(
                'resources.helper.Helper.Blockchain_helper._find_other_chains'
        ) as mock_find_other_chains:

            mock_find_other_chains.return_value = ret

            self.assertTrue(Test_compare.comp_list_of_block_obj( \
                    self.block_helper.consensus([genesis_block], test_peer_nodes), \
                    ret_chain))
            self.assertTrue(Test_compare.comp_list_of_block_obj( \
                    self.block_helper.consensus([genesis_block, second_block, third_block], test_peer_nodes), \
                    ret_chain))

        # tests when my chain is the same length, in which we take the earlier one, if both last blocks are mine blocks
        with patch(
                'resources.helper.Helper.Blockchain_helper._find_other_chains'
        ) as mock_find_other_chains:
            mock_find_other_chains.return_value = ret2

            test_result = self.block_helper.consensus(
                [genesis_block, block_late], test_peer_nodes)
            expected_result = [genesis_block, block_early_obj]

            boo_true = Test_compare.comp_list_of_block_obj(
                test_result, expected_result)

            self.assertTrue(boo_true)
Exemplo n.º 14
0
    def test_mineHandler(self):
        with patch("server.datetime") as mock_server_datetime,  \
             patch("resources.block.datetime") as mock_datetime, \
             patch("server.requests") as mock_requests:
            mock_requests.post.return_value = 1
            mock_datetime.datetime.now.return_value = 'NOW'
            mock_server_datetime.datetime.now.return_value = 'NOW'

            # test data
            # mock_server.miner_address = Server.miner_address

            host1 = "192.168.1.86:5000"
            host2 = "192.168.1.87:5000"

            trans1 = {
                "timestamp": str(mock_server_datetime.datetime.now()),
                "from": "asdf-random-public-key-asdf",
                "to": "qwer-random-public-key-qwer",
                "amount": 1
            }
            trans2 = {
                "timestamp": str(mock_server_datetime.datetime.now()),
                "from": "zxcv-random-public-key-zxcv",
                "to": "hjkl-random-public-key-hjkl",
                "amount": 3
            }

            data = {
                "proof-of-work": 18,
                "transactions": list([trans1, trans2])
            }

            genesis_block = Block.create_genesis_block()
            second_block = Block.create_next_block(genesis_block)
            third_block = Block(second_block.index + 1,
                                mock_server_datetime.datetime.now(),
                                data,
                                prev_hash=second_block.hash)

            mine_trans = {
                "timestamp": str(mock_server_datetime.datetime.now()),
                "from": "network",
                "to": Server.miner_address,
                "amount": 1
            }

            mined_data = {
                "proof-of-work": 36,
                "transactions": list([trans1, trans2, mine_trans])
            }

            mined_block = Block(third_block.index + 1,
                                mock_server_datetime.datetime.now(),
                                mined_data,
                                prev_hash=third_block.hash)

            expected_output = json.dumps({
                "index":
                mined_block.index,
                "timestamp":
                str(mined_block.timestamp),
                "data":
                mined_block.data,
                "hash":
                str(mined_block.hash)
            })

            with patch("server.Server.node_helper.consensus", return_value=[host1, host2]), \
                 patch("server.Server.block_helper.consensus", return_value=[genesis_block, second_block, third_block]), \
                 patch("server.Server.trans_helper.consensus", return_value=[trans1, trans2]), \
                 patch("server.Server.helper.proof_of_work", return_value=36), \
                 patch("server.Server.this_node_transactions", [trans1, trans2]) as mock_tnt, \
                 patch("server.Server.blockchain", []) as mock_bc, \
                 patch("server.Server.peer_nodes", []) as mock_pn:

                # test method call
                test_ret = Server.mine_handler()

                # test for node transactions (method sideeffect)
                # this tests the second sync function, usually will result in []
                # but this time mock sync returns [trans1, trans2]

                self.assertEqual(mock_tnt, [trans1, trans2])

                # test for block mined (method output)
                boo = Test_compare.comp_block_dict(json.loads(test_ret),
                                                   json.loads(expected_output))
                self.assertTrue(boo)

                # test for blockchain congruency (network effect)
                # NOTE: mined_block is not added here because of the second sync of mine method, and it is resuing the block consensus return
                boo = Test_compare.comp_list_of_block_obj(
                    mock_bc, [genesis_block, second_block, third_block])
                self.assertTrue(boo)

            # below is to test if the current chain is empty, genesis block must be created, and returned is the second (mined) block of chain
            with patch("server.Server.node_helper.consensus", return_value=[host1, host2]), \
                 patch("server.Server.block_helper.consensus", return_value=[]), \
                 patch("server.Server.trans_helper.consensus", return_value=[trans1, trans2]), \
                 patch("server.Server.helper.proof_of_work", return_value=36), \
                 patch("server.Server.this_node_transactions", data["transactions"]) as mock_tnt, \
                 patch("server.Server.blockchain", []) as mock_bc, \
                 patch("server.Server.peer_nodes", []) as mock_pn:
                mine_trans = {
                    "timestamp": str(mock_server_datetime.datetime.now()),
                    "from": "network",
                    "to": Server.miner_address,
                    "amount": 1
                }

                mined_data = {
                    "proof-of-work": 36,
                    "transactions": list([trans1, trans2, mine_trans])
                }

                mined_block = Block(genesis_block.index + 1,
                                    mock_server_datetime.datetime.now(),
                                    mined_data,
                                    prev_hash=genesis_block.hash)

                expected_output = json.dumps({
                    "index":
                    mined_block.index,
                    "timestamp":
                    str(mined_block.timestamp),
                    "data":
                    mined_block.data,
                    "hash":
                    str(mined_block.hash)
                })

                # test method call
                test_ret = Server.mine_handler()

                # test for block mined (method output)
                boo = Test_compare.comp_block_dict(json.loads(test_ret),
                                                   json.loads(expected_output))
                self.assertTrue(boo)
Exemplo n.º 15
0
    def test_updateList(self):
        # test data
        host1 = "192.168.1.86:5000"
        host2 = "192.168.1.87:5000"

        trans1 = {
            "timestamp": str(datetime.datetime.now()),
            "from": "asdf-random-public-key-asdf",
            "to": "qwer-random-public-key-qwer",
            "amount": 1
        }
        trans2 = {
            "timestamp": str(datetime.datetime.now()),
            "from": "zxcv-random-public-key-zxcv",
            "to": "hjkl-random-public-key-hjkl",
            "amount": 3
        }

        genesis_block = Block.create_genesis_block()
        block2 = Block.create_next_block(genesis_block)

        # test 1, ensure transaction
        with patch("server.Server.this_node_transactions", []) as mock_tnt, \
             patch("server.Server.trans_helper.ensure", return_value=[trans1, trans2]):

            Server._updateList(ensure_transactions=True, delete_data=None)
            self.assertEqual(mock_tnt, [trans1, trans2])

        # test 2, sync this node's transactions
        with patch("server.Server.this_node_transactions", []) as mock_tnt, \
             patch("server.Server.trans_helper.consensus", return_value=[trans1, trans2]):

            Server._updateList(node_transactions=True)
            self.assertEqual(mock_tnt, [trans1, trans2])

        # test 3, add transactions
        with patch("server.Server.this_node_transactions", []) as mock_tnt:

            Server._updateList(add_trans=True, trans=trans1)
            self.assertEqual(mock_tnt, [trans1])

        # test 4, sync this node's blockchain
        with patch("server.Server.blockchain", []) as mock_bc, \
             patch("server.Server.block_helper.consensus", return_value=[genesis_block, block2]):

            Server._updateList(blockchain=True)
            self.assertEqual(mock_bc, [genesis_block, block2])

        # test 5, sync this node's peer_nodes
        with patch("server.Server.peer_nodes", []) as mock_pn, \
             patch("server.Server.node_helper.consensus", return_value=[host1, host2]):

            Server._updateList(peer_nodes=True)
            self.assertEqual(mock_pn, [host1, host2])

        # test 6, sync this node's peer_nodes
        with patch("server.Server.peer_nodes", []) as mock_pn:

            Server._updateList(add_peer=True, peer=host1)
            self.assertEqual(mock_pn, [host1])
        pass