示例#1
0
def recover_sender(tx: Union[SignedEthTx, str]) -> str:
    '''
    Recover the sender from a signed ethereum transaction
    '''
    if type(tx) == dict:
        t = serialize(cast(SignedEthTx, tx))
    else:
        t = cast(str, tx)

    return Account.recoverTransaction(t)
示例#2
0
    def on_post(self, req, res):
        LOG.info("v2.eth.SendRawTransaction")

        session = req.context["session"]

        request_json = SendRawTransaction.validate(req)
        raw_tx_hex_list = request_json["raw_tx_hex_list"]

        # Get TokenList Contract
        ListContract = Contract.get_contract(
            "TokenList",
            config.TOKEN_LIST_CONTRACT_ADDRESS
        )

        # Check token status
        # NOTE: Check the token status before sending a transaction.
        for raw_tx_hex in raw_tx_hex_list:
            try:
                raw_tx = decode(HexBytes(raw_tx_hex))
                to_contract_address = to_checksum_address("0x" + raw_tx[3].hex())
            except Exception as err:
                LOG.info(f"RLP decoding failed: {err}")
                continue

            listed_token = session.query(Listing). \
                filter(Listing.token_address == to_contract_address). \
                first()

            if listed_token is not None:
                LOG.info(f"Token Address: {to_contract_address}")
                token_attribute = ListContract.functions.getTokenByAddress(to_contract_address).call()
                if token_attribute[1] != "":
                    try:
                        TokenContract = Contract.get_contract(token_attribute[1], to_contract_address)
                    except Exception as err:
                        LOG.warning(f"Could not get token status: {err}")
                        continue
                    if TokenContract.functions.status().call() is False:
                        raise SuspendedTokenError("Token is currently suspended")

        # Check block synchronization state
        # NOTE: If the block is out of sync, the nonce is not the correct value.
        block = session.query(Node).first()
        if block is None or not block.is_synced:
            raise ServiceUnavailable("Block synchronization is down")

        # Send transaction
        result = []
        for i, raw_tx_hex in enumerate(raw_tx_hex_list):
            # Get the contract address of the execution target.
            try:
                raw_tx = decode(HexBytes(raw_tx_hex))
                to_contract_address = to_checksum_address("0x" + raw_tx[3].hex())
                LOG.info(raw_tx)
            except Exception as err:
                result.append({"id": i + 1, "status": 0})
                LOG.error(f"RLP decoding failed: {err}")
                continue

            # Check that contract is executable
            executable_contract = session.query(ExecutableContract). \
                filter(to_contract_address == ExecutableContract.contract_address). \
                first()
            if executable_contract is None:
                # If it is not a default contract, return error status.
                if to_contract_address != config.PAYMENT_GATEWAY_CONTRACT_ADDRESS and \
                        to_contract_address != config.PERSONAL_INFO_CONTRACT_ADDRESS and \
                        to_contract_address != config.IBET_SB_EXCHANGE_CONTRACT_ADDRESS and \
                        to_contract_address != config.IBET_SHARE_EXCHANGE_CONTRACT_ADDRESS and \
                        to_contract_address != config.IBET_MEMBERSHIP_EXCHANGE_CONTRACT_ADDRESS and \
                        to_contract_address != config.IBET_CP_EXCHANGE_CONTRACT_ADDRESS:
                    result.append({"id": i + 1, "status": 0})
                    LOG.error("Not executable")
                    continue

            # Send raw transaction
            try:
                tx_hash = web3.eth.sendRawTransaction(raw_tx_hex)
            except ValueError as err:
                result.append({
                    "id": i + 1,
                    "status": 0,
                })
                LOG.error(f"Send transaction failed: {err}")
                continue

            # Handling a transaction execution result
            try:
                tx = web3.eth.waitForTransactionReceipt(tx_hash, timeout=config.TRANSACTION_WAIT_TIMEOUT)
            except TimeExhausted as err:
                status = 2  # execution success (pending transaction)

                # Transactions that are not promoted to pending and remain in the queued state
                # will return an error status.
                try:
                    from_address = Account.recoverTransaction(raw_tx_hex)
                except Exception as err:
                    result.append({"id": i + 1, "status": 0})
                    LOG.error(f"get sender address from signed transaction failed: {err}")
                    continue
                nonce = int("0x0" if raw_tx[0].hex() == "" else raw_tx[0].hex(), 16)
                txpool_inspect = GethTxPool.inspect
                if from_address in txpool_inspect.queued:
                    if str(nonce) in txpool_inspect.queued[from_address]:
                        status = 0  # execution failure

                result.append({
                    "id": i + 1,
                    "status": status,
                })
                LOG.warning(f"Transaction receipt timeout: {err}")
                continue
            except Exception as err:
                result.append({
                    "id": i + 1,
                    "status": 0,
                })
                LOG.error(f"Transaction failed: {err}")
                continue

            result.append({
                "id": i + 1,
                "status": tx["status"],
            })

        self.on_success(res, result)