示例#1
0
def create_transfer_transaction(
    shard_state,
    key,
    from_address,
    to_address,
    value,
    gas=21000,  # transfer tx min gas
    gas_price=1,
    nonce=None,
    data=b"",
    gas_token_id=None,
    transfer_token_id=None,
):
    if gas_token_id is None:
        gas_token_id = shard_state.env.quark_chain_config.genesis_token
    if transfer_token_id is None:
        transfer_token_id = shard_state.env.quark_chain_config.genesis_token
    """ Create an in-shard xfer tx
    """
    evm_tx = EvmTransaction(
        nonce=shard_state.get_transaction_count(from_address.recipient)
        if nonce is None else nonce,
        gasprice=gas_price,
        startgas=gas,
        to=to_address.recipient,
        value=value,
        data=data,
        from_full_shard_key=from_address.full_shard_key,
        to_full_shard_key=to_address.full_shard_key,
        network_id=shard_state.env.quark_chain_config.NETWORK_ID,
        gas_token_id=gas_token_id,
        transfer_token_id=transfer_token_id,
    )
    evm_tx.sign(key=key)
    return TypedTransaction(SerializedEvmTransaction.from_evm_tx(evm_tx))
示例#2
0
def contract_creation_tx(
    shard_state,
    key,
    from_address,
    to_full_shard_key,
    bytecode,
    gas=100000,
    gas_token_id=None,
    transfer_token_id=None,
):
    if gas_token_id is None:
        gas_token_id = shard_state.env.quark_chain_config.genesis_token
    if transfer_token_id is None:
        transfer_token_id = shard_state.env.quark_chain_config.genesis_token
    evm_tx = EvmTransaction(
        nonce=shard_state.get_transaction_count(from_address.recipient),
        gasprice=1,
        startgas=gas,
        value=0,
        to=b"",
        data=bytes.fromhex(bytecode),
        from_full_shard_key=from_address.full_shard_key,
        to_full_shard_key=to_full_shard_key,
        network_id=shard_state.env.quark_chain_config.NETWORK_ID,
        gas_token_id=gas_token_id,
        transfer_token_id=transfer_token_id,
    )
    evm_tx.sign(key)
    return TypedTransaction(SerializedEvmTransaction.from_evm_tx(evm_tx))
示例#3
0
def create_transfer_transaction(
    shard_state,
    key,
    from_address,
    to_address,
    value,
    gas=21000,  # transfer tx min gas
    gas_price=1,
    nonce=None,
    data=b"",
):
    """ Create an in-shard xfer tx
    """
    evm_tx = EvmTransaction(
        nonce=shard_state.get_transaction_count(from_address.recipient)
        if nonce is None else nonce,
        gasprice=gas_price,
        startgas=gas,
        to=to_address.recipient,
        value=value,
        data=data,
        from_full_shard_id=from_address.full_shard_id,
        to_full_shard_id=to_address.full_shard_id,
        network_id=shard_state.env.quark_chain_config.NETWORK_ID,
    )
    evm_tx.sign(key=key)
    return Transaction(in_list=[],
                       code=Code.create_evm_code(evm_tx),
                       out_list=[])
示例#4
0
    def create_transaction(self, account, nonce, x_shard_percent,
                           sample_evm_tx) -> Optional[Transaction]:
        shard_size = self.qkc_config.SHARD_SIZE
        shard_mask = shard_size - 1
        from_shard = self.shard_id

        # skip if from shard is specified and not matching current branch
        # FIXME: it's possible that clients want to specify '0x0' as the full shard ID, however it will not be supported
        if (sample_evm_tx.from_full_shard_id and
            (sample_evm_tx.from_full_shard_id & shard_mask) != from_shard):
            return None

        if sample_evm_tx.from_full_shard_id:
            from_full_shard_id = sample_evm_tx.from_full_shard_id
        else:
            from_full_shard_id = (account.address.full_shard_id & (~shard_mask)
                                  | from_shard)

        if not sample_evm_tx.to:
            to_address = random.choice(self.accounts).address
            recipient = to_address.recipient
            to_full_shard_id = to_address.full_shard_id & (
                ~shard_mask) | from_shard
        else:
            recipient = sample_evm_tx.to
            to_full_shard_id = from_full_shard_id

        if random.randint(1, 100) <= x_shard_percent:
            # x-shard tx
            to_shard = random.randint(0, self.qkc_config.SHARD_SIZE - 1)
            if to_shard == self.shard_id:
                to_shard = (to_shard + 1) % self.qkc_config.SHARD_SIZE
            to_full_shard_id = to_full_shard_id & (~shard_mask) | to_shard

        value = sample_evm_tx.value
        if not sample_evm_tx.data:
            value = random.randint(1, 100) * (10**15)

        gas_token_id = 1
        transfer_token_id = 1

        evm_tx = EvmTransaction(
            nonce=nonce,
            gasprice=sample_evm_tx.gasprice,
            startgas=sample_evm_tx.startgas,
            gas_token_id=gas_token_id,
            to=recipient,
            value=value,
            transfer_token_id=transfer_token_id,
            data=sample_evm_tx.data,
            from_full_shard_id=from_full_shard_id,
            to_full_shard_id=to_full_shard_id,
            network_id=self.qkc_config.NETWORK_ID,
        )
        evm_tx.sign(account.key)
        return Transaction(code=Code.create_evm_code(evm_tx))
