def compute_state_test_unit(state,
                            txdata,
                            indices,
                            konfig,
                            is_qkc_state,
                            qkc_env=None):
    state.env.config = konfig
    s = state.snapshot()
    if "transferTokenId" in txdata:
        transfer_token_id = parse_int_or_hex(
            txdata["transferTokenId"][indices["transferTokenId"]])
    else:
        transfer_token_id = token_id_encode("QKC")
    try:
        # Create the transaction
        tx = transactions.Transaction(
            nonce=parse_int_or_hex(txdata["nonce"] or b"0"),
            gasprice=parse_int_or_hex(txdata["gasPrice"] or b"0"),
            startgas=parse_int_or_hex(txdata["gasLimit"][indices["gas"]]
                                      or b"0"),
            to=decode_hex(remove_0x_head(txdata["to"])),
            value=parse_int_or_hex(txdata["value"][indices["value"]] or b"0"),
            data=decode_hex(remove_0x_head(txdata["data"][indices["data"]])),
            gas_token_id=token_id_encode("QKC"),
            transfer_token_id=transfer_token_id,
            # Should not set testing flag if testing QuarkChain state
            is_testing=not is_qkc_state,
        )
        tx.set_quark_chain_config(qkc_env.quark_chain_config)
        if "secretKey" in txdata:
            tx.sign(decode_hex(remove_0x_head(txdata["secretKey"])))
        else:
            tx._in_mutable_context = True
            tx.v = parse_int_or_hex(txdata["v"])
            tx._in_mutable_context = False
        # Run it
        prev = state.to_dict()
        success, output = apply_transaction(state,
                                            tx,
                                            tx_wrapper_hash=bytes(32))
    except InvalidTransaction as e:
        print("Exception: %r" % e)
        success, output = False, b""
    # touch coinbase, make behavior consistent with go-ethereum
    state.delta_token_balance(state.block_coinbase, token_id_encode("QKC"), 0)
    state.commit()
    post = state.to_dict()
    output_decl = {
        "hash": "0x" + encode_hex(state.trie.root_hash),
        "indexes": indices,
        "diff": mk_state_diff(prev, post),
    }
    state.revert(s)
    return output_decl
Exemple #2
0
def main():
    args = parser.parse_args()

    if args.name is not None:
        print("Token name %s to id: %d (%s)" %
              (args.name, token_id_encode(
                  args.name), hex(token_id_encode(args.name))))

    if args.id is not None:
        print("Token id %d (%s) to id: %s" %
              (args.id, hex(args.id), token_id_decode(args.id)))
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 test_encoding_change_from_dict_to_trie():
    db = InMemoryDb()
    b = TokenBalances(b"", db)
    # start with 16 entries - right below the threshold
    mapping = {
        token_id_encode("Q" + chr(65 + i)): int(i * 1e3) + 42
        for i in range(16)
    }
    b._balances = mapping.copy()
    b.commit()
    assert b.serialize().startswith(b"\x00")
    assert b.token_trie is None

    # add one more entry and expect changes
    journal = []
    new_token = token_id_encode("QKC")
    b.set_balance(journal, new_token, 123)
    assert b.balance(new_token) == 123
    b.commit()
    assert b.token_trie is not None
    assert b.serialize().startswith(b"\x01")
    root1 = b.token_trie.root_hash
    copied_mapping = mapping.copy()
    copied_mapping[new_token] = 123
    assert b.to_dict() == copied_mapping

    # clear all balances except QKC
    for k in mapping:
        b.set_balance(journal, k, 0)
    # still have those token keys in balance map
    assert b.balance(token_id_encode("QA")) == 0
    assert b.to_dict() == {new_token: 123}
    # trie hash should change after serialization
    b.commit()
    serialized = b.serialize()
    root2 = b.token_trie.root_hash
    assert serialized == b"\x01" + root2
    assert root1 != root2
    # balance map truncated, entries with 0 value will be ignored
    assert b._balances == {}
    assert b.balance(token_id_encode("QB")) == 0
    assert len(b._balances) == 0
    assert b.to_dict() == {new_token: 123}
    assert not b.is_blank()

    # remove the last entry
    b.set_balance(journal, new_token, 0)
    assert b.to_dict() == {}
    b.commit()
    assert b.token_trie.root_hash == BLANK_ROOT
    assert b._balances == {}
Exemple #5
0
 def commit(self, allow_empties=False):
     for addr, acct in self.cache.items():
         if acct.touched or acct.deleted:
             acct.commit()
             if self.account_exists(addr) or allow_empties:
                 if self.use_mock_evm_account:
                     assert len(
                         acct.token_balances._balances) <= 1, "QKC only"
                     _acct = _MockAccount(
                         acct.nonce,
                         acct.token_balances.balance(
                             token_id_encode("QKC")),
                         acct.storage,
                         acct.code_hash,
                     )
                 else:
                     _acct = _Account(
                         acct.nonce,
                         acct.token_balances.serialize(),
                         acct.storage,
                         acct.code_hash,
                         acct.full_shard_key,
                         b"",
                     )
                 self.trie.update(addr, rlp.encode(_acct))
             else:
                 self.trie.delete(addr)
     self.trie.deletes = []
     self.cache = {}
     self.journal = []
