コード例 #1
0
    def test_fork_recovery_rollbacked_already(self):
        # Switching to the new chain works, but test that if the _rollback() has already happened, _fork_recovery() does
        # not hiccup

        # Mock out irrelevant functions
        self.chain_manager._update_block_number_mapping = Mock()

        # Switching to the new chain should succeed!
        self.chain_manager.add_chain = Mock(return_value=True)
        self.chain_manager._rollback = Mock()

        block_1 = create_m_block(1, self.genesis_block, alice.address)
        block_2 = create_m_block(2, block_1, alice.address)

        block_1_alt = create_m_block(1, self.genesis_block, alice.address)
        block_2_alt = create_m_block(2, block_1_alt, alice.address)
        block_3_alt = create_m_block(3, block_2_alt, alice.address)

        fork_state = qrlstateinfo_pb2.ForkState(
            initiator_headerhash=block_3_alt.headerhash,
            fork_point_headerhash=self.genesis_block.headerhash,
            old_mainchain_hash_path=[b.headerhash for b in [block_1, block_2]],
            new_mainchain_hash_path=[
                b.headerhash for b in [block_1_alt, block_2_alt, block_3_alt]
            ])

        # State.get_block() should say that we are already on block_1_alt
        self.chain_manager._state.get_block.return_value = block_1_alt

        # _fork_recovery() will not call _rollback(), because it has already happened.
        self.chain_manager._fork_recovery(block_3_alt, fork_state)

        # _fork_recovery() should have _rollback()ed when trying to switch to the longer chain
        self.chain_manager._rollback.assert_not_called()
コード例 #2
0
ファイル: State.py プロジェクト: thomascherickal/QRL
 def get_fork_state(self) -> Optional[qrlstateinfo_pb2.ForkState]:
     try:
         data = self._db.get_raw(b'fork_state')
         fork_state = qrlstateinfo_pb2.ForkState()
         fork_state.ParseFromString(bytes(data))
         return fork_state
     except KeyError:
         return None
     except Exception as e:
         logger.error('Exception in get_fork_state')
         logger.exception(e)
         raise
コード例 #3
0
ファイル: test_State.py プロジェクト: zeta1999/QRL
    def test_fork_state(self):
        fork_state = qrlstateinfo_pb2.ForkState(
            initiator_headerhash=b'block2_right',
            fork_point_headerhash=b'block0_base_of_fork',
            old_mainchain_hash_path=[b'block1_right', b'block2_right'],
            new_mainchain_hash_path=[b'block1_left', b'block2_left'])
        self.assertIsNone(self.state.get_fork_state())

        self.state.put_fork_state(fork_state)
        self.assertEqual(fork_state, self.state.get_fork_state())

        self.state.delete_fork_state()
        self.assertIsNone(self.state.get_fork_state())
コード例 #4
0
ファイル: ChainManager.py プロジェクト: scottdonaldau/QRL
    def _try_branch_add_block(self,
                              block,
                              batch,
                              check_stale=True) -> (bool, bool):
        """
        This function returns list of bool types. The first bool represent
        if the block has been added successfully and the second bool
        represent the fork_flag, which becomes true when a block triggered
        into fork recovery.
        :param block:
        :param batch:
        :return: [Added successfully, fork_flag]
        """
        if self._last_block.headerhash == block.prev_headerhash:
            if not self._apply_block(block, batch):
                return False, False

        self._state.put_block(block, batch)

        last_block_metadata = self._state.get_block_metadata(
            self._last_block.headerhash)
        if last_block_metadata is None:
            logger.warning("Could not find log metadata for %s",
                           bin2hstr(self._last_block.headerhash))
            return False, False

        last_block_difficulty = int(
            UInt256ToString(last_block_metadata.cumulative_difficulty))

        new_block_metadata = self._add_block_metadata(block.headerhash,
                                                      block.timestamp,
                                                      block.prev_headerhash,
                                                      batch)
        new_block_difficulty = int(
            UInt256ToString(new_block_metadata.cumulative_difficulty))

        if new_block_difficulty > last_block_difficulty:
            if self._last_block.headerhash != block.prev_headerhash:
                fork_state = qrlstateinfo_pb2.ForkState(
                    initiator_headerhash=block.headerhash)
                self._state.put_fork_state(fork_state, batch)
                self._state.write_batch(batch)
                return self._fork_recovery(block, fork_state), True

            self._update_chainstate(block, batch)
            if check_stale:
                self.tx_pool.check_stale_txn(self._state, block.block_number)
            self.trigger_miner = True

        return True, False