示例#5
0
    def test_sendTransaction(self):
        id1 = Identity.create_random_identity()
        acc1 = Address.create_from_identity(id1, full_shard_key=0)
        acc2 = Address.create_random_account(full_shard_key=1)

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

            block = call_async(
                master.get_next_block_to_mine(address=acc2, branch_value=None))
            call_async(master.add_root_block(block))

            evm_tx = EvmTransaction(
                nonce=0,
                gasprice=6,
                startgas=30000,
                to=acc2.recipient,
                value=15,
                data=b"",
                from_full_shard_key=acc1.full_shard_key,
                to_full_shard_key=acc2.full_shard_key,
                network_id=slaves[0].env.quark_chain_config.NETWORK_ID,
                gas_token_id=master.env.quark_chain_config.genesis_token,
                transfer_token_id=master.env.quark_chain_config.genesis_token,
            )
            evm_tx.sign(id1.get_key())
            request = dict(
                to="0x" + acc2.recipient.hex(),
                gasPrice="0x6",
                gas=hex(30000),
                value="0xf",  # 15
                v=quantity_encoder(evm_tx.v),
                r=quantity_encoder(evm_tx.r),
                s=quantity_encoder(evm_tx.s),
                nonce="0x0",
                fromFullShardKey="0x00000000",
                toFullShardKey="0x00000001",
                network_id=hex(slaves[0].env.quark_chain_config.NETWORK_ID),
            )
            tx = TypedTransaction(SerializedEvmTransaction.from_evm_tx(evm_tx))
            response = send_request("sendTransaction", [request])

            self.assertEqual(response, "0x" + tx.get_hash().hex() + "00000000")
            state = clusters[0].get_shard_state(2 | 0)
            self.assertEqual(len(state.tx_queue), 1)
            self.assertEqual(
                state.tx_queue.pop_transaction(state.get_transaction_count),
                evm_tx)
def create_transaction(address, key, nonce, data, network_id) -> EvmTransaction:
    evm_tx = EvmTransaction(
        nonce=nonce,
        gasprice=1,
        startgas=1000000,
        to=b"",
        value=0,
        data=data,
        from_full_shard_key=address.full_shard_key,
        to_full_shard_key=address.full_shard_key,
        network_id=network_id,
    )
    evm_tx.sign(key)
    return evm_tx
def create_transaction(address, key, nonce, to, data,
                       network_id) -> EvmTransaction:
    evm_tx = EvmTransaction(
        nonce=nonce,
        gasprice=1,
        startgas=1000000,
        to=to.recipient,
        value=1000000 * (10**18),
        data=data,
        from_full_shard_id=address.full_shard_id,
        to_full_shard_id=to.full_shard_id,
        network_id=network_id,
    )
    evm_tx.sign(key)
    return evm_tx
def make_test_tx(s=100000, g=50, data='', nonce=0):
    return Transaction(nonce=nonce,
                       startgas=s,
                       gasprice=g,
                       value=0,
                       data=data,
                       to=b'\x35' * 20)