Exemple #6
0
def prometheus_balance(args):
    tokens = {
        token_name: token_id_encode(token_name)
        for token_name in args.tokens.strip().split(sep=",")
    }
    # Create a metric to track token total balance.
    balance_gauge = Gauge(
        "token_total_balance", "Total balance of specified tokens", ("shard", "token")
    )
    # A meta gauge to track block height, because if things go wrong, we want
    # to know which root block has the wrong balance.
    block_height_gauge = Gauge("block_height", "Height for root block and minor block")

    while True:
        try:
            # Call when rpc server is ready.
            latest_block_height = get_highest()
            total_balance = {}
            for token_name, token_id in tokens.items():
                total_balance[token_name] = get_time_and_balance(
                    latest_block_height, token_id
                )
        except Exception as e:
            print("failed to get latest root block height", e)
            # Rpc not ready, wait and try again.
            time.sleep(3)
            continue
        block_height_gauge.set(latest_block_height)
        for token_name, (_, balance_dict) in total_balance.items():
            balance_gauge.labels("total", token_name).set(sum(balance_dict.values()))
            for shard_id, shard_bal in balance_dict.items():
                balance_gauge.labels(shard_id, token_name).set(shard_bal)
        time.sleep(args.interval)
Exemple #7
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
            if isinstance(alloc_amount, dict):
                for k, v in alloc_amount.items():
                    evm_state.delta_token_balance(address.recipient,
                                                  token_id_encode(k), v)
            else:
                evm_state.delta_token_balance(address.recipient,
                                              self._qkc_config.genesis_token,
                                              alloc_amount)

        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_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 print_shard_balance(env, rb, full_shard_id):
    shard = Shard(env, full_shard_id, None)
    state = shard.state
    state.init_from_root_block(rb)

    print("Full shard id: %d" % full_shard_id)
    print("Block height: %d" % state.header_tip.height)
    print("Trie hash: %s" % state.meta_tip.hash_evm_state_root.hex())

    trie = Trie(state.raw_db, state.meta_tip.hash_evm_state_root)

    key = trie.next(bytes(32))
    total = 0
    while key is not None:
        rlpdata = trie.get(key)
        o = rlp.decode(rlpdata, _Account)
        tb = TokenBalances(o.token_balances, state.raw_db)
        balance = tb.balance(token_id_encode("QKC"))
        print("Key: %s, Balance: %s" % (key.hex(), balance))
        total += balance

        key = trie.next(key)

    print("Total balance in shard: %d" % total)
    return total, state.header_tip.height
Exemple #9
0
    def test_native_token_transfer_0_value_success(self):
        """to prevent storage spamming, do not delta_token_balance does not take action if value is 0
        """
        MALICIOUS0 = token_id_encode("MALICIOUS0")
        id1 = Identity.create_random_identity()
        acc1 = Address.create_from_identity(id1, full_shard_key=0)

        env = get_test_env(
            genesis_account=acc1,
            genesis_minor_token_balances={
                self.GENESIS_TOKEN: 10000000,
                "MALICIOUS0": 0,
            },
        )
        state = create_default_shard_state(env=env)
        tx = create_transfer_transaction(
            shard_state=state,
            key=id1.get_key(),
            from_address=acc1,
            to_address=acc1,
            value=0,
            gas=opcodes.GTXCOST,
            gas_token_id=self.genesis_token,
            transfer_token_id=MALICIOUS0,
        )
        self.assertFalse(state.add_tx(tx))
    def test_native_token_gas(self):
        """in-shard transfer QETH using native token as gas
        TODODLL: support native token as gas
        """
        QETH = token_id_encode("QETH")
        id1 = Identity.create_random_identity()
        acc1 = Address.create_from_identity(id1, full_shard_key=0)
        acc2 = Address.create_random_account(full_shard_key=0)
        acc3 = Address.create_random_account(full_shard_key=0)

        env = get_test_env(genesis_account=acc1,
                           genesis_minor_token_balances={"QETH": 10000000})
        state = create_default_shard_state(env=env)

        tx = create_transfer_transaction(
            shard_state=state,
            key=id1.get_key(),
            from_address=acc1,
            to_address=acc2,
            value=12345,
            gas=21000,
            gas_token_id=QETH,
            transfer_token_id=QETH,
        )
        self.assertFalse(
            state.add_tx(tx)
        )  # warning log: Failed to add transaction: Gas token must be QKC
        return

        self.assertTrue(state.add_tx(tx))
        b1 = state.create_block_to_mine(address=acc3)
        self.assertEqual(len(b1.tx_list), 1)
        state.finalize_and_add_block(b1)
        self.assertEqual(state.header_tip, b1.header)
        self.assertEqual(state.get_token_balance(id1.recipient, QETH),
                         10000000 - opcodes.GTXCOST)
        self.assertEqual(
            state.get_token_balance(acc1.recipient, QETH),
            10000000 - opcodes.GTXCOST - 12345,
        )
        self.assertEqual(state.get_token_balance(acc2.recipient, QETH), 12345)
        # tx fee
        self.assertEqual(
            state.get_token_balance(acc3.recipient, QETH),
            self.getAfterTaxReward(opcodes.GTXCOST),
        )
        # miner coinbase
        self.assertEqual(
            state.get_token_balance(acc3.recipient, self.genesis_token),
            self.getAfterTaxReward(self.shard_coinbase),
        )
        tx_list, _ = state.db.get_transactions_by_address(acc1)
        self.assertEqual(tx_list[0].value, 12345)
        self.assertEqual(tx_list[0].gas_token_id, QETH)
        self.assertEqual(tx_list[0].transfer_token_id, QETH)
        tx_list, _ = state.db.get_transactions_by_address(acc2)
        self.assertEqual(tx_list[0].value, 12345)
        self.assertEqual(tx_list[0].gas_token_id, QETH)
        self.assertEqual(tx_list[0].transfer_token_id, QETH)
Exemple #11
0
 def allowed_token_ids(self):
     if self._allowed_token_ids is None:
         self._allowed_token_ids = {self.genesis_token}
         for _, shard in self.shards.items():
             for _, token_dict in shard.GENESIS.ALLOC.items():
                 for token_id in token_dict:
                     self._allowed_token_ids.add(token_id_encode(token_id))
     return self._allowed_token_ids
    def test_native_token_transfer(self):
        """in-shard transfer QETH using genesis_token as gas
        """
        QETH = token_id_encode("QETH")
        id1 = Identity.create_random_identity()
        acc1 = Address.create_from_identity(id1, full_shard_key=0)
        acc2 = Address.create_random_account(full_shard_key=0)
        acc3 = Address.create_random_account(full_shard_key=0)

        env = get_test_env(
            genesis_account=acc1,
            genesis_minor_token_balances={
                self.GENESIS_TOKEN: 10000000,
                "QETH": 99999
            },
        )
        state = create_default_shard_state(env=env)

        tx = create_transfer_transaction(
            shard_state=state,
            key=id1.get_key(),
            from_address=acc1,
            to_address=acc2,
            value=12345,
            gas=21000,
            gas_token_id=self.genesis_token,
            transfer_token_id=QETH,
        )
        self.assertTrue(state.add_tx(tx))
        b1 = state.create_block_to_mine(address=acc3)
        self.assertEqual(len(b1.tx_list), 1)
        state.finalize_and_add_block(b1)
        self.assertEqual(state.header_tip, b1.header)
        self.assertEqual(
            state.get_token_balance(id1.recipient, self.genesis_token),
            10000000 - opcodes.GTXCOST,
        )
        self.assertEqual(state.get_token_balance(acc1.recipient, QETH),
                         99999 - 12345)
        self.assertEqual(state.get_token_balance(acc2.recipient, QETH), 12345)
        self.assertEqual(
            state.get_token_balance(acc3.recipient, self.genesis_token),
            self.getAfterTaxReward(opcodes.GTXCOST + self.shard_coinbase),
        )
        tx_list, _ = state.db.get_transactions_by_address(acc1)
        self.assertEqual(tx_list[0].value, 12345)
        self.assertEqual(tx_list[0].gas_token_id, self.genesis_token)
        self.assertEqual(tx_list[0].transfer_token_id, QETH)
        tx_list, _ = state.db.get_transactions_by_address(acc2)
        self.assertEqual(tx_list[0].value, 12345)
        self.assertEqual(tx_list[0].gas_token_id, self.genesis_token)
        self.assertEqual(tx_list[0].transfer_token_id, QETH)
Exemple #13
0
def test_token_id_exceptions():
    with pytest.raises(AssertionError):
        token_id_encode("qkc")
    with pytest.raises(AssertionError):
        token_id_encode(" ")
    with pytest.raises(AssertionError):
        token_id_encode("btc")
    with pytest.raises(AssertionError):
        token_id_encode(TOKEN_MAX + "Z")
    with pytest.raises(AssertionError):
        token_id_decode(2 ** 64 - 1)
    with pytest.raises(AssertionError):
        token_id_decode(-1)
    with pytest.raises(AssertionError):
        token_id_decode(TOKEN_ID_MAX + 1)
Exemple #14
0
def test_token_id_exceptions():
    with pytest.raises(AssertionError):
        token_id_encode("qkc")
    with pytest.raises(AssertionError):
        token_id_encode(" ")
    with pytest.raises(AssertionError):
        token_id_encode("btc")
    with pytest.raises(AssertionError):
        token_id_encode("ZZZZZZZZZZZZZ")
    with pytest.raises(AssertionError):
        token_id_decode(2 ** 64 - 1)
    with pytest.raises(AssertionError):
        token_id_decode(-1)
    with pytest.raises(AssertionError):
        token_id_decode(ZZZZZZZZZZZZ + 1)
Exemple #15
0
    def test_native_token_gas(self):
        """in-shard transfer QETH using native token as gas
        """
        qeth = token_id_encode("QETH")
        id1 = Identity.create_random_identity()
        acc1 = Address.create_from_identity(id1, full_shard_key=0)
        acc2 = Address.create_random_account(full_shard_key=0)
        # Miner
        acc3 = Address.create_random_account(full_shard_key=0)

        env = get_test_env(
            genesis_account=acc1,
            genesis_minor_token_balances={"QETH": 10000000},
            charge_gas_reserve=True,
        )
        state = create_default_shard_state(env=env)

        tx = create_transfer_transaction(
            shard_state=state,
            key=id1.get_key(),
            from_address=acc1,
            to_address=acc2,
            value=12345,
            gas=21000,
            gas_token_id=qeth,
            transfer_token_id=qeth,
        )

        self.assertTrue(state.add_tx(tx))
        b1 = state.create_block_to_mine(address=acc3)
        self.assertEqual(len(b1.tx_list), 1)
        state.finalize_and_add_block(b1)
        self.assertEqual(state.header_tip, b1.header)
        self.assertEqual(
            state.get_token_balance(acc1.recipient, qeth),
            10000000 - opcodes.GTXCOST - 12345,
        )
        self.assertEqual(state.get_token_balance(acc2.recipient, qeth), 12345)
        # after-tax coinbase + tx fee should only be in QKC
        self.assertEqual(
            state.get_token_balance(acc3.recipient, self.genesis_token),
            self.get_after_tax_reward(self.shard_coinbase + opcodes.GTXCOST),
        )
        tx_list, _ = state.db.get_transactions_by_address(acc1)
        self.assertEqual(tx_list[0].value, 12345)
        self.assertEqual(tx_list[0].gas_token_id, qeth)
        self.assertEqual(tx_list[0].transfer_token_id, qeth)
        tx_list, _ = state.db.get_transactions_by_address(acc2)
        self.assertEqual(tx_list[0].value, 12345)
        self.assertEqual(tx_list[0].gas_token_id, qeth)
        self.assertEqual(tx_list[0].transfer_token_id, qeth)
