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)
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)