def test_is_removable_v1(self, unstake_patcher, index, unstakes_info, result): stake_part = StakePart(0, 0, 0, unstakes_info) stake_part.set_complete(True) target = unstake_patcher._targets[index] assert unstake_patcher._is_removable_v1(stake_part, target) == result
def test_is_removable_v0(self, unstake_patcher, index, unstake, unstake_block_height, result): stake_part = StakePart(0, unstake, unstake_block_height) stake_part.set_complete(True) target = unstake_patcher._targets[index] assert unstake_patcher._is_removable_v0(stake_part, target) == result
def test_stake_part_make_key(self): key = StakePart.make_key(create_address()) self.assertEqual( ICON_EOA_ADDRESS_BYTES_SIZE + len(StakePart.PREFIX) + 1, len(key)) key = StakePart.make_key(create_address(1)) self.assertEqual( ICON_CONTRACT_ADDRESS_BYTES_SIZE + len(StakePart.PREFIX), len(key))
def test_normalize(self, revision, block_height, unstakes_info, expected_expired_unstake, expected_unstakes_info, expected_dirty): stake = random.randint(0, 100) stake_part = StakePart(stake=stake, unstakes_info=copy.deepcopy(unstakes_info)) expired_unstake = stake_part.normalize(block_height, revision) assert expired_unstake == expected_expired_unstake assert stake_part.unstakes_info == expected_unstakes_info assert stake_part.is_dirty() == expected_dirty
def test_stake_part_on_rev_8(self, block_height, params, expected): revision = 8 stake_part = StakePart(**params) expired_unstake: int = stake_part.normalize(block_height=block_height, revision=revision) assert expired_unstake == expected["expired_unstake"] assert stake_part.stake == expected["stake"] assert stake_part.total_stake == expected["stake"] + expected["unstake"] assert stake_part.unstake == expected["unstake"] assert stake_part.total_unstake == expected["unstake"] assert stake_part.unstake_block_height == expected[ "unstake_block_height"]
def test_normalize(self, context, mocker, revision, unstakes_info, current_block_height, flag, expected_balance): unstakes_info = copy.deepcopy(unstakes_info) mocker.patch.object(IconScoreContext, "revision", PropertyMock(return_value=revision)) stake, balance = 100, 100 coin_part = CoinPart(CoinPartType.GENERAL, flag, balance) stake_part = StakePart(stake=stake, unstake=0, unstake_block_height=0, unstakes_info=unstakes_info) account = Account(ADDRESS, current_block_height, revision, coin_part=coin_part, stake_part=stake_part) if unstakes_info is None: remaining_unstakes = [] else: remaining_unstakes = [ unstake_info for unstake_info in unstakes_info if unstake_info[1] >= current_block_height ] account.normalize(revision) assert account.stake == stake assert account.balance == expected_balance assert account.unstakes_info == remaining_unstakes
def test_account_stake(self): value: int = 0 stake_part = StakePart(stake=value) stake_part.set_complete(True) account = Account(create_address(), 0, stake_part=stake_part) self.assertEqual(value, account.stake) value: int = 100 stake_part = StakePart(stake=value) stake_part.set_complete(True) account = Account(create_address(), 0, stake_part=stake_part) self.assertEqual(value, account.stake)
def test_account_unstake_block_height(self): value: int = 0 stake_part = StakePart(unstake_block_height=value) stake_part.set_complete(True) account = Account(create_address(), 0, stake_part=stake_part) self.assertEqual(0, account.unstake_block_height) value: int = 300 stake_part = StakePart(unstake_block_height=value) stake_part.set_complete(True) account = Account(create_address(), 0, stake_part=stake_part) self.assertEqual(value, account.unstake_block_height)
def test_stake_part_add_stake(self): part = StakePart() part.set_complete(True) stake = 100 part.add_stake(100) self.assertEqual(stake, part.stake) self.assertTrue( part.is_set(BasePartState.DIRTY | BasePartState.COMPLETE))
def create_account( address: 'Address', balance: int, stake: int, unstake: int, unstake_block_height: int, delegated_amount: int, delegations: List[Tuple[Address, int]]) -> 'Account': coin_part = CoinPart(balance=balance) stake_part = StakePart(stake, unstake, unstake_block_height) delegation_part = DelegationPart(delegated_amount, delegations) return Account( address, 1024, coin_part=coin_part, stake_part=stake_part, delegation_part=delegation_part)
def test_account_for_stake_rev_multiple_unstake1(self): address: 'Address' = create_address() context: 'IconScoreContext' = Mock(spec=IconScoreContext) unstake_slot_max = 10 context.configure_mock(unstake_slot_max=unstake_slot_max) context.configure_mock(revision=Revision.MULTIPLE_UNSTAKE.value) coin_part: 'CoinPart' = CoinPart() stake_part: 'StakePart' = StakePart() account = Account(address, 0, Revision.MULTIPLE_UNSTAKE.value, coin_part=coin_part, stake_part=stake_part) balance = 1000 account.deposit(balance) stake1 = 500 unstake_block_height = 0 remain_balance = balance - stake1 account.set_stake(context, stake1, 0) self.assertEqual(stake1, account.stake) self.assertEqual(0, account.unstake) self.assertEqual(unstake_block_height, account.unstake_block_height) self.assertEqual(remain_balance, account.balance) stake2 = 100 block_height = 10 unstake = stake1 - stake2 remain_balance = balance - stake1 account.set_stake(context, stake2, block_height) expected_unstake_info = [[unstake, block_height]] self.assertEqual(stake2, account.stake) self.assertEqual(0, account.unstake) self.assertEqual(0, account.unstake_block_height) self.assertEqual(expected_unstake_info, account.unstakes_info) self.assertEqual(remain_balance, account.balance) stake3 = 600 block_height = 15 account.set_stake(context, stake3, block_height) expected_unstake_info = [] expected_balance = 400 self.assertEqual(stake3, account.stake) self.assertEqual(expected_unstake_info, account.unstakes_info) self.assertEqual(expected_balance, account.balance)
def test_remove_invalid_expired_unstakes_v1(self, unstake_patcher, unstakes_info, index): stake = random.randint(0, 1000) stake_part = StakePart(stake, 0, 0, copy.deepcopy(unstakes_info)) stake_part.set_complete(True) target = unstake_patcher._targets[index] stake_part = unstake_patcher._remove_invalid_expired_unstakes_v1( stake_part, target) assert stake_part.is_dirty() assert stake_part.stake == stake assert stake_part.unstake == 0 assert stake_part.unstake_block_height == 0 size = len(stake_part.unstakes_info) target_size = len(target.unstakes) assert size == len(unstakes_info) - target_size for i in range(size): index = target_size + i assert stake_part.unstakes_info[i] == unstakes_info[index] assert stake_part.total_unstake == unstakes_info[index][0] assert stake_part.total_stake == unstakes_info[index][0] + stake
def test_get_account(self, storage, context, mocker, flag, unstakes_info, current_block_height, expected_balance): unstakes_info = copy.deepcopy(unstakes_info) # test whether the `Account` saved in the wrong format is properly got on revision11. revision = Revision.FIX_BALANCE_BUG.value mocker.patch.object(IconScoreContext, "revision", PropertyMock(return_value=revision)) stake, balance = 100, 100 coin_part = CoinPart(CoinPartType.GENERAL, flag, balance) coin_part.set_dirty(True) stake_part = StakePart(stake=stake, unstake=0, unstake_block_height=0, unstakes_info=unstakes_info) stake_part.set_dirty(True) account = Account(ADDRESS, current_block_height, revision, coin_part=coin_part, stake_part=stake_part) account.coin_part._flags = flag context.block._height = current_block_height storage.put_account(context, account) if unstakes_info is None: remaining_unstakes = [] else: remaining_unstakes = [ unstake_info for unstake_info in unstakes_info if unstake_info[1] >= current_block_height ] account = storage.get_account(context, ADDRESS) assert account.balance == expected_balance assert account.unstakes_info == remaining_unstakes
def test_account_unstakes_info(self): value: int = 0 stake_part = StakePart(unstake=value) stake_part.set_complete(True) account = Account(create_address(), 0, Revision.MULTIPLE_UNSTAKE.value, stake_part=stake_part) self.assertEqual([], account.unstakes_info) info = [(10, 1), (20, 5)] stake_part = StakePart(unstakes_info=info) stake_part.set_complete(True) account = Account(create_address(), 0, Revision.MULTIPLE_UNSTAKE.value, stake_part=stake_part) self.assertEqual(info, account.unstakes_info)
def test_account_for_unstake_slot_max_case_1(self): address: 'Address' = create_address() context: 'IconScoreContext' = Mock(spec=IconScoreContext) unstake_slot_max = 10 context.configure_mock(unstake_slot_max=unstake_slot_max) context.configure_mock(revision=Revision.MULTIPLE_UNSTAKE.value) coin_part: 'CoinPart' = CoinPart() stake_part: 'StakePart' = StakePart() account = Account(address, 0, Revision.MULTIPLE_UNSTAKE.value, coin_part=coin_part, stake_part=stake_part) balance = 2000 account.deposit(balance) stake = 2000 unstake_block_height = 0 remain_balance = balance - stake account.set_stake(context, stake, 0) self.assertEqual(stake, account.stake) self.assertEqual(0, account.unstake) self.assertEqual(unstake_block_height, account.unstake_block_height) self.assertEqual(remain_balance, account.balance) unstake = 1 total_unstake = 0 expected_unstake_info = [] for i in range(unstake_slot_max): expected_unstake_info.append([unstake, unstake_slot_max + i]) stake -= unstake total_unstake += unstake account.set_stake(context, account.stake - unstake, unstake_slot_max + i) self.assertEqual(stake, account.stake) self.assertEqual(total_unstake, account.stake_part.total_unstake) self.assertEqual(remain_balance, account.balance) self.assertEqual(expected_unstake_info, account.unstakes_info) last_unstake = 100 account.set_stake(context, account.stake - last_unstake, unstake_slot_max + 2) expected_unstake_info[-1] = [101, unstake_slot_max * 2 - 1] self.assertEqual(expected_unstake_info, account.unstakes_info)
def test_account_unstake(self): value: int = 0 stake_part = StakePart(unstake=value) stake_part.set_complete(True) account = Account(create_address(), 0, Revision.IISS.value, stake_part=stake_part) self.assertEqual(0, account.unstake) value: int = 200 stake_part = StakePart(unstake=value) stake_part.set_complete(True) account = Account(create_address(), 0, Revision.IISS.value, stake_part=stake_part) self.assertEqual(value, account.unstake)
def test_stake_part_update(self): stake: int = 10 unstake: int = 0 unstake_block_height: int = 0 part1 = StakePart(stake, unstake, unstake_block_height) part1.normalize(0, Revision.IISS.value) self.assertEqual(stake, part1.stake) self.assertEqual(unstake, part1.unstake) self.assertEqual(unstake_block_height, part1.unstake_block_height) stake: int = 5 unstake: int = 5 unstake_block_height: int = 3 part2 = StakePart(stake, unstake, unstake_block_height) part2.normalize(unstake_block_height + 1, Revision.IISS.value) self.assertEqual(stake, part2.stake) self.assertEqual(0, part2.unstake) self.assertEqual(0, part2.unstake_block_height)
def test_account_flag(self): address: 'Address' = create_address() account: 'Account' = Account(address, 0, Revision.IISS.value) self.assertIsNone(account.coin_part) self.assertIsNone(account.stake_part) self.assertIsNone(account.delegation_part) coin_part: 'CoinPart' = CoinPart() account: 'Account' = Account(address, 0, Revision.IISS.value, coin_part=coin_part) self.assertIsNotNone(account.coin_part) self.assertIsNone(account.stake_part) self.assertIsNone(account.delegation_part) stake_part: 'StakePart' = StakePart() account: 'Account' = Account(address, 0, Revision.IISS.value, stake_part=stake_part) self.assertIsNone(account.coin_part) self.assertIsNotNone(account.stake_part) self.assertIsNone(account.delegation_part) delegation_part: 'DelegationPart' = DelegationPart() account: 'Account' = Account(address, 0, Revision.IISS.value, delegation_part=delegation_part) self.assertIsNone(account.coin_part) self.assertIsNone(account.stake_part) self.assertIsNotNone(account.delegation_part) account: 'Account' = Account(address, 0, Revision.IISS.value, coin_part=coin_part, stake_part=stake_part, delegation_part=delegation_part) self.assertIsNotNone(account.coin_part) self.assertIsNotNone(account.stake_part) self.assertIsNotNone(account.delegation_part)
def test_account_for_stake(self): address: 'Address' = create_address() context: 'IconScoreContext' = IconScoreContext() coin_part: 'CoinPart' = CoinPart() stake_part: 'StakePart' = StakePart() account = Account(address, 0, Revision.IISS.value, coin_part=coin_part, stake_part=stake_part) balance = 1000 account.deposit(balance) stake1 = 500 unstake_block_height = 0 remain_balance = balance - stake1 account.set_stake(context, stake1, 0) self.assertEqual(stake1, account.stake) self.assertEqual(0, account.unstake) self.assertEqual(unstake_block_height, account.unstake_block_height) self.assertEqual(remain_balance, account.balance) stake2 = 100 block_height = 10 unstake = stake1 - stake2 remain_balance = balance - stake1 account.set_stake(context, stake2, block_height) self.assertEqual(stake2, account.stake) self.assertEqual(unstake, account.unstake) self.assertEqual(block_height, account.unstake_block_height) self.assertEqual(remain_balance, account.balance) remain_balance = remain_balance + unstake account._current_block_height += 11 account.normalize(Revision.IISS.value) self.assertEqual(remain_balance, account.balance)
def test_stake_part(self): stake = 500 unstake = 0 unstake_block_height = 0 stake_part: 'StakePart' = StakePart() stake_part.normalize(0, Revision.IISS.value) stake_part.add_stake(stake) self.assertEqual(stake, stake_part.stake) self.assertEqual(unstake, stake_part.unstake) self.assertEqual(unstake_block_height, stake_part.unstake_block_height) unstake = 100 block_height = 10 remain_stake = stake - unstake stake_part.set_unstake(block_height, unstake) self.assertEqual(remain_stake, stake_part.stake) self.assertEqual(unstake, stake_part.unstake) self.assertEqual(block_height, stake_part.unstake_block_height)
def test_withdraw_unstake(self, stake, unstakes_info, amount, expected_unstakes_info): expected_total_unstake = sum(unstake for unstake, _ in expected_unstakes_info) stake_part = StakePart(stake=stake, unstakes_info=unstakes_info) stake_part.normalize(block_height=500, revision=Revision.FIX_UNSTAKE_BUG.value) # withdraw() assumes that amount is less than total_stake assert stake_part.total_unstake > amount stake_part.withdraw_unstake(amount) assert stake_part.stake == stake assert stake_part.unstakes_info == expected_unstakes_info assert stake_part.total_unstake == expected_total_unstake
def get_account(context: 'IconScoreContext', address: 'Address', intent: 'Intent' = Intent.TRANSFER) -> 'Account': """Returns the account indicated by address. :param context: :param address: account address :param intent: :return: (Account) If the account indicated by address is not present, create a new account. """ if address == SENDER_ADDRESS: return create_sender_account(stake=10_000) coin_part: Optional['CoinPart'] = None stake_part: Optional['StakePart'] = None delegation_part: Optional['DelegationPart'] = None part_flags: 'AccountPartFlag' = AccountPartFlag(intent) if AccountPartFlag.COIN in part_flags: coin_part: 'CoinPart' = CoinPart(balance=0) if AccountPartFlag.STAKE in part_flags: stake_part = StakePart(0, 0, 0) if AccountPartFlag.DELEGATION in part_flags: value: int = int.from_bytes(address.body, "big") delegated_amount = value if 1 <= value <= 10 else 0 delegation_part = DelegationPart(delegated_amount=delegated_amount) return Account(address, context.block.height, coin_part=coin_part, stake_part=stake_part, delegation_part=delegation_part)
def test_set_unstakes_info(self, unstakes_info, new_total_unstake, unstake_block_height, expected_unstakes_info): old_total_unsake: int = sum( info[0] for info in unstakes_info) if unstakes_info else 0 assert new_total_unstake != old_total_unsake stake = random.randint(0, 100) slot_max = 3 revision = Revision.FIX_UNSTAKE_BUG.value block_height = 500 stake_part = StakePart(stake=stake, unstakes_info=unstakes_info) stake_part.normalize(block_height, revision) unstake_delta: int = new_total_unstake - old_total_unsake stake_part.set_unstakes_info(unstake_block_height, new_total_unstake, slot_max) assert stake_part.is_dirty() assert stake_part.stake == stake - unstake_delta assert stake_part.unstakes_info == expected_unstakes_info assert stake_part.total_unstake == new_total_unstake assert stake_part.total_stake == stake_part.stake + stake_part.total_unstake
def test_remove_invalid_expired_unstakes_v0(self, unstake_patcher, index, unstake, unstake_block_height): stake = random.randint(0, 1000) stake_part = StakePart(stake, unstake, unstake_block_height) stake_part.set_complete(True) target = unstake_patcher._targets[index] assert stake_part.stake == stake assert stake_part.unstake == unstake assert stake_part.unstake_block_height == unstake_block_height assert not stake_part.is_dirty() stake_part = unstake_patcher._remove_invalid_expired_unstakes_v0( stake_part, target) assert stake_part.is_dirty() assert len(stake_part.unstakes_info) == 0 assert stake_part.stake == stake assert stake_part.unstake == 0 assert stake_part.unstake_block_height == 0
def test_stake_part_update_multiple_unstake(self): stake: int = 5 block_height = 3 unstake_info1 = [10, 1] unstake_info2 = [20, 2] unstake_info3 = [40, 3] unstake_info4 = [30, 5] unstake_info5 = [100, 5] unstakes_info = [ unstake_info1, unstake_info2, unstake_info3, unstake_info4, unstake_info5 ] part = StakePart(stake=stake, unstakes_info=unstakes_info) part.set_complete(True) part.normalize(block_height, Revision.MULTIPLE_UNSTAKE.value) self.assertEqual(stake, part.stake) self.assertEqual(0, part.unstake) self.assertEqual(0, part.unstake_block_height) expected_info = [[40, 3], [30, 5], [100, 5]] self.assertEqual(expected_info, part.unstakes_info)
def test_stake_part_total_unstake2(self): unstakes_info = [(10, 1), (20, 1)] part = StakePart(unstakes_info=unstakes_info) part.set_complete(True) self.assertEqual(30, part.total_unstake)
def test_stake_part_set_unstake_update(self): part = StakePart() part.set_complete(True) stake = 100 block_height = 10 part.add_stake(100) unstake = stake part.set_unstake(block_height, unstake) self.assertEqual(0, part.stake) self.assertEqual(stake, part.unstake) self.assertEqual(block_height, part.unstake_block_height) self.assertTrue( part.is_set(BasePartState.DIRTY | BasePartState.COMPLETE)) block_height += block_height unstake = 10 part.set_unstake(block_height, unstake) self.assertEqual(stake - unstake, part.stake) self.assertEqual(unstake, part.unstake) self.assertEqual(block_height, part.unstake_block_height) self.assertTrue( part.is_set(BasePartState.DIRTY | BasePartState.COMPLETE)) refund_unstake = part.normalize(block_height + 1, Revision.IISS.value) self.assertEqual(unstake, refund_unstake)
def _convert_stake_parts(cls, key: bytes, value: bytes): ret = StakePart.from_bytes(value) return str(Address.from_bytes(key[len(StakePart.PREFIX):])), str(ret)
def test_delegation_part_equal(self): part1 = StakePart() part1.normalize(0, Revision.IISS.value) part2 = StakePart() part2.normalize(1, Revision.IISS.value) self.assertEqual(part1, part2) offset = 100 part1.add_stake(offset) part3 = StakePart(stake=offset) part3.normalize(100, Revision.IISS.value) self.assertEqual(part1, part3)
def test_stake_part_from_bytes_to_bytes_multiple_unstake(self): part1 = StakePart() part1.normalize(0, Revision.IISS.value) data = part1.to_bytes(Revision.MULTIPLE_UNSTAKE.value) self.assertTrue(isinstance(data, bytes)) self.assertEqual(6, len(data)) part2 = StakePart.from_bytes(data) part2.normalize(0, Revision.IISS.value) self.assertEqual(part1.stake, part2.stake) self.assertEqual(part1.unstake, part2.unstake) self.assertEqual(part1.unstake_block_height, part2.unstake_block_height) self.assertEqual(part1.unstakes_info, part2.unstakes_info) part3 = StakePart(10, 20, 30) part3.normalize(0, Revision.IISS.value) part4 = StakePart.from_bytes( part3.to_bytes(Revision.MULTIPLE_UNSTAKE.value)) part4.normalize(0, Revision.IISS.value) self.assertEqual(part3.stake, part4.stake) self.assertEqual(part3.unstake, part4.unstake) self.assertEqual(part3.unstakes_info, part4.unstakes_info)