Exemple #16
0
def test_encoding_in_trie():
    encoding = b"\x01\x84\x8dBq\xe4N\xa4\x14f\xfe5Ua\xddC\xb1f\xc9'\xd2\xec\xa0\xa8\xdd\x90\x1a\x8edi\xec\xde\xb1"
    mapping = {
        token_id_encode("Q" + chr(65 + i)): int(i * 1e3) + 42
        for i in range(17)
    }
    db = InMemoryDb()
    # starting from blank account
    b0 = TokenBalances(b"", db)
    b0._balances = mapping.copy()
    b0.commit()
    assert b0.serialize() == encoding

    # check internal states
    assert b0.token_trie is not None

    # starting from RLP encoding
    b1 = TokenBalances(encoding, db)
    assert b1.to_dict() == mapping
    assert b1.serialize() == encoding

    # check internal states
    assert b1._balances == {}
    assert b1.token_trie is not None
    assert not b1.is_blank()
    assert b1.balance(token_id_encode("QC")) == mapping[token_id_encode("QC")]
    # underlying balance map populated
    assert len(b1._balances) == 1

    # serialize without commit should fail
    try:
        b1.serialize()
        pytest.fail()
    except AssertionError:
        pass
    # otherwise should succeed
    b1.commit()
    b1.serialize()
    def test_native_token_transfer_0_value_success(self):
        """to prevent storage spamming, do not delta_token_balance does not take action if value is 0
        """
        MALICIOUS0 = token_id_encode("MALICIOUS0")
        id1 = Identity.create_random_identity()
        acc1 = Address.create_from_identity(id1, full_shard_key=0)
        acc3 = Address.create_random_account(full_shard_key=0)

        env = get_test_env(
            genesis_account=acc1,
            genesis_minor_token_balances={
                self.GENESIS_TOKEN: 10000000,
                "MALICIOUS0": 0,
            },
        )
        state = create_default_shard_state(env=env)
        tx = create_transfer_transaction(
            shard_state=state,
            key=id1.get_key(),
            from_address=acc1,
            to_address=acc1,
            value=0,
            gas=opcodes.GTXCOST,
            gas_token_id=self.genesis_token,
            transfer_token_id=MALICIOUS0,
        )
        self.assertTrue(state.add_tx(tx))

        b1 = state.create_block_to_mine(address=acc3)
        self.assertEqual(len(b1.tx_list), 1)
        state.finalize_and_add_block(b1)
        self.assertEqual(state.header_tip, b1.header)
        self.assertEqual(
            state.get_token_balance(id1.recipient, self.genesis_token),
            10000000 - opcodes.GTXCOST,
        )
        self.assertEqual(state.get_token_balance(acc1.recipient, MALICIOUS0),
                         0)
        # MALICIOUS0 shall not be in the dict
        self.assertNotEqual(
            state.get_balances(acc1.recipient),
            {
                self.genesis_token: 10000000 - opcodes.GTXCOST,
                MALICIOUS0: 0
            },
        )
        self.assertEqual(
            state.get_balances(acc1.recipient),
            {self.genesis_token: 10000000 - opcodes.GTXCOST},
        )
    def test_disallowed_unknown_token(self):
        """do not allow tx with unknown token id
        """
        MALICIOUS0 = token_id_encode("MALICIOUS0")
        MALICIOUS1 = token_id_encode("MALICIOUS1")
        id1 = Identity.create_random_identity()
        acc1 = Address.create_from_identity(id1, full_shard_key=0)
        acc3 = Address.create_random_account(full_shard_key=0)

        env = get_test_env(
            genesis_account=acc1,
            genesis_minor_token_balances={self.GENESIS_TOKEN: 10000000},
        )
        state = create_default_shard_state(env=env)
        tx = create_transfer_transaction(
            shard_state=state,
            key=id1.get_key(),
            from_address=acc1,
            to_address=acc1,
            value=0,
            gas=opcodes.GTXCOST,
            gas_token_id=self.genesis_token,
            transfer_token_id=MALICIOUS0,
        )
        self.assertFalse(state.add_tx(tx))

        tx1 = create_transfer_transaction(
            shard_state=state,
            key=id1.get_key(),
            from_address=acc1,
            to_address=acc1,
            value=0,
            gas=opcodes.GTXCOST,
            gas_token_id=MALICIOUS1,
            transfer_token_id=self.genesis_token,
        )
        self.assertFalse(state.add_tx(tx1))
