Пример #1
0
def proc_transfer_mnt(ext, msg):
    from quarkchain.evm.messages import apply_msg

    # Data must be >= 96 bytes
    if msg.data.size < 96:
        return 0, 0, []
    gascost = 3
    if msg.gas < gascost:
        return 0, 0, []
    to = utils.int_to_addr(msg.data.extract32(0))
    mnt = msg.data.extract32(32)
    value = msg.data.extract32(64)
    data = msg.data.extract_all(96)
    new_msg = vm.Message(
        msg.sender,
        to,
        value,
        msg.gas - gascost,
        data,
        msg.depth + 1,
        code_address=to,
        static=msg.static,
        transfer_token_id=mnt,
        gas_token_id=msg.gas_token_id,
    )
    return apply_msg(ext, new_msg)
Пример #2
0
def proc_deploy_system_contract(ext, msg):
    from quarkchain.evm.messages import create_contract

    gascost = 3
    if msg.gas < gascost:
        return 0, 0, []

    data = msg.data.extract32(0)
    contract_index = data if data else 1

    try:
        target_addr, bytecode, enable_ts = _system_contracts[SystemContract(
            contract_index)]
    except (ValueError, KeyError):
        # Not a valid `SystemContract` or the dict doesn't contain its info
        return 0, 0, []

    if ext.block_timestamp < enable_ts:
        return 0, 0, []

    new_msg = vm.Message(
        msg.to,  # current special address
        b"",
        0,
        msg.gas - gascost,
        bytecode,
        msg.depth + 1,
        to_full_shard_key=msg.to_full_shard_key,
        transfer_token_id=msg.transfer_token_id,
        gas_token_id=msg.gas_token_id,
    )
    # Use predetermined contract address
    return create_contract(ext, new_msg, target_addr)
Пример #3
0
def proc_deploy_system_contract(ext, msg):
    from quarkchain.evm.messages import create_contract

    gascost = 3
    if msg.gas < gascost:
        return 0, 0, []

    data = msg.data.extract32(0)
    contract_index = data if data else 1
    if contract_index not in [e.value for e in SystemContract]:
        return 0, 0, []

    target_addr, bytecode, enable_ts = _system_contracts[SystemContract(
        contract_index)]
    if ext.block_timestamp < enable_ts:
        return 0, 0, []

    new_msg = vm.Message(
        msg.to,  # current special address
        b"",
        0,
        msg.gas - gascost,
        bytecode,
        msg.depth + 1,
        to_full_shard_key=msg.to_full_shard_key,
        transfer_token_id=msg.transfer_token_id,
        gas_token_id=msg.gas_token_id,
    )
    # Use predetermined contract address
    return create_contract(ext, new_msg, target_addr)
Пример #4
0
def apply_message(state, msg=None, **kwargs):
    if msg is None:
        msg = vm.Message(**kwargs)
    else:
        assert not kwargs
    ext = VMExt(state, transactions.Transaction(0, 0, 21000, b"", 0, b""))
    result, gas_remained, data = apply_msg(ext, msg)
    return bytearray_to_bytestr(data) if result else None
Пример #5
0
def proc_transfer_mnt(ext, msg):
    from quarkchain.evm.messages import apply_msg

    # Data must be >= 96 bytes and static call not allowed
    if msg.data.size < 96 or msg.static:
        return 0, 0, []
    to = utils.int_to_addr(msg.data.extract32(0))
    token_id = msg.data.extract32(32)
    value = msg.data.extract32(64)
    data = msg.data.extract_all(96)

    # Token ID should be within range
    if token_id > TOKEN_ID_MAX:
        return 0, 0, []

    # Doesn't allow target address to be this precompiled contract itself
    if to == decode_hex(b"000000000000000000000000000000514b430002"):
        return 0, 0, []

    gascost = 0
    if value > 0:
        gascost += opcodes.GCALLVALUETRANSFER
        if not ext.account_exists(to):
            gascost += opcodes.GCALLNEWACCOUNT
    # Out of gas
    if msg.gas < gascost:
        return 0, 0, []
    # Handle insufficient balance or exceeding max call depth
    if ext.get_balance(msg.sender,
                       token_id) < value or msg.depth >= vm.MAX_DEPTH:
        return 0, msg.gas - gascost, []
    new_msg = vm.Message(
        msg.sender,
        to,
        value,
        msg.gas - gascost + opcodes.GSTIPEND * (value > 0),
        data,
        msg.depth + 1,
        code_address=to,
        static=False,
        transfer_token_id=token_id,
        gas_token_id=msg.gas_token_id,
    )
    return apply_msg(ext, new_msg)
