Skip to content
This repository has been archived by the owner on Dec 15, 2021. It is now read-only.

Commit

Permalink
Fix a bug on PRepEngine._reset_block_validation_penalty
Browse files Browse the repository at this point in the history
* Add a unittest to prep/test_engine.py
  • Loading branch information
Chiwon Cho committed Dec 2, 2019
1 parent 591cc66 commit 5555808
Show file tree
Hide file tree
Showing 2 changed files with 74 additions and 7 deletions.
13 changes: 6 additions & 7 deletions iconservice/prep/engine.py
Original file line number Diff line number Diff line change
Expand Up @@ -226,7 +226,7 @@ def _on_term_ended(self, context: 'IconScoreContext') -> Tuple[dict, 'Term']:
context.storage.meta.put_last_main_preps(context, main_preps)

# All block validation penalties are released
self._release_block_validation_penalty(context)
self._reset_block_validation_penalty(context)

# Create a term with context.preps whose grades are up-to-date
new_term: 'Term' = self._create_next_term(context, self.term)
Expand Down Expand Up @@ -348,17 +348,16 @@ def _update_prep_grades(cls,

Logger.debug(tag=_TAG, msg="_update_prep_grades() end")

def _release_block_validation_penalty(self, context: 'IconScoreContext'):
"""Release block validation penalty every term end
@classmethod
def _reset_block_validation_penalty(cls, context: 'IconScoreContext'):
"""Reset block validation penalty in the end of every term
:param context:
:return:
"""

old_preps = self.preps

for prep in old_preps:
if prep.penalty == PenaltyReason.BLOCK_VALIDATION:
for prep in context.preps:
if prep.penalty == PenaltyReason.BLOCK_VALIDATION and prep.status == PRepStatus.ACTIVE:
dirty_prep = context.get_prep(prep.address, mutable=True)
dirty_prep.reset_block_validation_penalty()
context.put_dirty_prep(dirty_prep)
Expand Down
68 changes: 68 additions & 0 deletions tests/prep/test_engine.py
Original file line number Diff line number Diff line change
Expand Up @@ -453,11 +453,20 @@ def test_handle_get_prep_term_with_penalized_preps(self):
assert prep_item["status"] == PRepStatus.ACTIVE.value
assert prep_item["penalty"] == PenaltyReason.NONE.value

# The P-Reps which got penalized for consecutive 660 block validation failure
# are located at the end of the P-Rep list
prev_delegated = -1
for i, prep_item in enumerate(prep_list[-5:]):
assert prep_item["address"] == Address.from_prefix_and_int(AddressPrefix.EOA, i)
assert prep_item["status"] == PRepStatus.ACTIVE.value
assert prep_item["penalty"] == PenaltyReason.BLOCK_VALIDATION.value

delegated: int = prep_item["delegated"]
if prev_delegated >= 0:
assert prev_delegated >= delegated

prev_delegated = delegated

def test_handle_get_inactive_preps(self):
expected_block_height = 1234

Expand Down Expand Up @@ -516,3 +525,62 @@ def test_handle_get_inactive_preps(self):
assert len(expected_preps) == len(inactive_preps)
assert expected_block_height == response["blockHeight"]
assert expected_total_delegated == response["totalDelegated"]

def test__reset_block_validation_penalty(self):
engine = PRepEngine()
engine.term = self.term
engine.preps = self.preps

self.term.freeze()
self.preps.freeze()

assert engine.term.is_frozen()
assert engine.preps.is_frozen()

IconScoreContext.engine = Mock()
IconScoreContext.storage = Mock()
IconScoreContext.engine.prep = engine
context = _create_context()

assert engine.preps.size(active_prep_only=False) == context.preps.size(active_prep_only=False)
for i in range(engine.preps.size(active_prep_only=True)):
assert engine.preps.get_by_index(i) == context._preps.get_by_index(i)

# Impose block validation penalty on 5 Main P-Reps
indices = set()
for _ in range(5):
index = random.randint(0, self.main_prep_count - 1)
indices.add(index)

# Impose the block validation penalty on randomly chosen 5 or less than P-Reps
for i in indices:
prep = context.preps.get_by_index(i)
dirty_prep = context.get_prep(prep.address, mutable=True)
assert not dirty_prep.is_frozen()

dirty_prep.penalty = PenaltyReason.BLOCK_VALIDATION
dirty_prep.grade = PRepGrade.CANDIDATE

context.put_dirty_prep(dirty_prep)

context.update_dirty_prep_batch()

for i in indices:
prep = context.preps.get_by_index(i)
assert prep.is_frozen()
assert prep.status == PRepStatus.ACTIVE
assert prep.penalty == PenaltyReason.BLOCK_VALIDATION
assert prep.grade == PRepGrade.CANDIDATE

engine._reset_block_validation_penalty(context)

# The penalties of P-Reps in context should be reset
# to PenaltyReason.NONE at the last block of the current term
for prep in context.preps:
assert prep.status == PRepStatus.ACTIVE
assert prep.penalty == PenaltyReason.NONE

for i in indices:
prep = context.preps.get_by_index(i)
assert prep.status == PRepStatus.ACTIVE
assert prep.penalty == PenaltyReason.NONE

0 comments on commit 5555808

Please sign in to comment.