示例#9
0
    def create_transaction(self, account, nonce, x_shard_percent,
                           sample_evm_tx) -> Optional[TypedTransaction]:
        # skip if from shard is specified and not matching current branch
        # FIXME: it's possible that clients want to specify '0x0' as the full shard ID, however it will not be supported
        if (sample_evm_tx.from_full_shard_key
                and self.qkc_config.get_full_shard_id_by_full_shard_key(
                    sample_evm_tx.from_full_shard_key) != self.full_shard_id):
            return None

        if sample_evm_tx.from_full_shard_key:
            from_full_shard_key = sample_evm_tx.from_full_shard_key
        else:
            from_full_shard_key = self.full_shard_id

        if not sample_evm_tx.to:
            to_address = random.choice(self.accounts).address
            recipient = to_address.recipient
            to_full_shard_key = self.full_shard_id
        else:
            recipient = sample_evm_tx.to
            to_full_shard_key = from_full_shard_key

        if random.randint(1, 100) <= x_shard_percent:
            # x-shard tx
            to_full_shard_id = random.choice(
                self.qkc_config.get_full_shard_ids() - [self.full_shard_id])
            to_full_shard_key = to_full_shard_id

        value = sample_evm_tx.value
        if not sample_evm_tx.data:
            value = random.randint(1, 100) * (10**15)

        evm_tx = EvmTransaction(
            nonce=nonce,
            gasprice=sample_evm_tx.gasprice,
            startgas=sample_evm_tx.startgas,
            to=recipient,
            value=value,
            data=sample_evm_tx.data,
            gas_token_id=sample_evm_tx.gas_token_id,
            transfer_token_id=sample_evm_tx.transfer_token_id,
            from_full_shard_key=from_full_shard_key,
            to_full_shard_key=to_full_shard_key,
            network_id=self.qkc_config.NETWORK_ID,
        )
        evm_tx.sign(account.key)
        return TypedTransaction(SerializedEvmTransaction.from_evm_tx(evm_tx))
示例#10
0
    async def donate(self, from_address, to_address, value=hex(10 ** 18)):
        """Faucet function to send value (default 1 token) from from_address to to_address.
        from_address must be one of the addresses in genesis_data/alloc.json.
        Only allow one pending tx at a time.
        Return tx id if success else None
        """
        if value > 100 * (10 ** 18):
            return None

        key = self.master.env.quark_chain_config.alloc_accounts.get(
            from_address.hex(), None
        )
        if not key:
            return None

        from_address = Address.deserialize(from_address)
        to_address = Address.deserialize(to_address)

        # Do nothing if there is already a pending tx
        result = await self.master.get_transactions_by_address(
            from_address, bytes(1), 1
        )
        if result:
            tx_list, next_token = result
            if tx_list:
                return None

        account_branch_data = await self.master.get_primary_account_data(from_address)
        nonce = account_branch_data.transaction_count
        network_id = self.master.env.quark_chain_config.NETWORK_ID
        evm_tx = EvmTransaction(
            nonce,
            10 ** 9,
            30000,
            to_address.recipient,
            value,
            b"",
            from_full_shard_id=from_address.full_shard_id,
            to_full_shard_id=to_address.full_shard_id,
            network_id=network_id,
        )
        evm_tx.sign(key)
        tx = Transaction(code=Code.create_evm_code(evm_tx))
        success = await self.master.add_transaction(tx)
        if not success:
            return None
        return id_encoder(tx.get_hash(), from_address.full_shard_id)
示例#11
0
def _contract_tx_gen(shard_state, key, from_address, to_full_shard_id,
                     bytecode):
    evm_tx = EvmTransaction(
        nonce=shard_state.get_transaction_count(from_address.recipient),
        gasprice=1,
        startgas=1000000,
        value=0,
        to=b"",
        data=bytes.fromhex(bytecode),
        from_full_shard_id=from_address.full_shard_id,
        to_full_shard_id=to_full_shard_id,
        network_id=shard_state.env.quark_chain_config.NETWORK_ID,
    )
    evm_tx.sign(key)
    return Transaction(in_list=[],
                       code=Code.create_evm_code(evm_tx),
                       out_list=[])
def make_test_tx(s=100000, g=50, data=b"", nonce=0, key=None):
    evm_tx = EvmTransaction(
        nonce=nonce,
        startgas=s,
        gasprice=g,
        value=0,
        data=data,
        to=b"\x35" * 20,
        gas_token_id=0,
        transfer_token_id=0,
        r=1,
        s=1,
        v=28,
    )
    if key:
        evm_tx.sign(key=key)

    return TypedTransaction(SerializedEvmTransaction.from_evm_tx(evm_tx))
