diff --git a/TNLS-Gateways/solana-gateway/tests/solana-gateway.ts b/TNLS-Gateways/solana-gateway/tests/solana-gateway.ts index 500af85..36033ec 100644 --- a/TNLS-Gateways/solana-gateway/tests/solana-gateway.ts +++ b/TNLS-Gateways/solana-gateway/tests/solana-gateway.ts @@ -121,47 +121,50 @@ describe("solana-gateway", () => { ); }); - it('Prints tasks from task_state', async () => { + it("Prints tasks from task_state", async () => { // Fetch the raw data of the task_state account const accountInfo = await provider.connection.getAccountInfo(taskPDA); if (!accountInfo) { - console.log('Task State account does not exist'); + console.log("Task State account does not exist"); return; } const data = accountInfo.data; - + const TASK_SIZE = 41; const PAYLOAD_HASH_SIZE = 32; const TASK_ID_SIZE = 8; const COMPLETED_OFFSET = 40; // Last byte for completed flag - + // Calculate the number of tasks based on a known constant or from data length //const numTasks = Math.floor(data.length / TASK_SIZE); const numTasks = 20; console.log(`Number of tasks: ${numTasks}`); - + for (let i = 0; i < numTasks; i++) { const start = i * TASK_SIZE; const taskBuffer = data.slice(start, start + TASK_SIZE); - + // Extract payload_hash (32 bytes) - const payloadHash = taskBuffer.slice(0, PAYLOAD_HASH_SIZE).toString('hex'); - + const payloadHash = taskBuffer + .slice(0, PAYLOAD_HASH_SIZE) + .toString("hex"); + // Extract task_id (8 bytes), little-endian - const taskIdBuffer = taskBuffer.slice(PAYLOAD_HASH_SIZE, PAYLOAD_HASH_SIZE + TASK_ID_SIZE); + const taskIdBuffer = taskBuffer.slice( + PAYLOAD_HASH_SIZE, + PAYLOAD_HASH_SIZE + TASK_ID_SIZE + ); const taskId = Buffer.from(taskIdBuffer).readBigUInt64LE(); - + // Extract completed (1 byte) const completed = taskBuffer[COMPLETED_OFFSET] !== 0; - + console.log(`Task ID: ${taskId}`); console.log(` Payload Hash: 0x${payloadHash}`); console.log(` Completed: ${completed}`); - console.log(` Output: ${taskBuffer.toString('hex')}`); + console.log(` Output: ${taskBuffer.toString("hex")}`); } }); - - it("Performs task payout", async () => { // Fetch initial balances @@ -318,230 +321,227 @@ describe("solana-gateway", () => { ); // Fetch the transaction details - const txDetails = await provider.connection.getTransaction(txSignature, { - commitment: "confirmed", - }); - assert.ok(txDetails, "Transaction details not found"); - - // Extract logs from transaction meta - const logs = txDetails.meta.logMessages; - assert.ok(logs, "No logs found in transaction"); - - console.log(logs); - // Find the LogNewTask event in the logs - let logNewTaskBase64 = null; - for (const log of logs) { - if (log.startsWith("Program log: LogNewTask:")) { - console.log(log); - // Extract the base64-encoded data after the prefix - logNewTaskBase64 = log.split("Program log: LogNewTask:")[1].trim(); - break; + const txDetails = await provider.connection.getTransaction(txSignature, { + commitment: "confirmed", + }); + assert.ok(txDetails, "Transaction details not found"); + + // Extract logs from transaction meta + const logs = txDetails.meta.logMessages; + assert.ok(logs, "No logs found in transaction"); + + console.log(logs); + // Find the LogNewTask event in the logs + let logNewTaskBase64 = null; + for (const log of logs) { + if (log.startsWith("Program log: LogNewTask:")) { + console.log(log); + // Extract the base64-encoded data after the prefix + logNewTaskBase64 = log.split("Program log: LogNewTask:")[1].trim(); + break; + } } - } - assert.ok(logNewTaskBase64, "LogNewTask event not found in logs"); + assert.ok(logNewTaskBase64, "LogNewTask event not found in logs"); - // Decode the base64-encoded data - const logNewTaskDataBuffer = Buffer.from(logNewTaskBase64, "base64"); + // Decode the base64-encoded data + const logNewTaskDataBuffer = Buffer.from(logNewTaskBase64, "base64"); - // Define the Borsh schema - const borsh = require("borsh"); + // Define the Borsh schema + const borsh = require("borsh"); - class LogNewTask { - constructor(props) { - Object.assign(this, props); + class LogNewTask { + constructor(props) { + Object.assign(this, props); + } } - } - // Borsh schema for deserialization - const logNewTaskSchema = new Map([ - [ + // Borsh schema for deserialization + const logNewTaskSchema = new Map([ + [ + LogNewTask, + { + kind: "struct", + fields: [ + ["task_id", "u64"], + ["source_network", "string"], + ["user_address", ["u8"]], + ["routing_info", "string"], + ["payload_hash", [32]], + ["user_key", ["u8"]], + ["user_pubkey", ["u8"]], + ["routing_code_hash", "string"], + ["task_destination_network", "string"], + ["handle", "string"], + ["nonce", [12]], + ["callback_gas_limit", "u32"], + ["payload", ["u8"]], + ["payload_signature", [64]], + ], + }, + ], + ]); + + // Deserialize the data using Borsh + const logNewTaskData = borsh.deserialize( + logNewTaskSchema, LogNewTask, - { - kind: "struct", - fields: [ - ["task_id", "u64"], - ["source_network", "string"], - ["user_address", ["u8"]], - ["routing_info", "string"], - ["payload_hash", [32]], - ["user_key", ["u8"]], - ["user_pubkey", ["u8"]], - ["routing_code_hash", "string"], - ["task_destination_network", "string"], - ["handle", "string"], - ["nonce", [12]], - ["callback_gas_limit", "u32"], - ["payload", ["u8"]], - ["payload_signature", [64]], - ], - }, - ], - ]); - - // Deserialize the data using Borsh - const logNewTaskData = borsh.deserialize( - logNewTaskSchema, - LogNewTask, - logNewTaskDataBuffer - ); - - // Now, add assertions to verify the contents of logNewTaskData - - // Assert source_network - assert.strictEqual( - logNewTaskData.source_network, - "SolDN", - "Source network does not match" - ); - - // Assert task_destination_network - assert.strictEqual( - logNewTaskData.task_destination_network, - taskDestinationNetwork, - "Task destination network does not match" - ); - - // Assert payload_hash - const expectedPayloadHash = Buffer.from(getBytes(keccak256(plaintext))) - - const payloadHashFromLog = Buffer.from(logNewTaskData.payload_hash); - - assert.deepStrictEqual( - payloadHashFromLog, - expectedPayloadHash, - `Payload hash does not match. Expected: ${payloadHashFromLog}, Got: ${expectedPayloadHash}` - ); - - // Assert user_address - const userAddressBytes = bs58.decode(provider.publicKey.toBase58()); - const userAddressFromLog = Buffer.from(logNewTaskData.user_address); - - assert.deepStrictEqual( - userAddressFromLog, - userAddressBytes, - "User address does not match" - ); - - // Assert routing_info - assert.strictEqual( - logNewTaskData.routing_info, - routingContract, - "Routing info does not match" - ); - - // Assert routing_code_hash - assert.strictEqual( - logNewTaskData.routing_code_hash, - routingCodeHash, - "Routing code hash does not match" - ); - - // Assert handle - assert.strictEqual( - logNewTaskData.handle, - handle, - "Handle does not match" - ); - - // Assert nonce - assert.deepStrictEqual( - Array.from(logNewTaskData.nonce), - Array.from(nonce), - `Nonce does not match. Expected: ${logNewTaskData.nonce}, Got: ${nonce}` - ); - - // Assert callback_gas_limit - assert.strictEqual( - logNewTaskData.callback_gas_limit, - callbackGasLimit, - "Callback gas limit does not match" - ); - - // Assert payload - const payloadFromLog = Buffer.from(logNewTaskData.payload); - - assert.deepStrictEqual( - payloadFromLog, - plaintext, - "Payload does not match" - ); - - // Assert user_key - const userKeyFromLog = Buffer.from(logNewTaskData.user_key); - - assert.deepStrictEqual( - userKeyFromLog, - Buffer.from(new Uint8Array(4)), - "User key does not match" - ); - - // Assert user_pubkey - const userPubkeyFromLog = Buffer.from(logNewTaskData.user_pubkey); - - assert.deepStrictEqual( - userPubkeyFromLog, - Buffer.from(new Uint8Array(4)), - "User pubkey does not match" - ); - - // Assert payload_signature - const payloadSignatureFromLog = Buffer.from( - logNewTaskData.payload_signature - ); - - assert.deepStrictEqual( - Buffer.from(payloadSignatureFromLog), - Buffer.from(emptySignature), - "Payload signature does not match" - ); - - // Fetch the raw data of the task_state account - const accountInfo = await provider.connection.getAccountInfo(taskPDA); - if (!accountInfo) { - console.log('Task State account does not exist'); - return; - } - - const TASK_SIZE = 41; - const PAYLOAD_HASH_SIZE = 32; - const TASK_ID_SIZE = 8; - const COMPLETED_OFFSET = 40; // Last byte for completed flag - - // +8 bytes for the account discriminator. This is not obvious inside of the program, but needs to be kept in mind when handling the raw account data. - const start = logNewTaskData.task_id * TASK_SIZE + 8; - const taskBuffer = accountInfo.data.slice(start, start+TASK_SIZE); - - // Extract payload_hash (32 bytes)x - const payloadHash = taskBuffer.slice(0, PAYLOAD_HASH_SIZE); - - // Extract task_id (8 bytes), little-endian - const taskIdBuffer = taskBuffer.slice(PAYLOAD_HASH_SIZE, PAYLOAD_HASH_SIZE+TASK_ID_SIZE); - const taskId = Buffer.from(taskIdBuffer).readBigUInt64LE(); - - // Extract completed (1 byte) - const completed = taskBuffer[COMPLETED_OFFSET] !== 0; - - console.log(`Task ID: ${taskId}`); - console.log(` Payload Hash: 0x${payloadHash.toString('hex')}`); - console.log(` Completed: ${completed}`); - console.log(` Output: ${taskBuffer.toString('hex')}`); - - assert.deepStrictEqual( + logNewTaskDataBuffer + ); + + // Now, add assertions to verify the contents of logNewTaskData + + // Assert source_network + assert.strictEqual( + logNewTaskData.source_network, + "SolDN", + "Source network does not match" + ); + + // Assert task_destination_network + assert.strictEqual( + logNewTaskData.task_destination_network, + taskDestinationNetwork, + "Task destination network does not match" + ); + + // Assert payload_hash + const expectedPayloadHash = Buffer.from(getBytes(keccak256(plaintext))); + + const payloadHashFromLog = Buffer.from(logNewTaskData.payload_hash); + + assert.deepStrictEqual( + payloadHashFromLog, + expectedPayloadHash, + `Payload hash does not match. Expected: ${payloadHashFromLog}, Got: ${expectedPayloadHash}` + ); + + // Assert user_address + const userAddressBytes = bs58.decode(provider.publicKey.toBase58()); + const userAddressFromLog = Buffer.from(logNewTaskData.user_address); + + assert.deepStrictEqual( + userAddressFromLog, + userAddressBytes, + "User address does not match" + ); + + // Assert routing_info + assert.strictEqual( + logNewTaskData.routing_info, + routingContract, + "Routing info does not match" + ); + + // Assert routing_code_hash + assert.strictEqual( + logNewTaskData.routing_code_hash, + routingCodeHash, + "Routing code hash does not match" + ); + + // Assert handle + assert.strictEqual(logNewTaskData.handle, handle, "Handle does not match"); + + // Assert nonce + assert.deepStrictEqual( + Array.from(logNewTaskData.nonce), + Array.from(nonce), + `Nonce does not match. Expected: ${logNewTaskData.nonce}, Got: ${nonce}` + ); + + // Assert callback_gas_limit + assert.strictEqual( + logNewTaskData.callback_gas_limit, + callbackGasLimit, + "Callback gas limit does not match" + ); + + // Assert payload + const payloadFromLog = Buffer.from(logNewTaskData.payload); + + assert.deepStrictEqual(payloadFromLog, plaintext, "Payload does not match"); + + // Assert user_key + const userKeyFromLog = Buffer.from(logNewTaskData.user_key); + + assert.deepStrictEqual( + userKeyFromLog, + Buffer.from(new Uint8Array(4)), + "User key does not match" + ); + + // Assert user_pubkey + const userPubkeyFromLog = Buffer.from(logNewTaskData.user_pubkey); + + assert.deepStrictEqual( + userPubkeyFromLog, + Buffer.from(new Uint8Array(4)), + "User pubkey does not match" + ); + + // Assert payload_signature + const payloadSignatureFromLog = Buffer.from( + logNewTaskData.payload_signature + ); + + assert.deepStrictEqual( + Buffer.from(payloadSignatureFromLog), + Buffer.from(emptySignature), + "Payload signature does not match" + ); + + // Fetch the raw data of the task_state account + const accountInfo = await provider.connection.getAccountInfo(taskPDA); + if (!accountInfo) { + console.log("Task State account does not exist"); + return; + } + + const TASK_SIZE = 41; + const PAYLOAD_HASH_SIZE = 32; + const TASK_ID_SIZE = 8; + const COMPLETED_OFFSET = 40; // Last byte for completed flag + + // +8 bytes for the account discriminator. This is not obvious inside of the program, but needs to be kept in mind when handling the raw account data. + const start = logNewTaskData.task_id * TASK_SIZE + 8; + const taskBuffer = accountInfo.data.slice(start, start + TASK_SIZE); + + // Extract payload_hash (32 bytes)x + const payloadHash = taskBuffer.slice(0, PAYLOAD_HASH_SIZE); + + // Extract task_id (8 bytes), little-endian + const taskIdBuffer = taskBuffer.slice( + PAYLOAD_HASH_SIZE, + PAYLOAD_HASH_SIZE + TASK_ID_SIZE + ); + const taskId = Buffer.from(taskIdBuffer).readBigUInt64LE(); + + // Extract completed (1 byte) + const completed = taskBuffer[COMPLETED_OFFSET] !== 0; + + console.log(`Task ID: ${taskId}`); + console.log(` Payload Hash: 0x${payloadHash.toString("hex")}`); + console.log(` Completed: ${completed}`); + console.log(` Output: ${taskBuffer.toString("hex")}`); + + assert.deepStrictEqual( Buffer.from(logNewTaskData.payload_hash), Buffer.from(payloadHash), - `Stored payloadHash do not match. Expected: ${Buffer.from(logNewTaskData.payload_hash).toString('hex')}, Got: ${payloadHash.toString('hex')}` + `Stored payloadHash do not match. Expected: ${Buffer.from( + logNewTaskData.payload_hash + ).toString("hex")}, Got: ${payloadHash.toString("hex")}` ); - assert.deepStrictEqual( + assert.deepStrictEqual( Number(logNewTaskData.task_id), Number(taskId), `Stored Task_ids do not match. Expected: ${logNewTaskData.task_id}, Got: ${taskId}` ); - console.log( - "All assertions passed, LogNewTask event verified successfully." - ); + console.log( + "All assertions passed, LogNewTask event verified successfully." + ); }); /*it("Performs post execution", async () => { diff --git a/TNLS-Relayers/eth_interface.py b/TNLS-Relayers/eth_interface.py index b4f5bfd..553b274 100644 --- a/TNLS-Relayers/eth_interface.py +++ b/TNLS-Relayers/eth_interface.py @@ -1,6 +1,7 @@ import json from copy import deepcopy from logging import getLogger, basicConfig, INFO, StreamHandler +import logging from typing import List from concurrent.futures import ThreadPoolExecutor, as_completed from threading import Lock, Timer @@ -31,12 +32,13 @@ def __init__(self, private_key="", provider=None, contract_address="", chain_id= self.nonce = self.provider.eth.get_transaction_count(self.address, 'pending') # Set up logging - basicConfig( - level=INFO, - format="%(asctime)s [Eth Interface: %(levelname)8.8s] %(message)s", - handlers=[StreamHandler()], - ) - self.logger = getLogger() + self.logger = getLogger("ETH Interface") + self.logger.setLevel(INFO) + handler = StreamHandler() + formatter = logging.Formatter("%(asctime)s [ETH Interface: %(levelname)4.8s] %(message)s") + handler.setFormatter(formatter) + self.logger.addHandler(handler) + self.logger.propagate = False # Initialize lock, executor, and sync interval self.nonce_lock = Lock() @@ -210,13 +212,18 @@ def __init__(self, interface, address, abi, **_kwargs): self.abi = abi self.interface = interface self.contract = interface.provider.eth.contract(address=self.address, abi=self.abi) - basicConfig( - level=INFO, - format="%(asctime)s [Eth Contract: %(levelname)8.8s] %(message)s", - handlers=[StreamHandler()], - ) + + # Set up logging + self.logger = getLogger("ETH Interface") + self.logger.setLevel(INFO) + handler = StreamHandler() + formatter = logging.Formatter("%(asctime)s [ETH Interface: %(levelname)4.8s] %(message)s") + handler.setFormatter(formatter) + self.logger.addHandler(handler) + self.logger.propagate = False + + self.lock = Lock() - self.logger = getLogger() self.logger.info("Initialized Eth contract with address: %s", self.address) def get_function(self, function_name): diff --git a/TNLS-Relayers/relayer.py b/TNLS-Relayers/relayer.py index 3af5f51..fd5eae8 100644 --- a/TNLS-Relayers/relayer.py +++ b/TNLS-Relayers/relayer.py @@ -15,7 +15,8 @@ stringify object as json send json string to destination network """ -from logging import getLogger, basicConfig, DEBUG, StreamHandler +from logging import getLogger, basicConfig, DEBUG, StreamHandler, INFO +import logging from threading import Thread from time import sleep from typing import Dict, Tuple @@ -65,12 +66,14 @@ def __init__( } # Configure the logger - basicConfig( - level=DEBUG, - format="%(asctime)s [relayer: %(levelname)8.8s] %(message)s", - handlers=[StreamHandler()], - ) - self.logger = getLogger() + # Set up logging + self.logger = getLogger("Relayer") + self.logger.setLevel(INFO) + handler = StreamHandler() + formatter = logging.Formatter("%(asctime)s [Relayer: %(levelname)4.8s] %(message)s") + handler.setFormatter(formatter) + self.logger.addHandler(handler) + self.logger.propagate = False self.num_loops = num_loops # Number of loops to run (if specified) def poll_for_transactions(self): @@ -112,7 +115,7 @@ def fetch_transactions(block_num): Returns: A tuple containing the block number and a list of parsed tasks. """ - + #block_num = 6846784 # Get transactions from the specified block transactions = chain_interface.get_transactions(contract_interface, height=block_num) tasks_tmp = [] diff --git a/TNLS-Relayers/scrt_interface.py b/TNLS-Relayers/scrt_interface.py index 75470c6..9de79c5 100644 --- a/TNLS-Relayers/scrt_interface.py +++ b/TNLS-Relayers/scrt_interface.py @@ -1,6 +1,7 @@ import json from copy import deepcopy -from logging import getLogger, basicConfig, DEBUG, StreamHandler +from logging import getLogger, DEBUG, StreamHandler, INFO +import logging from threading import Lock, Timer from concurrent.futures import ThreadPoolExecutor from typing import List @@ -197,12 +198,13 @@ def __init__(self, interface, address, abi, code_hash): self.code_hash = code_hash self.abi = json.loads(abi) self.interface = interface - basicConfig( - level=DEBUG, - format="%(asctime)s [SCRT interface: %(levelname)8.8s] %(message)s", - handlers=[StreamHandler()], - ) - self.logger = getLogger() + self.logger = getLogger("SCRT Interface") + self.logger.setLevel(INFO) + handler = StreamHandler() + formatter = logging.Formatter("%(asctime)s [SCRT Interface: %(levelname)4.8s] %(message)s") + handler.setFormatter(formatter) + self.logger.addHandler(handler) + self.logger.propagate = False self.lock = Lock() self.logger.info(f"Initialized SCRT interface for contract {self.address}") pass diff --git a/TNLS-Relayers/sol_interface.py b/TNLS-Relayers/sol_interface.py index 593554f..6f8bc28 100644 --- a/TNLS-Relayers/sol_interface.py +++ b/TNLS-Relayers/sol_interface.py @@ -6,7 +6,8 @@ from threading import Lock from solana.transaction import Transaction from concurrent.futures import ThreadPoolExecutor, as_completed -from logging import getLogger, basicConfig, INFO, StreamHandler +from logging import getLogger, INFO, StreamHandler +import logging from borsh_construct import CStruct, U64, String, U8, U32, Bytes from solders.system_program import ID as SYS_PROGRAM_ID from solders.instruction import Instruction, AccountMeta @@ -68,13 +69,14 @@ def __init__(self, private_key="", provider=None, contract_address="", chain_id= self.lock = Lock() # Thread lock for synchronization self.executor = ThreadPoolExecutor(max_workers=1) # Thread pool executor with one worker - # Set up logging - basicConfig( - level=INFO, - format="%(asctime)s [Solana Interface: %(levelname)8.8s] %(message)s", - handlers=[StreamHandler()], - ) - self.logger = getLogger() # Get the logger instance + # Create a separate logger instance + self.logger = getLogger("SolanaInterface") + self.logger.setLevel(INFO) + handler = StreamHandler() + formatter = logging.Formatter("%(asctime)s [Solana Interface: %(levelname)4.8s] %(message)s") + handler.setFormatter(formatter) + self.logger.addHandler(handler) + self.logger.propagate = False def sign_and_send_transaction(self, txn): """ diff --git a/TNLS-Relayers/web_app.py b/TNLS-Relayers/web_app.py index be3caeb..06434f9 100644 --- a/TNLS-Relayers/web_app.py +++ b/TNLS-Relayers/web_app.py @@ -1,6 +1,7 @@ import json import os -from logging import getLogger, basicConfig, INFO, StreamHandler +from logging import getLogger, INFO, StreamHandler +import logging from pathlib import Path from flask import Flask, current_app, Blueprint @@ -174,12 +175,13 @@ def generate_full_config(config_file, providers=None): - keys_dict: A dictionary for storing keys (currently empty). """ # Set up basic logging configuration for the application - basicConfig( - level=INFO, - format="%(asctime)s [Eth Interface: %(levelname)8.8s] %(message)s", - handlers=[StreamHandler()], - ) - logger = getLogger() + logger = getLogger("Setup Interface") + logger.setLevel(INFO) + handler = StreamHandler() + formatter = logging.Formatter("%(asctime)s [Setup Interface: %(levelname)4.8s] %(message)s") + handler.setFormatter(formatter) + logger.addHandler(handler) + logger.propagate = False # Load the configuration dictionary from the YAML file with open(config_file) as f: