Exemple #1
0
    def test_proc_balance_mnt(self):
        default_addr = b"\x00" * 19 + b"\x34"
        token_id = 1234567
        token_id_bytes = token_id.to_bytes(32, byteorder="big")
        state = State()

        self.__mint(state, default_addr, token_id_bytes, encode_int32(2020))
        balance = state.get_balance(default_addr, token_id)
        self.assertEqual(balance, 2020)

        data = b"\x00" * 12 + default_addr + token_id_bytes
        # Gas not enough
        msg = Message(default_addr, default_addr, gas=399, data=data)
        ret_tuple = proc_balance_mnt(VmExtBase(state), msg)
        self.assertEqual(ret_tuple, (0, 0, []))

        # Success case
        testcases = [
            (default_addr, token_id, 2020),  # Balance already set
            (default_addr, 54321, 0),  # Non-existent token
            (Address.create_random_account(0).recipient, token_id, 0),  # Blank
        ]
        for addr, tid, bal in testcases:
            data = b"\x00" * 12 + addr + tid.to_bytes(32, byteorder="big")
            msg = Message(addr, addr, gas=500, data=data)
            result, gas_remained, ret = proc_balance_mnt(VmExtBase(state), msg)
            ret_int = int.from_bytes(ret, byteorder="big")
            self.assertEqual(result, 1)
            self.assertEqual(gas_remained, 500 - 400)
            self.assertEqual(ret_int, bal)
Exemple #2
0
    def create_minor_block(
        self, root_block: RootBlock, full_shard_id: int, evm_state: EvmState
    ) -> MinorBlock:
        """ Create genesis block for shard.
        Genesis block's hash_prev_root_block is set to the genesis root block.
        Genesis state will be committed to the given evm_state.
        Based on ALLOC, genesis_token will be added to initial accounts.
        """
        branch = Branch(full_shard_id)
        shard_config = self._qkc_config.shards[full_shard_id]
        genesis = shard_config.GENESIS

        for address_hex, alloc_amount in genesis.ALLOC.items():
            address = Address.create_from(bytes.fromhex(address_hex))
            check(
                self._qkc_config.get_full_shard_id_by_full_shard_key(
                    address.full_shard_key
                )
                == full_shard_id
            )
            evm_state.full_shard_key = address.full_shard_key
            for k, v in alloc_amount.items():
                evm_state.delta_token_balance(address.recipient, token_id_encode(k), v)

        evm_state.commit()

        meta = MinorBlockMeta(
            hash_merkle_root=bytes.fromhex(genesis.HASH_MERKLE_ROOT),
            hash_evm_state_root=evm_state.trie.root_hash,
            xshard_tx_cursor_info=XshardTxCursorInfo(root_block.header.height, 0, 0),
        )

        local_fee_rate = 1 - self._qkc_config.reward_tax_rate  # type: Fraction
        coinbase_tokens = {
            self._qkc_config.genesis_token: shard_config.COINBASE_AMOUNT
            * local_fee_rate.numerator
            // local_fee_rate.denominator
        }

        coinbase_address = Address.create_empty_account(full_shard_id)

        header = MinorBlockHeader(
            version=genesis.VERSION,
            height=genesis.HEIGHT,
            branch=branch,
            hash_prev_minor_block=bytes.fromhex(genesis.HASH_PREV_MINOR_BLOCK),
            hash_prev_root_block=root_block.header.get_hash(),
            evm_gas_limit=genesis.GAS_LIMIT,
            hash_meta=sha3_256(meta.serialize()),
            coinbase_amount_map=TokenBalanceMap(coinbase_tokens),
            coinbase_address=coinbase_address,
            create_time=genesis.TIMESTAMP,
            difficulty=genesis.DIFFICULTY,
            extra_data=bytes.fromhex(genesis.EXTRA_DATA),
        )
        return (
            MinorBlock(header=header, meta=meta, tx_list=[]),
            TokenBalanceMap(coinbase_tokens),
        )
Exemple #3
0
    def test_proc_transfer_mnt(self):
        sender = b"\x00" * 19 + b"\x34"
        precompiled = decode_hex(b"000000000000000000000000000000514b430002")
        token_id = 1234567
        token_id_bytes = token_id.to_bytes(32, byteorder="big")
        state = State()

        self.__mint(
            state,
            sender,
            token_id_encode("QKC").to_bytes(32, byteorder="big"),
            encode_int32(30000),
        )
        self.__mint(state, sender, token_id_bytes, encode_int32(100))
        balance = state.get_balance(sender, token_id)
        self.assertEqual(balance, 100)
        balance = state.get_balance(sender, token_id_encode("QKC"))
        self.assertEqual(balance, 30000)

        new_addr = b"\x01" * 20
        testcases = [
            # Format: (index, description, to, value, gas, expected ret, post check)
            (1, "no value transfer", sender, 0, 0, (1, 0, []), None),
            (2, "value transfer needs more gas", sender, 1, 8999, (0, 0, []),
             None),
            # Should have stipend gas left
            (3, "value transfer needs more gas", sender, 1, 9000, (1, 2300,
                                                                   []), None),
            (4, "tx on new addr needs more gas", new_addr, 1, 33999,
             (0, 0, []), None),
            (
                5,
                "tx on new addr needs more gas",
                new_addr,
                42,
                34000,
                (1, 2300, []),
                lambda err_msg: self.assertEqual(
                    state.get_balance(new_addr, token_id), 42, err_msg),
            ),
            (6, "insufficient balance", sender, 333, 9000, (0, 0, []), None),
            (7, "target address is special", precompiled, 0, 9000, (0, 0, []),
             None),
        ]
        for i, desc, addr, value, gas, expected_ret, post_check in testcases:
            # Data = to address + token ID ++ value ++ (optional) msg data
            data = (b"\x00" * 12 + addr + token_id_bytes +
                    value.to_bytes(32, byteorder="big"))
            msg = Message(sender, sender, gas=gas, data=data)
            ret = proc_transfer_mnt(VMExt(state, sender, gas_price=1), msg)
            self.assertEqual(ret, expected_ret, "%d: %s" % (i, desc))
            if callable(post_check):
                post_check("%d: %s" % (i, desc))
Exemple #4
0
    def create_minor_block(self, root_block: RootBlock, shard_id: int,
                           evm_state: EvmState) -> MinorBlock:
        """ Create genesis block for shard.
        Genesis block's hash_prev_root_block is set to the genesis root block.
        Genesis state will be committed to the given evm_state.
        """
        branch = Branch.create(self._qkc_config.SHARD_SIZE, shard_id)
        shard_config = self._qkc_config.SHARD_LIST[shard_id]
        genesis = shard_config.GENESIS

        for address_hex, amount_in_wei in genesis.ALLOC.items():
            address = Address.create_from(bytes.fromhex(address_hex))
            check(
                address.get_shard_id(self._qkc_config.SHARD_SIZE) == shard_id)
            evm_state.full_shard_id = address.full_shard_id
            evm_state.delta_balance(address.recipient, amount_in_wei)

        evm_state.commit()

        meta = MinorBlockMeta(
            hash_merkle_root=bytes.fromhex(genesis.HASH_MERKLE_ROOT),
            hash_evm_state_root=evm_state.trie.root_hash,
        )

        local_fee_rate = 1 - self._qkc_config.reward_tax_rate  # type: Fraction
        coinbase_amount = (shard_config.COINBASE_AMOUNT *
                           local_fee_rate.numerator //
                           local_fee_rate.denominator)
        coinbase_address = Address.create_empty_account(shard_id)

        header = MinorBlockHeader(
            version=genesis.VERSION,
            height=genesis.HEIGHT,
            branch=branch,
            hash_prev_minor_block=bytes.fromhex(genesis.HASH_PREV_MINOR_BLOCK),
            hash_prev_root_block=root_block.header.get_hash(),
            evm_gas_limit=genesis.GAS_LIMIT,
            hash_meta=sha3_256(meta.serialize()),
            coinbase_amount=coinbase_amount,
            coinbase_address=coinbase_address,
            create_time=genesis.TIMESTAMP,
            difficulty=genesis.DIFFICULTY,
            extra_data=bytes.fromhex(genesis.EXTRA_DATA),
        )
        return MinorBlock(header=header, meta=meta, tx_list=[])
