Skip to content

Commit

Permalink
feat: Adding debug mode to local node.
Browse files Browse the repository at this point in the history
Signed-off-by: Stefan Stefanov <[email protected]>
  • Loading branch information
stefan-stefanooov committed Dec 18, 2023
1 parent 3f56e1a commit 2ccfdf1
Show file tree
Hide file tree
Showing 9 changed files with 143 additions and 19 deletions.
3 changes: 2 additions & 1 deletion .env
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ PLATFORM_JAVA_OPTS="-XX:+UnlockExperimentalVMOptions -XX:+UseZGC -Xlog:gc*:gc.lo
NETWORK_NODE_LOGS_ROOT_PATH=./network-logs/node
APPLICATION_ROOT_PATH=./compose-network/network-node
APPLICATION_CONFIG_PATH=./compose-network/network-node/data/config
RECORD_PARSER_ROOT_PATH=./src/record-parser
RECORD_PARSER_ROOT_PATH=./src/services/record-parser

#### Network Node Memory Limits ####
NETWORK_NODE_MEM_LIMIT=8gb
Expand Down Expand Up @@ -78,6 +78,7 @@ RELAY_RATE_LIMIT_DISABLED=true

#### Record Stream Uploader ####
STREAM_EXTENSION=rcd.gz
STREAM_SIG_EXTENSION=rcd_sig