Exemple #19
0
def test_reset_balance_in_trie_and_revert():
    db = InMemoryDb()
    b = TokenBalances(b"", db)
    mapping = {
        token_id_encode("Q" + chr(65 + i)): int(i * 1e3) + 42
        for i in range(17)
    }
    b._balances = mapping.copy()
    b.commit()
    assert b._balances == {}

    journal = []
    b.set_balance(journal, 999, 999)
    b.set_balance(journal, token_id_encode("Q" + chr(65 + 0)), 1)
    assert b.balance(999) == 999
    assert b.balance(token_id_encode("Q" + chr(65 + 0))) == 1
    b.reset(journal)
    assert b.is_blank()
    assert b.to_dict() == {}
    for op in journal:
        op()
    assert not b.is_blank()
    assert b.to_dict() == mapping
    assert b._balances != {}
Exemple #20
0
 async def gasPrice(self, full_shard_key: str, token_id: Optional[str] = None):
     full_shard_key = shard_id_decoder(full_shard_key)
     if full_shard_key is None:
         return None
     parsed_token_id = (
         quantity_decoder(token_id) if token_id else token_id_encode("QKC")
     )
     branch = Branch(
         self.master.env.quark_chain_config.get_full_shard_id_by_full_shard_key(
             full_shard_key
         )
     )
     ret = await self.master.gas_price(branch, parsed_token_id)
     if ret is None:
         return None
     return quantity_encoder(ret)
Exemple #21
0
 def allowed_token_ids(self):
     if self._allowed_token_ids is None:
         self._allowed_token_ids = {self.genesis_token}
         for _, shard in self.shards.items():
             for _, alloc_data in shard.GENESIS.ALLOC.items():
                 # genesis config is 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 in balances:
                     if k in ("code", "storage"):
                         continue
                     self._allowed_token_ids.add(token_id_encode(k))
     return self._allowed_token_ids
Exemple #22
0
 def get_and_cache_account(self, address):
     if address in self.cache:
         return self.cache[address]
     if self.executing_on_head and False:
         try:
             rlpdata = self.db[b"address:" + address]
         except KeyError:
             rlpdata = b""
     else:
         rlpdata = self.trie.get(address)
     if rlpdata != trie.BLANK_NODE:
         if self.use_mock_evm_account:
             o = rlp.decode(rlpdata, _MockAccount)
             raw_token_balances = TokenBalances(b"", self.db)
             raw_token_balances._balances = {
                 token_id_encode("QKC"): o.balance
             }
             token_balances = raw_token_balances.serialize()
             full_shard_key = self.full_shard_key
         else:
             o = rlp.decode(rlpdata, _Account)
             token_balances = o.token_balances
             full_shard_key = o.full_shard_key
         o = Account(
             nonce=o.nonce,
             token_balances=token_balances,
             storage=o.storage,
             code_hash=o.code_hash,
             full_shard_key=full_shard_key,
             env=self.env,
             address=address,
             db=self.db,
         )
     else:
         o = Account.blank_account(
             self.env,
             address,
             self.full_shard_key,
             self.config["ACCOUNT_INITIAL_NONCE"],
             db=self.db,
         )
     self.cache[address] = o
     o._mutable = True
     o._cached_rlp = None
     return o
Exemple #23
0
 def commit(self, allow_empties=False):
     for addr, acct in self.cache.items():
         if acct.touched or acct.deleted:
             acct.commit()
             self.deletes.extend(acct.storage_trie.deletes)
             self.changed[addr] = True
             if self.account_exists(addr) or allow_empties:
                 if self.use_mock_evm_account:
                     assert len(
                         acct.token_balances._balances) <= 1, "QKC only"
                     _acct = _MockAccount(
                         acct.nonce,
                         acct.token_balances.balance(
                             token_id_encode("QKC")),
                         acct.storage,
                         acct.code_hash,
                     )
                 else:
                     _acct = _Account(
                         acct.nonce,
                         acct.token_balances.serialize(),
                         acct.storage,
                         acct.code_hash,
                         acct.full_shard_key,
                         b"",
                     )
                 self.trie.update(addr, rlp.encode(_acct))
                 if self.executing_on_head:
                     self.db.put(b"address:" + addr, rlp.encode(_acct))
             else:
                 self.trie.delete(addr)
                 if self.executing_on_head:
                     try:
                         self.db.remove(b"address:" + addr)
                     except KeyError:
                         pass
     self.deletes.extend(self.trie.deletes)
     self.trie.deletes = []
     self.cache = {}
     self.journal = []
    def test_gasPrice(self):
        id1 = Identity.create_random_identity()
        acc1 = Address.create_from_identity(id1, full_shard_key=0)

        with ClusterContext(
                1, acc1, small_coinbase=True) as clusters, jrpc_server_context(
                    clusters[0].master):
            master = clusters[0].master
            slaves = clusters[0].slave_list

            # run for multiple times
            for _ in range(3):
                tx = create_transfer_transaction(
                    shard_state=clusters[0].get_shard_state(2 | 0),
                    key=id1.get_key(),
                    from_address=acc1,
                    to_address=acc1,
                    value=0,
                    gas_price=12,
                )
                self.assertTrue(slaves[0].add_tx(tx))

                block = call_async(
                    master.get_next_block_to_mine(address=acc1,
                                                  branch_value=0b10))
                self.assertTrue(
                    call_async(clusters[0].get_shard(2 | 0).add_block(block)))

            for using_eth_endpoint in (True, False):
                if using_eth_endpoint:
                    resp = send_request("eth_gasPrice", ["0x0"])
                else:
                    resp = send_request(
                        "gasPrice",
                        ["0x0",
                         quantity_encoder(token_id_encode("QKC"))])

                self.assertEqual(resp, "0xc")