Пример #6
0
def apply_xshard_desposit(state, deposit, gas_used_start):
    state.logs = []
    state.suicides = []
    state.refunds = 0
    state.full_shard_key = deposit.to_address.full_shard_key

    state.delta_token_balance(
        deposit.from_address.recipient, deposit.transfer_token_id, deposit.value
    )

    message_data = vm.CallData(
        [safe_ord(x) for x in deposit.message_data], 0, len(deposit.message_data)
    )

    message = vm.Message(
        deposit.from_address.recipient,
        deposit.to_address.recipient,
        deposit.value,
        deposit.gas_remained,
        message_data,
        code_address=deposit.to_address.recipient,
        from_full_shard_key=deposit.from_address.full_shard_key,
        to_full_shard_key=deposit.to_address.full_shard_key,
        tx_hash=deposit.tx_hash,
        transfer_token_id=deposit.transfer_token_id,
        gas_token_id=deposit.gas_token_id,
    )

    # MESSAGE
    ext = VMExt(
        state, sender=deposit.from_address.recipient, gas_price=deposit.gas_price
    )

    return apply_transaction_message(
        state,
        message,
        ext,
        should_create_contract=deposit.create_contract,
        gas_used_start=gas_used_start,
        is_cross_shard=True,
        contract_address=deposit.to_address.recipient
        if deposit.create_contract
        else b"",
    )
Пример #7
0
def proc_deploy_root_chain_staking_contract(ext, msg):
    from quarkchain.evm.messages import create_contract

    gascost = 3
    if msg.gas < gascost:
        return 0, 0, []

    target_addr, bytecode = _system_contracts[SystemContract.ROOT_CHAIN_POSW]
    new_msg = vm.Message(
        msg.to,  # current special address
        b"",
        0,
        msg.gas - gascost,
        bytecode,
        msg.depth + 1,
        to_full_shard_key=msg.to_full_shard_key,
        transfer_token_id=msg.transfer_token_id,
        gas_token_id=msg.gas_token_id,
    )
    # Use predetermined contract address
    return create_contract(ext, new_msg, target_addr)
Пример #8
0
def _call_general_native_token_manager(state, data: bytes) -> (int, int):
    contract_addr = SystemContract.GENERAL_NATIVE_TOKEN.addr()
    code = state.get_code(contract_addr)
    if not code:
        return 0, 0
    # Only contract itself can invoke payment
    sender = contract_addr
    # Call the `calculateGasPrice` function
    message = vm.Message(
        sender,
        contract_addr,
        0,
        1000000,  # Mock gas to guarantee msg will be applied
        data,
        code_address=contract_addr,
    )
    ext = VMExt(state, sender, gas_price=0)
    result, _, output = apply_msg(ext, message)
    if not result:
        return 0, 0
    refund_rate = int.from_bytes(output[:32], byteorder="big")
    converted_gas_price = int.from_bytes(output[32:64], byteorder="big")
    return refund_rate, converted_gas_price
