def get_balance_body(cls, address, contract): return { "from": cls.get_address(cls.ZERO_ADDRESS), "to": cls.get_address(contract), "value": digit.int_to_hex(0), "gas": digit.int_to_hex(cls.DEFAULT_GAS), # K M G -> 10G "gasPrice": digit.int_to_hex(cls.DEFAULT_GAS_PRICE), "data": cls.GET_BALANCE_ABI + cls.get_address(address, contract) }
def get_value(cls, value, contract=None) -> str: """ 获取合适的金额, 若是合约类型, 则补全至合适的位数, 并且没有0x开头 :param value: 金额 :param contract: :return: hex or hex not have ox """ if contract is None: return digit.int_to_hex(value) real_value = digit.int_to_hex(value, has_0x=False) return real_value.zfill(cls.TRANSFER_VALUE_LENGTH)
def get_transfer_template(cls, sender=None, receiver=None, value=0, gas=0, gas_price=0, data="", contract=None): return { "from": cls.get_address(sender), "to": cls.get_address(contract or receiver), "value": digit.int_to_hex(value), "gas": digit.int_to_hex(gas or cls.DEFAULT_GAS), # K M G -> 10G "gasPrice": digit.int_to_hex(gas_price or cls.DEFAULT_GAS_PRICE), "data": digit.add_0x(data) }
def get_transfer_body(cls, sender=None, receiver=None, gas: int = None, gas_price: int = None, value: int = 0, contract=None) -> dict: if gas is None: gas = cls.DEFAULT_GAS if gas_price is None: gas_price = cls.DEFAULT_GAS_PRICE body = { "from": cls.get_address(sender), "to": cls.get_address(receiver), "value": cls.get_value(value) if contract is None else '0x0', "gas": digit.int_to_hex(gas), # K M G -> 10G "gasPrice": digit.int_to_hex(gas_price), } if contract is not None: body['to'] = digit.add_0x(contract) body['data'] = cls.TRANSFER_ABI + cls.get_address( receiver, contract) + cls.get_value(value, contract) return body
def scan(self): self.block_info = self.rpc.get_block_height() self.newest_height = self.block_info.current_height self.highest_height = self.block_info.highest_height # 延迟扫 SCAN_DELAY_NUMBER 个块 need_to_height = self.newest_height - self.SCAN_DELAY_NUMBER self.logger.info('起始扫块高度:{} 最新高度:{} 需要同步:{}'.format( self.current_scan_height, self.newest_height, need_to_height - self.current_scan_height)) while self.current_scan_height < need_to_height: self.logger.info('当前已扫块高度:{} 最新高度:{} 需要同步:{} 节点最高高度:{}'.format( self.current_scan_height, self.newest_height, need_to_height - self.current_scan_height, self.highest_height)) for height in range(self.current_scan_height, need_to_height, self.SCAN_HEIGHT_NUMBER): # 分批处理, 一次处理 SCAN_HEIGHT_NUMBER 或 剩余要处理的块 block_batch = min(self.SCAN_HEIGHT_NUMBER, need_to_height - self.current_scan_height) blocks = self.rpc.get_block_by_number([ digit.int_to_hex(height) for height in range(height, height + block_batch) ]) save_tx_count = 0 with runtime.app.app_context(): # 一次处理一批 session = db.session() try: for block in blocks: if block is None: return block_height = digit.hex_to_int(block['number']) block_hash = block['hash'] block_timestamp = digit.hex_to_int( block['timestamp']) block_time = datetime.fromtimestamp( block_timestamp) session.begin(subtransactions=True) db_block = Block(height=block_height, block_hash=block_hash, block_time=block_time) session.add(db_block) session.commit() for transaction in block.get('transactions', []): tx = EthereumResolver.resolver_transaction( transaction) if tx.sender in runtime.project_address: # 提现的暂时不要 continue if tx.receiver in runtime.project_address: receipt_raw_tx = self.rpc.get_transaction_receipt( tx.tx_hash) if tx.contract: coin = runtime.coins.get(tx.contract) else: coin = runtime.coins.get( self.COIN_NAME) if coin is None: continue if receipt_raw_tx: receipt_tx = EthereumResolver.resolver_receipt( receipt_raw_tx) else: self.logger.error( '请求 {} receipt 错误, 重新处理') raise tx.status = receipt_tx.status # session.begin(subtransactions=True) # db_tx = Transaction(block_id=db_block.id, coin_id=coin['coin_id'], # tx_hash=tx.tx_hash, height=db_block.height, # block_time=block_timestamp, # amount=tx.value, sender=tx.sender, receiver=tx.receiver, # gas=tx.gas, gas_price=tx.gas_price, # is_send=SendEnum.NOT_PUSH.value, # fee=receipt_tx.gas_used * tx.gas_price, # contract=tx.contract, status=receipt_tx.status, # type=TxTypeEnum.DEPOSIT.value) Transaction.add_transaction_or_update( block_id=db_block.id, coin_id=coin['coin_id'], tx_hash=tx.tx_hash, height=db_block.height, block_time=block_timestamp, amount=tx.value, sender=tx.sender, receiver=tx.receiver, gas=tx.gas, gas_price=tx.gas_price, is_send=SendEnum.NOT_PUSH.value, fee=receipt_tx.gas_used * tx.gas_price, contract=tx.contract, status=receipt_tx.status, type=TxTypeEnum.DEPOSIT.value, session=session, commit=False) save_tx_count += 1 # session.add(db_tx) # session.commit() # 添加推送信息 session.query(SyncConfig).filter( SyncConfig.id == self.config_id).update({ 'synced_height': height + block_batch, 'highest_height': self.highest_height }) self.current_scan_height = height + block_batch session.commit() self.logger.info("本次同步高度为:{} -- {}, 保存交易: {} 笔".format( height, height + block_batch, save_tx_count)) except Exception as e: self.logger.error('同步块出现异常, 事务回滚. {}'.format(e)) session.rollback() return self.logger.info("扫链结束, 本次同步")
def get_smart_fee(self, confirm_height="latest", contract=None): method = 'eth_estimateGas' if contract is None: return digit.int_to_hex(21000) payload = EthereumResolver.get_transfer_body(contract=contract) return self._single_post(method, payload)
# name, symbol, decimal, total return (EthereumResolver.parse_abi_name(rsp[0]), EthereumResolver.parse_abi_name(rsp[1]), EthereumResolver.parse_abi_name(rsp[2]), EthereumResolver.parse_abi_name(rsp[3])) if __name__ == '__main__': import json rpc = EthereumRpcBase('http://192.168.10.201:37001') rpc.get_contract_info('0xdac17f958d2ee523a2206206994597c13d831ec7') # print(rpc.get_block_height()) # print(rpc.get_block_by_hash('0x1a2f')) # print(rpc.get_block_by_hash(['0x1a2f', '0x9878'])) # print(rpc.get_transaction_by_hash(['0x529bad6226fa1c843ea2b8cf70a2e4eaf95098783a3ee575994c87a6b726cb37', # "0xcf13c31e274f7494d90ca996b26a64ce9e41b06c6a4cad6e37e2ddf04b81e47f"])) # # print(rpc.get_transaction_by_hash('0x529bad6226fa1c843ea2b8cf70a2e4eaf95098783a3ee575994c87a6b726cb37')) # print(rpc.get_transaction_by_hash('0x529bad6226fa1c843ea2b8cf70a2e4eaf95098783a3ee575994c87a6b726cb37', # details=False)) # print(rpc.get_transaction_receipt('0x529bad6226fa1c843ea2b8cf70a2e4eaf95098783a3ee575994c87a6b726cb37')) # print(rpc.get_transaction_receipt(['0x529bad6226fa1c843ea2b8cf70a2e4eaf95098783a3ee575994c87a6b726cb37', # "0xcf13c31e274f7494d90ca996b26a64ce9e41b06c6a4cad6e37e2ddf04b81e47f"])) # print(rpc.get_wallet_balance()) blocks = rpc.get_block_by_number( [digit.int_to_hex(height) for height in range(5000000, 5000010)]) print(json.dumps(blocks))
def get_tx_by_tx_hash(tx_hash: str): rpc = RpcConfig.get_rpc() if rpc is None: return ResponseObject.error(**out_data_missing) chain_info = rpc.get_block_height() tx = Transaction.get_tx_coin_by_tx_hash(tx_hash=tx_hash) if tx: return ResponseObject.success( data={ "sender": tx.Transaction.sender, "receiver": tx.Transaction.receiver, "txHash": tx.Transaction.tx_hash, "value": safe_math.divided(tx.Transaction.amount, safe_math.e_calc( tx.Coin.decimal)).to_eng_string(), "blockHeight": tx.Transaction.height, "blockTime": tx.Transaction.block_time, "contract": tx.Transaction.contract, "isValid": True if tx.Transaction.status == 1 else False, "confirmNumber": chain_info.highest_height - tx.Transaction.height if tx.Transaction.height > 0 else 0 }) else: tx_origin, receipt_origin = rpc.get_transaction_by_hash(tx_hash) if tx_origin and receipt_origin: tx, receipt = EthereumResolver.resolver_transaction( tx_origin), EthereumResolver.resolver_receipt(receipt_origin) block_info = rpc.get_block_by_number(int_to_hex(tx.block_height), False) if not block_info: return ResponseObject.error(**rpc_block_not_found) block = EthereumResolver.resolver_block(block_info, False) if tx.contract is not None: coin = Coin.get_erc20_usdt_coin() else: coin = Coin.get_coin(name='Ethereum') if coin is None: return ResponseObject.error(**coin_missing) return ResponseObject.success( data={ "sender": tx.sender, "receiver": tx.receiver, "txHash": tx.tx_hash, "value": safe_math.divided(tx.value, safe_math.e_calc( coin.decimal)).to_eng_string(), "blockHeight": tx.block_height, "blockTime": block.timestamp, "contract": tx.contract, "isValid": True if receipt.status == 1 else False, "confirmNumber": chain_info.highest_height - tx.block_height }) return ResponseObject.error(**tx_miss)
def get_hex_highest_height(self): return digit.int_to_hex(self._highest_height)
def get_hex_current_height(self): return digit.int_to_hex(self._current_height)