Example #1
0
class TestBlockChain(unittest.TestCase):
    chain = None
    db_name = 'blockchain_db'

    def setUp(self):
        test_util.print_testname(self._testMethodName)
        # BlockChain 을 만듬
        test_db = test_util.make_level_db(self.db_name)
        self.assertIsNotNone(test_db, "DB생성 불가")
        self.chain = BlockChain(test_db)

        test_util.print_testname(self._testMethodName)

    def tearDown(self):
        # Blockchain을 삭제
        leveldb.DestroyDB(self.db_name)

    def generate_test_block(self):
        """
        임시 블럭 생성하는 메소드
        :return: 임시 블럭
        """

        block = Block()
        for x in range(0, 10):
            tx = Transaction()
            hashed_value = tx.put_data("{args:[]}")
            self.assertNotEqual(hashed_value, "", "트랜잭션 생성 실패")
            self.assertTrue(block.put_transaction(tx), "Block에 트랜잭션 추가 실패")

        return block

    def test_genesis_block_by_key(self):
        """
        제네시스 블럭을 찾는다
        """
        # 키를 통하여 블럭을 찾는다
        last_block_hash = self.chain.last_block.block_hash
        logging.debug("LAST BLOCK : %s", last_block_hash)
        last_block = self.chain.find_block_by_hash(last_block_hash)
        self.assertIsNotNone(last_block, "제네시스 블럭을 가져올 수 없습니다.")

    def test_find_do_not_exist_block(self):
        """
        블럭체인에 없는 블럭을 찾는다
        """
        none_block_key = "bf5570f5a1810b7af78caf4bc70a660f0df51e42baf91d4de5b2328de0e83dfc"
        none_block = self.chain.find_block_by_hash(none_block_key)
        self.assertIsNot(none_block, "존재하지 않는 블럭이 출력되었습니다.")

    def test_find_block_by_height(self):
        # GIVEN
        size = 10
        find_block_index = int(size*random.random())
        find_block_height = 0
        find_block_hash = None
        for x in range(size):
            last_block = self.chain.last_block
            n_block = self.generate_test_block()
            n_block.generate_block(last_block)
            n_block.block_status = BlockStatus.confirmed
            if find_block_index == x:
                find_block_hash = n_block.block_hash
                find_block_height = n_block.height
            self.chain.add_block(n_block)

        logging.debug("find block hash : %s ", find_block_hash)
        logging.debug("find block height : %d ", find_block_height)

        # WHEN
        find_block_by_hash = self.chain.find_block_by_hash(find_block_hash)
        find_block_by_height = self.chain.find_block_by_height(find_block_height)

        # THEN
        self.assertEqual(find_block_by_hash.block_hash, find_block_by_height.block_hash)

    def test_add_some_block_and_find_by_key(self):
        """몇개의 블럭을 추가한 후 임의의 블럭을 찾는다
        """
        # GIVEN
        size = 10
        find_block_index = int(size*random.random())
        find_block_hash = None
        for x in range(size):
            last_block = self.chain.last_block
            n_block = self.generate_test_block()
            n_block.generate_block(last_block)
            n_block.block_status = BlockStatus.confirmed
            if find_block_index == x:
                find_block_hash = n_block.block_hash
            logging.debug("new block height : %i", n_block.height)
            self.chain.add_block(n_block)

        logging.debug("find block index : %i ", find_block_index)
        logging.debug("find block hash : %s ", find_block_hash)

        # WHEN
        find_block = self.chain.find_block_by_hash(find_block_hash)
        logging.debug("find block height : %i", find_block.height)

        # THEN
        self.assertEqual(find_block_hash, find_block.block_hash)

    def test_add_and_find_tx(self):
        """block db 에 block_hash - block_object 를 저장할때, tx_hash - tx_object 도 저장한다.
        get tx by tx_hash 시 해당 block 을 효율적으로 찾기 위해서
        """
        tx = self.__add_single_tx_to_block_return_tx_with_test()

        saved_tx = self.chain.find_tx_by_key(tx.get_tx_hash())
        logging.debug("saved_tx: " + str(saved_tx.get_tx_hash()))

        self.assertEqual(tx.get_tx_hash(), saved_tx.get_tx_hash(), "Fail Find Transaction")

    def test_add_and_verify_results(self):
        """invoke_result = "{"code" : "invoke_result_code" , "error_message": "message" }"

        """
        tx = self.__add_single_tx_to_block_return_tx_with_test()

        invoke_result = self.chain.find_invoke_result_by_tx_hash(tx.get_tx_hash())
        self.assertEqual(invoke_result['code'], message_code.Response.success)

    def __add_single_tx_to_block_return_tx_with_test(self):
        last_block = self.chain.last_block
        block = Block()
        tx = Transaction()
        hashed_value = tx.put_data("1234")
        self.assertNotEqual(hashed_value, "", "트랜잭션 생성 실패")
        self.assertTrue(block.put_transaction(tx), "Block에 트랜잭션 추가 실패")

        logging.debug("tx_hash: " + tx.get_tx_hash())

        block.generate_block(last_block)
        block.block_status = BlockStatus.confirmed
        # add_block include __add_tx_to_block_db what we want to test
        self.assertTrue(self.chain.add_block(block),
                        "Fail Add Block to BlockChain in test_add_tx_to_block_db")
        return tx

    def test_unicode_decode_error(self):
        """ Transaction hash 는 UTF-8 인코딩이나 block hash 값은 sha256 hex byte array 이므로 인코딩 에러가 발생함
        """

        last_block = self.chain.last_block
        unexpected_transaction = self.chain.find_tx_by_key(last_block.block_hash)
        self.assertIsNone(unexpected_transaction, "unexpected_transaction is not None")

    def test_blockchain_is_singleton(self):
        x = BlockChain(test_util.make_level_db())
        y = BlockChain(test_util.make_level_db())

        self.assertTrue((x is y))