Exemple #25
0
 def get_and_cache_account(self, address, should_cache=True):
     if address in self.cache:
         return self.cache[address]
     rlpdata = self.trie.get(address)
     if rlpdata != trie.BLANK_NODE:
         if self.use_mock_evm_account:
             o = rlp.decode(rlpdata, _MockAccount)
             raw_token_balances = TokenBalances(b"", self.db)
             raw_token_balances._balances = {
                 token_id_encode("QKC"): o.balance
             }
             token_balances = raw_token_balances.serialize()
             full_shard_key = self.full_shard_key
         else:
             o = rlp.decode(rlpdata, _Account)
             token_balances = o.token_balances
             full_shard_key = o.full_shard_key
         o = Account(
             nonce=o.nonce,
             token_balances=token_balances,
             storage=o.storage,
             code_hash=o.code_hash,
             full_shard_key=full_shard_key,
             env=self.env,
             address=address,
             db=self.db,
         )
     else:
         o = Account.blank_account(
             self.env,
             address,
             self.full_shard_key,
             self.config["ACCOUNT_INITIAL_NONCE"],
             db=self.db,
         )
     if should_cache:
         self.cache[address] = o
     return o
Exemple #26
0
 def genesis_token(self):
     if self._genesis_token is None:
         self._genesis_token = token_id_encode(self.GENESIS_TOKEN)
     return self._genesis_token
Exemple #27
0
 def default_chain_token(self):
     if self._default_chain_token is None:
         self._default_chain_token = token_id_encode(
             self.DEFAULT_CHAIN_TOKEN)
     return self._default_chain_token
Exemple #28
0
def validate_transaction(state, tx):
    # (1) The transaction signature is valid;
    if not tx.sender:  # sender is set and validated on Transaction initialization
        raise UnsignedTransaction(tx)

    if tx.version == 2:
        # When tx.version == 2 (EIP155 tx), check
        # 0. EIP155_SIGNER enable
        # 1. tx.v == tx.network_id * 2 + 35 (+ 1)
        # 2. gas_token_id & transfer_token_id should equal to default_token_id (like qkc)
        # 3. tx.from_chain_id == tx.to_chain_id and tx.from_shard_key = 0 & tx.to_shard_key = 0
        # 4. tx.network_id == chain_config.ETH_CHAIN_ID, where chain_config is derived from tx.from_chain_id
        chain_config = state.qkc_config.CHAINS[tx.from_chain_id]
        default_token_id = token_id_encode(chain_config.DEFAULT_CHAIN_TOKEN)
        if (state.qkc_config.ENABLE_EIP155_SIGNER_TIMESTAMP is not None
                and state.timestamp <
                state.qkc_config.ENABLE_EIP155_SIGNER_TIMESTAMP):
            raise InvalidTransaction("EIP155 Signer is not enable yet.")
        if tx.v != 35 + tx.network_id * 2 and tx.v != 36 + tx.network_id * 2:
            raise InvalidTransaction(
                "network_id {} does not match the signature v {}.".format(
                    tx.network_id, tx.v))
        if tx.from_chain_id != tx.to_chain_id:
            raise InvalidTransaction(
                "EIP155 Signer do not support cross shard transaction.")
        if tx.from_shard_key != 0 or tx.to_shard_key != 0:
            raise InvalidTransaction(
                "EIP155 Signer do not support cross shard transaction.")
        if tx.gas_token_id != default_token_id:
            raise InvalidTransaction(
                "EIP155 Signer only support {} as gas token.".format(
                    chain_config.DEFAULT_CHAIN_TOKEN))
        if tx.transfer_token_id != default_token_id:
            raise InvalidTransaction(
                "EIP155 Signer only support {} as transfer token.".format(
                    chain_config.DEFAULT_CHAIN_TOKEN))
        assert (tx.network_id == chain_config.ETH_CHAIN_ID,
                "Invalid network_id.")
        assert (
            tx.eth_chain_id - state.qkc_config.BASE_ETH_CHAIN_ID -
            1 == tx.from_chain_id,
            "Invalid Eth_Chain_Id.",
        )

    # (1a) startgas, gasprice, gas token id, transfer token id must be <= UINT128_MAX
    if (tx.startgas > UINT128_MAX or tx.gasprice > UINT128_MAX
            or tx.gas_token_id > TOKEN_ID_MAX
            or tx.transfer_token_id > TOKEN_ID_MAX):
        raise InvalidTransaction(
            "startgas, gasprice, and token_id must <= UINT128_MAX")

    # (2) the transaction nonce is valid (equivalent to the
    #     sender account's current nonce);
    req_nonce = state.get_nonce(tx.sender)
    if req_nonce != tx.nonce:
        raise InvalidNonce(rp(tx, "nonce", tx.nonce, req_nonce))

    # (3) the gas limit is no smaller than the intrinsic gas,
    # g0, used by the transaction;
    total_gas = tx.intrinsic_gas_used
    if tx.startgas < total_gas:
        raise InsufficientStartGas(rp(tx, "startgas", tx.startgas, total_gas))

    default_chain_token = state.shard_config.default_chain_token
    bal = {
        tx.transfer_token_id: state.get_balance(tx.sender,
                                                tx.transfer_token_id)
    }
    if tx.transfer_token_id != tx.gas_token_id:
        bal[tx.gas_token_id] = state.get_balance(tx.sender, tx.gas_token_id)

    # (4) requires non-zero balance for transfer_token_id and gas_token_id if non-default
    for token_id in [tx.transfer_token_id, tx.gas_token_id]:
        if token_id != default_chain_token and bal[token_id] == 0:
            raise InvalidNativeToken(
                "{}: non-default token {} has zero balance".format(
                    tx.__repr__(), token_id_decode(token_id)))

    # (5) the sender account balance contains at least the cost required in up-front payment
    cost = Counter({tx.transfer_token_id: tx.value}) + Counter(
        {tx.gas_token_id: tx.gasprice * tx.startgas})
    for token_id, b in bal.items():
        if b < cost[token_id]:
            raise InsufficientBalance(
                rp(
                    tx,
                    "token %s balance" % token_id_decode(token_id),
                    b,
                    cost[token_id],
                ))

    # (6) if gas token non-default, need to check system contract for gas conversion
    if tx.gasprice != 0 and tx.gas_token_id != default_chain_token:
        snapshot = state.snapshot()
        _, genesis_token_gas_price = pay_native_token_as_gas(
            state, tx.gas_token_id, tx.startgas, tx.gasprice)
        state.revert(snapshot)
        if genesis_token_gas_price == 0:
            raise InvalidNativeToken(
                "{}: non-default gas token {} not ready for being used to pay gas"
                .format(tx.__repr__(), token_id_decode(tx.gas_token_id)))
        # should be guaranteed by previous check. check added to make sure
        bal_gas_reserve = state.get_balance(
            SystemContract.GENERAL_NATIVE_TOKEN.addr(), state.genesis_token)
        if bal_gas_reserve < genesis_token_gas_price * tx.startgas:
            raise InvalidNativeToken(
                "{}: non-default gas token {} not enough reserve balance for conversion"
                .format(tx.__repr__(), token_id_decode(tx.gas_token_id)))

    # (7) check block gas limit
    if state.gas_used + tx.startgas > state.gas_limit:
        raise BlockGasLimitReached(
            rp(tx, "gaslimit", state.gas_used + tx.startgas, state.gas_limit))

    return True