Пример #9
0
def apply_transaction(state, tx: transactions.Transaction, tx_wrapper_hash):
    """tx_wrapper_hash is the hash for quarkchain.core.Transaction
    TODO: remove quarkchain.core.Transaction wrapper and use evm.Transaction directly
    """
    state.logs = []
    state.suicides = []
    state.refunds = 0
    validate_transaction(state, tx)

    state.full_shard_key = tx.to_full_shard_key

    intrinsic_gas = tx.intrinsic_gas_used
    log_tx.debug("TX NEW", txdict=tx.to_dict())

    # start transacting #################
    if tx.sender != null_address:
        state.increment_nonce(tx.sender)

    # part of fees should go to root chain miners
    local_fee_rate = (1 - state.qkc_config.reward_tax_rate
                      if state.qkc_config else Fraction(1))

    # buy startgas
    assert state.get_balance(tx.sender) >= tx.startgas * tx.gasprice
    state.delta_balance(tx.sender, -tx.startgas * tx.gasprice)

    message_data = vm.CallData([safe_ord(x) for x in tx.data], 0, len(tx.data))
    message = vm.Message(
        tx.sender,
        tx.to,
        tx.value,
        tx.startgas - intrinsic_gas,
        message_data,
        code_address=tx.to,
        is_cross_shard=tx.is_cross_shard,
        from_full_shard_key=tx.from_full_shard_key,
        to_full_shard_key=tx.to_full_shard_key,
        tx_hash=tx_wrapper_hash,
    )

    # MESSAGE
    ext = VMExt(state, tx)

    contract_address = b""
    if tx.to != b"":
        result, gas_remained, data = apply_msg(ext, message)
    else:  # CREATE
        result, gas_remained, data = create_contract(ext, message)
        contract_address = (data if data else b""
                            )  # data could be [] when vm failed execution

    assert gas_remained >= 0

    log_tx.debug("TX APPLIED",
                 result=result,
                 gas_remained=gas_remained,
                 data=data)

    gas_used = tx.startgas - gas_remained

    # pay CORRECT tx fee (after tax) to coinbase so that each step of state is accurate
    # Transaction failed
    if not result:
        log_tx.debug(
            "TX FAILED",
            reason="out of gas",
            startgas=tx.startgas,
            gas_remained=gas_remained,
        )
        state.delta_balance(tx.sender, tx.gasprice * gas_remained)
        fee = (tx.gasprice * gas_used * local_fee_rate.numerator //
               local_fee_rate.denominator)
        state.delta_balance(state.block_coinbase, fee)
        state.block_fee += tx.gasprice * gas_used
        output = b""
        success = 0
    # Transaction success
    else:
        log_tx.debug("TX SUCCESS", data=data)
        state.refunds += len(set(state.suicides)) * opcodes.GSUICIDEREFUND
        if state.refunds > 0:
            log_tx.debug("Refunding",
                         gas_refunded=min(state.refunds, gas_used // 2))
            gas_remained += min(state.refunds, gas_used // 2)
            gas_used -= min(state.refunds, gas_used // 2)
            state.refunds = 0
        # sell remaining gas
        state.delta_balance(tx.sender, tx.gasprice * gas_remained)
        # if x-shard, reserve part of the gas for the target shard miner
        fee = (tx.gasprice *
               (gas_used -
                (opcodes.GTXXSHARDCOST if tx.is_cross_shard else 0)) *
               local_fee_rate.numerator // local_fee_rate.denominator)
        state.delta_balance(state.block_coinbase, fee)
        state.block_fee += fee
        if tx.to:
            output = bytearray_to_bytestr(data)
        else:
            output = data
        success = 1

        # TODO: check if the destination address is correct, and consume xshard gas of the state
        # the xshard gas and fee is consumed by destination shard block

    state.gas_used += gas_used

    # Clear suicides
    suicides = state.suicides
    state.suicides = []
    for s in suicides:
        state.set_balance(s, 0)
        state.del_account(s)

    # Pre-Metropolis: commit state after every tx
    if not state.is_METROPOLIS() and not SKIP_MEDSTATES:
        state.commit()

    # Construct a receipt
    r = mk_receipt(state, success, state.logs, contract_address,
                   state.full_shard_key)
    state.logs = []
    state.add_receipt(r)
    state.set_param("bloom", state.bloom | r.bloom)
    state.set_param("txindex", state.txindex + 1)

    return success, output
Пример #10
0
def apply_transaction(state, tx: transactions.Transaction, tx_wrapper_hash):
    """tx_wrapper_hash is the hash for quarkchain.core.Transaction
    TODO: remove quarkchain.core.Transaction wrapper and use evm.Transaction directly
    """
    state.logs = []
    state.suicides = []
    state.refunds = 0
    validate_transaction(state, tx)

    state.full_shard_key = tx.to_full_shard_key

    intrinsic_gas = tx.intrinsic_gas_used
    log_tx.debug("TX NEW", txdict=tx.to_dict())

    # start transacting #################
    state.increment_nonce(tx.sender)

    # part of fees should go to root chain miners
    local_fee_rate = (1 - state.qkc_config.reward_tax_rate
                      if state.qkc_config else Fraction(1))

    # buy startgas
    gasprice, refund_rate = tx.gasprice, 100
    # convert gas if using non-genesis native token
    if gasprice != 0 and tx.gas_token_id != state.genesis_token:
        refund_rate, converted_genesis_token_gas_price = pay_native_token_as_gas(
            state, tx.gas_token_id, tx.startgas, tx.gasprice)
        # guaranteed by validation
        check(converted_genesis_token_gas_price > 0)
        gasprice = converted_genesis_token_gas_price
        contract_addr = SystemContract.GENERAL_NATIVE_TOKEN.addr()
        # guaranteed by validation
        check(
            state.deduct_value(
                contract_addr,
                state.genesis_token,
                tx.startgas * converted_genesis_token_gas_price,
            ))
        state.delta_token_balance(contract_addr, tx.gas_token_id,
                                  tx.startgas * tx.gasprice)

    check(
        state.deduct_value(tx.sender, tx.gas_token_id,
                           tx.startgas * tx.gasprice))

    message_data = vm.CallData([safe_ord(x) for x in tx.data], 0, len(tx.data))
    message = vm.Message(
        tx.sender,
        tx.to,
        tx.value,
        tx.startgas - intrinsic_gas,
        message_data,
        code_address=tx.to,
        from_full_shard_key=tx.from_full_shard_key
        if not tx.is_testing else None,
        to_full_shard_key=tx.to_full_shard_key if not tx.is_testing else None,
        tx_hash=tx_wrapper_hash,
        transfer_token_id=tx.transfer_token_id,
        # always genesis token for gas token
        gas_token_id=state.genesis_token,
    )

    # MESSAGE
    ext = VMExt(state, tx.sender, gasprice)

    contract_address = b""
    if not tx.is_cross_shard:
        return apply_transaction_message(state,
                                         message,
                                         ext,
                                         tx.to == b"",
                                         intrinsic_gas,
                                         refund_rate=refund_rate)

    # handle xshard
    local_gas_used = intrinsic_gas
    remote_gas_reserved = 0
    if transfer_failure_by_posw_balance_check(ext, message):
        success = 0
        # Currently, burn all gas
        local_gas_used = tx.startgas
    elif tx.to == b"":
        check(state.deduct_value(tx.sender, tx.transfer_token_id, tx.value))
        remote_gas_reserved = tx.startgas - intrinsic_gas
        ext.add_cross_shard_transaction_deposit(
            quarkchain.core.CrossShardTransactionDeposit(
                tx_hash=tx_wrapper_hash,
                from_address=quarkchain.core.Address(tx.sender,
                                                     tx.from_full_shard_key),
                to_address=quarkchain.core.Address(
                    mk_contract_address(tx.sender, state.get_nonce(tx.sender),
                                        tx.from_full_shard_key),
                    tx.to_full_shard_key,
                ),
                value=tx.value,
                # convert to genesis token and use converted gas price
                gas_token_id=state.genesis_token,
                gas_price=gasprice,
                transfer_token_id=tx.transfer_token_id,
                message_data=tx.data,
                create_contract=True,
                gas_remained=remote_gas_reserved,
                refund_rate=refund_rate,
            ))
        success = 1
    else:
        check(state.deduct_value(tx.sender, tx.transfer_token_id, tx.value))
        if (state.qkc_config.ENABLE_EVM_TIMESTAMP is None
                or state.timestamp >= state.qkc_config.ENABLE_EVM_TIMESTAMP):
            remote_gas_reserved = tx.startgas - intrinsic_gas
        ext.add_cross_shard_transaction_deposit(
            quarkchain.core.CrossShardTransactionDeposit(
                tx_hash=tx_wrapper_hash,
                from_address=quarkchain.core.Address(tx.sender,
                                                     tx.from_full_shard_key),
                to_address=quarkchain.core.Address(tx.to,
                                                   tx.to_full_shard_key),
                value=tx.value,
                # convert to genesis token and use converted gas price
                gas_token_id=state.genesis_token,
                gas_price=gasprice,
                transfer_token_id=tx.transfer_token_id,
                message_data=tx.data,
                create_contract=False,
                gas_remained=remote_gas_reserved,
                refund_rate=refund_rate,
            ))
        success = 1
    gas_remained = tx.startgas - local_gas_used - remote_gas_reserved

    _refund(state, message, ext.tx_gasprice * gas_remained, refund_rate)

    # if x-shard, reserve part of the gas for the target shard miner for fee
    fee = (ext.tx_gasprice * (local_gas_used -
                              (opcodes.GTXXSHARDCOST if success else 0)) *
           local_fee_rate.numerator // local_fee_rate.denominator)
    state.delta_token_balance(state.block_coinbase, state.genesis_token, fee)
    add_dict(state.block_fee_tokens, {state.genesis_token: fee})

    output = []

    state.gas_used += local_gas_used
    if (state.qkc_config.ENABLE_EVM_TIMESTAMP is None
            or state.timestamp >= state.qkc_config.ENABLE_EVM_TIMESTAMP):
        state.gas_used -= opcodes.GTXXSHARDCOST if success else 0

    # Construct a receipt
    r = mk_receipt(state, success, state.logs, contract_address,
                   state.full_shard_key)
    state.logs = []
    state.add_receipt(r)
    return success, output
Пример #11
0
def apply_transaction(state, tx: transactions.Transaction, tx_wrapper_hash):
    """tx_wrapper_hash is the hash for quarkchain.core.Transaction
    TODO: remove quarkchain.core.Transaction wrapper and use evm.Transaction directly
    """
    state.logs = []
    state.suicides = []
    state.refunds = 0
    validate_transaction(state, tx)

    state.full_shard_key = tx.to_full_shard_key

    intrinsic_gas = tx.intrinsic_gas_used
    log_tx.debug("TX NEW", txdict=tx.to_dict())

    # start transacting #################
    state.increment_nonce(tx.sender)

    # part of fees should go to root chain miners
    local_fee_rate = (1 - state.qkc_config.reward_tax_rate
                      if state.qkc_config else Fraction(1))

    # buy startgas
    assert (state.get_balance(tx.sender, token_id=tx.gas_token_id) >=
            tx.startgas * tx.gasprice)
    state.delta_token_balance(tx.sender, tx.gas_token_id,
                              -tx.startgas * tx.gasprice)

    message_data = vm.CallData([safe_ord(x) for x in tx.data], 0, len(tx.data))
    message = vm.Message(
        tx.sender,
        tx.to,
        tx.value,
        tx.startgas - intrinsic_gas,
        message_data,
        code_address=tx.to,
        from_full_shard_key=tx.from_full_shard_key
        if not tx.is_testing else None,
        to_full_shard_key=tx.to_full_shard_key if not tx.is_testing else None,
        tx_hash=tx_wrapper_hash,
        transfer_token_id=tx.transfer_token_id,
        gas_token_id=tx.gas_token_id,
    )

    # MESSAGE
    ext = VMExt(state, tx.sender, tx.gasprice)

    contract_address = b""
    if tx.is_cross_shard:
        local_gas_used = intrinsic_gas
        remote_gas_reserved = 0
        if transfer_failure_by_posw_balance_check(ext, message):
            success = 0
            # Currently, burn all gas
            local_gas_used = tx.startgas
        elif tx.to == b"":
            state.delta_token_balance(tx.sender, tx.transfer_token_id,
                                      -tx.value)
            remote_gas_reserved = tx.startgas - intrinsic_gas
            ext.add_cross_shard_transaction_deposit(
                quarkchain.core.CrossShardTransactionDeposit(
                    tx_hash=tx_wrapper_hash,
                    from_address=quarkchain.core.Address(
                        tx.sender, tx.from_full_shard_key),
                    to_address=quarkchain.core.Address(
                        mk_contract_address(
                            tx.sender,
                            state.get_nonce(tx.sender),
                            tx.from_full_shard_key,
                        ),
                        tx.to_full_shard_key,
                    ),
                    value=tx.value,
                    gas_price=tx.gasprice,
                    gas_token_id=tx.gas_token_id,
                    transfer_token_id=tx.transfer_token_id,
                    message_data=tx.data,
                    create_contract=True,
                    gas_remained=remote_gas_reserved,
                ))
            success = 1
        else:
            state.delta_token_balance(tx.sender, tx.transfer_token_id,
                                      -tx.value)
            if (state.qkc_config.ENABLE_EVM_TIMESTAMP is None or
                    state.timestamp >= state.qkc_config.ENABLE_EVM_TIMESTAMP):
                remote_gas_reserved = tx.startgas - intrinsic_gas
            ext.add_cross_shard_transaction_deposit(
                quarkchain.core.CrossShardTransactionDeposit(
                    tx_hash=tx_wrapper_hash,
                    from_address=quarkchain.core.Address(
                        tx.sender, tx.from_full_shard_key),
                    to_address=quarkchain.core.Address(tx.to,
                                                       tx.to_full_shard_key),
                    value=tx.value,
                    gas_price=tx.gasprice,
                    gas_token_id=tx.gas_token_id,
                    transfer_token_id=tx.transfer_token_id,
                    message_data=tx.data,
                    create_contract=False,
                    gas_remained=remote_gas_reserved,
                ))
            success = 1
        gas_remained = tx.startgas - local_gas_used - remote_gas_reserved

        # Refund
        state.delta_token_balance(message.sender, message.gas_token_id,
                                  ext.tx_gasprice * gas_remained)

        # if x-shard, reserve part of the gas for the target shard miner for fee
        fee = (tx.gasprice * (local_gas_used -
                              (opcodes.GTXXSHARDCOST if success else 0)) *
               local_fee_rate.numerator // local_fee_rate.denominator)
        state.delta_token_balance(state.block_coinbase, tx.gas_token_id, fee)
        add_dict(state.block_fee_tokens, {message.gas_token_id: fee})

        output = []

        state.gas_used += local_gas_used
        if (state.qkc_config.ENABLE_EVM_TIMESTAMP is None
                or state.timestamp >= state.qkc_config.ENABLE_EVM_TIMESTAMP):
            state.gas_used -= opcodes.GTXXSHARDCOST if success else 0

        # Construct a receipt
        r = mk_receipt(state, success, state.logs, contract_address,
                       state.full_shard_key)
        state.logs = []
        state.add_receipt(r)
        return success, output

    return apply_transaction_message(state, message, ext, tx.to == b"",
                                     intrinsic_gas)