Example #2
0
class TestBlockChain(unittest.TestCase):
    chain = None
    db_name = 'blockchain_db'
    __peer_id = 'aaa'

    def setUp(self):
        test_util.print_testname(self._testMethodName)
        self.peer_auth = test_util.create_default_peer_auth()

        set_mock(self)
        # BlockChain 을 만듬
        test_db = test_util.make_level_db(self.db_name)
        self.assertIsNotNone(test_db, "DB생성 불가")
        self.chain = BlockChain(test_db)

    def tearDown(self):
        # Blockchain을 삭제
        ObjectManager().peer_service = None
        leveldb.DestroyDB(self.db_name)
        os.system("rm -rf ./blockchain_db*")

    def generate_test_block(self):
        """
        임시 블럭 생성하는 메소드
        :return: 임시 블럭
        """

        block = Block(channel_name=conf.LOOPCHAIN_DEFAULT_CHANNEL)
        for x in range(0, 10):
            tx = test_util.create_basic_tx(self.__peer_id, self.peer_auth)
            self.assertNotEqual(tx.tx_hash, "", "트랜잭션 생성 실패")
            self.assertTrue(block.put_transaction(tx), "Block에 트랜잭션 추가 실패")

        return block

    def test_genesis_block_by_key(self):
        """
        제네시스 블럭을 찾는다
        """
        # 키를 통하여 블럭을 찾는다
        block = test_util.add_genesis_block()
        self.chain.add_block(block)

        last_block_hash = self.chain.last_block.block_hash
        logging.debug("LAST BLOCK : %s", last_block_hash)
        last_block = self.chain.find_block_by_hash(last_block_hash)
        self.assertIsNotNone(last_block, "제네시스 블럭을 가져올 수 없습니다.")

    def test_find_do_not_exist_block(self):
        """
        블럭체인에 없는 블럭을 찾는다
        """
        none_block_key = "bf5570f5a1810b7af78caf4bc70a660f0df51e42baf91d4de5b2328de0e83dfc"
        none_block = self.chain.find_block_by_hash(none_block_key)
        self.assertIsNot(none_block, "존재하지 않는 블럭이 출력되었습니다.")

    @unittest.skip
    def test_nonce(self):
        """test get, verify, set nonce

        :return:
        """
        # GIVEN
        new_nonce = self.chain.get_new_nonce_by_address("ABC")
        util.logger.spam(f"test_block_chain:test_nonce new_nonce({new_nonce})")

        # WHEN
        verify_result = self.chain.verify_nonce_by_address("ABC", new_nonce)
        util.logger.spam(f"test_block_chain:test_nonce verify_result({verify_result})")
        self.assertTrue(verify_result)
        set_result = self.chain._BlockChain__set_nonce_by_address("ABC", new_nonce)
        self.assertTrue(set_result)

        # THEN
        next_new_nonce = self.chain.get_new_nonce_by_address("ABC")
        util.logger.spam(f"test_block_chain:test_nonce new_nonce({next_new_nonce})")
        self.assertEqual(hex(int(new_nonce, 16) + 1), next_new_nonce)

    def test_tx_list_by_address(self):
        """test add tx_hash to tx_list by address

        :return:
        """
        # GIVEN
        for i in range(201):
            self.chain.add_tx_to_list_by_address("ABC", "112233_" + str(i))

        # WHEN
        current_tx_list, last_list_index = self.chain.get_tx_list_by_address("ABC")
        util.logger.spam(f"test_get_current_tx_list_by_address "
                         f"length of tx_list({len(current_tx_list)}) next_index({last_list_index})")

        oldest_tx_list, first_index = self.chain.get_tx_list_by_address("ABC", 1)
        util.logger.spam(f"test_get_oldest_tx_list_by_address "
                         f"length of tx_list({len(oldest_tx_list)}) next_index({first_index})")

        # THEN
        self.assertEqual(first_index, 0)
        self.assertEqual(last_list_index, 2)
        self.assertEqual(len(oldest_tx_list), conf.MAX_TX_LIST_SIZE_BY_ADDRESS + 1)

    def test_find_block_by_height(self):
        # GIVEN
        size = 10
        find_block_index = int(size*random.random())
        find_block_height = 0
        find_block_hash = None
        for x in range(size):
            last_block = self.chain.last_block
            n_block = self.generate_test_block()
            n_block.generate_block(last_block)
            n_block.block_status = BlockStatus.confirmed
            if find_block_index == x:
                find_block_hash = n_block.block_hash
                find_block_height = n_block.height
            self.chain.add_block(n_block)

        logging.debug("find block hash : %s ", find_block_hash)
        logging.debug("find block height : %d ", find_block_height)

        # WHEN
        find_block_by_hash = self.chain.find_block_by_hash(find_block_hash)
        find_block_by_height = self.chain.find_block_by_height(find_block_height)

        # THEN
        self.assertEqual(find_block_by_hash.block_hash, find_block_by_height.block_hash)

    def test_add_some_block_and_find_by_key(self):
        """몇개의 블럭을 추가한 후 임의의 블럭을 찾는다
        """
        # GIVEN
        size = 10
        find_block_index = int(size*random.random())
        find_block_hash = None
        for x in range(size):
            last_block = self.chain.last_block
            n_block = self.generate_test_block()
            n_block.generate_block(last_block)
            n_block.block_status = BlockStatus.confirmed
            if find_block_index == x:
                find_block_hash = n_block.block_hash
            logging.debug("new block height : %i", n_block.height)
            self.chain.add_block(n_block)

        logging.debug("find block index : %i ", find_block_index)
        logging.debug("find block hash : %s ", find_block_hash)

        # WHEN
        find_block = self.chain.find_block_by_hash(find_block_hash)
        logging.debug("find block height : %i", find_block.height)

        # THEN
        self.assertEqual(find_block_hash, find_block.block_hash)

    def test_add_and_find_tx(self):
        """block db 에 block_hash - block_object 를 저장할때, tx_hash - tx_object 도 저장한다.
        get tx by tx_hash 시 해당 block 을 효율적으로 찾기 위해서
        """
        tx = self.__add_single_tx_block_blockchain_return_tx()
        logging.debug("add tx hash : " + tx.tx_hash)

        saved_tx = self.chain.find_tx_by_key(tx.tx_hash)
        logging.debug("saved_tx: " + str(saved_tx.tx_hash))

        self.assertEqual(tx.tx_hash, saved_tx.tx_hash, "Fail Find Transaction")

    def test_add_and_verify_results(self):
        """invoke_result = "{"code" : "invoke_result_code" , "error_message": "message" }"

        """
        test_util.add_genesis_block()
        block = test_util.add_genesis_block()
        self.chain.add_block(block)

        tx = self.__add_single_tx_block_blockchain_return_tx()

        invoke_result = self.chain.find_invoke_result_by_tx_hash(tx.tx_hash)
        self.assertEqual(invoke_result['code'], ScoreResponse.SUCCESS)

    def __add_single_tx_block_blockchain_return_tx(self):
        last_block = self.chain.last_block
        block = Block(channel_name=conf.LOOPCHAIN_DEFAULT_CHANNEL)
        tx = test_util.create_basic_tx(self.__peer_id, self.peer_auth)
        block.put_transaction(tx)

        logging.debug("tx_hash: " + tx.tx_hash)

        block.generate_block(last_block)
        block.block_status = BlockStatus.confirmed

        # add_block to blockchain
        self.assertTrue(self.chain.add_block(block),
                        "Fail Add Block to BlockChain")
        return tx

    def test_unicode_decode_error(self):
        """ Transaction hash 는 UTF-8 인코딩이나 block hash 값은 sha256 hex byte array 이므로 인코딩 에러가 발생함
        """
        test_util.add_genesis_block()
        block = test_util.add_genesis_block()
        self.chain.add_block(block)

        last_block = self.chain.last_block
        unexpected_transaction = self.chain.find_tx_by_key(last_block.block_hash)
        self.assertIsNone(unexpected_transaction, "unexpected_transaction is not None")

    # blockchain is no more singleton. (for multi chain)
    @unittest.skip
    def test_blockchain_is_singleton(self):
        x = BlockChain(test_util.make_level_db())
        y = BlockChain(test_util.make_level_db())

        self.assertTrue((x is y))