示例#13
0
    def test_sendTransaction(self):
        id1 = Identity.create_random_identity()
        acc1 = Address.create_from_identity(id1, full_shard_id=0)
        acc2 = Address.create_random_account(full_shard_id=1)

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

            branch = Branch.create(2, 0)
            evm_tx = EvmTransaction(
                nonce=0,
                gasprice=6,
                startgas=30000,
                to=acc2.recipient,
                value=15,
                data=b"",
                from_full_shard_id=acc1.full_shard_id,
                to_full_shard_id=acc2.full_shard_id,
                network_id=slaves[0].env.quark_chain_config.NETWORK_ID,
            )
            evm_tx.sign(id1.get_key())
            request = dict(
                to="0x" + acc2.recipient.hex(),
                gasPrice="0x6",
                gas=hex(30000),
                value="0xf",  # 15
                v=quantity_encoder(evm_tx.v),
                r=quantity_encoder(evm_tx.r),
                s=quantity_encoder(evm_tx.s),
                nonce="0x0",
                fromFullShardId="0x00000000",
                toFullShardId="0x00000001",
                network_id=hex(slaves[0].env.quark_chain_config.NETWORK_ID),
            )
            tx = Transaction(code=Code.create_evm_code(evm_tx))
            response = send_request("sendTransaction", [request])

            self.assertEqual(response, "0x" + tx.get_hash().hex() + "00000000")
            self.assertEqual(len(slaves[0].shards[branch].state.tx_queue), 1)
            self.assertEqual(
                slaves[0].shards[branch].state.tx_queue.pop_transaction(),
                evm_tx)
示例#14
0
def test_perf_evm():
    N = 5000
    IDN = 10
    print("Creating %d identities" % IDN)
    id_list = []
    for i in range(IDN):
        id_list.append(Identity.create_random_identity())

    acc_list = []
    for i in range(IDN):
        acc_list.append(Address.create_from_identity(id_list[i]))

    print("Creating %d transactions..." % N)
    start_time = time.time()
    tx_list = []
    from_list = []
    for i in range(N):
        from_id = id_list[random.randint(0, IDN - 1)]
        to_addr = acc_list[random.randint(0, IDN - 1)]
        evm_tx = EvmTransaction(
            nonce=0,
            gasprice=1,
            startgas=2,
            to=to_addr.recipient,
            value=3,
            data=b"",
            from_full_shard_key=0,
            to_full_shard_key=0,
            network_id=1,
        )
        evm_tx.sign(key=from_id.get_key())
        tx_list.append(evm_tx)
        from_list.append(from_id.get_recipient())
    duration = time.time() - start_time
    print("Creations PS: %.2f" % (N / duration))

    print("Verifying transactions")
    start_time = time.time()
    for i in range(N):
        tx_list[i]._sender = None
        assert tx_list[i].sender == from_list[i]
    duration = time.time() - start_time
    print("Verifications PS: %.2f" % (N / duration))
示例#15
0
    def test_tx_size(self):
        id1 = Identity.create_from_key(b"0" * 32)
        acc1 = Address.create_from_identity(id1, full_shard_key=0)

        evm_tx = EvmTransaction(
            nonce=0,
            gasprice=1,
            startgas=30000,
            to=acc1.recipient,
            value=0,
            data=b"",
            from_full_shard_key=0xFFFF,
            to_full_shard_key=0xFFFF,
            network_id=1,
            gas_token_id=12345,
            transfer_token_id=1234,
        )
        evm_tx.sign(key=id1.get_key())
        tx = TypedTransaction(SerializedEvmTransaction.from_evm_tx(evm_tx))
        self.assertEqual(len(tx.serialize()), TX_MIN_SIZE)

        evm_tx = EvmTransaction(
            nonce=TT256 - 1,
            gasprice=TT256 - 1,
            startgas=TT256 - 1,
            to=acc1.recipient,
            value=TT256 - 1,
            data=b"",
            from_full_shard_key=SHARD_KEY_MAX,
            to_full_shard_key=SHARD_KEY_MAX,
            network_id=1,
            gas_token_id=TOKEN_ID_MAX,
            transfer_token_id=TOKEN_ID_MAX,
        )
        evm_tx.sign(key=id1.get_key())
        tx = TypedTransaction(SerializedEvmTransaction.from_evm_tx(evm_tx))
        self.assertEqual(len(tx.serialize()), TX_MAX_SIZE)