Exemple #29
0
    def test_contract_suicide(self):
        """
        Kill Call Data: 0x41c0e1b5
        """
        QETH = token_id_encode("QETH")
        id1 = Identity.create_random_identity()
        acc1 = Address.create_from_identity(id1, full_shard_key=0)
        id2 = Identity.create_random_identity()
        acc2 = Address.create_from_identity(id2, full_shard_key=0)
        acc3 = Address.create_random_account(full_shard_key=0)

        env = get_test_env(
            genesis_account=acc1,
            genesis_minor_token_balances={
                self.GENESIS_TOKEN: 200 * 10 ** 18,
                "QETH": 99999,
            },
        )
        state = create_default_shard_state(env=env)

        # 1. create contract
        BYTECODE = "6080604052348015600f57600080fd5b5060948061001e6000396000f3fe6080604052600436106039576000357c01000000000000000000000000000000000000000000000000000000009004806341c0e1b514603b575b005b348015604657600080fd5b50604d604f565b005b3373ffffffffffffffffffffffffffffffffffffffff16fffea165627a7a7230582034cc4e996685dcadcc12db798751d2913034a3e963356819f2293c3baea4a18c0029"
        """
        pragma solidity ^0.5.1;
        contract Sample {
          function () payable external{}
          function kill() external {selfdestruct(msg.sender);}
        }
        """
        CREATION_GAS = 92417
        tx = contract_creation_tx(
            shard_state=state,
            key=id1.get_key(),
            from_address=acc1,
            to_full_shard_key=acc1.full_shard_key,
            bytecode=BYTECODE,
            gas_token_id=self.genesis_token,
            transfer_token_id=self.genesis_token,
        )
        self.assertTrue(state.add_tx(tx))
        b1 = state.create_block_to_mine(address=acc3)
        self.assertEqual(len(b1.tx_list), 1)
        state.finalize_and_add_block(b1)
        self.assertEqual(state.header_tip, b1.header)
        self.assertEqual(len(state.evm_state.receipts), 1)
        self.assertEqual(state.evm_state.receipts[0].state_root, b"\x01")
        self.assertEqual(state.evm_state.receipts[0].gas_used, CREATION_GAS)
        contract_address = mk_contract_address(acc1.recipient, 0, acc1.full_shard_key)
        self.assertEqual(contract_address, state.evm_state.receipts[0].contract_address)
        self.assertEqual(
            acc1.full_shard_key, state.evm_state.receipts[0].contract_full_shard_key
        )
        self.assertEqual(
            state.get_token_balance(id1.recipient, self.genesis_token),
            200 * 10 ** 18 - CREATION_GAS,
        )
        self.assertEqual(
            state.get_token_balance(acc3.recipient, self.genesis_token),
            self.get_after_tax_reward(CREATION_GAS + self.shard_coinbase),
        )
        tx_list, _ = state.db.get_transactions_by_address(acc1)
        self.assertEqual(tx_list[0].value, 0)
        self.assertEqual(tx_list[0].gas_token_id, self.genesis_token)
        self.assertEqual(tx_list[0].transfer_token_id, self.genesis_token)

        # 2. send some default token
        tx_send = create_transfer_transaction(
            shard_state=state,
            key=id1.get_key(),
            from_address=acc1,
            to_address=Address(contract_address, acc1.full_shard_key),
            value=10 * 10 ** 18,
            gas=opcodes.GTXCOST + 40,
            gas_price=1,
            nonce=None,
            data=b"",
            gas_token_id=self.genesis_token,
            transfer_token_id=self.genesis_token,
        )
        self.assertTrue(state.add_tx(tx_send))
        b2 = state.create_block_to_mine(address=acc3)
        self.assertEqual(len(b2.tx_list), 1)
        state.finalize_and_add_block(b2)
        self.assertEqual(state.header_tip, b2.header)
        self.assertEqual(len(state.evm_state.receipts), 1)
        self.assertEqual(state.evm_state.receipts[0].state_root, b"\x01")
        self.assertEqual(state.evm_state.receipts[0].gas_used, opcodes.GTXCOST + 40)
        self.assertEqual(
            state.get_token_balance(id1.recipient, self.genesis_token),
            200 * 10 ** 18 - CREATION_GAS - (opcodes.GTXCOST + 40) - 10 * 10 ** 18,
        )
        self.assertEqual(
            state.get_token_balance(contract_address, self.genesis_token), 10 * 10 ** 18
        )

        # 3. suicide
        SUICIDE_GAS = 13199
        tx_kill = create_transfer_transaction(
            shard_state=state,
            key=id2.get_key(),
            from_address=acc2,
            to_address=Address(contract_address, acc1.full_shard_key),
            value=0,
            gas=1000000,
            gas_price=0,  # !!! acc2 has no token yet...
            nonce=None,
            data=bytes.fromhex("41c0e1b5"),
            gas_token_id=self.genesis_token,
            transfer_token_id=self.genesis_token,
        )
        self.assertTrue(state.add_tx(tx_kill))
        b3 = state.create_block_to_mine(address=acc3)
        self.assertEqual(len(b3.tx_list), 1)
        state.finalize_and_add_block(b3)
        self.assertEqual(state.header_tip, b3.header)
        self.assertEqual(len(state.evm_state.receipts), 1)
        self.assertEqual(state.evm_state.receipts[0].state_root, b"\x01")
        self.assertEqual(state.evm_state.receipts[0].gas_used, SUICIDE_GAS)
        self.assertEqual(
            state.get_token_balance(id2.recipient, self.genesis_token), 10 * 10 ** 18
        )
        self.assertEqual(
            state.get_token_balance(contract_address, self.genesis_token), 0
        )
