def ShutdownClient(chain_info): chain_id = chain_info["chain-id"] key_name = chain_info["key-name"] RelayerHelper.DeleteKey( chain_id, key_name) # rly keys delete kira-alpha prefix_kira-alpha RelayerHelper.DeleteLiteClient(chain_id) # rly lite delete kira-alpha RelayerHelper.ChainDelete(chain_id) # rly chains delete kira-alpha
def QueryFeeTokenBalance(chain_info): chain_id = chain_info["chain-id"] denom = chain_info.get("default-denom") if not denom: print( f"WARNING: Chain {chain_id} does not have a default denom for the fee token defined" ) return 0 balances = RelayerHelper.TryQueryBalance(chain_id) return RelayerHelper.GetAmountByDenom(balances, denom)
def AssertRefreshBalances(chain_info): chain_id = chain_info["chain-id"] denom = chain_info["default-denom"] address = chain_info.get("address", "undefined") chain_info["balance"] = balances = RelayerHelper.TryQueryBalance(chain_id) if RelayerHelper.GetAmountByDenom(balances, denom) <= 0: raise Exception( f"Insufficient {denom} balance of the account '{chain_id}:{address}', client will not be able to further continue the connections unless {denom} tokens are available." ) return chain_info
def ShutdownConnection(connection): chain_info_src = connection.get("src", None) chain_info_dst = connection.get("dst", None) chain_id_src = None if not chain_info_src else chain_info_src["chain-id"] chain_id_dst = None if not chain_info_dst else chain_info_dst["chain-id"] path = connection.get( "path", f"{chain_id_src}_{chain_id_dst}" ) # delete default path if custom one was not defined if path: # rly pth delete kira-alpha_gameofzoneshub-1 | rly pth delete kira-1_kira-alpha print(f"INFO: Shutting down {path} connection...") RelayerHelper.DeletePath(path) else: print( f"WARNING: Path was not present in the connection object, can't remove None" ) if chain_info_src and len(chain_info_src) > 0: ClientHelper.ShutdownClient(chain_info_src) else: print( f"WARNING: Source chain was not present in the connection object, can't remove None" ) if chain_info_dst and len(chain_info_dst) > 0: ClientHelper.ShutdownClient(chain_info_dst) else: print( f"WARNING: Destination chain not present in the connection object, can't remove None" )
def ReConnect(connection, timeout): chain_info_src = connection["src"] chain_info_dst = connection["dst"] chain_id_src = chain_info_src["chain-id"] chain_id_dst = chain_info_dst["chain-id"] path = f"{chain_id_src}_{chain_id_dst}" status = QueryStatus(path) # TO DO disconnect gracefully if status exists if (not (not status)): print("WARNING! TODO: Disconnect gracefully") RelayerHelper.DeletePath(path) else: RelayerHelper.DeletePath(path) return Connect(connection, timeout)
def DeleteLiteClient(chain_info): chain_id = chain_info["chain-id"] print(f"INFO: Re-starting {chain_id} lite client...") if not RelayerHelper.DeleteLiteClient(chain_id): print(f"ERROR: Failed to update {chain_id} lite client") return False print(f"SUCCESS: Updated {chain_id} lite client") return True
def TestConnection(connection): src_chain_info = connection["src"] dst_chain_info = connection["dst"] src_id = src_chain_info["chain-id"] dst_id = dst_chain_info["chain-id"] path = connection["path"] min_ttl = connection["min-ttl"] if not RelayerHelper.UpdateLiteClient(src_id) or ( not RelayerHelper.QueryLiteClientHeader(src_id)): print( f"FAILURE: Could not update source '{src_id}' lite client or fetch header" ) return False if not RelayerHelper.UpdateLiteClient(dst_id) or ( not RelayerHelper.QueryLiteClientHeader(dst_id)): print( f"FAILURE: Could not update destination '{dst_id}' lite client or fetch header" ) return False status = QueryStatus(path) is_connected = TestStatus(status) ttl = RelayerHelper.GetRemainingTimesToLive(connection) if is_connected: print( f"SUCCESS: Connection of the path {path} is maitained, testing ttl..." ) if not ttl or ttl["min"] <= 0: print( f"FAILURE: Could not acquire remaining TTL or {ttl} indicates dropped connection." ) is_connected = False else: print(f"FAILURE: Connection of the path {path} is faulty.") if None != status: print( f"INFO: Path {path} status: Chains {status['chains']} | Clients {status['clients']} | Connection {status['connection']} | Channel {status['channel']}, TTL: {ttl}" ) else: print(f"WARNING: Failed to query connection status") return is_connected
def S3FileExists(bucket, s3_key_path): out = RelayerHelper.callRaw( f"AWSHelper s3 object-exists --bucket='{bucket}' --path='{s3_key_path}' --throw-if-not-found=False --silent=True", True) if None == out: raise Exception( f"Call failed when checking if file exists as {s3_key_path} in the {bucket} S3 bucket" ) return StringHelper.ToBool(out)
def GasUpdateAssert(chain_info, gas): chain_id = chain_info["chain-id"] if not RelayerHelper.ConfigureDefaultGas( chain_id, gas): # rly ch edit kira-alpha gas 100000 raise Exception( f"WARNING: Failed to configure gas of the {chain_id} chain") if not UpdateLiteClient(chain_info): raise Exception( "Failed to update lite client after adjusting gas prices") print(f"SUCCESS: New gas price for {chain_id} chain was set to {gas}") return True
def TryS3ReadText(bucket, s3_key_path): out = RelayerHelper.callRaw( f"AWSHelper s3 download-text --bucket='{bucket}' --path='{s3_key_path}' --silent=true", True) if None == out: print( f"ERROR: Failed to read {s3_key_path} file from {bucket} bucket in S3" ) else: print( f"SUCCESS: Read all {len(out)} characters from {bucket}/{s3_key_path} path in S3" ) return out
def S3WriteText(text, bucket, s3_key_path): tmp_file = f"/tmp/{str(uuid.uuid4())}" StringHelper.WriteJsonToFile(text, tmp_file) print(f"INFO: Writing {tmp_file} to {bucket}/{s3_key_path} file in S3...") result = RelayerHelper.callRaw( f"AWSHelper s3 upload-object --bucket='{bucket}' --path='{s3_key_path}' --input='{tmp_file}'", True) os.remove(tmp_file) if result == None: raise Exception( f"ERROR: Failed to upload {tmp_file} into {bucket}/{s3_key_path} path on S3." ) return True
def IsConnected(connection): path = connection["path"] status = QueryStatus(path) if status == None: return None if not TestStatus(status): print(f"WARNING: Path {path} is not connected, status: {status}") return False ttl = RelayerHelper.GetRemainingTimesToLive(connection) if ttl == None: return None if not ttl or ttl["min"] <= 0: print(f"WARNING: Path {path} expired, TTL: {ttl}") return False return True
def S3ReadText(bucket, s3_key_path): if not S3FileExists(bucket, s3_key_path): print(f"WARNING: File {bucket}/{s3_key_path} does not exist in S3") return {} out = RelayerHelper.callRaw( f"AWSHelper s3 download-text --bucket='{bucket}' --path='{s3_key_path}' --silent=true --throw-if-not-found=False", True) if None == out: raise Exception( f"Failed to read {s3_key_path} file from {bucket} bucket in S3") else: print( f"SUCCESS: Read all {len(out)} characters from {bucket}/{s3_key_path} path in S3" ) return out
def InitializeClientWithJsonFile(json_path, key_prefix, mnemonic, bucket): print(f"INFO: Initializing IBC client with JSON file: {json_path}") chain_info = json.load(open(json_path)) chain_info["file-path"] = json_path chain_info["bucket"] = bucket chain_info = InitializeClient(chain_info, key_prefix, mnemonic) chain_id = chain_info["chain-id"] denom = chain_info["default-denom"] address = chain_info.get("address", "undefined") print(f"INFO: Requesting {denom} tokens from {chain_id} faucet...") if not RelayerHelper.TryRequestTokens(chain_id): print( f"WARNING: Failed to request {denom} tokens from the {chain_id} faucet..." ) chain_info = AssertRefreshBalances(chain_info) return chain_info
def S3ReadJson( bucket, s3_key_path ): # AWSHelper s3 object-exists --bucket='kira-core-goz' --path='relayer/kira-alpha_kira-1-1b/alpha/state.json' --throw-if-not-found=False if not S3FileExists(bucket, s3_key_path): print(f"WARNING: File {bucket}/{s3_key_path} does not exist in S3") return {} out = RelayerHelper.callJson( f"AWSHelper s3 download-text --bucket='{bucket}' --path='{s3_key_path}' --silent=true --throw-if-not-found=False", True) if None == out: raise Exception( f"Failed to read {s3_key_path} file from {bucket} bucket in S3") else: print( f"SUCCESS: Read all {len(out)} json elements from {bucket}/{s3_key_path} path in S3" ) return out
def Transfer(token): amount = 0 if not token["amount"] else int(token["amount"]) denom = token["denom"] if len(denom.split("/")) >= 5: print( f"FAILURE: Failed sending {min_amount} {denom} from {src_id} to {dst_id}, tokens with too long paths are not transferable." ) elif amount <= min_amount: print( f"WARNING: Failed sending {min_amount} {denom} from {src_id} to {dst_id}, source address has only {amount} {denom} left." ) elif (not RelayerHelper.TransferTokens( src_id, dst_id, f"{min_amount}{denom}", dst_address)): print( f"FAILURE: Failed sending {min_amount} {denom} from {src_id} to {dst_id}" ) else: print( f"SUCCESS: Sent {min_amount}{denom} from {src_id} to {dst_id}")
def TransferEachToken(src_chain_info, dst_chain_info, path, min_amount): src_id = src_chain_info["chain-id"] dst_id = dst_chain_info["chain-id"] src_balance = src_chain_info["balance"] dst_balance = dst_chain_info["balance"] dst_address = dst_chain_info["address"] def Transfer(token): amount = 0 if not token["amount"] else int(token["amount"]) denom = token["denom"] if len(denom.split("/")) >= 5: print( f"FAILURE: Failed sending {min_amount} {denom} from {src_id} to {dst_id}, tokens with too long paths are not transferable." ) elif amount <= min_amount: print( f"WARNING: Failed sending {min_amount} {denom} from {src_id} to {dst_id}, source address has only {amount} {denom} left." ) elif (not RelayerHelper.TransferTokens( src_id, dst_id, f"{min_amount}{denom}", dst_address)): print( f"FAILURE: Failed sending {min_amount} {denom} from {src_id} to {dst_id}" ) else: print( f"SUCCESS: Sent {min_amount}{denom} from {src_id} to {dst_id}") if (len(src_balance) <= 0) or (len(dst_balance) <= 0): print( f"WARNING: Can't send tokens from {src_id} to {dst_id}, source or destination address does not have any tokens left." ) else: for token in src_balance: #Parallel(n_jobs=max_parallelism)(delayed(Transfer)(token) for token in src_balance) Transfer(token) if not RelayerHelper.TransactRelay(path): print(f"ERROR: Failed sending remaining packets")
time_to_upload = int(upload_period - upload_elapsed) total_uptime = connection["total-uptime"] = total_uptime + loop_elapsed loop_start = time.time() current_session = time.time() - time_start if failed_tx_counter > 10: print(f"FAILURE: More than 10 transactions failed in the row") break if not IBCHelper.TestConnection(connection): print( f"FAILURE: Connection was dropped or failed to query status. Current session duration: {timedelta(seconds=current_session)}" ) break ttl = RelayerHelper.GetRemainingTimesToLive(connection) if not ttl: print(f"FAILURE: Could not fetch remaining TTL") break ttl_src = int(ttl["src"]) # source connection time to live ttl_dst = int(ttl["dst"]) # destination connection time to live connection["src"] = src = ClientHelper.AssertRefreshBalances(src) connection["dst"] = dst = ClientHelper.AssertRefreshBalances(dst) src_balances = src["balance"] dst_balances = dst["balance"] src_tokens = RelayerHelper.GetAmountByDenom(src_balances, src_denom) dst_tokens = RelayerHelper.GetAmountByDenom(dst_balances, dst_denom) src_cfg = RelayerHelper.ShowChain(
def QueryStatus(path): path_info = RelayerHelper.QueryPath( path) # rly pth show kira-alpha_kira-1-b -j status = None if (not path_info) else path_info["status"] return status
def TryS3FileExists(bucket, s3_key_path): return False if None == RelayerHelper.callRaw( f"AWSHelper s3 object-exists --bucket='{bucket}' --path='{s3_key_path}' --throw-if-not-found=True", False) else True
dst_denom = dst["default-denom"] src_key = src["key-name"] dst_key = dst["key-name"] connection["init-time"] = init_time connection["max-init-time"] = max_init_time = state_file.get("max-init-time", init_time) connection["min-init-time"] = min_init_time = state_file.get("min-init-time", init_time) upload_time = connection["upload-time"] = state_file.get("upload-time", 0) # time when state_info was uploaded for the last time total_uptime = connection["total-uptime"] = state_file.get("total-uptime", 0) loop_start = time_start src_gas_min = src.get("gas-min", 50000) dst_gas_min = dst.get("gas-min", 50000) src_gas_max = src.get("gas-max", src_gas_min) dst_gas_max = dst.get("gas-max", src_gas_min) src_cfg = RelayerHelper.ShowChain(src_chain_id) # rly ch show kira-alpha -j dst_cfg = RelayerHelper.ShowChain(dst_chain_id) # rly ch show kira-1 -j src_gas_default = src_cfg.get("gas", src_gas_min) dst_gas_default = dst_cfg.get("gas", dst_gas_min) print(f"INFO: Connection was established within {init_time}s") print(f"INFO: Max init time: {max_init_time}s") print(f"INFO: Min init time: {min_init_time}s") print(f"INFO: SRC => Gas Min ({src_gas_min}), Gas Now ({src_gas_default}), Gas Max ({src_gas_max})") print(f"INFO: DST => Gas Min ({dst_gas_min}), Gas Now ({dst_gas_default}), Gas Max ({dst_gas_max})") while True: loop_elapsed = int(time.time() - loop_start) upload_elapsed = int(time.time() - upload_time) time_to_upload = int(upload_period - upload_elapsed) total_uptime = connection["total-uptime"] = total_uptime + loop_elapsed
def InitializeClientWithMnemonic(chain_info, mnemonic): print(f"INFO: Initializing client with mnemonic...") chain_id = chain_info["chain-id"] chain_info_path = chain_info["file-path"] key_name = chain_info["key-name"] bucket = chain_info["bucket"] s3_key_path = chain_info["s3-path"] if not mnemonic: raise Exception( f"Failed to recover key {key_name}. Mnemonic was not defined.") if not RelayerHelper.UpsertChainFromFile( chain_info_path): # rly chains add -f $TESTCHAIN_JSON_PATH raise Exception( f"Failed adding new chain from '{chain_info_path}' file :(") if not RelayerHelper.KeyExists(chain_id, key_name): print( f"WARNING: Key {key_name} of the {chain_id} chain does not exist, restoring..." ) RelayerHelper.RestoreKey( chain_id, key_name, mnemonic) # rly keys restore $s k$s "$RLYKEY_MNEMONIC" if not RelayerHelper.KeyExists(chain_id, key_name): raise Exception( f"Failed to restore key {key_name} of the chain {chain_id}") print(f"SUCCESS: Key {key_name} of the chain {chain_id} was restored") else: print(f"INFO: Key {key_name} of the {chain_id} already exists") if not RelayerHelper.ConfigureDefaultKey( chain_id, key_name): # rly ch edit kira-alpha key prefix_kira-alpha raise Exception( f"Failed to configure chain {chain_id} to use {key_name} key by default" ) print( f"SUCCESS: Key {key_name} was configured as default of the chain {chain_id}" ) chain_info["address"] = address = RelayerHelper.QueryChainAddress(chain_id) if not address: raise Exception(f"Failed to query {chain_id} chain address") chain_info["address"] = str(chain_info["address"], "utf-8") if not StateHelper.TryS3FileExists(bucket, s3_key_path): print( f"INFO: Relayer key {key_name} was not present in S3, uploading..." ) key = {"mnemonic": mnemonic, "address": address} StateHelper.S3WriteText(key, bucket, s3_key_path) # will throw if fails to upload chain_info["balance"] = balance = RelayerHelper.TryQueryBalance(chain_id) if (not balance) or (len(balance) <= 0): print( f"WARNING: Address {address} on the chain {chain_id} has no tokens deposited or query failed to fetch balance!" ) chain_info["balance"] = balance = None return chain_info
def Connect(connection, timeout): chain_info_src = connection["src"] chain_info_dst = connection["dst"] chain_id_src = chain_info_src["chain-id"] chain_id_dst = chain_info_dst["chain-id"] path = connection["path"] min_ttl = connection["min-ttl"] path_info = connection.get("path-info", None) if (chain_id_src == chain_id_dst): raise Exception( f"Source chain and destination chain id's cant be the same, but both were: {chain_id_src}" ) return connection if not RelayerHelper.PathExists(path): DeleteLiteClients(connection) if (not (not path_info)): print( f"INFO: Path {path} does not exists, but recovery state is available" ) RelayerHelper.AddPath(connection) else: print( f"INFO: Path {path} does not exists and recovery is not available, re-generating path" ) if not RelayerHelper.ReGeneratePath(chain_id_src, chain_id_dst, path): raise Exception(f"Failed to re-generate new {path} path") else: connection["path-info"] = path_info = None if not RelayerHelper.PathExists(path): # by now path must exist raise Exception(f"Failed to assert {path} path existence" ) # probably networking issues if not ReArmConnection(connection, timeout): print(f"WARNING: Failed to rearm {path} connection") else: print(f"SUCCESS, connection was re-armed. Status: {QueryStatus(path)}") if not RestartLiteClients( connection ): # it should always be possible to restart lite clients raise Exception( f"Could NOT restart lite clients, it will not be possible to connect" ) ttl = RelayerHelper.GetRemainingTimesToLive(connection) if None != ttl and ttl["min"] < min_ttl: # connection expired print(f"WARNING: Path {path} expired, TTL: {ttl}") RelayerHelper.DeletePath(path) connection["path-info"] = None return Connect(connection, timeout) elif ttl == None: raise Exception(f"Failed to read TTL") if not IsConnected(connection): raise Exception( f"Failed to connect {chain_id_src} and {chain_id_dst} via {path}") connection["ttl"] = ttl = RelayerHelper.GetRemainingTimesToLive(connection) if not ttl: # Assert there are no networking issues, NOTE: Auto rotate RPC add should occur before this section raise Exception( f"Failed to acquire TTL information of chain {chain_id_src} and {chain_id_dst} connected via {path} path" ) print( f"SUCCESS: Chains {chain_id_src} and {chain_id_dst} are connected, TTL: {ttl}" ) connection["path-info"] = path_info = RelayerHelper.QueryPath( path) # rly pth show kira-alpha_gameofzoneshub-1 -j if not path_info: # assert path info availability raise Exception( f"Failed to acquire path information of a successfully connected chain {chain_id_src} and {chain_id_dst} connected via {path}" ) return connection
def ReArmConnection(connection, timeout): print(f"INFO: Re-arming connection...") chain_info_src = connection["src"] chain_info_dst = connection["dst"] chain_id_src = chain_info_src["chain-id"] chain_id_dst = chain_info_dst["chain-id"] path = connection["path"] print(f"INFO: Updating lite clients...") if not UpdateLiteClients(connection): print(f"WARNING: Failed to update lite clients, restarting...") if not RestartLiteClients(connection): raise Exception( f"Failed to restart lite clients, connection can't be established, exiting..." ) status = QueryStatus(path) if TestStatus(status): print(f"INFO: Path {path} was already connected") return True if (not (not status)): print( f"INFO: Path {path} status: Chains {status['chains']} | Clients {status['clients']} | Connection {status['connection']} | Channel {status['channel']}" ) if not status["clients"]: if not RelayerHelper.TransactClients( path, timeout ): # rly transact clients kira-alpha_kira-1-1b --debug print( f"ERROR: Failed to create clients (Step 1) between {chain_id_src} and {chain_id_dst}, path: '{path}'" ) return False else: print( f"SUCCESS: Established clients (Step 1) between {chain_id_src} and {chain_id_dst}, path: '{path}'" ) if not status["connection"]: if not RelayerHelper.TransactConnection( path, timeout ): # rly transact connection kira-alpha_kira-1-1b --debug print( f"ERROR: Failed to create connection (step 2) between {chain_id_src} and {chain_id_dst}, path: '{path}'" ) return False else: print( f"SUCCESS: Established connection (Step 2) between {chain_id_src} and {chain_id_dst}, path: '{path}'" ) if not status[ "channel"]: # rly transact channel kira-alpha_kira-1-1b --debug if not RelayerHelper.TransactChannel(path, timeout): print( f"ERROR: Failed to create channel (step 3) between {chain_id_src} and {chain_id_dst}, path: '{path}'" ) return False else: print( f"SUCCESS: Established channel (Step 3) between {chain_id_src} and {chain_id_dst}, path: '{path}'" ) return True
"max-init-time", init_time) connection["min-init-time"] = min_init_time = state_file.get( "min-init-time", init_time) upload_time = connection["upload-time"] = state_file.get( "upload-time", 0) # time when state_info was uploaded for the last time total_uptime = connection["total-uptime"] = state_file.get("total-uptime", 0) total_transactions = connection["total-transactions"] = state_file.get( "total-transactions", 0) loop_start = time_start failed_tx_counter = 0 src_gas_min = src.get("gas-min", 200001) dst_gas_min = dst.get("gas-min", 200001) src_gas_max = src.get("gas-max", src_gas_min) dst_gas_max = dst.get("gas-max", src_gas_min) src_cfg = RelayerHelper.ShowChain(src_chain_id) # rly ch show kira-alpha -j dst_cfg = RelayerHelper.ShowChain(dst_chain_id) # rly ch show kira-1 -j src_gas_default = src_cfg.get("gas", src_gas_min) dst_gas_default = dst_cfg.get("gas", dst_gas_min) print(f"INFO: Connection was established within {init_time}s") print(f"INFO: Max init time: {max_init_time}s") print(f"INFO: Min init time: {min_init_time}s") print( f"INFO: SRC => Gas Min ({src_gas_min}), Gas Now ({src_gas_default}), Gas Max ({src_gas_max})" ) print( f"INFO: DST => Gas Min ({dst_gas_min}), Gas Now ({dst_gas_default}), Gas Max ({dst_gas_max})" ) while True: