def send_inventory(self, serialized_transaction) -> msg_getdata: message = msg_inv() inventory = CInv() inventory.type = MSG_TX hash_transaction = Hash(serialized_transaction) inventory.hash = hash_transaction message.inv.append(inventory) timeout = time() + NODE_COMMUNICATION_TIMEOUT while time() < timeout: node = self.connect() if node is None: self.reset_connection() continue if not self.send_message(message): self.terminate(node) continue messages = self.capture_messages([ msg_getdata, ]) if not messages: self.terminate(node) continue logger.info('[%s] Node responded correctly.', node) return messages[0]
def publish(self, raw_transaction: str) -> Optional[str]: ''' Method for publishing transactions. Args: raw_transaction (str): hex string containing signed transaction Returns: str, None: transaction address or None if transaction wasn't published Example: >>> raw_transaction = '010000000184a38a4e8743964249665fb241fbd3...35b' >>> network.publish(raw_transaction) 70eefae0106b787e592e12914e4040efd8181dd299fa314d8f66da6a95cd1cfe ''' for attempt in range(1, TRANSACTION_BROADCASTING_MAX_ATTEMPTS + 1): transaction_address = self.broadcast_transaction(raw_transaction) if transaction_address is None: logger.warning( 'Transaction broadcast attempt no. %s failed. Retrying...', attempt) continue logger.info( 'Transaction broadcast is successful. End of broadcasting process.' ) return transaction_address logger.warning( '%s attempts to broadcast transaction failed. Broadcasting process terminates!', TRANSACTION_BROADCASTING_MAX_ATTEMPTS)
def audit_contract(self, tx_address: str) -> EthereumContract: tx_dict = self.get_transaction(tx_address) if not tx_dict: logger.info( f'Cannot audit contract, no such transaction: {tx_address} ({self.name})' ) return return EthereumContract(self, tx_dict)
def sign(transaction: Transaction, private_key: str) -> Transaction: ''' Signing the transaction. Args: transaction (Transaction): Ethereum unsigned transaction object private_key (str): private key Returns: Transaction: Ethereum signed transaction object ''' transaction.sign(private_key) logger.info('Transaction signed') return transaction
def publish(self, raw_transaction: str): for attempt in range(1, TRANSACTION_BROADCASTING_MAX_ATTEMPTS + 1): transaction_address = self.broadcast_transaction(raw_transaction) if transaction_address is None: logger.warning( 'Transaction broadcast attempt no. %s failed. Retrying...', attempt) continue logger.info( 'Transaction broadcast is successful. End of broadcasting process.' ) return transaction_address logger.warning( '%s attempts to broadcast transaction failed. Broadcasting process terminates!', TRANSACTION_BROADCASTING_MAX_ATTEMPTS)
def get_utxo(cls, address, amount): if cls.is_test_network() and cls.name != 'test-bitcoin': logger.info('%s: network is not supported to get utxo', cls.name) raise NotImplementedError network = cls.symbols[0].lower() if network == 'doge' or cls.name == 'test-bitcoin': return get_utxo_from_api(network, address, amount, use_blockcypher=True, testnet=cls.is_test_network()) if network not in CRYPTOID_SUPPORTED_NETWORKS: logger.info('%s: network is not supported', network) raise NotImplementedError api_key = os.getenv('CRYPTOID_API_KEY') return get_utxo_from_api(network, address, amount, cryptoid_api_key=api_key)
def send_inventory(self, serialized_transaction) -> Optional[msg_getdata]: ''' Sends inventory message with given serialized transaction to connected node. Returns: msg_getdata, None: get data request or None if something went wrong Note: This method is used by `broadcast_transaction` to inform connected node about existence of the new transaction. ''' message = msg_inv() inventory = CInv() inventory.type = MSG_TX hash_transaction = Hash(serialized_transaction) inventory.hash = hash_transaction message.inv.append(inventory) timeout = time() + NODE_COMMUNICATION_TIMEOUT while time() < timeout: node = self.connect() if node is None: self.reset_connection() continue if not self.send_message(message): self.terminate(node) continue messages = self.capture_messages([ msg_getdata, ]) if not messages: self.terminate(node) continue logger.info('[%s] Node responded correctly.', node) return messages[0]
def audit_contract(self, tx_address: str) -> EthereumContract: ''' Getting details about an Atomic Swap contract. Args: transaction_address (str): hex string with transaction address which created an Atomic Swap Returns: EthereumContract: contract object Example: >>> from clove.network import EthereumTestnet >>> network = EthereumTestnet() >>> network.audit_contract('0xfe4bcc1b522923ca6f8dc2721134c7d8636b34737aeafb2d6d0868d73e226891') <clove.network.ethereum.contract.EthereumContract at 0x7f7b3fec3e80> ''' tx_dict = self.get_transaction(tx_address) if not tx_dict: logger.info( f'Cannot audit contract, no such transaction: {tx_address} ({self.name})' ) return return EthereumContract(self, tx_dict)
def broadcast_transaction(self, raw_transaction: str) -> Optional[str]: ''' Sends given transaction to connected node. Args: raw_transaction (str): hex string containing signed transaction Returns: str, None: transaction address if transaction was sent, None otherwise. ''' deserialized_transaction = self.deserialize_raw_transaction( raw_transaction) serialized_transaction = deserialized_transaction.serialize() get_data = self.send_inventory(serialized_transaction) if not get_data: logger.debug( ConnectionProblem( 'Clove could not get connected with any of the nodes for too long.' )) self.reset_connection() return node = self.get_current_node() if all(el.hash != Hash(serialized_transaction) for el in get_data.inv): logger.debug( UnexpectedResponseFromNode( 'Node did not ask for our transaction', node)) self.reset_connection() return message = msg_tx() message.tx = deserialized_transaction if not self.send_message(message, 20): return logger.info('[%s] Looking for reject message.', node) messages = self.capture_messages([ msg_reject, ], timeout=REJECT_TIMEOUT, buf_size=8192, ignore_empty=True) if messages: logger.debug(TransactionRejected(messages[0], node)) self.reset_connection() return logger.info('[%s] Reject message not found.', node) transaction_address = b2lx(deserialized_transaction.GetHash()) logger.info('[%s] Transaction %s has just been sent.', node, transaction_address) return transaction_address
with open(file_path, 'r') as f: file_lines = f.readlines() file_length = len(file_lines) indices = [ i for i, line in enumerate(file_lines) if 'Class with all the necessary' in line ] if not indices: logger.error("Couldn't find network class in %s", filename) continue try: count = search_checklocktime(file_lines, indices[0], filename) if count is None: fork.append(filename) logger.info("%s network is forked and cannot be searched", filename) continue elif count == 0: failed.append(filename) logger.error( "Couldn't find OP_CHECKLOCKTIMEVERIFY in %s network", filename) continue found.append(filename) logger.info("Found %s in %s network", count, filename) except (HTTPError, URLError): failed.append(filename) logger.error("HTTP error in %s network", filename) continue
def sign(transaction: Transaction, private_key: str) -> Transaction: transaction.sign(private_key) logger.info('Transaction signed') return transaction