Skip to content
This repository was archived by the owner on Mar 11, 2024. It is now read-only.
Merged
27 changes: 19 additions & 8 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -567,7 +567,11 @@
"runtime": "node",
"configurationAttributes": {
"launch": {
"required": [],
"required": [
"txHash",
"workingDirectory",
"providerUrl"
],
"properties": {
"stopOnEntry": {
"type": "boolean",
Expand All @@ -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. When the network is not being forked, this flag is ignored.",
"default": false
}
}
}
Expand All @@ -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": [
Expand All @@ -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
}
}
],
Expand Down
56 changes: 34 additions & 22 deletions src/commands/DebuggerCommands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,12 @@ 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';
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}$/;

Expand Down Expand Up @@ -68,7 +68,7 @@ export namespace DebuggerCommands {
txHash = txHashSelection.detail || txHashSelection.label;
}

await startDebugging(txHash, workingDirectory, providerUrl);
await startDebugging({txHash, workingDirectory, providerUrl, disableFetchExternal: false});
}
}

Expand All @@ -85,30 +85,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,
fetchExternal?: boolean
): Promise<void> {
const workspaceFolder = workspace.getWorkspaceFolder(Uri.parse(workingDirectory));
const config: DebugConfiguration = {
files: [],
export async function startDebugging(args: DebuggerTypes.DebugArgs): Promise<void> {
const workspaceFolder =
args.workingDirectory === undefined ? undefined : workspace.getWorkspaceFolder(Uri.parse(args.workingDirectory));
const config: DebugConfiguration & DebuggerTypes.ILaunchRequestArguments = {
type: DEBUG_TYPE,
name: 'Debug Transactions',
providerUrl,
request: 'launch',
txHash,
type: DEBUG_TYPE,
workingDirectory,

// TODO: are these `timeout` and `files` properties used?
timeout: 30000,
fetchExternal,
files: [],

...args,
};

debug.startDebugging(workspaceFolder, config).then(() => {
Expand All @@ -121,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}'.`);
}
}
5 changes: 0 additions & 5 deletions src/debugAdapter/constants/contractJson.ts

This file was deleted.

6 changes: 0 additions & 6 deletions src/debugAdapter/constants/transaction.ts

This file was deleted.

4 changes: 0 additions & 4 deletions src/debugAdapter/constants/truffleConfig.ts

This file was deleted.

19 changes: 0 additions & 19 deletions src/debugAdapter/constants/variablesView.ts

This file was deleted.

3 changes: 1 addition & 2 deletions src/debugAdapter/contracts/contractJsonsProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,14 @@

import fs from 'fs-extra';
import path from 'path';
import {CONTRACT_JSON_ENCODING} from '../constants/contractJson';
import {IContractJsonModel} from '../models/IContractJsonModel';

export class ContractJsonsProvider {
private contractBuildDirectory: string;
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;
}
Expand Down
6 changes: 5 additions & 1 deletion src/debugAdapter/debugNetwork.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand All @@ -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;
Expand Down
17 changes: 16 additions & 1 deletion src/debugAdapter/debugSession.ts
Original file line number Diff line number Diff line change
Expand Up @@ -101,18 +101,33 @@ export class SolidityDebugSession extends LoggingDebugSession {
args: DebuggerTypes.ILaunchRequestArguments
): Promise<void> {
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(<Required<DebuggerTypes.DebugArgs>>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, name: string) {
if (!arg) {
throw new Error(`\`${name}\` must be specified to initiate the Truffle Debugger`);
}
}
}

protected async disconnectRequest(
Expand Down
16 changes: 0 additions & 16 deletions src/debugAdapter/functions.ts

This file was deleted.

2 changes: 1 addition & 1 deletion src/debugAdapter/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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')) {
Expand Down
39 changes: 34 additions & 5 deletions src/debugAdapter/models/debuggerTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,18 +17,47 @@ 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.
*
* `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;
}

// 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 {
Expand Down
14 changes: 6 additions & 8 deletions src/debugAdapter/runtimeInterface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<void> {
public async attach(args: Required<DebuggerTypes.DebugArgs>): Promise<void> {
// 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;
Expand Down
3 changes: 2 additions & 1 deletion src/debugAdapter/transaction/transactionInputDataDecoder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
Loading