コード例 #5
0
    def test_add_chain_fails_if_apply_block_fails(self):
        block_1 = create_m_block(1, self.genesis_block, alice.address)
        block_2 = create_m_block(2, block_1, alice.address)

        block_1_alt = create_m_block(1, self.genesis_block, alice.address)
        block_2_alt = create_m_block(2, block_1_alt, alice.address)
        block_3_alt = create_m_block(3, block_2_alt, alice.address)

        fork_state = qrlstateinfo_pb2.ForkState(
            initiator_headerhash=block_3_alt.headerhash,
            fork_point_headerhash=self.genesis_block.headerhash,
            old_mainchain_hash_path=[b.headerhash for b in [block_1, block_2]],
            new_mainchain_hash_path=[
                b.headerhash for b in [block_1_alt, block_2_alt, block_3_alt]
            ])

        # we want to add_chain(block_*_alt chain), but for some reason applying a Block to the State didn't work.
        self.chain_manager._apply_block = Mock(return_value=False)
        ans = self.chain_manager.add_chain(
            [block_1_alt.headerhash, block_2_alt.headerhash], fork_state)
        self.assertFalse(ans)
コード例 #6
0
    def test_add_chain_fails_if_fork_recovery_didnt_complete_successfully(
            self):
        block_1 = create_m_block(1, self.genesis_block, alice.address)
        block_2 = create_m_block(2, block_1, alice.address)

        block_1_alt = create_m_block(1, self.genesis_block, alice.address)
        block_2_alt = create_m_block(2, block_1_alt, alice.address)
        block_3_alt = create_m_block(3, block_2_alt, alice.address)

        fork_state = qrlstateinfo_pb2.ForkState(
            initiator_headerhash=block_3_alt.headerhash,
            fork_point_headerhash=self.genesis_block.headerhash,
            old_mainchain_hash_path=[b.headerhash for b in [block_1, block_2]],
            new_mainchain_hash_path=[
                b.headerhash for b in [block_1_alt, block_2_alt, block_3_alt]
            ])
        # We want to add_chain(block_*_alt chain), but we're still on block_1 (we should have rolled back to genesis)
        self.chain_manager._last_block = block_1
        ans = self.chain_manager.add_chain(
            [block_1_alt.headerhash, block_2_alt.headerhash], fork_state)
        self.assertFalse(ans)
コード例 #7
0
    def test_fork_recovery_failed(self):
        # When switching to the longer chain fails, _fork_recovery() must _rollback and restore the shorter chain.
        # Mock out irrelevant functions
        self.chain_manager._update_block_number_mapping = Mock()

        # Switching to the new chain should fail!
        self.chain_manager.add_chain = Mock(return_value=False)
        self.chain_manager._rollback = Mock()

        block_1 = create_m_block(1, self.genesis_block, alice.address)
        block_2 = create_m_block(2, block_1, alice.address)

        block_1_alt = create_m_block(1, self.genesis_block, alice.address)
        block_2_alt = create_m_block(2, block_1_alt, alice.address)
        block_3_alt = create_m_block(3, block_2_alt, alice.address)

        fork_state = qrlstateinfo_pb2.ForkState(
            initiator_headerhash=block_3_alt.headerhash,
            fork_point_headerhash=self.genesis_block.headerhash,
            old_mainchain_hash_path=[b.headerhash for b in [block_1, block_2]],
            new_mainchain_hash_path=[
                b.headerhash for b in [block_1_alt, block_2_alt, block_3_alt]
            ])

        # _fork_recovery() will _rollback() to the genesis block and go on the longer chain.
        # At this point, _rollback() should return the old hash path as a backup
        # in case switching to the longer chain fails.
        self.chain_manager._rollback.return_value = [
            block_2.headerhash, block_1.headerhash
        ]

        self.chain_manager._fork_recovery(block_3_alt, fork_state)

        # _fork_recovery() should have _rollback()ed when trying to switch to the longer chain
        self.chain_manager._rollback.assert_any_call(
            self.genesis_block.headerhash, fork_state)
        # _fork_recovery() should have _rollback()ed to the genesis block when trying to restore the shorter chain
        self.chain_manager._rollback.assert_called_with(
            self.genesis_block.headerhash)