From 480767954884fcfe75d44a037f5046e2fc021ec7 Mon Sep 17 00:00:00 2001 From: Luis Mastrangelo Date: Thu, 10 Nov 2022 22:50:57 +0100 Subject: [PATCH 01/11] feat: add `disableFetchExternal` debugger flag --- package.json | 27 +++++++++++++------ src/commands/DebuggerCommands.ts | 17 ++++++------ src/debugAdapter/debugSession.ts | 17 +++++++++++- src/debugAdapter/models/debuggerTypes.ts | 21 +++++++++++---- src/debugAdapter/runtimeInterface.ts | 14 +++++----- src/helpers/uriHandlerController.ts | 19 +++++-------- .../SolidityDebugSessionClient.ts | 2 +- test/debugAdapter/runtimeInterface.test.ts | 3 ++- 8 files changed, 75 insertions(+), 45 deletions(-) diff --git a/package.json b/package.json index 8c9b5154..c2828fc7 100644 --- a/package.json +++ b/package.json @@ -567,7 +567,11 @@ "runtime": "node", "configurationAttributes": { "launch": { - "required": [], + "required": [ + "txHash", + "workingDirectory", + "providerUrl" + ], "properties": { "stopOnEntry": { "type": "boolean", @@ -581,23 +585,28 @@ }, "txHash": { "type": "string", - "description": "Transaction hash to debug", + "description": "The transaction hash to debug.", "default": "0x" }, "files": { "type": "string[]", - "description": "Array of file paths of solidity files to debug", + "description": "Array of file paths of solidity files to debug.", "default": [] }, "workingDirectory": { "type": "string", - "description": "Directory of truffle project", + "description": "Directory of the Truffle project where to find the Truffle config file.", "default": "${workspaceFolder}" }, "providerUrl": { "type": "string", - "description": "URL of provider", + "description": "Provider's URL of the Ethereum network to connect to.", "default": "http://127.0.0.1:8545" + }, + "disableFetchExternal": { + "type": "boolean", + "description": "When set, do not try to fetch external contract sources when debugging a forked network instance.", + "default": false } } } @@ -611,7 +620,8 @@ "txHash": "0x", "files": [], "workingDirectory": "${workspaceFolder}", - "providerUrl": "http://127.0.0.1:8545" + "providerUrl": "http://127.0.0.1:8545", + "disableFetchExternal": false } ], "configurationSnippets": [ @@ -625,8 +635,9 @@ "stopOnEntry": false, "txHash": "0x", "files": [], - "workingDirectory": "^\"\\${workspaceFolder}/", - "providerUrl": "http://127.0.0.1:8545" + "workingDirectory": "^\"\\${workspaceFolder}\"", + "providerUrl": "http://127.0.0.1:8545", + "disableFetchExternal": false } } ], diff --git a/src/commands/DebuggerCommands.ts b/src/commands/DebuggerCommands.ts index 70fdc0ce..552388a5 100644 --- a/src/commands/DebuggerCommands.ts +++ b/src/commands/DebuggerCommands.ts @@ -12,6 +12,7 @@ import {Web3Wrapper} from '@/debugAdapter/web3Wrapper'; import {getTruffleWorkspace, getPathByPlatform} from '@/helpers/workspace'; import {showInputBox, showQuickPick} from '@/helpers/userInteraction'; import {Telemetry} from '@/TelemetryClient'; +import {DebuggerTypes} from '@/debugAdapter/models/debuggerTypes'; const TX_REGEX = /^(?:0x)?[0-9a-fA-F]{64}$/; @@ -68,7 +69,7 @@ export namespace DebuggerCommands { txHash = txHashSelection.detail || txHashSelection.label; } - await startDebugging(txHash, workingDirectory, providerUrl); + await startDebugging(txHash, workingDirectory, providerUrl, false); } } @@ -96,19 +97,19 @@ export async function startDebugging( txHash: string, workingDirectory: string, providerUrl: string, - fetchExternal?: boolean + disableFetchExternal: boolean ): Promise { const workspaceFolder = workspace.getWorkspaceFolder(Uri.parse(workingDirectory)); - const config: DebugConfiguration = { - files: [], + const config: DebugConfiguration & DebuggerTypes.ILaunchRequestArguments = { + type: DEBUG_TYPE, name: 'Debug Transactions', - providerUrl, request: 'launch', + timeout: 30000, + files: [], + providerUrl, txHash, - type: DEBUG_TYPE, workingDirectory, - timeout: 30000, - fetchExternal, + disableFetchExternal, }; debug.startDebugging(workspaceFolder, config).then(() => { diff --git a/src/debugAdapter/debugSession.ts b/src/debugAdapter/debugSession.ts index 10fb5965..cee40732 100644 --- a/src/debugAdapter/debugSession.ts +++ b/src/debugAdapter/debugSession.ts @@ -101,18 +101,33 @@ export class SolidityDebugSession extends LoggingDebugSession { args: DebuggerTypes.ILaunchRequestArguments ): Promise { await this.sendErrorIfFailed(response, async () => { + validateRequiredArg(args.txHash, `txHash`); + validateRequiredArg(args.workingDirectory, `workingDirectory`); + validateRequiredArg(args.providerUrl, `providerUrl`); + + if (args.disableFetchExternal === undefined) { + args.disableFetchExternal = false; + } + // make sure to 'Stop' the buffered logging if 'trace' is not set // logger.setup enable logs in client logger.setup(args.noDebug ? Logger.LogLevel.Verbose : Logger.LogLevel.Stop, false); // start the program in the runtime - await this._runtime.attach(args.txHash, args.workingDirectory, args.providerUrl); + // This cast is only necessary because TypeScript does not narrow types in properties + await this._runtime.attach(>args); await this._runtime.processInitialBreakPoints(); // Events order is important this.sendEvent(new DebuggerTypes.LaunchedEvent()); this.sendEvent(new StoppedEvent(EVENT_REASONS.breakpoint, MAIN_THREAD.id)); }); + + function validateRequiredArg(arg: string | undefined | null, name: string) { + if (!arg) { + throw new Error(`\`${name}\` must be specified to initiate the Truffle Debugger`); + } + } } protected async disconnectRequest( diff --git a/src/debugAdapter/models/debuggerTypes.ts b/src/debugAdapter/models/debuggerTypes.ts index 8f375461..223b51e1 100644 --- a/src/debugAdapter/models/debuggerTypes.ts +++ b/src/debugAdapter/models/debuggerTypes.ts @@ -17,18 +17,29 @@ export namespace DebuggerTypes { column: number; } + /** + * Represents the arguments needed to initiate a new Truffle `DebugSession` request. + * + * All properties in this interface are defined as optional given that the Debugger + * can be started from a [launch configuration](https://code.visualstudio.com/docs/editor/debugging#_launch-configurations), + * where any property might be missing. + */ + export interface DebugArgs { + txHash?: string; + workingDirectory?: string; + providerUrl?: string; + disableFetchExternal?: boolean; + } + // The interface should always match schema in the package.json. - export interface ILaunchRequestArguments extends DebugProtocol.LaunchRequestArguments { + export interface ILaunchRequestArguments extends DebugProtocol.LaunchRequestArguments, DebugArgs { + // TODO: Are these attributes being used? If not we should remove it in a future PR. // Automatically stop target after launch. If not specified, target does not stop. stopOnEntry?: boolean; // enable logging the Debug Adapter Protocol trace?: boolean; host?: string; - txHash: string; files?: string[]; - workingDirectory: string; - providerUrl: string; - fetchExternal?: boolean; } export class LaunchedEvent implements DebugProtocol.Event { diff --git a/src/debugAdapter/runtimeInterface.ts b/src/debugAdapter/runtimeInterface.ts index c5bcd3bc..fe5c61a1 100644 --- a/src/debugAdapter/runtimeInterface.ts +++ b/src/debugAdapter/runtimeInterface.ts @@ -134,27 +134,25 @@ export default class RuntimeInterface extends EventEmitter { /** * This function attaches the debugger and starts the debugging process. * - * @param txHash The transaction hash to debug. - * @param workingDirectory The workspace path where the truffle project is located. - * @param providerUrl The url provider where the contracts were deployed. + * @param args The `DebugArgs` to initialize the `DebugSession` this `RuntimeInterface` belong to. * @returns */ - public async attach(txHash: string, workingDirectory: string, providerUrl: string): Promise { + public async attach(args: Required): Promise { // Gets the contracts compilation - const result = await prepareContracts(workingDirectory); + const result = await prepareContracts(args.workingDirectory); // Sets the properties to use during the debugger process this._mappedSources = result.mappedSources; - const networkId = this.getNetworkId(providerUrl); + const networkId = args.disableFetchExternal ? undefined : this.getNetworkId(args.providerUrl); // Sets the truffle debugger options const options: truffleDebugger.DebuggerOptions = { - provider: providerUrl, + provider: args.providerUrl, compilations: result.shimCompilations, lightMode: networkId !== undefined, }; - this._session = await this.generateSession(txHash, networkId, options); + this._session = await this.generateSession(args.txHash, networkId, options); this.serializeExternalSources(); this._isDebuggerAttached = true; diff --git a/src/helpers/uriHandlerController.ts b/src/helpers/uriHandlerController.ts index c7ebb986..e6797364 100644 --- a/src/helpers/uriHandlerController.ts +++ b/src/helpers/uriHandlerController.ts @@ -1,7 +1,7 @@ import {startDebugging} from '@/commands'; import {Constants} from '@/Constants'; -import {DebuggerTypes} from '@/debugAdapter/models/debuggerTypes'; import {Uri, UriHandler, window} from 'vscode'; + /** * This enum is used to identify the different types of commands that can be executed. */ @@ -25,23 +25,16 @@ export class UriHandlerController implements UriHandler { const searchParams = new URLSearchParams(uri.query); // Convert the URI parameters to a TDebugInformation object. - const launchRequest: DebuggerTypes.ILaunchRequestArguments = { - txHash: searchParams.get('txHash')!, - workingDirectory: searchParams.get('workingDirectory')!, - providerUrl: searchParams.get('providerUrl')!, - fetchExternal: searchParams.get('fetchExternal')! === 'true', - }; + const txHash = searchParams.get('txHash')!; + const workingDirectory = searchParams.get('workingDirectory')!; + const providerUrl = searchParams.get('providerUrl')!; + const disableFetchExternal = !!searchParams.get('disableFetchExternal'); // Checks the command and executes the corresponding action. switch (command) { case Commands.debug: // Calls the debugger with the given parameters. - await startDebugging( - launchRequest.txHash, - launchRequest.workingDirectory, - launchRequest.providerUrl, - launchRequest.fetchExternal! - ); + await startDebugging(txHash, workingDirectory, providerUrl, disableFetchExternal); break; } } catch (error) { diff --git a/test/debugAdapter/SolidityDebugSessionClient.ts b/test/debugAdapter/SolidityDebugSessionClient.ts index 7d7c0502..dc9ca037 100644 --- a/test/debugAdapter/SolidityDebugSessionClient.ts +++ b/test/debugAdapter/SolidityDebugSessionClient.ts @@ -7,7 +7,7 @@ const baseDebugAdapterResponseMock = {request_seq: 1, success: true, command: '' export class SolidityDebugSessionClient extends SolidityDebugSession { public execProtectedLaunchRequest() { - const mockArgs = {txHash: '', workingDirectory: '', files: [], providerUrl: ''}; + const mockArgs = {txHash: '0x', workingDirectory: '/path', files: [], providerUrl: 'http://127.0.0.1:8545'}; return this.launchRequest(baseDebugAdapterResponseMock, mockArgs); } diff --git a/test/debugAdapter/runtimeInterface.test.ts b/test/debugAdapter/runtimeInterface.test.ts index 4c69bc64..e3d742fe 100644 --- a/test/debugAdapter/runtimeInterface.test.ts +++ b/test/debugAdapter/runtimeInterface.test.ts @@ -82,7 +82,8 @@ const baseSessionMock: truffleDebugger.Session = { async function initMockRuntime() { const runtimeInterface = new RuntimeInterface(); - await runtimeInterface.attach('', '', ''); + const args = {txHash: '', workingDirectory: '', providerUrl: '', disableFetchExternal: false}; + await runtimeInterface.attach(args); return runtimeInterface; } From e4d496d9704a5bfae0e75a1a8e5e9e5acd775164 Mon Sep 17 00:00:00 2001 From: Luis Mastrangelo Date: Thu, 10 Nov 2022 22:55:55 +0100 Subject: [PATCH 02/11] docs: improve description and comments --- package.json | 2 +- src/debugAdapter/models/debuggerTypes.ts | 18 ++++++++++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index c2828fc7..2acc4f12 100644 --- a/package.json +++ b/package.json @@ -605,7 +605,7 @@ }, "disableFetchExternal": { "type": "boolean", - "description": "When set, do not try to fetch external contract sources when debugging a forked network instance.", + "description": "When set, do not try to fetch external contract sources when debugging a forked network instance. When the network is not being forked, this flag is ignored.", "default": false } } diff --git a/src/debugAdapter/models/debuggerTypes.ts b/src/debugAdapter/models/debuggerTypes.ts index 223b51e1..07b16695 100644 --- a/src/debugAdapter/models/debuggerTypes.ts +++ b/src/debugAdapter/models/debuggerTypes.ts @@ -23,11 +23,29 @@ export namespace DebuggerTypes { * All properties in this interface are defined as optional given that the Debugger * can be started from a [launch configuration](https://code.visualstudio.com/docs/editor/debugging#_launch-configurations), * where any property might be missing. + * + * `package.json` also defines these properties. */ export interface DebugArgs { + /** + * The transaction hash to debug. + */ txHash?: string; + + /** + * Directory of the Truffle project where to find the Truffle config file. + */ workingDirectory?: string; + + /** + * Provider's URL of the Ethereum network to connect to. + */ providerUrl?: string; + + /** + * When set, do not try to fetch external contract sources when debugging a forked network instance. + * When the network is not being forked, this flag is ignored. + */ disableFetchExternal?: boolean; } From 5b5cb3c03a51eb97288b88debec21140390868a1 Mon Sep 17 00:00:00 2001 From: Luis Mastrangelo Date: Fri, 11 Nov 2022 15:28:07 +0100 Subject: [PATCH 03/11] refactor: remove unnecessary casts --- src/commands/DebuggerCommands.ts | 29 +++++++++++------------------ src/debugAdapter/debugSession.ts | 2 +- src/helpers/uriHandlerController.ts | 22 ++++++++++++++-------- 3 files changed, 26 insertions(+), 27 deletions(-) diff --git a/src/commands/DebuggerCommands.ts b/src/commands/DebuggerCommands.ts index 552388a5..6763fb88 100644 --- a/src/commands/DebuggerCommands.ts +++ b/src/commands/DebuggerCommands.ts @@ -69,7 +69,7 @@ export namespace DebuggerCommands { txHash = txHashSelection.detail || txHashSelection.label; } - await startDebugging(txHash, workingDirectory, providerUrl, false); + await startDebugging({txHash, workingDirectory, providerUrl, disableFetchExternal: false}); } } @@ -86,30 +86,23 @@ async function getQuickPickItems(txProvider: TransactionProvider) { } /** - * This functions is responsible for starting the solidity debugger with the given parameters. - * - * @param txHash A transaction hash. - * @param workingDirectory The working directory of the project. - * @param providerUrl The network provider url. - * @param fetchExternal Indicates if the debugger should fetch external contracts. + * Responsible for starting the Solidity debugger with the given arguments. + * + @param args The `DebugArgs` to initialize the `DebugSession`. */ -export async function startDebugging( - txHash: string, - workingDirectory: string, - providerUrl: string, - disableFetchExternal: boolean -): Promise { - const workspaceFolder = workspace.getWorkspaceFolder(Uri.parse(workingDirectory)); +export async function startDebugging(args: DebuggerTypes.DebugArgs): Promise { + const workspaceFolder = + args.workingDirectory === undefined ? undefined : workspace.getWorkspaceFolder(Uri.parse(args.workingDirectory)); const config: DebugConfiguration & DebuggerTypes.ILaunchRequestArguments = { type: DEBUG_TYPE, name: 'Debug Transactions', request: 'launch', + + // TODO: are these `timeout` and `files` properties used? timeout: 30000, files: [], - providerUrl, - txHash, - workingDirectory, - disableFetchExternal, + + ...args, }; debug.startDebugging(workspaceFolder, config).then(() => { diff --git a/src/debugAdapter/debugSession.ts b/src/debugAdapter/debugSession.ts index cee40732..e75ed271 100644 --- a/src/debugAdapter/debugSession.ts +++ b/src/debugAdapter/debugSession.ts @@ -123,7 +123,7 @@ export class SolidityDebugSession extends LoggingDebugSession { this.sendEvent(new StoppedEvent(EVENT_REASONS.breakpoint, MAIN_THREAD.id)); }); - function validateRequiredArg(arg: string | undefined | null, name: string) { + function validateRequiredArg(arg: string | undefined, name: string) { if (!arg) { throw new Error(`\`${name}\` must be specified to initiate the Truffle Debugger`); } diff --git a/src/helpers/uriHandlerController.ts b/src/helpers/uriHandlerController.ts index e6797364..4c9c4f19 100644 --- a/src/helpers/uriHandlerController.ts +++ b/src/helpers/uriHandlerController.ts @@ -24,18 +24,24 @@ export class UriHandlerController implements UriHandler { const command = uri.path.replace('/', ''); const searchParams = new URLSearchParams(uri.query); - // Convert the URI parameters to a TDebugInformation object. - const txHash = searchParams.get('txHash')!; - const workingDirectory = searchParams.get('workingDirectory')!; - const providerUrl = searchParams.get('providerUrl')!; - const disableFetchExternal = !!searchParams.get('disableFetchExternal'); - // Checks the command and executes the corresponding action. switch (command) { - case Commands.debug: + case Commands.debug: { + // Convert the URI parameters to a `DebugArgs` object. + // The `??` operator converts `null` to `undefined`. + const args = { + txHash: searchParams.get('txHash') ?? undefined, + workingDirectory: searchParams.get('workingDirectory') ?? undefined, + providerUrl: searchParams.get('providerUrl') ?? undefined, + disableFetchExternal: !!searchParams.get('disableFetchExternal'), + }; + // Calls the debugger with the given parameters. - await startDebugging(txHash, workingDirectory, providerUrl, disableFetchExternal); + await startDebugging(args); break; + } + default: + window.showWarningMessage(`Unrecognized action to handle \`${command}\``); } } catch (error) { // Display an error message if something went wrong. From 9296becc0adb455d34e4806486625da6c2d0ed90 Mon Sep 17 00:00:00 2001 From: Luis Mastrangelo Date: Fri, 11 Nov 2022 18:19:52 +0100 Subject: [PATCH 04/11] refactor: remove unnecessary constants & module --- src/debugAdapter/constants/contractJson.ts | 5 ----- src/debugAdapter/contracts/contractJsonsProvider.ts | 3 +-- 2 files changed, 1 insertion(+), 7 deletions(-) delete mode 100644 src/debugAdapter/constants/contractJson.ts diff --git a/src/debugAdapter/constants/contractJson.ts b/src/debugAdapter/constants/contractJson.ts deleted file mode 100644 index a5175f13..00000000 --- a/src/debugAdapter/constants/contractJson.ts +++ /dev/null @@ -1,5 +0,0 @@ -// Copyright (c) Consensys Software Inc. All rights reserved. -// Licensed under the MIT license. - -export const CONTRACT_JSON_EXTENSION = '.json'; -export const CONTRACT_JSON_ENCODING = 'utf-8'; diff --git a/src/debugAdapter/contracts/contractJsonsProvider.ts b/src/debugAdapter/contracts/contractJsonsProvider.ts index e452136c..dec2b195 100644 --- a/src/debugAdapter/contracts/contractJsonsProvider.ts +++ b/src/debugAdapter/contracts/contractJsonsProvider.ts @@ -3,7 +3,6 @@ import fs from 'fs-extra'; import path from 'path'; -import {CONTRACT_JSON_ENCODING} from '../constants/contractJson'; import {IContractJsonModel} from '../models/IContractJsonModel'; export class ContractJsonsProvider { @@ -11,7 +10,7 @@ export class ContractJsonsProvider { private contractJsonEncoding: string; private _cachedContractJsons: {[fileName: string]: IContractJsonModel} | undefined; - constructor(contractBuildDirectory: string, contractJsonEncoding = CONTRACT_JSON_ENCODING) { + constructor(contractBuildDirectory: string, contractJsonEncoding = 'utf-8') { this.contractBuildDirectory = contractBuildDirectory; this.contractJsonEncoding = contractJsonEncoding; } From 2c26c31cc97e03825471fc95548f0a7f04a13fca Mon Sep 17 00:00:00 2001 From: Luis Mastrangelo Date: Fri, 11 Nov 2022 21:13:54 +0100 Subject: [PATCH 05/11] refactor: refine `const`s scope --- src/debugAdapter/constants/transaction.ts | 6 ------ src/debugAdapter/transaction/transactionInputDataDecoder.ts | 3 ++- src/debugAdapter/transaction/transactionProvider.ts | 3 ++- 3 files changed, 4 insertions(+), 8 deletions(-) delete mode 100644 src/debugAdapter/constants/transaction.ts diff --git a/src/debugAdapter/constants/transaction.ts b/src/debugAdapter/constants/transaction.ts deleted file mode 100644 index a8638511..00000000 --- a/src/debugAdapter/constants/transaction.ts +++ /dev/null @@ -1,6 +0,0 @@ -// Copyright (c) Consensys Software Inc. All rights reserved. -// Licensed under the MIT license. - -export const TRANSACTION_NUMBER_TO_SHOW = 5; -export const TRANSACTION_DEFAULT_METHOD_NAME = 'constructor'; -export const LAST_BLOCK_QUERY = 'latest'; diff --git a/src/debugAdapter/transaction/transactionInputDataDecoder.ts b/src/debugAdapter/transaction/transactionInputDataDecoder.ts index 6820bd06..a8e51e91 100644 --- a/src/debugAdapter/transaction/transactionInputDataDecoder.ts +++ b/src/debugAdapter/transaction/transactionInputDataDecoder.ts @@ -2,9 +2,10 @@ // Licensed under the MIT license. import abiDecoder from 'abi-decoder'; -import {TRANSACTION_DEFAULT_METHOD_NAME} from '../constants/transaction'; import {ITransactionInputData} from '../models/ITransactionInputData'; +const TRANSACTION_DEFAULT_METHOD_NAME = 'constructor'; + export class TransactionInputDataDecoder { public addContractAbi(abi: []) { abiDecoder.addABI(abi); diff --git a/src/debugAdapter/transaction/transactionProvider.ts b/src/debugAdapter/transaction/transactionProvider.ts index a879fbad..4f4b038c 100644 --- a/src/debugAdapter/transaction/transactionProvider.ts +++ b/src/debugAdapter/transaction/transactionProvider.ts @@ -2,7 +2,6 @@ // Licensed under the MIT license. import {Constants} from '@/Constants'; -import {TRANSACTION_NUMBER_TO_SHOW} from '../constants/transaction'; import {ContractJsonsProvider} from '../contracts/contractJsonsProvider'; import {groupBy} from '../helpers'; import {IContractJsonModel} from '../models/IContractJsonModel'; @@ -11,6 +10,8 @@ import {ITransactionResponse} from '../models/ITransactionResponse'; import {Web3Wrapper} from '../web3Wrapper'; import {TransactionInputDataDecoder} from './transactionInputDataDecoder'; +const TRANSACTION_NUMBER_TO_SHOW = 5; + export class TransactionProvider { private _web3: Web3Wrapper; private _contractBuildsDirectory: string; From 1ab04caa9e6380feb6fc0b20574caddb2f5127b1 Mon Sep 17 00:00:00 2001 From: Luis Mastrangelo Date: Fri, 11 Nov 2022 21:17:37 +0100 Subject: [PATCH 06/11] refactor: refine more `const`s scope --- src/debugAdapter/constants/truffleConfig.ts | 4 ---- src/debugAdapter/debugNetwork.ts | 6 +++++- 2 files changed, 5 insertions(+), 5 deletions(-) delete mode 100644 src/debugAdapter/constants/truffleConfig.ts diff --git a/src/debugAdapter/constants/truffleConfig.ts b/src/debugAdapter/constants/truffleConfig.ts deleted file mode 100644 index 61b17214..00000000 --- a/src/debugAdapter/constants/truffleConfig.ts +++ /dev/null @@ -1,4 +0,0 @@ -// Copyright (c) Consensys Software Inc. All rights reserved. -// Licensed under the MIT license. - -export const TRUFFLE_CONFIG_NAME = 'truffle-config.js'; diff --git a/src/debugAdapter/debugNetwork.ts b/src/debugAdapter/debugNetwork.ts index 7f9906e6..d3a80df4 100644 --- a/src/debugAdapter/debugNetwork.ts +++ b/src/debugAdapter/debugNetwork.ts @@ -3,7 +3,6 @@ import path from 'path'; import {IConfiguration, INetwork, INetworkOption} from '@/helpers/ConfigurationReader'; -import {TRUFFLE_CONFIG_NAME} from './constants/truffleConfig'; import {TreeManager} from '@/services/tree/TreeManager'; import {ItemType} from '@/Models/ItemType'; import {Constants} from '@/Constants'; @@ -14,6 +13,11 @@ import {LocalProject} from '@/Models/TreeItems/LocalProject'; import {LocalNetworkNode} from '@/Models/TreeItems'; import {ConfigurationReader} from '../helpers/debugConfigurationReader'; +/** + * TODO: We should removed this hardcoded name since there might be multiple Truffle config files in the same workspace. + */ +const TRUFFLE_CONFIG_NAME = 'truffle-config.js'; + export class DebugNetwork { public workingDirectory: string; private _basedConfig: ConfigurationReader.TruffleConfig | undefined; From 01b4e7e8c6f794f84e8c4f1f20b23a755c8591e2 Mon Sep 17 00:00:00 2001 From: Luis Mastrangelo Date: Fri, 11 Nov 2022 21:27:31 +0100 Subject: [PATCH 07/11] refactor: continue to merge def and usages --- src/debugAdapter/constants/variablesView.ts | 19 ------------------- src/debugAdapter/variablesHandler.ts | 19 ++++++++++++++++++- test/debugAdapter/variablesHandler.test.ts | 3 +-- 3 files changed, 19 insertions(+), 22 deletions(-) delete mode 100644 src/debugAdapter/constants/variablesView.ts diff --git a/src/debugAdapter/constants/variablesView.ts b/src/debugAdapter/constants/variablesView.ts deleted file mode 100644 index 2b77e233..00000000 --- a/src/debugAdapter/constants/variablesView.ts +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright (c) Consensys Software Inc. All rights reserved. -// Licensed under the MIT license. - -const VARIABLE_REFERANCE = { - all: 1, - dynamicVariables: 2, -}; - -export const SCOPES = { - all: { - name: 'All', - ref: VARIABLE_REFERANCE.all, - }, - dynamicVariables: { - ref: VARIABLE_REFERANCE.dynamicVariables, - }, -}; - -export const OBJECT_VARIABLE_DISPLAY_NAME = 'Object'; diff --git a/src/debugAdapter/variablesHandler.ts b/src/debugAdapter/variablesHandler.ts index 0299ea6f..a706a624 100644 --- a/src/debugAdapter/variablesHandler.ts +++ b/src/debugAdapter/variablesHandler.ts @@ -4,11 +4,28 @@ import {Handles, Scope} from '@vscode/debugadapter'; import {DebugProtocol} from '@vscode/debugprotocol'; import _ from 'lodash'; -import {OBJECT_VARIABLE_DISPLAY_NAME, SCOPES} from './constants/variablesView'; import {TranslatedResult} from './helpers'; import {IExpressionEval} from './models/IExpressionEval'; import RuntimeInterface from './runtimeInterface'; +/** + * > **NOTE**. This is only `export`ed to be used in tests. + */ +export const SCOPES = { + all: { + name: 'All', + ref: 1, + }, + dynamicVariables: { + ref: 2, + }, +}; + +/** + * > **NOTE**. This is only `export`ed to be used in tests. + */ +export const OBJECT_VARIABLE_DISPLAY_NAME = 'Object'; + export default class VariablesHandler { private _runtime: RuntimeInterface; private readonly _scopes: Scope[]; diff --git a/test/debugAdapter/variablesHandler.test.ts b/test/debugAdapter/variablesHandler.test.ts index 0e577628..e9f1321a 100644 --- a/test/debugAdapter/variablesHandler.test.ts +++ b/test/debugAdapter/variablesHandler.test.ts @@ -1,9 +1,8 @@ import assert from 'assert'; import sinon from 'sinon'; import {Handles} from '@vscode/debugadapter'; -import {OBJECT_VARIABLE_DISPLAY_NAME, SCOPES} from '../../src/debugAdapter/constants/variablesView'; import RuntimeInterface from '../../src/debugAdapter/runtimeInterface'; -import VariablesHandler from '../../src/debugAdapter/variablesHandler'; +import VariablesHandler, {OBJECT_VARIABLE_DISPLAY_NAME, SCOPES} from '../../src/debugAdapter/variablesHandler'; describe('VariablesHandler unit tests', () => { const runtimeInterface = new RuntimeInterface(); From aefcb0952f99901174046d4829a8bfc17c79bdf3 Mon Sep 17 00:00:00 2001 From: Luis Mastrangelo Date: Sat, 12 Nov 2022 17:25:51 +0100 Subject: [PATCH 08/11] docs: improve note formatting --- src/debugAdapter/variablesHandler.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/debugAdapter/variablesHandler.ts b/src/debugAdapter/variablesHandler.ts index a706a624..badc2468 100644 --- a/src/debugAdapter/variablesHandler.ts +++ b/src/debugAdapter/variablesHandler.ts @@ -9,7 +9,7 @@ import {IExpressionEval} from './models/IExpressionEval'; import RuntimeInterface from './runtimeInterface'; /** - * > **NOTE**. This is only `export`ed to be used in tests. + * > **NOTE**. _This is only `export`ed to be used in tests._ */ export const SCOPES = { all: { @@ -22,7 +22,7 @@ export const SCOPES = { }; /** - * > **NOTE**. This is only `export`ed to be used in tests. + * > **NOTE**. _This is only `export`ed to be used in tests._ */ export const OBJECT_VARIABLE_DISPLAY_NAME = 'Object'; From bfcadc54b380b104191f43f4a18275a1ea35a386 Mon Sep 17 00:00:00 2001 From: Luis Mastrangelo Date: Sat, 12 Nov 2022 17:26:47 +0100 Subject: [PATCH 09/11] refactor: refine function scope --- src/commands/DebuggerCommands.ts | 20 +++++++++++++++++- src/debugAdapter/functions.ts | 16 -------------- test/commands/DebuggerCommands.test.ts | 29 +++++++++++++++++++++++++- 3 files changed, 47 insertions(+), 18 deletions(-) delete mode 100644 src/debugAdapter/functions.ts diff --git a/src/commands/DebuggerCommands.ts b/src/commands/DebuggerCommands.ts index 6763fb88..0187c63a 100644 --- a/src/commands/DebuggerCommands.ts +++ b/src/commands/DebuggerCommands.ts @@ -6,7 +6,6 @@ import {debug, DebugConfiguration, QuickPickItem, Uri, QuickPickItemKind, worksp import {DEBUG_TYPE} from '@/debugAdapter/constants/debugAdapter'; import {DebugNetwork} from '@/debugAdapter/debugNetwork'; -import {shortenHash} from '@/debugAdapter/functions'; import {TransactionProvider} from '@/debugAdapter/transaction/transactionProvider'; import {Web3Wrapper} from '@/debugAdapter/web3Wrapper'; import {getTruffleWorkspace, getPathByPlatform} from '@/helpers/workspace'; @@ -115,3 +114,22 @@ function generateDescription(contractName?: string, methodName?: string) { const contractNameWithoutExt = path.basename(contractName || '', '.json'); return `${contractNameWithoutExt}.${methodName}()`; } + +/** + * Shorten the checksummed version of the input `hash` to have `0x + chars ... chars` characters. + * It assumes that `hash` starts with the prefix `0x`. + * + * > **NOTE**. _This is only `export`ed to be used in tests._ + * + * @param hash the hash to shorten. + * @param chars the desired length to append both at the start and at the end. + * @returns the shortened `hash`. + */ +export function shortenHash(hash: string, chars = 4): string { + try { + const parsed = hash; + return `${parsed.substring(0, chars + 2)}...${parsed.substring(parsed.length - chars)}`; + } catch (error) { + throw Error(`Invalid 'address' parameter '${hash}'.`); + } +} diff --git a/src/debugAdapter/functions.ts b/src/debugAdapter/functions.ts deleted file mode 100644 index 64f719b0..00000000 --- a/src/debugAdapter/functions.ts +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright (c) Consensys Software Inc. All rights reserved. -// Licensed under the MIT license. - -// All common functions across the debugAdapter package go in here. - -// import { getAddress } from '@ethersproject/address' - -// shorten the checksummed version of the input hash to have 0x + 4 characters at start and end -export function shortenHash(address: string, chars = 4): string { - try { - const parsed = address; // getAddress(address) - return `${parsed.substring(0, chars + 2)}...${parsed.substring(parsed.length - chars)}`; - } catch (error) { - throw Error(`Invalid 'address' parameter '${address}'.`); - } -} diff --git a/test/commands/DebuggerCommands.test.ts b/test/commands/DebuggerCommands.test.ts index 2bcec68b..888662d7 100644 --- a/test/commands/DebuggerCommands.test.ts +++ b/test/commands/DebuggerCommands.test.ts @@ -14,12 +14,13 @@ import * as userInteraction from '../../src/helpers/userInteraction'; import {TestConstants} from '../TestConstants'; import * as helpers from '@/helpers/workspace'; +import {shortenHash} from '@/commands/DebuggerCommands'; const truffleWorkspace = new helpers.TruffleWorkspace( path.join(__dirname, TestConstants.truffleCommandTestDataFolder, 'truffle-config.js') ); -describe('DebuggerCommands unit tests', () => { +describe('DebuggerCommands mock tests', () => { let mockGetTxHashes: sinon.SinonStub<[(number | undefined)?], Promise>; let mockGetTxInfos: sinon.SinonStub<[string[]], Promise>; let debugCommands: any; @@ -81,3 +82,29 @@ describe('DebuggerCommands unit tests', () => { assert.strictEqual(createQuickPickFn.called, true, 'createQuickPic should be called'); }); }); + +describe('DebuggerCommands unit tests', () => { + it('should `shortenHash` for a transaction hash', async () => { + { + const label = shortenHash('0xa50fda6a7e20710d5320cbe7f3a2f8ae9ffeee56fb50e5f0e68a2141d554d81e'); + assert.strictEqual(label, '0xa50f...d81e'); + } + + { + const label = shortenHash('0xa50fda6a7e20710d5320cbe7f3a2f8ae9ffeee56fb50e5f0e68a2141d554d81e', 2); + assert.strictEqual(label, '0xa5...1e'); + } + + { + const label = shortenHash('0xa50fda6a7e20710d5320cbe7f3a2f8ae9ffeee56fb50e5f0e68a2141d554d81e', 0); + assert.strictEqual(label, '0x...'); + } + }); + + it('should `shortenHash` for an address hash', async () => { + { + const label = shortenHash('0xc448123202fda0547aa8587b496ea87fa479e7e8'); + assert.strictEqual(label, '0xc448...e7e8'); + } + }); +}); From ea655dabdc5dbc08137e0b6227fefd852b7a5fd7 Mon Sep 17 00:00:00 2001 From: Luis Mastrangelo Date: Sat, 12 Nov 2022 17:33:32 +0100 Subject: [PATCH 10/11] refactor: remove unused `export` --- src/debugAdapter/helpers.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/debugAdapter/helpers.ts b/src/debugAdapter/helpers.ts index 74192ac4..8a0f3c1c 100644 --- a/src/debugAdapter/helpers.ts +++ b/src/debugAdapter/helpers.ts @@ -134,7 +134,7 @@ function createResult( * If the value can't be transformed then the raw version is returned. * @returns the formatted value. */ -export function translate(variable: Format.Values.Result, breaklength = 20): TranslatedResult { +function translate(variable: Format.Values.Result, breaklength = 20): TranslatedResult { switch (variable.kind) { case 'value': if (!_.has(variable, 'type.typeClass')) { From 3dce969a546831e59e4db3ae2166ed74faab0c23 Mon Sep 17 00:00:00 2001 From: Luis Mastrangelo Date: Sat, 12 Nov 2022 18:24:43 +0100 Subject: [PATCH 11/11] refactor: simplify tests --- test/commands/DebuggerCommands.test.ts | 28 +++++++++----------------- 1 file changed, 10 insertions(+), 18 deletions(-) diff --git a/test/commands/DebuggerCommands.test.ts b/test/commands/DebuggerCommands.test.ts index 888662d7..e12d82d8 100644 --- a/test/commands/DebuggerCommands.test.ts +++ b/test/commands/DebuggerCommands.test.ts @@ -85,26 +85,18 @@ describe('DebuggerCommands mock tests', () => { describe('DebuggerCommands unit tests', () => { it('should `shortenHash` for a transaction hash', async () => { - { - const label = shortenHash('0xa50fda6a7e20710d5320cbe7f3a2f8ae9ffeee56fb50e5f0e68a2141d554d81e'); - assert.strictEqual(label, '0xa50f...d81e'); - } - - { - const label = shortenHash('0xa50fda6a7e20710d5320cbe7f3a2f8ae9ffeee56fb50e5f0e68a2141d554d81e', 2); - assert.strictEqual(label, '0xa5...1e'); - } - - { - const label = shortenHash('0xa50fda6a7e20710d5320cbe7f3a2f8ae9ffeee56fb50e5f0e68a2141d554d81e', 0); - assert.strictEqual(label, '0x...'); - } + assert.strictEqual( + shortenHash('0xa50fda6a7e20710d5320cbe7f3a2f8ae9ffeee56fb50e5f0e68a2141d554d81e'), + '0xa50f...d81e' + ); + assert.strictEqual( + shortenHash('0xa50fda6a7e20710d5320cbe7f3a2f8ae9ffeee56fb50e5f0e68a2141d554d81e', 2), + '0xa5...1e' + ); + assert.strictEqual(shortenHash('0xa50fda6a7e20710d5320cbe7f3a2f8ae9ffeee56fb50e5f0e68a2141d554d81e', 0), '0x...'); }); it('should `shortenHash` for an address hash', async () => { - { - const label = shortenHash('0xc448123202fda0547aa8587b496ea87fa479e7e8'); - assert.strictEqual(label, '0xc448...e7e8'); - } + assert.strictEqual(shortenHash('0xc448123202fda0547aa8587b496ea87fa479e7e8'), '0xc448...e7e8'); }); });