#### ENVOY ####
ENVOY_IMAGE_PREFIX=envoyproxy/
Expand Down
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -108,13 +108,17 @@ Available commands:
--balance to set starting hbar balance of the created accounts.
--async to enable or disable asynchronous creation of accounts.
--b or --blocklist to enable or disable account blocklisting. Depending on how many private keys are blocklisted, this will affect the generated on startup accounts.
-g, --enable-debug Enable or disable debugging of the local node [boolean] [default: false]
stop - Stops the local hedera network and delete all the existing data.
restart - Restart the local hedera network.
generate-accounts <n> - Generates N accounts, default 10.
options:
--h or --host to override the default host.
--balance to set starting hbar balance of the created accounts.
--async to enable or disable asynchronous creation of accounts.
debug [timestamp] - Parses and prints the contents of the record file that has been created
during the selected timestamp.
Important: Local node must be started with the -g, --enable-debug flag to enable this feature
```

Note: Generated accounts are 3 types (ECDSA, Alias ECDSA and ED25519). All of them are usable via HederaSDK. Only Alias ECDSA accounts can be imported into wallet like Metamask or used in ethers.
Expand Down
12 changes: 12 additions & 0 deletions src/data/StateData.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import { NetworkPrepState } from '../state/NetworkPrepState';
import { StartState } from '../state/StartState';
import { StopState } from '../state/StopState';
import { StateConfiguration } from '../types/StateConfiguration';
import { DebugState } from '../state/DebugState';

export class StateData {

Expand All @@ -39,6 +40,8 @@ export class StateData {
return this.getStopConfiguration();
case 'accountCreation':
return this.getAccountCreationConfiguration();
case 'debug':
return this.getDebugConfiguration();
default:
return undefined;
}
Expand Down Expand Up @@ -92,4 +95,13 @@ export class StateData {
]
}
}

private getDebugConfiguration(): StateConfiguration {
return {
'stateMachineName' : 'debug',
'states' : [
new DebugState()
]
}
}
}
45 changes: 30 additions & 15 deletions src/services/CLIService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ export class CLIService implements IService{
this.userComposeOption(yargs);
this.userComposeDirOption(yargs);
this.blocklistingOption(yargs);
this.enableDebugOption(yargs);
this.isStartup = true;
}

Expand All @@ -72,20 +73,22 @@ export class CLIService implements IService{

public getCurrentArgv(){
const argv = this.currentArgv as ArgumentsCamelCase<{}>;
const accounts: number = argv.accounts as number;
const async: any = argv.async as boolean;
const balance: number = argv.balance as number;
const detached: boolean = this.isStartup ? argv.detached as boolean : true;
const host: string = argv.host as string;
const network: NetworkType = this.resolveNetwork(argv.network as string);
const limits: boolean = argv.limits as boolean;
const devMode: boolean = argv.dev as boolean;
const fullMode: boolean = argv.full as boolean;
const multiNode: boolean = argv.multinode as boolean;
const userCompose: boolean = argv.usercompose as boolean;
const userComposeDir: string = argv.composedir as string;
const blocklisting: boolean = argv.blocklist as boolean;
const startup: boolean = this.isStartup;
const accounts = argv.accounts as number;
const async = argv.async as boolean;
const balance = argv.balance as number;
const detached = this.isStartup ? argv.detached as boolean : true;
const host = argv.host as string;
const network = this.resolveNetwork(argv.network as string);
const limits = argv.limits as boolean;
const devMode = argv.dev as boolean;
const fullMode = argv.full as boolean;
const multiNode = argv.multinode as boolean;
const userCompose = argv.usercompose as boolean;
const userComposeDir = argv.composedir as string;
const blocklisting = argv.blocklist as boolean;
const timestamp = argv.timestamp as string;
const enableDebug = argv.enableDebug as boolean;
const startup = this.isStartup;

const currentArgv: CLIOptions = {
accounts,
Expand All @@ -101,7 +104,9 @@ export class CLIService implements IService{
userCompose,
userComposeDir,
blocklisting,
startup
startup,
timestamp,
enableDebug
};

return currentArgv;
Expand Down Expand Up @@ -240,6 +245,16 @@ export class CLIService implements IService{
default: false
});
}

private enableDebugOption(yargs: Argv<{}>): void {
yargs.option('enable-debug', {
alias: 'g',
type: 'boolean',
describe: 'Enable or disable debugging of the local node',
demandOption: false,
default: false
});
}

private resolveNetwork(network: string): NetworkType {
switch (network) {
Expand Down
2 changes: 1 addition & 1 deletion src/services/record-parser/src/Parser.java
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import static com.hedera.services.utils.forensics.RecordParsers.parseV6RecordStreamEntriesIn;
import static com.hedera.node.app.service.mono.utils.forensics.RecordParsers.parseV6RecordStreamEntriesIn;
public class Parser {
public static void main(String[] args) {
try {
Expand Down
87 changes: 86 additions & 1 deletion src/state/DebugState.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,20 @@
*
*/

import { resolve } from 'path';
import { readdirSync, copyFileSync, unlinkSync } from 'fs';
import shell from 'shelljs';
import { IOBserver } from '../controller/IObserver';
import { LoggerService } from '../services/LoggerService';
import { ServiceLocator } from '../services/ServiceLocator';
import { IState } from './IState';
import { CLIService } from '../services/CLIService';

const RELATIVE_TMP_DIR_PATH = '../../src/services/record-parser/temp';
const RELATIVE_RECORDS_DIR_PATH = '../../network-logs/node/recordStreams/record0.0.3';
const NO_RECORD_FILE_FOUND_ERROR = 'No record file found for the given timestamp.';
const INVALID_TIMESTAMP_ERROR = 'Invalid timestamp string. Accepted formats are: 0000000000.000000000 and 0000000000-000000000'
const DEBUG_MODE_ERROR = 'Debug mode is not enabled to use this command. Please use the --enable-debug flag to enable it.';

export class DebugState implements IState{
private logger: LoggerService;
Expand All @@ -41,6 +51,81 @@ export class DebugState implements IState{
}

public async onStart(): Promise<void> {
throw new Error('Method not implemented.');
try {
const { timestamp, devMode } = ServiceLocator.Current.get<CLIService>(CLIService.name).getCurrentArgv();
DebugState.checkForDebugMode(devMode);
this.logger.trace('Debug State Starting...', this.stateName);
const jsTimestampNum = DebugState.getAndValidateTimestamp(timestamp)

const tempDir = resolve(__dirname, RELATIVE_TMP_DIR_PATH);
const recordFilesDirPath = resolve(__dirname, RELATIVE_RECORDS_DIR_PATH);
this.findAndCopyRecordFileToTmpDir(jsTimestampNum, recordFilesDirPath, tempDir)
// Perform the parsing
await shell.exec(
'docker exec network-node bash /opt/hgcapp/recordParser/parse.sh'
);

DebugState.cleanTempDir(tempDir);
} catch (error: any) {
this.logger.error(error.message);
return
}
}

private static cleanTempDir(dirPath: string): void {
for (const tempFile of readdirSync(dirPath)) {
if (tempFile !== '.gitignore') {
unlinkSync(resolve(dirPath, tempFile));
}
}
}

private static checkForDebugMode(debugMode: boolean): void {
if (!debugMode) {
throw new Error(DEBUG_MODE_ERROR);
}
}

private static getAndValidateTimestamp(timestamp: string): number {
const timestampRegEx = /^\d{10}[.-]\d{9}$/;
if (!timestampRegEx.test(timestamp)) {
throw new Error(INVALID_TIMESTAMP_ERROR);
}

// Parse the timestamp to a record file filename
let jsTimestamp = timestamp
.replace('.', '')
.replace('-', '')
.substring(0, 13);
return parseInt(jsTimestamp);
}

private findAndCopyRecordFileToTmpDir(jsTimestampNum: number, recordFilesDirPath: string, tmpDirPath: string): void {
// Copy the record file to a temp directory
const files = readdirSync(recordFilesDirPath);
const recordExt = `.${process.env.STREAM_EXTENSION}`;
for (const file of files) {
const recordFileName = file.replace(recordExt, '');
const fileTimestamp = new Date(recordFileName.replace(/_/g, ':')).getTime();
if (fileTimestamp >= jsTimestampNum) {
if (file.endsWith(recordExt)) {
this.logger.trace(`Parsing record file [${file}]\n`);
}

const sigFile = recordFileName + `.${process.env.STREAM_SIG_EXTENSION}`;
copyFileSync(
resolve(recordFilesDirPath, file),
resolve(tmpDirPath, file)
);
copyFileSync(
resolve(recordFilesDirPath, sigFile),
resolve(tmpDirPath, sigFile)
);

return
}
}

throw new Error(NO_RECORD_FILE_FOUND_ERROR);
}
}
5 changes: 5 additions & 0 deletions src/state/InitState.ts
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,7 @@ export class InitState implements IState{
private configureMirrorNodeProperties() {
this.logger.trace('Configuring required mirror node properties, depending on selected configuration...', this.stateName);
const turboMode = !this.cliOptions.fullMode;
const debugMode = this.cliOptions.enableDebug;

// const multiNode = this.cliOptions.multiNode;

Expand All @@ -144,6 +145,10 @@ export class InitState implements IState{
application.hedera.mirror.importer.downloader.sources = originalNodeConfiguration.turboNodeProperties.sources;
}

if(debugMode) {
application.hedera.mirror.importer.downloader.local.deleteAfterProcessing = false
}

// if (multiNode) {
// application['hedera']['mirror']['monitor']['nodes'] = originalNodeConfiguration.multiNodeProperties
// }
Expand Down
2 changes: 1 addition & 1 deletion src/state/StartState.ts
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ export class StartState implements IState{
}

return shell.exec(
`docker compose -f ${composeFiles.join(' -f ')} up -d 2>${this.dockerService.getNullOutput()}`
`docker compose -f ${composeFiles.join(' -f ')} up -d 2>${this.dockerService.getNullOutput()}`
);
}

Expand Down
2 changes: 2 additions & 0 deletions src/types/CLIOptions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,4 +35,6 @@ export interface CLIOptions {
userComposeDir: string,
blocklisting: boolean,
startup: boolean,
timestamp: string,
enableDebug: boolean
}

0 comments on commit 2ccfdf1

Please sign in to comment.