def test_rollback_multi_blocks(self): # Prevent icon_service_engine from sending RollbackRequest to rc IconScoreContext.engine.iiss.rollback_reward_calculator = Mock() # Inspect the current term response = self.get_prep_term() assert response["sequence"] == 2 prev_block: 'Block' = self.icon_service_engine._get_last_block() # Transfer 3000 icx to new 10 accounts init_balance = icx_to_loop(3000) accounts: List['EOAAccount'] = self.create_eoa_accounts(10) self.distribute_icx(accounts=accounts, init_balance=init_balance) for account in accounts: balance: int = self.get_balance(account.address) assert balance == init_balance # accounts[0] transfers 10 ICX to receiver sender: EOAAccount = accounts[0] receiver: EOAAccount = self.create_eoa_account() value = icx_to_loop(10) tx = self.create_transfer_icx_tx(from_=sender.address, to_=receiver.address, value=value) # 2 == Base TX + ICX transfer TX tx_results: List['TransactionResult'] = self.process_confirm_block( tx_list=[tx]) assert len(tx_results) == 2 # ICX transfer TX success check tx_result: 'TransactionResult' = tx_results[1] assert tx_results[0].status == 1 # Sender balance check sender_balance: int = self.get_balance(sender.address) assert sender_balance == init_balance - value - tx_result.step_price * tx_result.step_used # Receiver balance check receiver_balance: int = self.get_balance(receiver.address) assert receiver_balance == value # Rollback the state to the previous block height block: 'Block' = self.icon_service_engine._get_last_block() assert prev_block.height == block.height - 2 self._rollback(prev_block) # Check if the balances of accounts are reverted for account in accounts: balance: int = self.get_balance(account.address) assert balance == 0 # Check if the balance of receiver is reverted to 0 receiver_balance: int = self.get_balance(receiver.address) assert receiver_balance == 0 # Check the last block self._check_if_last_block_is_reverted(prev_block)
def test_run_on_icx_received(self, create_address, tx_hash, step_price): from_ = create_address() to = create_address() value = icx_to_loop(5) step_limit = 2_000_000 step_used = step_limit init_balance = icx_to_loop(100) tx = Transaction( version=3, nid=1, tx_hash=tx_hash, from_=from_, to=to, value=value, step_limit=step_limit, ) tx_result = TransactionResult( tx_hash=tx_hash, status=1, tx_index=0, step_price=step_price, step_used=step_used, ) def func() -> Iterable[Tuple["Transaction", "TransactionResult"]]: yield tx, tx_result calculator = BalanceCalculator(to) balance, _ = calculator.run(func(), init_balance=init_balance) expected_balance = init_balance + value assert balance == expected_balance
def test_rollback_set_delegation(self): # Prevent icon_service_engine from sending RollbackRequest to rc IconScoreContext.engine.iiss.rollback_reward_calculator = Mock() accounts: List['EOAAccount'] = self.create_eoa_accounts(1) self.distribute_icx(accounts=accounts, init_balance=icx_to_loop(3000)) user_account = accounts[0] # Keep the previous states in order to compare with the rollback result prev_get_preps: dict = self.get_prep_list() prev_block: 'Block' = self.icon_service_engine._get_last_block() # Move 22th P-Rep up to 1st with setDelegation delegating: int = icx_to_loop(1) transactions = [] for i, account in enumerate(accounts): # Stake 100 icx tx = self.create_set_stake_tx(from_=user_account, value=icx_to_loop(100)) transactions.append(tx) # Delegate 1 icx to itself tx = self.create_set_delegation_tx( from_=account, origin_delegations=[(self._accounts[PREP_MAIN_PREPS - 1], delegating)]) transactions.append(tx) self.process_confirm_block_tx(transactions) # Check whether a setDelegation tx is done current_get_preps: dict = self.get_prep_list() assert current_get_preps["blockHeight"] == prev_block.height + 1 prev_prep_info: dict = prev_get_preps["preps"][PREP_MAIN_PREPS - 1] current_prep_info: dict = current_get_preps["preps"][0] for field in prev_prep_info: if field == "delegated": assert prev_prep_info[ field] == current_prep_info[field] - delegating else: assert prev_prep_info[field] == current_prep_info[field] # Rollback self._rollback(prev_block) current_get_preps: dict = self.get_prep_list() assert current_get_preps == prev_get_preps self._check_if_last_block_is_reverted(prev_block)
def _create_term(total_supply: int, total_delegated: int): return Term(sequence=0, start_block_height=100, period=43120, irep=icx_to_loop(50000), total_supply=total_supply, total_delegated=total_delegated)
def test_rollback_register_prep(self): # Prevent icon_service_engine from sending RollbackRequest to rc IconScoreContext.engine.iiss.rollback_reward_calculator = Mock() accounts: List['EOAAccount'] = self.create_eoa_accounts(1) self.distribute_icx(accounts=accounts, init_balance=icx_to_loop(3000)) # Keep the previous states in order to compare with the rollback result prev_get_preps: dict = self.get_prep_list() prev_block: 'Block' = self.icon_service_engine._get_last_block() # Register a new P-Rep transactions = [] for i, account in enumerate(accounts): # Register a P-Rep tx = self.create_register_prep_tx(from_=account) transactions.append(tx) self.process_confirm_block_tx(transactions) # Check whether a registerPRep tx is done current_get_preps: dict = self.get_prep_list() assert current_get_preps["blockHeight"] == prev_block.height + 1 assert len( current_get_preps["preps"]) == len(prev_get_preps["preps"]) + 1 # Rollback self._rollback(prev_block) current_get_preps: dict = self.get_prep_list() assert current_get_preps == prev_get_preps self._check_if_last_block_is_reverted(prev_block)
def create_dummy_preps(size: int, main_preps: int, elected_preps: int) -> 'PRepContainer': assert elected_preps <= size <= 1000 preps = PRepContainer() # Create dummy preps for i in range(size): address = Address.from_prefix_and_int(AddressPrefix.EOA, i) delegated = icx_to_loop(1000 - i) if i < main_preps: grade = PRepGrade.MAIN elif i < elected_preps: grade = PRepGrade.SUB else: grade = PRepGrade.CANDIDATE prep = PRep(address, grade=grade, block_height=i, delegated=delegated) prep.freeze() assert prep.grade == grade assert prep.delegated == delegated assert prep.block_height == i preps.add(prep) assert preps.size(active_prep_only=True) == size assert preps.size(active_prep_only=False) == size return preps
def test_rollback_icx_transfer(self): # Prevent icon_service_engine from sending RollbackRequest to rc IconScoreContext.engine.iiss.rollback_reward_calculator = Mock() # Inspect the current term response = self.get_prep_term() assert response["sequence"] == 2 prev_block: 'Block' = self.icon_service_engine._get_last_block() # Transfer 3000 icx to new 10 accounts init_balance = icx_to_loop(3000) accounts: List['EOAAccount'] = self.create_eoa_accounts(10) self.distribute_icx(accounts=accounts, init_balance=init_balance) for account in accounts: balance: int = self.get_balance(account.address) assert balance == init_balance # Rollback the state to the previous block height self._rollback(prev_block) # Check if the balances of accounts are reverted for account in accounts: balance: int = self.get_balance(account.address) assert balance == 0 # Check the last block self._check_if_last_block_is_reverted(prev_block)
def test_run_on_claim_iscore(self, address, tx_hash, step_price): score_address = ICON_SERVICE_ADDRESS value = icx_to_loop(0) step_limit = 2_000_000 step_used = step_limit init_balance = icx_to_loop(100) data_type = "call" data = Transaction.CallData("claimIScore", None) tx = Transaction( version=3, nid=1, tx_hash=tx_hash, from_=address, to=score_address, value=value, step_limit=step_limit, data_type=data_type, data=data, ) claimed_icx = icx_to_loop(6) claimed_iscore = claimed_icx * 1000 event_log = EventLog( score_address, indexed=["IScoreClaimed(int,int)"], data=[claimed_iscore, claimed_icx], ) tx_result = TransactionResult( tx_hash=tx_hash, status=1, tx_index=0, step_price=step_price, step_used=step_used, event_logs=[event_log], ) def func() -> Iterable[Tuple["Transaction", "TransactionResult"]]: yield tx, tx_result calculator = BalanceCalculator(address) balance, _ = calculator.run(func(), init_balance=init_balance) expected_balance = init_balance - step_price * step_used + claimed_icx assert balance == expected_balance
def test_run_on_set_stake(self, address, tx_hash, step_price): score_address = ICON_SERVICE_ADDRESS value = icx_to_loop(0) step_limit = 2_000_000 step_used = step_limit init_balance = icx_to_loop(200) data_type = "call" stake = icx_to_loop(100) data = Transaction.CallData(method="setStake", params={"value": hex(stake)}) tx = Transaction( version=3, nid=1, tx_hash=tx_hash, from_=address, to=score_address, value=value, step_limit=step_limit, data_type=data_type, data=data, ) tx_result = TransactionResult( tx_hash=tx_hash, status=TransactionResult.Status.SUCCESS, tx_index=0, step_price=step_price, step_used=step_used, ) def func() -> Iterable[Tuple["Transaction", "TransactionResult"]]: yield tx, tx_result calculator = BalanceCalculator(address) balance, stake_info = calculator.run(func(), init_balance=init_balance) expected_balance = init_balance - step_price * step_used assert balance == expected_balance assert stake_info.stake == stake assert stake_info.unstake == 0 assert stake_info.tx_hash == tx_hash
def test_invoke_v2_with_zero_fee_and_malformed_to_address(self): block_height = 1 block_hash = create_block_hash() block_timestamp = 0 tx_hash = create_tx_hash() value = 1 * 10**18 to = MalformedAddress.from_string('') fixed_fee: int = 10**16 tx_v2 = { 'method': 'icx_sendTransaction', 'params': { 'from': self._admin.address, 'to': to, 'value': value, 'fee': fixed_fee, 'timestamp': 1234567890, 'txHash': tx_hash } } block = Block(block_height, block_hash, block_timestamp, self.genesis_block.hash, 0) tx_results, state_root_hash, _, _, is_shutdown = self.icon_service_engine.invoke( block, [tx_v2]) self.assertIsInstance(state_root_hash, bytes) self.assertEqual(len(state_root_hash), 32) self.assertEqual(len(tx_results), 1) self.assertFalse(is_shutdown) tx_result: 'TransactionResult' = tx_results[0] self.assertIsNone(tx_result.failure) self.assertIsNone(tx_result.score_address) self.assertEqual(tx_result.status, 1) self.assertEqual(tx_result.block_height, block_height) self.assertEqual(tx_result.block_hash, block_hash) self.assertEqual(tx_result.tx_index, 0) self.assertEqual(tx_result.tx_hash, tx_hash) # step_used MUST BE 10**6 on protocol v2 self.assertEqual(tx_result.step_used, 10**6) self.assertEqual(tx_result.step_price, 0) # Write updated states to levelDB self.icon_service_engine.commit(block.height, block.hash, block.hash) # Check whether fee charging works well from_balance: int = self.get_balance(self._admin.address) to_balance: int = self.get_balance(to) fee = tx_result.step_price * tx_result.step_used self.assertEqual(0, fee) self.assertEqual(value, to_balance) self.assertEqual(from_balance, icx_to_loop(TOTAL_SUPPLY) - value - fee)
def test_invoke_v3_without_fee(self): block_height = 1 block_hash = create_block_hash() block_timestamp = 0 tx_hash = create_tx_hash() value = 1 * 10**18 tx_v3 = { 'method': 'icx_sendTransaction', 'params': { 'nid': 3, 'version': 3, 'from': self._admin.address, 'to': self._to, 'value': value, 'stepLimit': 1000000, 'timestamp': 1234567890, 'txHash': tx_hash } } block = Block(block_height, block_hash, block_timestamp, self.genesis_block.hash, 0) tx_results, state_root_hash, _, _, is_shutdown = self.icon_service_engine.invoke( block, [tx_v3]) self.assertIsInstance(state_root_hash, bytes) self.assertEqual(len(state_root_hash), 32) self.assertEqual(len(tx_results), 1) self.assertFalse(is_shutdown) tx_result: 'TransactionResult' = tx_results[0] self.assertIsNone(tx_result.failure) self.assertIsNone(tx_result.score_address) self.assertEqual(tx_result.status, 1) self.assertEqual(tx_result.block_height, block_height) self.assertEqual(tx_result.block_hash, block_hash) self.assertEqual(tx_result.tx_index, 0) self.assertEqual(tx_result.tx_hash, tx_hash) # step_used MUST BE 10**6 on protocol v2 self.assertEqual(tx_result.step_used, 10**6) self.assertEqual(tx_result.step_price, 0) self.icon_service_engine.commit(block.height, block.hash, block.hash) # Check whether fee charging works well from_balance: int = self.get_balance(self._admin.address) fee = tx_result.step_price * tx_result.step_used self.assertEqual(fee, 0) self.assertEqual(from_balance, icx_to_loop(TOTAL_SUPPLY) - value - fee)
def test_rollback_with_term_change(self): # Prevent icon_service_engine from sending RollbackRequest to rc IconScoreContext.engine.iiss.rollback_reward_calculator = Mock() main_prep_count = PREP_MAIN_PREPS elected_prep_count = PREP_MAIN_AND_SUB_PREPS calculate_period = self.CALCULATE_PERIOD # Inspect the current term term_2 = self.get_prep_term() assert term_2["sequence"] == 2 preps = term_2["preps"] term_start_block_height = term_2["startBlockHeight"] term_end_block_height = term_2["endBlockHeight"] _check_elected_prep_grades(preps, main_prep_count, elected_prep_count) main_preps: List['Address'] = _get_main_preps(preps, main_prep_count) rollback_block: 'Block' = self.icon_service_engine._get_last_block() assert rollback_block.height == term_start_block_height # Transfer 3000 icx to new 10 accounts init_balance = icx_to_loop(3000) accounts: List['EOAAccount'] = self.create_eoa_accounts(10) self.distribute_icx(accounts=accounts, init_balance=init_balance) for account in accounts: balance: int = self.get_balance(account.address) assert balance == init_balance count = term_end_block_height - self.get_last_block().height + 1 self.make_empty_blocks( count=count, prev_block_generator=main_preps[0], prev_block_validators=[address for address in main_preps[1:]]) # TERM-3: Nothing term_3: dict = self.get_prep_term() assert term_3["sequence"] == 3 assert term_3["startBlockHeight"] == self.get_last_block().height self._rollback(rollback_block) term: dict = self.get_prep_term() assert term == term_2 # Check if the balances of accounts are reverted for account in accounts: balance: int = self.get_balance(account.address) assert balance == 0
def create_sender_account(stake: int): total_delegating = 0 old_delegations: List[Tuple['Address', int], ...] = [] for i in range(IISS_MAX_DELEGATIONS): value = i + 1 address = Address.from_prefix_and_int(AddressPrefix.EOA, value) old_delegations.append((address, value)) total_delegating += value sender_address = SENDER_ADDRESS return create_account( address=sender_address, balance=icx_to_loop(10), stake=stake, unstake=0, unstake_block_height=0, delegated_amount=0, delegations=old_delegations)
def test_change_block_hash_before_iiss1(self): tx_list = [] tx = self.create_transfer_icx_tx(from_=self._admin, to_=self._accounts[0], value=icx_to_loop(1)) tx_list.append(tx) block, _ = self.make_and_req_block(tx_list=tx_list) new_block_hash = create_block_hash() self._write_precommit_state_in_leader(block_height=block.height, old_block_hash=block.hash, new_block_hash=new_block_hash) self.assertEqual(self.get_last_block().hash, new_block_hash) self.assertEqual(IconScoreContext.storage.icx.last_block.hash, new_block_hash)
def _create_preps(size: int): preps = PRepContainer() # Create dummy preps for i in range(size): address = Address.from_prefix_and_int(AddressPrefix.EOA, i) delegated = icx_to_loop(1000 - i) prep = PRep(address, block_height=i, delegated=delegated) prep.freeze() assert prep.grade == PRepGrade.CANDIDATE assert prep.delegated == delegated assert prep.block_height == i preps.add(prep) return preps
def _genesis_invoke(self) -> tuple: tx_hash = create_tx_hash() timestamp_us = create_timestamp() request_params = { 'txHash': tx_hash, 'version': self._version, 'timestamp': timestamp_us } tx = { 'method': 'icx_sendTransaction', 'params': request_params, 'genesisData': { "accounts": [ { "name": "genesis", "address": self._genesis, "balance": 0 }, { "name": "fee_treasury", "address": self._fee_treasury, "balance": 0 }, { "name": "_admin", "address": self._admin.address, "balance": icx_to_loop(TOTAL_SUPPLY) } ] }, } block_hash = create_block_hash() block = Block(self._block_height + 1, block_hash, timestamp_us, None, 0) invoke_response: tuple = self.icon_service_engine.invoke( block, [tx] ) self.icon_service_engine.commit(block.height, block.hash, None) self._block_height += 1 self._prev_block_hash = block_hash return invoke_response
def test_from_dict(self, address, block_hash, tx_hash, timestamp): from_ = address to = Address.from_string("cx0000000000000000000000000000000000000000") version = 0x3 nid = 0x1 step_limit = 0x1A2C0 data_type = "call" signature = "Ot+ouYw5Fdb4XkfODSv+8X3q7Kn8Fse4D51nLmzY62cPgR/5HZ26JTMCxO6D44pbbCumy8vS6e70XdB+ddL/mwA=" method = "setStake" params = {"value": hex(icx_to_loop(2))} tx_data = { "version": hex(version), "nid": hex(nid), "from": str(from_), "to": str(to), "stepLimit": hex(step_limit), "timestamp": hex(timestamp), "dataType": data_type, "data": { "method": method, "params": params }, "signature": signature, "txHash": bytes_to_hex(tx_hash), } tx = Transaction.from_dict(tx_data) assert tx.version == version assert tx.nid == nid assert tx.from_ == from_ assert tx.to == to assert tx.value == 0 assert tx.timestamp == timestamp assert tx._step_limit == step_limit assert tx.tx_hash == tx_hash assert tx.nonce is None assert tx.data_type == data_type assert isinstance(tx.data, Transaction.CallData) assert tx.data.method == method assert tx.data.params == params
def setUp(self) -> None: context = Mock() self.total_supply = icx_to_loop(800_460_000) self.total_delegated = 0 main_prep_count = PREP_MAIN_PREPS elected_prep_count = PREP_MAIN_AND_SUB_PREPS sub_prep_count = elected_prep_count - main_prep_count new_preps: 'PRepContainer' = _create_preps(size=elected_prep_count * 2) term = Term(sequence=0, start_block_height=100, period=43120, irep=icx_to_loop(50000), total_supply=self.total_supply, total_delegated=self.total_delegated) term.set_preps(new_preps, main_prep_count, elected_prep_count) assert len(term.main_preps) == main_prep_count assert len(term.sub_preps) == elected_prep_count - main_prep_count assert len(term) == elected_prep_count # Case 0: Network has just decentralized without any delegation PRepEngine._update_prep_grades(context, new_preps=new_preps, old_term=None, new_term=term) assert len(term.main_preps) == main_prep_count assert len(term.sub_preps) == sub_prep_count assert len(term) == elected_prep_count assert len(term) == len(context.storage.prep.put_prep.mock_calls) _check_prep_grades(new_preps, main_prep_count, len(term)) self.term = term self.preps = new_preps self.main_prep_count = PREP_MAIN_PREPS self.elected_prep_count = PREP_MAIN_AND_SUB_PREPS self.sub_prep_count = PREP_MAIN_AND_SUB_PREPS - PREP_MAIN_PREPS
def prep_engine(): preps = utils.create_dummy_preps(size=TOTAL_PREPS, main_preps=MAIN_PREPS, elected_preps=ELECTED_PREPS) preps.freeze() assert preps.is_frozen() assert not preps.is_dirty() term = Term(sequence=0, start_block_height=100, period=TERM_PERIOD, irep=icx_to_loop(50000), total_supply=preps.total_delegated, total_delegated=preps.total_delegated) term.set_preps(preps, MAIN_PREPS, ELECTED_PREPS) term.freeze() assert term.is_frozen() assert not term.is_dirty() prep_engine = PRepEngine() prep_engine.preps = preps prep_engine.term = term prep_engine.prep_address_converter = mock.Mock()() return prep_engine
def test_invoke_v2_with_malformed_to_address_and_type_converter(self): to = '' to_address = MalformedAddress.from_string(to) fixed_fee: int = 10**16 value = 1 * 10**18 block_height = 1 block_hash: bytes = create_block_hash(b'block') prev_block_hash: bytes = self.genesis_block.hash tx_hash: bytes = create_tx_hash(b'tx') timestamp: int = int(time.time() * 1000) request = { 'block': { 'blockHeight': hex(block_height), 'blockHash': block_hash.hex(), 'prevBlockHash': prev_block_hash.hex(), 'timestamp': str(timestamp) }, 'transactions': [{ 'method': 'icx_sendTransaction', 'params': { 'from': str(self._admin.address), 'to': to, 'fee': hex(fixed_fee), 'value': hex(value), 'timestamp': '0x574024617ae39', 'nonce': '0x1', 'signature': 'yKMiB12Os0ZK9+XYiBSwydvMXA0y/LS9HzmZwtczQ1VAK98/mGUOmpwTjByFArjdkx72GOWIOzu6eqyZnKeHBAE=', 'txHash': tx_hash.hex() } }] } params = TypeConverter.convert(request, ParamType.INVOKE) converted_block_params = params['block'] block = Block.from_dict(converted_block_params) self.assertEqual(block_height, block.height) self.assertEqual(block_hash, block.hash) self.assertEqual(prev_block_hash, block.prev_hash) self.assertEqual(timestamp, block.timestamp) transactions: list = params['transactions'] self.assertIsInstance(transactions[0]['params']['to'], MalformedAddress) tx_results, state_root_hash, _, _, is_shutdown = self.icon_service_engine.invoke( block, transactions) self.assertIsInstance(state_root_hash, bytes) self.assertEqual(len(state_root_hash), 32) self.assertEqual(len(tx_results), 1) self.assertFalse(is_shutdown) tx_result: 'TransactionResult' = tx_results[0] self.assertIsNone(tx_result.failure) self.assertIsNone(tx_result.score_address) self.assertEqual(tx_result.status, 1) self.assertEqual(tx_result.block_height, block_height) self.assertEqual(tx_result.block_hash, block_hash) self.assertEqual(tx_result.tx_index, 0) self.assertEqual(tx_result.tx_hash, tx_hash) # step_used MUST BE 10**6 on protocol v2 self.assertEqual(tx_result.step_used, 10**6) self.assertEqual(tx_result.step_price, 0) # Write updated states to levelDB self.icon_service_engine.commit(block.height, block.hash, block.hash) # Check whether fee charging works well from_balance: int = self.get_balance(self._admin.address) to_balance: int = self.get_balance(to_address) fee = tx_result.step_price * tx_result.step_used self.assertEqual(0, fee) self.assertEqual(value, to_balance) self.assertEqual(from_balance, icx_to_loop(TOTAL_SUPPLY) - value - fee)
def test_change_block_hash3(self): """ about commit, rollback :return: """ self.init_decentralized() self.transfer_icx(from_=self._admin.address, to_=self._accounts[0], value=icx_to_loop(1)) tx_list = [] tx = self.create_transfer_icx_tx(from_=self._admin, to_=self._accounts[0], value=icx_to_loop(5)) tx_list.append(tx) block_height = 10**2 icx = 10**3 iscore = icx * 10**3 RewardCalcProxy.claim_iscore = Mock(return_value=(iscore, block_height)) RewardCalcProxy.commit_claim = Mock() tx = self.create_claim_tx(from_=self._accounts[0]) tx_list.append(tx) last_block = self.get_last_block() block, tx_rets = self.make_and_req_block(tx_list=tx_list) new_hash: bytes = create_block_hash() self._write_precommit_state_in_leader(block_height=block.height, old_block_hash=block.hash, new_block_hash=new_hash) m = RewardCalcProxy.commit_block actual_height = m.call_args[0][1] actual_hash = m.call_args[0][2] assert block.height == actual_height assert block.hash == actual_hash m = RewardCalcProxy.commit_claim actual_height = m.call_args[0][2] actual_hash = m.call_args[0][3] assert block.height == actual_height assert block.hash == actual_hash RewardCalcProxy.rollback = Mock(return_value=(True, last_block.height, last_block.hash)) self.rollback(block_height=last_block.height, block_hash=last_block.hash) m = RewardCalcProxy.rollback actual_height = m.call_args[0][0] actual_hash = m.call_args[0][1] assert last_block.height == actual_height assert last_block.hash == actual_hash
def test_rollback_score_state(self): # Prevent icon_service_engine from sending RollbackRequest to rc IconScoreContext.engine.iiss.rollback_reward_calculator = Mock() init_balance = icx_to_loop(100) deploy_step_limit = 2 * 10**9 sender_account: 'EOAAccount' = self.create_eoa_account() sender_address: 'Address' = sender_account.address score_value = 1234 deploy_params = {"value": hex(score_value)} # Transfer 10 ICX to sender_account self.distribute_icx([sender_account], init_balance=init_balance) # Save the balance of sender address balance: int = self.get_balance(sender_address) assert init_balance == balance # Deploy a SCORE tx: dict = self.create_deploy_score_tx( score_root="sample_deploy_scores", score_name="install/sample_score", from_=sender_address, to_=ZERO_SCORE_ADDRESS, deploy_params=deploy_params, step_limit=deploy_step_limit) tx_results: List['TransactionResult'] = self.process_confirm_block( tx_list=[tx]) # Skip tx_result[0]. It is the result of a base transaction tx_result: 'TransactionResult' = tx_results[1] score_address: 'Address' = tx_result.score_address assert isinstance(score_address, Address) assert score_address.is_contract # Check if the score works well with a query request response = self.query_score(from_=sender_address, to_=score_address, func_name="get_value") assert response == score_value # Check the balance is reduced balance: int = self.get_balance(sender_address) assert init_balance == balance + tx_result.step_price * tx_result.step_used # Save the previous block prev_block: 'Block' = self.icon_service_engine._get_last_block() # Send a transaction to change the score state old_balance = balance tx_results: List['TransactionResult'] = self.score_call( from_=sender_address, to_=score_address, func_name="increase_value", step_limit=10**8, expected_status=True) tx_result: 'TransactionResult' = tx_results[1] assert tx_result.step_used > 0 assert tx_result.step_price > 0 assert tx_result.to == score_address balance: int = self.get_balance(sender_address) assert old_balance == balance + tx_result.step_used * tx_result.step_price # Check if the score works well with a query request response = self.query_score(from_=sender_address, to_=score_address, func_name="get_value") assert response == score_value + 1 # Rollback: Go back to the block where a score has not been deployed yet self._rollback(prev_block) # Check if the score state is reverted response = self.query_score(from_=sender_address, to_=score_address, func_name="get_value") assert response == score_value
def test_replace_prep(self): """ scenario 1 when it starts new preps on new term, normal case, while 100 block. expected : all new preps have maintained until 100 block because it already passed GRACE_PERIOD """ main_prep_count = PREP_MAIN_PREPS elected_prep_count = PREP_MAIN_AND_SUB_PREPS total_prep_count = elected_prep_count * 2 calculate_period = self.CALCULATE_PERIOD # Inspect the current term response = self.get_prep_term() assert response["sequence"] == 2 self.distribute_icx(accounts=self._accounts[:PREP_MAIN_PREPS], init_balance=icx_to_loop(1)) # Distribute 3000 icx to new 100 accounts accounts: List['EOAAccount'] = self.create_eoa_accounts(total_prep_count) self.distribute_icx(accounts=accounts, init_balance=icx_to_loop(3000)) transactions = [] for i, account in enumerate(accounts): # Register a P-Rep tx = self.create_register_prep_tx(from_=account) transactions.append(tx) # Stake 100 icx tx = self.create_set_stake_tx(from_=account, value=icx_to_loop(100)) transactions.append(tx) # Delegate 1 icx to itself tx = self.create_set_delegation_tx( from_=account, origin_delegations=[ (account, icx_to_loop(1)) ] ) transactions.append(tx) self.process_confirm_block_tx(transactions) self.make_blocks_to_end_calculation() self.make_empty_blocks(1) # TERM-3: Nothing term_3: dict = self.get_prep_term() assert term_3["sequence"] == 3 preps = term_3["preps"] _check_elected_prep_grades(preps, main_prep_count, elected_prep_count) main_preps_3: List['Address'] = _get_main_preps(preps, main_prep_count) assert term_3["totalDelegated"] == icx_to_loop(1) * total_prep_count # Check if block validation statistics works well self.make_empty_blocks( count=calculate_period, prev_block_generator=main_preps_3[0], prev_block_validators=[address for address in main_preps_3[1:]] ) # All main P-Reps succeeded to validate all blocks in a term for i, address in enumerate(main_preps_3): assert address == accounts[i].address response = self.get_prep(address) assert response["totalBlocks"] == calculate_period assert response["validatedBlocks"] == calculate_period assert response["unvalidatedSequenceBlocks"] == 0 # TERM-4: Block validation penalty ----------------------------------------- account_on_block_validation_penalty: 'EOAAccount' = accounts[1] term_4: dict = self.get_prep_term() assert term_4["sequence"] == 4 preps = term_4["preps"] _check_elected_prep_grades(preps, main_prep_count, elected_prep_count) main_preps_4: List['Address'] = _get_main_preps(preps, main_prep_count) assert main_preps_3 == main_preps_4 self.make_empty_blocks( count=self.BLOCK_VALIDATION_PENALTY_THRESHOLD + 1, prev_block_generator=main_preps_4[0], prev_block_validators=[ address for address in main_preps_4[1:] if address != account_on_block_validation_penalty.address ] ) term_4: dict = self.get_prep_term() assert term_4["sequence"] == 4 preps = term_4["preps"] # A main P-Rep got penalized for consecutive 660 block validation failure _check_elected_prep_grades(preps, main_prep_count, elected_prep_count - 1) main_preps_4: List['Address'] = _get_main_preps(preps, main_prep_count) # The first sub P-Rep replaced the the second main P-Rep assert main_preps_4[1] == accounts[main_prep_count].address assert main_preps_4[1] != account_on_block_validation_penalty prep_on_penalty: dict = self.get_prep(account_on_block_validation_penalty.address) assert prep_on_penalty["status"] == PRepStatus.ACTIVE.value assert prep_on_penalty["penalty"] == PenaltyReason.BLOCK_VALIDATION.value assert prep_on_penalty["unvalidatedSequenceBlocks"] == self.BLOCK_VALIDATION_PENALTY_THRESHOLD + 1 assert prep_on_penalty["totalBlocks"] == \ prep_on_penalty["validatedBlocks"] + \ prep_on_penalty["unvalidatedSequenceBlocks"] # checks if adding the prep receiving a block validation penalty on preps of getPRepTerm API self._check_preps_on_get_prep_term([prep_on_penalty]) count = term_4["endBlockHeight"] - term_4["blockHeight"] + 1 self.make_empty_blocks( count=count, prev_block_generator=main_preps_4[0], prev_block_validators=main_preps_4[1:] ) # Term-5: Unregister P-Rep # accounts[1] prep returns to the main P-Rep group term_5 = self.get_prep_term() assert term_5["sequence"] == 5 preps = term_5["preps"] _check_elected_prep_grades(preps, main_prep_count, elected_prep_count) main_preps_5: List['Address'] = _get_main_preps(preps, main_prep_count) assert main_preps_5[1] == account_on_block_validation_penalty.address prep = self.get_prep(account_on_block_validation_penalty.address) assert prep["penalty"] == PenaltyReason.NONE.value assert prep["unvalidatedSequenceBlocks"] == 0 assert prep["grade"] == PRepGrade.MAIN.value assert prep["totalBlocks"] == prep_on_penalty["totalBlocks"] assert prep["validatedBlocks"] == prep_on_penalty["validatedBlocks"] index = 2 unregistered_account = accounts[index] assert main_preps_5[index] == accounts[index].address self.unregister_prep(unregistered_account, expected_status=True, prev_block_generator=main_preps_5[0], prev_block_validators=main_preps_5) # Changed main P-Rep list are applied to the next block self.make_empty_blocks(1, prev_block_generator=main_preps_5[0], prev_block_validators=[ address for address in main_preps_5 if address != unregistered_account ]) unregistered_prep: dict = self.get_prep(unregistered_account.address) assert unregistered_prep["status"] == PRepStatus.UNREGISTERED.value assert unregistered_prep["grade"] == PRepGrade.CANDIDATE.value assert unregistered_prep["penalty"] == PenaltyReason.NONE.value term_5 = self.get_prep_term() preps = term_5["preps"] # checks if adding the unregistered prep on preps of getPRepTerm API (1) self._check_preps_on_get_prep_term([]) _check_elected_prep_grades(preps, main_prep_count, elected_prep_count - 1) main_preps_5: List['Address'] = _get_main_preps(preps, main_prep_count) assert preps[index]["address"] != unregistered_account.address assert preps[index]["address"] == accounts[main_prep_count].address count = term_5["endBlockHeight"] - term_5["blockHeight"] + 1 self.make_empty_blocks(count, prev_block_generator=main_preps_5[0], prev_block_validators=[prep for prep in main_preps_5]) # TERM-6: Low productivity penalty account_on_low_productivity_penalty: 'EOAAccount' = account_on_block_validation_penalty term_6 = self.get_prep_term() assert term_6["sequence"] == 6 preps = term_6["preps"] # checks if adding the unregistered prep on preps of getPRepTerm API (2) self._check_preps_on_get_prep_term([]) _check_elected_prep_grades(preps, main_prep_count, elected_prep_count) main_preps_6: List['Address'] = _get_main_preps(preps, main_prep_count) self.make_empty_blocks( count=2, prev_block_generator=main_preps_6[0], prev_block_validators=[ address for address in main_preps_6 if address != account_on_low_productivity_penalty.address ] ) prep_on_penalty = self.get_prep(account_on_low_productivity_penalty) assert prep_on_penalty["status"] == PRepStatus.DISQUALIFIED.value assert prep_on_penalty["penalty"] == PenaltyReason.LOW_PRODUCTIVITY.value assert prep_on_penalty["unvalidatedSequenceBlocks"] == 2 assert prep_on_penalty["grade"] == PRepGrade.CANDIDATE.value assert prep_on_penalty["validatedBlocks"] * 100 // prep_on_penalty["totalBlocks"] < \ self.LOW_PRODUCTIVITY_PENALTY_THRESHOLD term_6 = self.get_prep_term() preps = term_6["preps"] # checks if adding the prep receiving a low productivity penalty on preps of getPRepTerm API self._check_preps_on_get_prep_term([]) _check_elected_prep_grades(preps, main_prep_count, elected_prep_count - 1) main_preps_6: List['Address'] = _get_main_preps(preps, main_prep_count) assert main_preps_6[1] != account_on_low_productivity_penalty.address assert main_preps_6[1] == accounts[main_prep_count + 1].address count = term_6["endBlockHeight"] - term_6["blockHeight"] + 1 self.make_empty_blocks(count, prev_block_generator=main_preps_6[0], prev_block_validators=[prep for prep in main_preps_6]) # TERM-7: Disqualify P-Rep account_on_disqualification = accounts[main_prep_count + 1] term_7 = self.get_prep_term() assert term_7["sequence"] == 7 preps = term_7["preps"] _check_elected_prep_grades(preps, main_prep_count, elected_prep_count) main_preps_7: List['Address'] = _get_main_preps(preps, main_prep_count) assert main_preps_7[-1] == account_on_disqualification.address tx_result: 'TransactionResult' = self.register_proposal( main_preps_7[0], title="P-Rep Disqualification", description="the P-Rep is malicious", type_=ProposalType.PREP_DISQUALIFICATION.value, value={"address": str(account_on_disqualification.address)}) assert tx_result.status == TransactionResult.SUCCESS assert len(main_preps_7) == main_prep_count tx_hash: bytes = tx_result.tx_hash transactions = [] for i, prep in enumerate(main_preps_7[1:]): vote: bool = prep != account_on_disqualification tx = self.create_vote_proposal_tx(from_=prep, id_=tx_hash, vote=vote) transactions.append(tx) tx_results: List['TransactionResult'] = self.process_confirm_block( transactions, prev_block_generator=main_preps_7[0], prev_block_validators=main_preps_7[1:] ) assert tx_results[-1].status == TransactionResult.FAILURE prep_on_disqualification_penalty = self.get_prep(account_on_disqualification) assert prep_on_disqualification_penalty["status"] == PRepStatus.DISQUALIFIED.value assert prep_on_disqualification_penalty["grade"] == PRepGrade.CANDIDATE.value assert prep_on_disqualification_penalty["penalty"] == PenaltyReason.PREP_DISQUALIFICATION.value term_7_1 = self.get_prep_term() assert term_7_1["sequence"] == 7 preps = term_7_1["preps"] # checks if adding the prep receiving a disqualification penalty on preps of getPRepTerm API self._check_preps_on_get_prep_term([]) _check_elected_prep_grades(preps, main_prep_count, elected_prep_count - 1) main_preps_7: List['Address'] = _get_main_preps(preps, main_prep_count) assert main_preps_7[-1] != account_on_disqualification.address # The first sub P-Rep replaces the main P-Rep which is disqualified by network proposal assert main_preps_7[-1] == term_7["preps"][main_prep_count]["address"]
def test_rollback_score_deploy(self): # Prevent icon_service_engine from sending RollbackRequest to rc IconScoreContext.engine.iiss.rollback_reward_calculator = Mock() init_balance = icx_to_loop(100) deploy_step_limit = 2 * 10**9 sender_account: 'EOAAccount' = self.create_eoa_account() sender_address: 'Address' = sender_account.address # Transfer 10 ICX to sender_account self.distribute_icx([sender_account], init_balance=init_balance) # Save the balance of sender address balance: int = self.get_balance(sender_address) assert init_balance == balance # Save the previous block prev_block: 'Block' = self.icon_service_engine._get_last_block() # Deploy a SCORE tx: dict = self.create_deploy_score_tx( score_root="sample_deploy_scores", score_name="install/sample_score", from_=sender_address, to_=ZERO_SCORE_ADDRESS, step_limit=deploy_step_limit) tx_results: List['TransactionResult'] = self.process_confirm_block( tx_list=[tx]) # Skip tx_result[0]. It is the result of a base transaction tx_result: 'TransactionResult' = tx_results[1] score_address: 'Address' = tx_result.score_address assert isinstance(score_address, Address) assert score_address.is_contract # Check if the score works well with a query request response = self.query_score(from_=sender_address, to_=score_address, func_name="hello") assert response == "Hello" # Check the balance is reduced balance: int = self.get_balance(sender_address) assert init_balance == balance + tx_result.step_price * tx_result.step_used # Rollback: Go back to the block where a score has not been deployed yet self._rollback(prev_block) # Check if the score deployment is revoked successfully with pytest.raises(ScoreNotFoundException): self.query_score(from_=sender_address, to_=score_address, func_name="hello") # Check if the balance of sender address is revoked balance: int = self.get_balance(sender_address) assert init_balance == balance # Deploy the same SCORE again tx: dict = self.create_deploy_score_tx( score_root="sample_deploy_scores", score_name="install/sample_score", from_=sender_address, to_=ZERO_SCORE_ADDRESS, step_limit=deploy_step_limit) tx_results: List['TransactionResult'] = self.process_confirm_block( tx_list=[tx]) # Skip tx_result[0]. It is the result of a base transaction tx_result: 'TransactionResult' = tx_results[1] new_score_address = tx_result.score_address assert isinstance(score_address, Address) assert new_score_address.is_contract assert score_address != new_score_address # Check if the score works well with a query request response = self.query_score(from_=sender_address, to_=new_score_address, func_name="hello") assert response == "Hello"
def test_handle_get_prep_term_with_penalized_preps(self): block_height = 200 sequence = 78 period = 43120 start_block_height = 200 end_block_height = 200 + period - 1 irep = icx_to_loop(40000) total_supply = icx_to_loop(800_460_000) total_delegated = icx_to_loop(1000) params = {} context = Mock() context.block.height = block_height main_prep_count = 22 elected_prep_count = 100 total_prep_count = 106 term = Term(sequence=sequence, start_block_height=start_block_height, period=period, irep=irep, total_supply=total_supply, total_delegated=total_delegated) preps = PRepContainer() for i in range(total_prep_count): address = Address.from_prefix_and_int(AddressPrefix.EOA, i) delegated = icx_to_loop(1000 - i) penalty = PenaltyReason.NONE status = PRepStatus.ACTIVE if 0 <= i <= 4: # block validation penalty preps: 5 penalty: 'PenaltyReason' = PenaltyReason.BLOCK_VALIDATION elif i == 5: # unregistered preps: 1 status = PRepStatus.UNREGISTERED elif 6 <= i <= 7: # low productivity preps: 2 status = PRepStatus.DISQUALIFIED penalty = PenaltyReason.LOW_PRODUCTIVITY elif 8 <= i <= 10: # disqualified preps: 3 status = PRepStatus.DISQUALIFIED penalty = PenaltyReason.PREP_DISQUALIFICATION prep = PRep(address, block_height=i, delegated=delegated, penalty=penalty, status=status) prep.freeze() preps.add(prep) preps.freeze() assert preps.size(active_prep_only=False) == total_prep_count electable_preps = filter(lambda x: x.is_electable(), preps) term.set_preps(electable_preps, main_prep_count=main_prep_count, elected_prep_count=elected_prep_count) engine = PRepEngine() engine.term = term engine.preps = preps ret: dict = engine.handle_get_prep_term(context) assert ret["blockHeight"] == block_height assert ret["sequence"] == sequence assert ret["startBlockHeight"] == start_block_height assert ret["endBlockHeight"] == end_block_height assert ret["totalSupply"] == total_supply assert ret["totalDelegated"] == total_delegated assert ret["irep"] == irep prep_list: List[Dict[str, Union[int, str, 'Address']]] = ret["preps"] assert len(prep_list) == elected_prep_count for i, prep_snapshot in enumerate(term.preps): prep_item: Dict[str, Union[int, str, 'Address']] = prep_list[i] assert prep_item["address"] == prep_snapshot.address 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_send_icx2(self): from_: 'Address' = self._admin.address default_step_cost = 100_000 input_step_cost = 200 step_price = 10**10 revision = Revision.LATEST.value self.update_governance() self.set_revision(Revision.LATEST.value) # Estimate the step limit of icx transfer tx step_limit = self._calculate_step_limit( revision, data=None, default_step_cost=default_step_cost, input_step_cost=input_step_cost) # The latest confirmed block root_block = self.get_last_block() # Check that "from_" address has enough icx to transfer from_balance: int = self.get_balance(from_) self.assertTrue(from_balance > 0) # Prepare empty addresses count = 3 parent_addresses = [] child_addresses = [] for _ in range(count): address: 'Address' = create_address() balance: int = self.get_balance(address) assert balance == 0 parent_addresses.append(address) address: 'Address' = create_address() balance: int = self.get_balance(address) assert balance == 0 child_addresses.append(address) parent_blocks = [] child_blocks = [] # from_ sends 10 ICX to addresses[0] for i in range(count): balance = self.get_balance(from_) assert balance == from_balance value = icx_to_loop(1) # Root -> Parent ======================================== tx = self.create_transfer_icx_tx(from_=from_, to_=parent_addresses[i], value=value, disable_pre_validate=False, support_v2=False, step_limit=step_limit) block, hash_list = self.make_and_req_block_for_2_depth_invocation( [tx], prev_block=root_block) parent_blocks.append(block) # Root -> Parent -> Child ===================================== value //= 2 tx = self.create_transfer_icx_tx(from_=parent_addresses[i], to_=child_addresses[i], value=value, disable_pre_validate=True, support_v2=False, step_limit=step_limit) block, hash_list = self.make_and_req_block_for_2_depth_invocation( [tx], prev_block=block) child_blocks.append(block) index = 0 block = parent_blocks[index] self._write_precommit_state(block) precommit_data_manager = self.icon_service_engine._precommit_data_manager for i in range(count): balance = self.get_balance(parent_addresses[i]) assert balance == (icx_to_loop(1) if i == index else 0) assert self.get_balance(child_addresses[i]) == 0 if i == index: assert precommit_data_manager.get(parent_blocks[i].hash) assert precommit_data_manager.get(child_blocks[i].hash) else: assert precommit_data_manager.get( parent_blocks[i].hash) is None assert precommit_data_manager.get(child_blocks[i].hash) is None last_block: 'Block' = precommit_data_manager.last_block parent_blocks[index].cumulative_fee = step_limit * step_price assert len(precommit_data_manager) == 2 assert last_block == parent_blocks[index]
def test_send_icx(self): from_: 'Address' = self._admin.address step_price = 10**10 default_step_cost = 100_000 input_step_cost = 200 value = icx_to_loop(7) self.update_governance() for revision in range(Revision.THREE.value, Revision.LATEST.value + 1): self.set_revision(revision) # The latest confirmed block root_block = self.get_last_block() # Check that "from_" address has enough icx to transfer balance0: int = self.get_balance(from_) self.assertTrue(balance0 > value) # Check "to" address balance. It should be 0 addresses = [] for _ in range(2): address: 'Address' = create_address() balance: int = self.get_balance(address) assert balance == 0 addresses.append(address) # Estimate the step limit of icx transfer tx step_limit = self._calculate_step_limit( revision, data=None, default_step_cost=default_step_cost, input_step_cost=input_step_cost) # Root -> Parent ======================================== # from_ sends 10 ICX to addresses[0] tx = self.create_transfer_icx_tx(from_=from_, to_=addresses[0], value=value, disable_pre_validate=False, support_v2=False, step_limit=step_limit) prev_block = root_block block, hash_list = self.make_and_req_block_for_2_depth_invocation( [tx], prev_block=prev_block) assert block.prev_hash == prev_block.hash assert block.height == prev_block.height + 1 parent_block = block # Before confirming a parent block for address in addresses: balance = self.get_balance(address) assert balance == 0 # Root -> Parent -> Child ===================================== prev_block = block # addresses[0] sends 5 ICX to addresses[1] tx = self.create_transfer_icx_tx(from_=addresses[0], to_=addresses[1], value=icx_to_loop(5), disable_pre_validate=True, support_v2=False, step_limit=step_limit) block, hash_list = self.make_and_req_block_for_2_depth_invocation( [tx], prev_block=prev_block) assert block.prev_hash == prev_block.hash assert block.height == prev_block.height + 1 child_block = block # Before confirming a parent block for address in addresses: balance = self.get_balance(address) assert balance == 0 self._write_precommit_state(parent_block) balance = self.get_balance(addresses[0]) assert balance == icx_to_loop(7) balance = self.get_balance(addresses[1]) assert balance == 0 self._write_precommit_state(child_block) balance = self.get_balance(addresses[0]) assert balance < icx_to_loop(5) balance = self.get_balance(addresses[1]) assert balance == icx_to_loop(5)
def init_decentralized(self): # decentralized self.update_governance() # set Revision REV_IISS self.set_revision(Revision.IISS.value) total_supply = icx_to_loop(TOTAL_SUPPLY) # Minimum_delegate_amount is 0.02 * total_supply # In this test delegate 0.03*total_supply because `Issue transaction` exists since REV_IISS minimum_delegate_amount_for_decentralization: int = total_supply * 2 // 1000 + 1 init_balance: int = minimum_delegate_amount_for_decentralization * 2 # distribute icx PREP_MAIN_PREPS ~ PREP_MAIN_PREPS + PREP_MAIN_PREPS - 1 self.distribute_icx( accounts=self._accounts[PREP_MAIN_PREPS:PREP_MAIN_AND_SUB_PREPS], init_balance=init_balance) # stake PREP_MAIN_PREPS ~ PREP_MAIN_PREPS + PREP_MAIN_PREPS - 1 stake_amount: int = minimum_delegate_amount_for_decentralization tx_list: list = [] for i in range(PREP_MAIN_PREPS): tx: dict = self.create_set_stake_tx( from_=self._accounts[PREP_MAIN_PREPS + i], value=stake_amount) tx_list.append(tx) self.process_confirm_block_tx(tx_list) # distribute 3000 icx to the self._accounts # which range from 0 to PREP_MAIN_PREPS, exclusive self.distribute_icx(accounts=self._accounts[:PREP_MAIN_PREPS], init_balance=icx_to_loop(3000)) # register PRep tx_list: list = [] for account in self._accounts[:PREP_MAIN_PREPS]: tx: dict = self.create_register_prep_tx(from_=account) tx_list.append(tx) self.process_confirm_block_tx(tx_list) # delegate to PRep tx_list: list = [] for i in range(PREP_MAIN_PREPS): tx: dict = self.create_set_delegation_tx( from_=self._accounts[PREP_MAIN_PREPS + i], origin_delegations=[ (self._accounts[i], minimum_delegate_amount_for_decentralization) ]) tx_list.append(tx) self.process_confirm_block_tx(tx_list) # get main prep response: dict = self.get_main_prep_list() expected_response: dict = {"preps": [], "totalDelegated": 0} self.assertEqual(expected_response, response) # set Revision REV_IISS (decentralization) self.set_revision(Revision.DECENTRALIZATION.value) # Update governance SCORE-1.0.0 to support network proposal self.update_governance("1_0_0", True) # make blocks to start decentralization self.make_blocks_to_end_calculation() # get main prep response: dict = self.get_main_prep_list() expected_preps: list = [] expected_total_delegated: int = 0 for account in self._accounts[:PREP_MAIN_PREPS]: expected_preps.append({ 'address': account.address, 'delegated': minimum_delegate_amount_for_decentralization }) expected_total_delegated += minimum_delegate_amount_for_decentralization expected_response: dict = { "preps": expected_preps, "totalDelegated": expected_total_delegated } self.assertEqual(expected_response, response) # delegate to PRep 0 tx_list: list = [] for account in self._accounts: tx: dict = self.create_set_delegation_tx(from_=account, origin_delegations=[]) tx_list.append(tx) self.process_confirm_block_tx(tx_list) self.make_blocks_to_end_calculation() # get main prep response: dict = self.get_main_prep_list() expected_preps: list = [] for account in self._accounts[:PREP_MAIN_PREPS]: expected_preps.append({'address': account.address, 'delegated': 0}) expected_response: dict = { "preps": expected_preps, "totalDelegated": 0 } self.assertEqual(expected_response, response) max_expired_block_height: int = self._config[ConfigKey.IISS_META_DATA][ ConfigKey.UN_STAKE_LOCK_MAX] self.make_blocks(self._block_height + max_expired_block_height + 1) tx_list: list = [] for account in self._accounts: tx: dict = self.create_set_stake_tx(from_=account, value=0) tx_list.append(tx) self.process_confirm_block_tx(tx_list) tx_list: list = [] step_price: int = self.get_step_price() fee: int = DEFAULT_STEP_LIMIT * step_price for account in self._accounts: balance: int = self.get_balance(account) if balance - fee > 0: tx: dict = self.create_transfer_icx_tx(from_=account, to_=self._admin, value=balance - fee) tx_list.append(tx) self.process_confirm_block_tx(tx_list)