From 553d81a03127863d3eb146132c1efe7e04a5ba11 Mon Sep 17 00:00:00 2001 From: Altynbek Orumbayev Date: Thu, 31 Oct 2024 00:40:13 +0100 Subject: [PATCH] fix: filename generation and match timestamp format on utils-py --- docs/code/functions/writeAVMDebugTrace.md | 2 +- src/debugging/writeAVMDebugTrace.spec.ts | 46 ++++++++++++++++- src/debugging/writeAVMDebugTrace.ts | 62 ++++++++++++++++++----- 3 files changed, 94 insertions(+), 16 deletions(-) diff --git a/docs/code/functions/writeAVMDebugTrace.md b/docs/code/functions/writeAVMDebugTrace.md index c021970..1dff60a 100644 --- a/docs/code/functions/writeAVMDebugTrace.md +++ b/docs/code/functions/writeAVMDebugTrace.md @@ -36,4 +36,4 @@ console.log(`Trace content: ${result.traceContent}`); ## Defined in -[debugging/writeAVMDebugTrace.ts:20](https://github.com/algorandfoundation/algokit-utils-ts-debug/blob/main/src/debugging/writeAVMDebugTrace.ts#L20) +[debugging/writeAVMDebugTrace.ts:65](https://github.com/algorandfoundation/algokit-utils-ts-debug/blob/main/src/debugging/writeAVMDebugTrace.ts#L65) diff --git a/src/debugging/writeAVMDebugTrace.spec.ts b/src/debugging/writeAVMDebugTrace.spec.ts index fb87ad0..c9a1e66 100644 --- a/src/debugging/writeAVMDebugTrace.spec.ts +++ b/src/debugging/writeAVMDebugTrace.spec.ts @@ -2,13 +2,15 @@ import { Config, EventType, performAtomicTransactionComposerSimulate } from '@al import { algorandFixture } from '@algorandfoundation/algokit-utils/testing' import { describe, expect, test } from '@jest/globals' import algosdk, { makeEmptyTransactionSigner } from 'algosdk' +import { SimulateResponse } from 'algosdk/dist/types/client/v2/algod/models/types' import * as fs from 'fs/promises' import * as os from 'os' import * as path from 'path' import { DEBUG_TRACES_DIR } from '../constants' import { registerDebugEventHandlers } from '../index' +import { generateDebugTraceFilename } from './writeAVMDebugTrace' -describe('simulateAndPersistResponse tests', () => { +describe('writeAVMDebugTrace tests', () => { const localnet = algorandFixture() beforeAll(async () => { @@ -45,3 +47,45 @@ describe('simulateAndPersistResponse tests', () => { jest.restoreAllMocks() }) }) + +describe('generateDebugTraceFilename', () => { + const TEST_CASES: Array<[string, object, string]> = [ + [ + 'single payment transaction', + { + lastRound: 1000, + txnGroups: [ + { + txnResults: [{ txnResult: { txn: { txn: { type: 'pay' } } } }], + }, + ], + }, + '1pay', + ], + [ + 'multiple transaction types', + { + lastRound: 1000, + txnGroups: [ + { + txnResults: [ + { txnResult: { txn: { txn: { type: 'pay' } } } }, + { txnResult: { txn: { txn: { type: 'pay' } } } }, + { txnResult: { txn: { txn: { type: 'axfer' } } } }, + { txnResult: { txn: { txn: { type: 'appl' } } } }, + { txnResult: { txn: { txn: { type: 'appl' } } } }, + { txnResult: { txn: { txn: { type: 'appl' } } } }, + ], + }, + ], + }, + '2pay_1axfer_3appl', + ], + ] + + test.each(TEST_CASES)('%s', (testName, mockResponse, expectedPattern) => { + const timestamp = '20230101_120000' + const filename = generateDebugTraceFilename(mockResponse as SimulateResponse, timestamp) + expect(filename).toBe(`${timestamp}_lr${(mockResponse as SimulateResponse).lastRound}_${expectedPattern}.trace.avm.json`) + }) +}) diff --git a/src/debugging/writeAVMDebugTrace.ts b/src/debugging/writeAVMDebugTrace.ts index 2c9a899..697619c 100644 --- a/src/debugging/writeAVMDebugTrace.ts +++ b/src/debugging/writeAVMDebugTrace.ts @@ -1,7 +1,52 @@ import { AVMTracesEventData } from '@algorandfoundation/algokit-utils' +import { SimulateResponse } from 'algosdk/dist/types/client/v2/algod/models/types' import { DEBUG_TRACES_DIR } from '../constants' import { getProjectRoot, joinPaths, writeToFile } from '../utils' +type TxnTypeCount = { + type: string + count: number +} + +/** + * Formats a date to YYYYMMDD_HHMMSS in UTC, equivalent to algokit-utils-py format: + * datetime.now(tz=timezone.utc).strftime("%Y%m%d_%H%M%S") + */ +export function formatTimestampUTC(date: Date): string { + // Get UTC components + const year = date.getUTCFullYear() + const month = String(date.getUTCMonth() + 1).padStart(2, '0') // Months are zero-based + const day = String(date.getUTCDate()).padStart(2, '0') + const hours = String(date.getUTCHours()).padStart(2, '0') + const minutes = String(date.getUTCMinutes()).padStart(2, '0') + const seconds = String(date.getUTCSeconds()).padStart(2, '0') + + // Format the datetime string + return `${year}${month}${day}_${hours}${minutes}${seconds}` +} + +export function generateDebugTraceFilename(simulateResponse: SimulateResponse, timestamp: string): string { + const txnGroups = simulateResponse.txnGroups + const txnTypesCount = txnGroups.reduce((acc: Map, txnGroup) => { + txnGroup.txnResults.forEach(({ txnResult }) => { + const { type } = txnResult.txn.txn + if (!acc.has(type)) { + acc.set(type, { type, count: 0 }) + } + const entry = acc.get(type)! + entry.count++ + }) + return acc + }, new Map()) + + const txnTypesStr = Array.from(txnTypesCount.values()) + .map(({ count, type }) => `${count}${type}`) + .join('_') + + const lastRound = simulateResponse.lastRound + return `${timestamp}_lr${lastRound}_${txnTypesStr}.trace.avm.json` +} + /** * Generates an AVM debug trace from the provided simulation response and persists it to a file. * @@ -20,22 +65,11 @@ import { getProjectRoot, joinPaths, writeToFile } from '../utils' export async function writeAVMDebugTrace(input: AVMTracesEventData): Promise { try { const simulateResponse = input.simulateResponse - const txnGroups = simulateResponse.txnGroups const projectRoot = await getProjectRoot() - - const txnTypesCount = txnGroups.reduce((acc: Record, txnGroup) => { - const txnType = txnGroup.txnResults[0].txnResult.txn.txn.type - acc[txnType] = (acc[txnType] || 0) + 1 - return acc - }, {}) - - const txnTypesStr = Object.entries(txnTypesCount) - .map(([type, count]) => `${count}${type}`) - .join('_') - - const timestamp = new Date().toISOString().replace(/[:.]/g, '') + const timestamp = formatTimestampUTC(new Date()) const outputRootDir = joinPaths(projectRoot, DEBUG_TRACES_DIR) - const outputFilePath = joinPaths(outputRootDir, `${timestamp}_${txnTypesStr}.trace.avm.json`) + const filename = generateDebugTraceFilename(simulateResponse, timestamp) + const outputFilePath = joinPaths(outputRootDir, filename) await writeToFile(outputFilePath, JSON.stringify(simulateResponse.get_obj_for_encoding(), null, 2)) } catch (error) {