示例#16
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
示例#17
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)
示例#18
0
class TestTypedSignature(unittest.TestCase):

    raw_tx = Transaction(
        nonce=0x0d,
        gasprice=0x02540be400,
        startgas=0x7530,
        to=bytes.fromhex("314b2cd22c6d26618ce051a58c65af1253aecbb8"),
        value=0x056bc75e2d63100000,
        data=b"",
        from_full_shard_key=0xc47decfd,
        to_full_shard_key=0xc49c1950,
        network_id=0x03,
    )

    tx = [
        {
            "type": "uint256",
            "name": "nonce",
            "value": "0x0d"
        },
        {
            "type": "uint256",
            "name": "gasPrice",
            "value": "0x02540be400"
        },
        {
            "type": "uint256",
            "name": "gasLimit",
            "value": "0x7530"
        },
        {
            "type": "uint160",
            "name": "to",
            "value": "0x314b2cd22c6d26618ce051a58c65af1253aecbb8",
        },
        {
            "type": "uint256",
            "name": "value",
            "value": "0x056bc75e2d63100000"
        },
        {
            "type": "bytes",
            "name": "data",
            "value": "0x"
        },
        {
            "type": "uint32",
            "name": "fromFullShardId",
            "value": "0xc47decfd"
        },
        {
            "type": "uint32",
            "name": "toFullShardId",
            "value": "0xc49c1950"
        },
        {
            "type": "uint256",
            "name": "networkId",
            "value": "0x03"
        },
        {
            "type": "string",
            "name": "qkcDomain",
            "value": "bottom-quark"
        },
    ]

    def test_typed(self):
        assert tx_to_typed_data(self.raw_tx) == self.tx

    def test_solidity_pack(self):
        schema = list(
            map(lambda x: "{} {}".format(x["type"], x["name"]), self.tx))
        types = list(map(lambda x: x["type"], self.tx))
        data = list(
            map(
                lambda x: bytes.fromhex(x["value"][2:])
                if x["type"] == "bytes" else x["value"],
                self.tx,
            ))
        h1 = solidity_pack(["string"] * len(self.tx), schema)
        h2 = solidity_pack(types, data)
        assert (
            h1.hex() ==
            "75696e74323536206e6f6e636575696e7432353620676173507269636575696e74323536206761734c696d697475696e7431363020746f75696e743235362076616c75656279746573206461746175696e7433322066726f6d46756c6c5368617264496475696e74333220746f46756c6c5368617264496475696e74323536206e6574776f726b4964737472696e6720716b63446f6d61696e"
        )
        assert (
            h2.hex() ==
            "000000000000000000000000000000000000000000000000000000000000000d00000000000000000000000000000000000000000000000000000002540be4000000000000000000000000000000000000000000000000000000000000007530314b2cd22c6d26618ce051a58c65af1253aecbb80000000000000000000000000000000000000000000000056bc75e2d63100000c47decfdc49c19500000000000000000000000000000000000000000000000000000000000000003626f74746f6d2d717561726b"
        )

    def test_typed_signature_hash(self):
        h = typed_signature_hash(self.tx)
        assert h == "0x57dfcc7be8e4249fb6e75a45dc5ecdfed0309ed951b6adc69b8a659c7eca33bf"

    def test_recover(self):
        """
        """
        self.raw_tx._in_mutable_context = True
        self.raw_tx.version = 1
        self.raw_tx.r = (
            0xb5145678e43df2b7ea8e0e969e51dbf72c956dd52e234c95393ad68744394855)
        self.raw_tx.s = (
            0x44515b465dbbf746a484239c11adb98f967e35347e17e71b84d850d8e5c38a6a)
        self.raw_tx.v = 0x1b
        self.raw_tx._in_mutable_context = False
        assert self.raw_tx.sender == bytes.fromhex(
            "8b74a79290a437aa9589be3227d9bb81b22beff1")
