def test_calc_delegations(self): cached_accounts: Dict['Address', Tuple['Account', int]] = OrderedDict() context = Mock() context.storage.icx.get_account = Mock(side_effect=get_account) new_delegations: List[Tuple['Address', int]] = [] for i in range(10): value: int = i + 11 address = Address.from_prefix_and_int(AddressPrefix.EOA, value) new_delegations.append((address, value)) sender_account = context.storage.icx.get_account(context, SENDER_ADDRESS, Intent.ALL) cached_accounts[SENDER_ADDRESS] = sender_account, 0 # Prepare old delegations for i in range(10): value: int = i + 1 address = Address.from_prefix_and_int(AddressPrefix.EOA, value) account = context.storage.icx.get_account(context, address, Intent.DELEGATED) cached_accounts[address] = account, -value IISSEngine._calc_delegations(context, new_delegations, cached_accounts) # 0: sender_account, 1~10: old_accounts 11~20: new_accounts for i, address in enumerate(cached_accounts): account, delegated_offset = cached_accounts[address] assert account.address == address if i == 0: assert address == SENDER_ADDRESS assert delegated_offset == 0 elif 1 <= i <= 10: assert delegated_offset == -i else: # 11 <= i <= 20 assert delegated_offset == i
def test_get_old_delegations_from_sender_account(self): cached_accounts: Dict['Address', Tuple['Account', int]] = {} context = Mock() context.storage.icx.get_account = Mock(side_effect=get_account) sender_account = context.storage.icx.get_account(context, SENDER_ADDRESS, Intent.ALL) cached_accounts[SENDER_ADDRESS] = sender_account, 0 # Get old delegations from delegating accounts IISSEngine._get_old_delegations_from_sender_account(context, SENDER_ADDRESS, cached_accounts) assert len(cached_accounts) == 11 # sender_account(1) + old delegated_accounts(10) for i, address in enumerate(cached_accounts): item: Tuple['Account', int] = cached_accounts[address] account = item[0] delegated_offset = item[1] assert address == account.address if i == 0: assert delegated_offset == 0 else: delegation: Tuple['Account', int] = sender_account.delegations[i - 1] assert address == delegation[0] assert delegated_offset == -delegation[1]
def test_convert_params_of_set_delegation_with_duplicate_address(self, context): delegations = [] for i in range(2): address = Address.from_prefix_and_int(AddressPrefix.EOA, 1) value = random.randint(1, 100) delegations.append({"address": address, "value": value}) with pytest.raises(InvalidParamsException): IISSEngine._convert_params_of_set_delegation(context, delegations)
def test_convert_params_of_set_delegation_with_value_less_than_0(self, context): delegations = [] values = [1, 2, 3, 4, -100] for i in range(5): address = Address.from_prefix_and_int(AddressPrefix.EOA, i + 1) value = values[i] delegations.append({"address": address, "value": value}) with pytest.raises(InvalidParamsException): IISSEngine._convert_params_of_set_delegation(context, delegations)
def test_check_voting_power_is_enough_with_not_enough_stake(self): def _get_account(_context: 'IconScoreContext', _address: 'Address', _intent: 'Intent' = Intent.TRANSFER) -> 'Account': return create_sender_account(stake=100) cached_accounts: Dict['Address', Tuple['Account', int]] = {} context = Mock() context.storage.icx.get_account = Mock(side_effect=_get_account) total_delegating = sum(range(11, 21)) # new_delegations with pytest.raises(InvalidRequestException): IISSEngine._check_voting_power_is_enough( context, SENDER_ADDRESS, total_delegating, cached_accounts)
def test_convert_params_of_set_delegation_with_too_many_delegations(self, context): max_delegations: int = self._get_expected_max_delegations(context) delegations = [] for i in range(max_delegations + 1): address = Address.from_prefix_and_int(AddressPrefix.EOA, i + 1) value = random.randint(1, 10_000) delegations.append({ "address": str(address), "value": hex(value) }) with pytest.raises(InvalidParamsException): IISSEngine._convert_params_of_set_delegation(context, delegations)
def test_handle_set_delegation_with_1_account(self): context = Mock() context.revision = Revision.DECENTRALIZATION.value context.tx.origin = SENDER_ADDRESS context.msg = Message(SENDER_ADDRESS, 0) context.storage.icx.get_account = Mock(side_effect=get_account) new_delegations = [{ "address": Address.from_prefix_and_int(AddressPrefix.EOA, 1), "value": 100 }] class IISSEngineListenerImpl(IISSEngineListener): def on_set_stake(self, _context: 'IconScoreContext', account: 'Account'): assert False def on_set_delegation(self, _context: 'IconScoreContext', updated_accounts: List['Account']): # sender_account(1) + updated_delegated_account(10) assert len(updated_accounts) == 11 delegated_address = Address.from_prefix_and_int(AddressPrefix.EOA, 1) for i, account in enumerate(updated_accounts): assert isinstance(account, Account) address = account.address if i == 0: # sender_account assert account.delegated_amount == 0 assert len(account.delegations) == 1 assert account.delegation_part.delegations_amount == 100 item = account.delegations[0] assert item[0] == Address.from_prefix_and_int(AddressPrefix.EOA, 1) assert item[1] == 100 else: assert account.delegations_amount == 0 if address == delegated_address: assert account.delegated_amount == 100 else: assert account.delegated_amount == 0 engine = IISSEngine() engine.add_listener(IISSEngineListenerImpl()) engine.handle_set_delegation(context, new_delegations)
def test_calculate_unstake_lock_period(self): lmin = IISS_DAY_BLOCK * 5 lmax = IISS_DAY_BLOCK * 20 rpoint = 7000 for x in range(0, 100): ret = IISSEngine._calculate_unstake_lock_period(lmin, lmax, rpoint, x, 100) diff = abs(ret - EXPECTED_LOCK_PERIOD_PRE_STAKE_PERCENT[x]) assert diff <= 1
def test_handle_set_delegation_with_21_accounts(self): context = Mock() context.revision = Revision.DECENTRALIZATION.value context.tx.origin = SENDER_ADDRESS context.msg = Message(SENDER_ADDRESS, 0) context.storage.icx.get_account = Mock(side_effect=get_account) total_delegating, delegations = create_delegations_param() class IISSEngineListenerImpl(IISSEngineListener): def on_set_stake(self, _context: 'IconScoreContext', account: 'Account'): assert False def on_set_delegation(self, _context: 'IconScoreContext', updated_accounts: List['Account']): assert len(updated_accounts) == 21 for i, account in enumerate(updated_accounts): assert isinstance(account, Account) address = account.address assert address == Address.from_prefix_and_int(AddressPrefix.EOA, i) if i == 0: # sender_account assert account.delegated_amount == 0 assert len(account.delegations) == 10 assert account.delegation_part.delegations_amount == sum(range(11, 21)) for j, item in enumerate(account.delegations): address: 'Address' = item[0] value: int = item[1] _id = j + 11 assert address == Address.from_prefix_and_int(AddressPrefix.EOA, _id) assert value == _id else: assert account.delegations_amount == 0 if i <= 10: assert account.delegated_amount == 0 else: assert account.delegated_amount == i engine = IISSEngine() engine.add_listener(IISSEngineListenerImpl()) engine.handle_set_delegation(context, delegations)
def test_put_delegation_to_state_db(self): cached_accounts: Dict['Address', Tuple['Account', int]] = OrderedDict() context = Mock() context.revision = Revision.DECENTRALIZATION.value context.storage.icx.get_account = Mock(side_effect=get_account) total_delegating = 0 new_delegations: List[Tuple['Address', int]] = [] for i in range(10): value: int = i + 11 address = Address.from_prefix_and_int(AddressPrefix.EOA, value) new_delegations.append((address, value)) total_delegating += value sender_account = context.storage.icx.get_account(context, SENDER_ADDRESS, Intent.ALL) cached_accounts[SENDER_ADDRESS] = sender_account, 0 # Put old delegations to cached_accounts for address, value in sender_account.delegations: account = context.storage.icx.get_account(context, address, Intent.DELEGATED) cached_accounts[address] = account, -value # Put new delegations to cached_accounts for i in range(10): value: int = i + 11 address = Address.from_prefix_and_int(AddressPrefix.EOA, value) account = context.storage.icx.get_account(context, address, Intent.DELEGATED) cached_accounts[address] = account, value updated_accounts: List['Account'] = IISSEngine._put_delegation_to_state_db( context, SENDER_ADDRESS, new_delegations, cached_accounts) # sender_account(1) + old_delegated_accounts(10) + new_delegated_accounts(10) assert len(updated_accounts) == len(cached_accounts) == 21 assert len(context.storage.icx.put_account.call_args_list) == len(cached_accounts) for i, address in enumerate(cached_accounts): call_args = context.storage.icx.put_account.call_args_list[i] account = call_args[0][1] assert isinstance(account, Account) assert address == account.address assert account == updated_accounts[i] if i == 0: assert account.address == SENDER_ADDRESS assert account.delegated_amount == 0 assert account.delegations == new_delegations assert account.delegations_amount == total_delegating else: # Assume that all delegated accounts do not delegate any other accounts assert account.delegations_amount == 0 if i <= 10: # old delegations assert account.delegated_amount == 0 else: assert account.delegated_amount == cached_accounts[address][1]
def unlock_period(total_stake, total_supply): p = Engine._calculate_unstake_lock_period( default_icon_config[ConfigKey.IISS_META_DATA][ ConfigKey.UN_STAKE_LOCK_MIN], default_icon_config[ConfigKey.IISS_META_DATA][ ConfigKey.UN_STAKE_LOCK_MAX], default_icon_config[ConfigKey.IISS_META_DATA][ConfigKey.REWARD_POINT], total_stake, total_supply, ) return p
def test_check_voting_power_is_enough(self): def _get_account(_context: 'IconScoreContext', _address: 'Address', _intent: 'Intent' = Intent.TRANSFER) -> 'Account': return create_sender_account(stake=155) cached_accounts: Dict['Address', Tuple['Account', int]] = {} context = Mock() context.storage.icx.get_account = Mock(side_effect=_get_account) total_delegating = sum(range(11, 21)) # new_delegations IISSEngine._check_voting_power_is_enough( context, SENDER_ADDRESS, total_delegating, cached_accounts) sender_item: Tuple['Account', int] = cached_accounts[SENDER_ADDRESS] assert len(cached_accounts) == 1 assert sender_item[0] == _get_account(context, SENDER_ADDRESS, Intent.ALL) assert sender_item[1] == 0 # delegated_amount_offset assert sender_item[0].delegations_amount == sum(range(1, 11)) # old delegations assert sender_item[0].stake >= total_delegating
def test_convert_params_of_set_delegation_ok(self, context): max_delegations: int = self._get_expected_max_delegations(context) delegations = [] total_delegating = 0 for i in range(max_delegations): address = Address.from_prefix_and_int(AddressPrefix.EOA, i + 1) value = random.randint(1, 10_000) delegations.append({"address": address, "value": value}) total_delegating += value ret_total_delegating, ret_delegations = IISSEngine._convert_params_of_set_delegation(context, delegations) assert ret_total_delegating == total_delegating for i in range(len(delegations)): item: Tuple['Address', int] = ret_delegations[i] address: 'Address' = item[0] value: int = item[1] assert address == delegations[i]["address"] assert value == delegations[i]["value"]
def test_convert_params_of_set_delegation_with_value_0(self, context): max_delegations: int = self._get_expected_max_delegations(context) delegations = [] total_delegating = 0 zero_value_cnt: int = 5 for i in range(max_delegations): address = Address.from_prefix_and_int(AddressPrefix.EOA, i + 1) value = 0 if i < zero_value_cnt else i + 1 delegations.append({"address": address, "value": value}) total_delegating += value ret_total_delegating, ret_delegations = IISSEngine._convert_params_of_set_delegation(context, delegations) assert ret_total_delegating == total_delegating == sum([i + 1 for i in range(5, max_delegations)]) assert len(ret_delegations) == max_delegations - zero_value_cnt i = zero_value_cnt # 5 delegations including 0 value were dropped. for address, value in ret_delegations: delegation: Dict[str, Optional[str, int]] = delegations[i] assert address == delegation["address"] assert value == delegation["value"] i += 1
def test_invoke(self): context = Mock(revision=Revision.IISS.value - 1) engine = IISSEngine() with pytest.raises(InvalidParamsException): engine.invoke(context, "stake", {})
def test_internal_handle_set_delegation(self): """Test case old_delegations: 1 ~ 10 delegated amount new_delegations: 101 ~ 110 delegated amount sender_account does not delegate to itself :return: """ context = Mock() context.revision = Revision.DECENTRALIZATION.value context.storage.icx.get_account = Mock(side_effect=get_account) total_delegating, delegations = create_delegations_param() ret_total_delegating, ret_delegations = IISSEngine._convert_params_of_set_delegation(context, delegations) assert ret_total_delegating == total_delegating for i in range(len(delegations)): item: Tuple['Address', int] = ret_delegations[i] address: 'Address' = item[0] value: int = item[1] assert address, value == delegations[i]["address"] assert value == delegations[i]["value"] # IISSEngine._check_voting_power_is_enough() cached_accounts: Dict['Address', Tuple['Account', int]] = {} IISSEngine._check_voting_power_is_enough( context, SENDER_ADDRESS, total_delegating, cached_accounts) assert len(cached_accounts) == 1 assert cached_accounts[SENDER_ADDRESS][0] == create_sender_account(stake=10_000) assert cached_accounts[SENDER_ADDRESS][1] == 0 # delegated_amount sender_account: 'Account' = cached_accounts[SENDER_ADDRESS][0] # Get old delegations from delegating accounts IISSEngine._get_old_delegations_from_sender_account(context, SENDER_ADDRESS, cached_accounts) assert len(cached_accounts) == 11 # sender_account(1) + old delegated_accounts(10) for i, address in enumerate(cached_accounts): item: Tuple['Account', int] = cached_accounts[address] account = item[0] delegated_offset = item[1] assert address == account.address if i > 0: delegation: Tuple['Account', int] = sender_account.delegations[i - 1] assert address == delegation[0] assert delegated_offset == -delegation[1] IISSEngine._calc_delegations(context, ret_delegations, cached_accounts) # 0: sender_account, 1~10: old_accounts 11~20: new_accounts for i, address in enumerate(cached_accounts): account, delegated_offset = cached_accounts[address] assert account.address == address if i == 0: assert address == SENDER_ADDRESS assert delegated_offset == 0 elif 1 <= i <= 10: assert delegated_offset == -i else: # 11 <= i <= 20 assert delegated_offset == i updated_accounts: List['Account'] = \ IISSEngine._put_delegation_to_state_db(context, SENDER_ADDRESS, ret_delegations, cached_accounts) # sender_account(1) + old_delegated_accounts(10) + new_delegated_accounts(10) assert len(updated_accounts) == len(cached_accounts) == 21 assert len(context.storage.icx.put_account.call_args_list) == len(cached_accounts) for i, address in enumerate(cached_accounts): call_args = context.storage.icx.put_account.call_args_list[i] account = call_args[0][1] assert isinstance(account, Account) assert address == account.address assert account == updated_accounts[i] if i == 0: assert account.address == SENDER_ADDRESS assert account.delegated_amount == 0 elif 1 <= i <= 10: # old delegations assert account.delegated_amount == 0 else: assert account.delegated_amount == cached_accounts[address][1]