Example #1
0
    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
Example #3
0
    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)
Example #4
0
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)
Example #5
0
    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)
Example #6
0
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
Example #7
0
    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
Example #10
0
    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)
Example #11
0
    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)
Example #12
0
    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
Example #13
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)
Example #14
0
    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)
Example #15
0
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
Example #16
0
    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
Example #17
0
    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
Example #18
0
    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
Example #20
0
    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)
Example #21
0
    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
Example #22
0
    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"]
Example #24
0
    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"
Example #25
0
    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)
Example #28
0
    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)