Exemple #5
0
    def test_proc_mint_mnt(self):
        sys_contract_addr = decode_hex(
            b"514b430000000000000000000000000000000002")
        random_addr = Address.create_random_account().recipient
        testcases = [(sys_contract_addr, True), (random_addr, False)]

        minter = b"\x00" * 19 + b"\x34"
        token_id = b"\x00" * 28 + b"\x11" * 4
        amount = b"\x00" * 30 + b"\x22" * 2
        data = b"\x00" * 12 + minter + token_id + amount

        for addr, expect_success in testcases:
            msg = Message(addr, addr, gas=34001, data=data)
            state = State()
            result, gas_remained, ret = proc_mint_mnt(VmExtBase(state), msg)
            balance = state.get_balance(
                minter, int.from_bytes(token_id, byteorder="big"))

            if expect_success:
                self.assertListEqual([result, gas_remained],
                                     [1, 34001 - 34000])
                self.assertEqual(len(ret), 32)
                self.assertEqual(int.from_bytes(ret, byteorder="big"), 1)
                self.assertEqual(balance,
                                 int.from_bytes(amount, byteorder="big"))

                # Mint again with exactly the same parameters
                result, gas_remained, ret = proc_mint_mnt(
                    VmExtBase(state), msg)
                balance = state.get_balance(
                    minter, int.from_bytes(token_id, byteorder="big"))
                self.assertListEqual([result, gas_remained], [1, 34001 - 9000])
                self.assertEqual(len(ret), 32)
                self.assertEqual(int.from_bytes(ret, byteorder="big"), 1)
                self.assertEqual(balance,
                                 2 * int.from_bytes(amount, byteorder="big"))
            else:
                self.assertListEqual([result, gas_remained], [0, 0])
                self.assertEqual(len(ret), 0)
                self.assertEqual(balance, 0)
Exemple #6
0
def init_state(env, pre):
    # Setup env
    db = InMemoryDb()
    stateEnv = Env(config=konfig)
    stateEnv.db = db
    state = State(
        env=stateEnv,
        block_prevhash=decode_hex(remove_0x_head(env['previousHash'])),
        prev_headers=[
            mk_fake_header(i) for i in range(
                parse_int_or_hex(env['currentNumber']) -
                1, max(-1,
                       parse_int_or_hex(env['currentNumber']) - 257), -1)
        ],
        block_number=parse_int_or_hex(env['currentNumber']),
        block_coinbase=decode_hex(remove_0x_head(env['currentCoinbase'])),
        block_difficulty=parse_int_or_hex(env['currentDifficulty']),
        gas_limit=parse_int_or_hex(env['currentGasLimit']),
        timestamp=parse_int_or_hex(env['currentTimestamp']))

    # Fill up pre
    for address, h in list(pre.items()):
        assert len(address) in (40, 42)
        address = decode_hex(remove_0x_head(address))
        assert set(h.keys()) == set(['code', 'nonce', 'balance', 'storage'])
        state.set_nonce(address, parse_int_or_hex(h['nonce']))
        state.set_balance(address, parse_int_or_hex(h['balance']))
        state.set_code(address, decode_hex(remove_0x_head(h['code'])))
        for k, v in h['storage'].items():
            state.set_storage_data(address,
                                   big_endian_to_int(decode_hex(k[2:])),
                                   big_endian_to_int(decode_hex(v[2:])))

    state.commit(allow_empties=True)
    # state.commit()
    return state