示例#19
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
class TestTypedSignature(unittest.TestCase):

    raw_tx = Transaction(
        nonce=0x0d,
        gasprice=0x02540be400,
        startgas=0x7530,
        to=bytes.fromhex("314b2cd22c6d26618ce051a58c65af1253aecbb8"),
        value=0x056bc75e2d63100000,
        data=b"",
        network_id=0x03,
        from_full_shard_key=0xc47decfd,
        to_full_shard_key=0xc49c1950,
        gas_token_id=0x0111,
        transfer_token_id=0x0222,
    )

    tx = [
        {
            "type": "uint256",
            "name": "nonce",
            "value": "0x0d"
        },
        {
            "type": "uint256",
            "name": "gasPrice",
            "value": "0x02540be400"
        },
        {
            "type": "uint256",
            "name": "gasLimit",
            "value": "0x7530"
        },
        {
            "type": "uint160",
            "name": "to",
            "value": "0x314b2cd22c6d26618ce051a58c65af1253aecbb8",
        },
        {
            "type": "uint256",
            "name": "value",
            "value": "0x056bc75e2d63100000"
        },
        {
            "type": "bytes",
            "name": "data",
            "value": "0x"
        },
        {
            "type": "uint256",
            "name": "networkId",
            "value": "0x03"
        },
        {
            "type": "uint32",
            "name": "fromFullShardKey",
            "value": "0xc47decfd"
        },
        {
            "type": "uint32",
            "name": "toFullShardKey",
            "value": "0xc49c1950"
        },
        {
            "type": "uint64",
            "name": "gasTokenId",
            "value": "0x0111"
        },
        {
            "type": "uint64",
            "name": "transferTokenId",
            "value": "0x0222"
        },
        {
            "type": "string",
            "name": "qkcDomain",
            "value": "bottom-quark"
        },
    ]

    def test_typed(self):
        self.assertEqual(tx_to_typed_data(self.raw_tx), self.tx)

    def test_solidity_pack(self):
        schema = list(
            map(lambda x: "{} {}".format(x["type"], x["name"]), self.tx))
        types = list(map(lambda x: x["type"], self.tx))
        data = list(
            map(
                lambda x: bytes.fromhex(x["value"][2:])
                if x["type"] == "bytes" else x["value"],
                self.tx,
            ))
        h1 = solidity_pack(["string"] * len(self.tx), schema)
        h2 = solidity_pack(types, data)

        self.assertEqual(
            h1.hex(),
            "75696e74323536206e6f6e636575696e7432353620676173507269636575696e74323536206761734c696d697475696e7431363020746f75696e743235362076616c75656279746573206461746175696e74323536206e6574776f726b496475696e7433322066726f6d46756c6c53686172644b657975696e74333220746f46756c6c53686172644b657975696e74363420676173546f6b656e496475696e743634207472616e73666572546f6b656e4964737472696e6720716b63446f6d61696e",
        )
        self.assertEqual(
            h2.hex(),
            "000000000000000000000000000000000000000000000000000000000000000d00000000000000000000000000000000000000000000000000000002540be4000000000000000000000000000000000000000000000000000000000000007530314b2cd22c6d26618ce051a58c65af1253aecbb80000000000000000000000000000000000000000000000056bc75e2d631000000000000000000000000000000000000000000000000000000000000000000003c47decfdc49c195000000000000001110000000000000222626f74746f6d2d717561726b",
        )

    def test_typed_signature_hash(self):
        h = typed_signature_hash(self.tx)
        self.assertEqual(
            h,
            "0xe768719d0a211ffb0b7f9c7bc6af9286136b3dd8b6be634a57dc9d6bee35b492"
        )

    def test_recover(self):
        """
        """
        self.raw_tx._in_mutable_context = True
        self.raw_tx.version = 1
        self.raw_tx.r = (
            0xb5145678e43df2b7ea8e0e969e51dbf72c956dd52e234c95393ad68744394855)
        self.raw_tx.s = (
            0x44515b465dbbf746a484239c11adb98f967e35347e17e71b84d850d8e5c38a6a)
        self.raw_tx.v = 0x1b
        self.raw_tx._in_mutable_context = False
        self.assertEqual(self.raw_tx.sender.hex(),
                         "2e6144d0a4786e6f62892eee59c24d1e81e33272")