Exemple #30
0
    def test_xshard_native_token_gas_received(self):
        qeth = token_id_encode("QETHXX")
        id1 = Identity.create_random_identity()
        acc1 = Address.create_from_identity(id1, full_shard_key=0)
        acc2 = Address.create_from_identity(id1, full_shard_key=16)
        acc3 = Address.create_random_account(full_shard_key=0)

        env0 = get_test_env(
            genesis_account=acc1,
            genesis_minor_token_balances={"QETHXX": 9999999},
            shard_size=64,
        )
        env1 = get_test_env(
            genesis_account=acc1,
            genesis_minor_token_balances={"QETHXX": 9999999},
            shard_size=64,
        )
        state0 = create_default_shard_state(env=env0, shard_id=0)
        state1 = create_default_shard_state(env=env1, shard_id=16)

        # Add a root block to allow later minor blocks referencing this root block to
        # be broadcasted
        root_block = (
            state0.root_tip.create_block_to_append()
            .add_minor_block_header(state0.header_tip)
            .add_minor_block_header(state1.header_tip)
            .finalize()
        )
        state0.add_root_block(root_block)
        state1.add_root_block(root_block)

        # Add one block in shard 0
        b0 = state0.create_block_to_mine()
        state0.finalize_and_add_block(b0)

        b1 = state1.get_tip().create_block_to_append()
        b1.header.hash_prev_root_block = root_block.header.get_hash()
        tx = create_transfer_transaction(
            shard_state=state1,
            key=id1.get_key(),
            from_address=acc2,
            to_address=acc1,
            value=8888888,
            gas=opcodes.GTXXSHARDCOST + opcodes.GTXCOST,
            gas_price=2,
            gas_token_id=qeth,
            transfer_token_id=qeth,
        )
        b1.add_tx(tx)

        # Add a x-shard tx from remote peer
        state0.add_cross_shard_tx_list_by_minor_block_hash(
            h=b1.header.get_hash(),
            tx_list=CrossShardTransactionList(
                tx_list=[
                    CrossShardTransactionDeposit(
                        tx_hash=tx.get_hash(),
                        from_address=acc2,
                        to_address=acc1,
                        value=8888888,
                        gas_price=2,
                        gas_token_id=self.genesis_token,
                        transfer_token_id=qeth,
                    )
                ]
            ),
        )

        # Create a root block containing the block with the x-shard tx
        root_block = (
            state0.root_tip.create_block_to_append()
            .add_minor_block_header(b0.header)
            .add_minor_block_header(b1.header)
            .finalize()
        )
        state0.add_root_block(root_block)

        # Add b0 and make sure all x-shard tx's are added
        b2 = state0.create_block_to_mine(address=acc3)
        state0.finalize_and_add_block(b2)

        self.assertEqual(
            state0.get_token_balance(acc1.recipient, qeth), 9999999 + 8888888
        )
        # Half coinbase collected by root + tx fee
        self.assertEqual(
            state0.get_token_balance(acc3.recipient, self.genesis_token),
            self.get_after_tax_reward(self.shard_coinbase + opcodes.GTXXSHARDCOST * 2),
        )

        # X-shard gas used
        self.assertEqual(
            state0.evm_state.xshard_receive_gas_used, opcodes.GTXXSHARDCOST
        )