Exemple #7
0
    def create_minor_block(
            self, root_block: RootBlock, full_shard_id: int,
            evm_state: EvmState) -> Tuple[MinorBlock, TokenBalanceMap]:
        """ Create genesis block for shard.
        Genesis block's hash_prev_root_block is set to the genesis root block.
        Genesis state will be committed to the given evm_state.
        Based on ALLOC, genesis_token will be added to initial accounts.
        """
        branch = Branch(full_shard_id)
        shard_config = self._qkc_config.shards[full_shard_id]
        genesis = shard_config.GENESIS

        for address_hex, alloc_data in genesis.ALLOC.items():
            address = Address.create_from(bytes.fromhex(address_hex))
            check(
                self._qkc_config.get_full_shard_id_by_full_shard_key(
                    address.full_shard_key) == full_shard_id)
            evm_state.full_shard_key = address.full_shard_key
            recipient = address.recipient
            if "code" in alloc_data:
                code = decode_hex(remove_0x_head(alloc_data["code"]))
                evm_state.set_code(recipient, code)
                evm_state.set_nonce(recipient, 1)
            if "storage" in alloc_data:
                for k, v in alloc_data["storage"].items():
                    evm_state.set_storage_data(
                        recipient,
                        big_endian_to_int(decode_hex(k[2:])),
                        big_endian_to_int(decode_hex(v[2:])),
                    )
            # backward compatible:
            # v1: {addr: {QKC: 1234}}
            # v2: {addr: {balances: {QKC: 1234}, code: 0x, storage: {0x12: 0x34}}}
            balances = alloc_data
            if "balances" in alloc_data:
                balances = alloc_data["balances"]
            for k, v in balances.items():
                if k in ("code", "storage"):
                    continue
                evm_state.delta_token_balance(recipient, token_id_encode(k), v)

        evm_state.commit()

        meta = MinorBlockMeta(
            hash_merkle_root=bytes.fromhex(genesis.HASH_MERKLE_ROOT),
            hash_evm_state_root=evm_state.trie.root_hash,
            xshard_tx_cursor_info=XshardTxCursorInfo(root_block.header.height,
                                                     0, 0),
        )

        local_fee_rate = 1 - self._qkc_config.reward_tax_rate  # type: Fraction
        coinbase_tokens = {
            self._qkc_config.genesis_token:
            shard_config.COINBASE_AMOUNT * local_fee_rate.numerator //
            local_fee_rate.denominator
        }

        coinbase_address = Address.create_empty_account(full_shard_id)

        header = MinorBlockHeader(
            version=genesis.VERSION,
            height=genesis.HEIGHT,
            branch=branch,
            hash_prev_minor_block=bytes.fromhex(genesis.HASH_PREV_MINOR_BLOCK),
            hash_prev_root_block=root_block.header.get_hash(),
            evm_gas_limit=genesis.GAS_LIMIT,
            hash_meta=sha3_256(meta.serialize()),
            coinbase_amount_map=TokenBalanceMap(coinbase_tokens),
            coinbase_address=coinbase_address,
            create_time=genesis.TIMESTAMP,
            difficulty=genesis.DIFFICULTY,
            extra_data=bytes.fromhex(genesis.EXTRA_DATA),
        )
        return (
            MinorBlock(header=header, meta=meta, tx_list=[]),
            TokenBalanceMap(coinbase_tokens),
        )
def init_state(env, pre, is_qkc_state, qkc_env=None):
    # Setup env
    db = InMemoryDb()
    state_env = Env(config=konfig)
    state_env.db = db
    state = State(
        env=state_env,
        block_prevhash=decode_hex(remove_0x_head(env["previousHash"])),
        prev_headers=[
            mk_fake_header(i)
            for i in range(
                parse_int_or_hex(env["currentNumber"]) - 1,
                max(-1, parse_int_or_hex(env["currentNumber"]) - 257),
                -1,
            )
        ],
        block_number=parse_int_or_hex(env["currentNumber"]),
        block_coinbase=decode_hex(remove_0x_head(env["currentCoinbase"])),
        block_difficulty=parse_int_or_hex(env["currentDifficulty"]),
        gas_limit=parse_int_or_hex(env["currentGasLimit"]),
        timestamp=parse_int_or_hex(env["currentTimestamp"]),
        qkc_config=qkc_env.quark_chain_config,
        # If testing QuarkChain states, should not use mock account
        use_mock_evm_account=not is_qkc_state,
    )

    seen_token_ids = set()
    # Fill up pre
    for address, h in list(pre.items()):
        assert len(address) in (40, 42)
        address = decode_hex(remove_0x_head(address))
        state.set_nonce(address, parse_int_or_hex(h["nonce"]))
        if is_qkc_state and "balances" in h:
            # In QuarkChain state tests, can either specify balance map or single balance
            for token_id, balance in h["balances"].items():
                parsed_token_id = parse_int_or_hex(token_id)
                state.set_token_balance(
                    address, parsed_token_id, parse_int_or_hex(balance)
                )
                seen_token_ids.add(parsed_token_id)
        else:
            state.set_balance(address, parse_int_or_hex(h["balance"]))
        state.set_code(address, decode_hex(remove_0x_head(h["code"])))
        for k, v in h["storage"].items():
            state.set_storage_data(
                address,
                big_endian_to_int(decode_hex(k[2:])),
                big_endian_to_int(decode_hex(v[2:])),
            )

    # Update allowed token IDs
    if seen_token_ids:
        state.qkc_config._allowed_token_ids = seen_token_ids

    state.commit(allow_empties=True)
    return state