Skip to content

Commit

Permalink
chore: added option for verbosity
Browse files Browse the repository at this point in the history
  • Loading branch information
aruokhai committed Oct 1, 2024
1 parent 7c79208 commit 606d73c
Show file tree
Hide file tree
Showing 12 changed files with 98 additions and 48 deletions.
3 changes: 2 additions & 1 deletion config/config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@ db:
synchronize: false
app:
port: <port>
schedulerInterval: <interval> #interval in seconds
schedulerInterval: <cron interval>
verbose: <boolean>
network: <network>
requestRetry:
delay: <number> # delay in Milliseconds
Expand Down
3 changes: 2 additions & 1 deletion config/dev.config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@ db:
synchronize: true
app:
port: 3000
schedulerInterval: 10
schedulerInterval: '*/10 * * * * *'
verbose: true
network: regtest
requestRetry:
delay: 3000
Expand Down
3 changes: 2 additions & 1 deletion config/e2e.config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@ db:
synchronize: true
app:
port: 3000
schedulerInterval: 10
schedulerInterval: '*/10 * * * * *'
verbose: false
network: regtest
requestRetry:
delay: 500
Expand Down
6 changes: 6 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
"@nestjs/typeorm": "^10.0.2",
"@nestjs/websockets": "^10.3.7",
"axios": "^1.7.2",
"cron-validator": "^1.3.1",
"currency.js": "^2.0.4",
"js-yaml": "^4.1.0",
"reflect-metadata": "^0.1.13",
Expand Down
50 changes: 24 additions & 26 deletions src/block-data-providers/base-block-data-provider.abstract.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { OperationStateService } from '@/operation-state/operation-state.service';
import { Logger } from '@nestjs/common';
import { Logger, OnModuleInit } from '@nestjs/common';
import {
IndexerService,
TransactionInput,
Expand All @@ -17,33 +17,38 @@ export interface BaseOperationState {

export abstract class BaseBlockDataProvider<
OperationState extends BaseOperationState,
> {
> implements OnModuleInit
{
protected abstract readonly logger: Logger;
protected abstract readonly operationStateKey: string;
protected cacheSize = 6;
protected readonly CRON_JOB_NAME = 'providerSync';
protected readonly cronJobName = 'providerSync';

protected constructor(
protected readonly configService: ConfigService,
private readonly indexerService: IndexerService,
private readonly operationStateService: OperationStateService,
private readonly transactionService: TransactionsService,
private readonly schedulerRegistry: SchedulerRegistry,
) {
const schedulerIntervalInSeconds = this.configService.get<string>(
) {}

onModuleInit() {
this.initiateCronJob();
}

abstract sync(): void;

private initiateCronJob() {
const schedulerInterval = this.configService.get<string>(
'app.schedulerInterval',
);

const job = new CronJob(
`*/${schedulerIntervalInSeconds} * * * * *`,
() => this.sync(),
);
this.schedulerRegistry.addCronJob(this.CRON_JOB_NAME, job);
const job = new CronJob(schedulerInterval, () => this.sync());

this.schedulerRegistry.addCronJob(this.cronJobName, job);
job.start();
}

abstract sync(): void;

async indexTransaction(
txid: string,
vin: TransactionInput[],
Expand All @@ -68,24 +73,25 @@ export abstract class BaseBlockDataProvider<
)?.state;
}

async setState(partialState: Partial<OperationState>): Promise<void> {
const oldState = (await this.getState()) || ({} as OperationState);

async setState(
currentState: OperationState,
partialState: Partial<OperationState>,
): Promise<void> {
if (partialState.blockCache) {
const updatedBlockCache = {
...oldState.blockCache,
...currentState.blockCache,
...partialState.blockCache,
};

if (this.cacheSize < Object.keys(updatedBlockCache).length) {
delete updatedBlockCache[oldState.indexedBlockHeight - 5];
delete updatedBlockCache[currentState.indexedBlockHeight - 5];
}

partialState.blockCache = updatedBlockCache;
}

const newState = {
...oldState,
...currentState,
...partialState,
};

Expand Down Expand Up @@ -117,14 +123,6 @@ export abstract class BaseBlockDataProvider<
if (storedBlockHash === fetchedBlockHash) {
return counter;
}
console.log(
'reorg found at count: ',
counter,
' and hash: ',
storedBlockHash,
' ',
fetchedBlockHash,
);

await this.transactionService.deleteTransactionByBlockHash(
storedBlockHash,
Expand Down
10 changes: 10 additions & 0 deletions src/block-data-providers/bitcoin-core/provider.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ import {
rawTransactions,
} from '@/block-data-providers/bitcoin-core/provider-fixtures';
import { Test, TestingModule } from '@nestjs/testing';
import { TransactionsService } from '@/transactions/transactions.service';
import { SchedulerRegistry } from '@nestjs/schedule';

describe('Bitcoin Core Provider', () => {
let provider: BitcoinCoreProvider;
Expand Down Expand Up @@ -46,6 +48,14 @@ describe('Bitcoin Core Provider', () => {
getOperationState: jest.fn(),
},
},
{
provide: TransactionsService,
useClass: jest.fn(),
},
{
provide: SchedulerRegistry,
useClass: jest.fn(),
},
],
}).compile();

Expand Down
15 changes: 7 additions & 8 deletions src/block-data-providers/bitcoin-core/provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import {
SATS_PER_BTC,
TAPROOT_ACTIVATION_HEIGHT,
} from '@/common/constants';
import { Cron, CronExpression, SchedulerRegistry } from '@nestjs/schedule';
import { SchedulerRegistry } from '@nestjs/schedule';
import {
IndexerService,
TransactionInput,
Expand Down Expand Up @@ -66,16 +66,16 @@ export class BitcoinCoreProvider
}

async onApplicationBootstrap() {
const getState = await this.getState();
if (getState) {
const currentState = await this.getState();
if (currentState) {
this.logger.log(
`Restoring state from previous run: ${JSON.stringify(
getState,
currentState,
)}`,
);
} else {
this.logger.log('No previous state found. Starting from scratch.');
const state: BitcoinCoreOperationState = {
const updatedState: BitcoinCoreOperationState = {
currentBlockHeight: 0,
blockCache: {},
indexedBlockHeight:
Expand All @@ -85,15 +85,14 @@ export class BitcoinCoreProvider
: 0,
};

await this.setState(state);
await this.setState(currentState, updatedState);
}
}

async sync() {
if (this.isSyncing) return;
this.isSyncing = true;

console.log("sync running");
const state = await this.getState();
if (!state) {
throw new Error('State not found');
Expand Down Expand Up @@ -133,7 +132,7 @@ export class BitcoinCoreProvider
);
}

await this.setState({
await this.setState(state, {
indexedBlockHeight: height,
blockCache: { [height]: blockHash },
});
Expand Down
14 changes: 7 additions & 7 deletions src/block-data-providers/esplora/provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ import {
EsploraTransaction,
} from '@/block-data-providers/esplora/interface';
import { TAPROOT_ACTIVATION_HEIGHT } from '@/common/constants';
import { Cron, CronExpression, SchedulerRegistry } from '@nestjs/schedule';
import { TransactionsService } from '@/transactions/transactions.service';
import { SchedulerRegistry } from '@nestjs/schedule';

@Injectable()
export class EsploraProvider
Expand Down Expand Up @@ -64,16 +64,16 @@ export class EsploraProvider
}

async onApplicationBootstrap() {
const getState = await this.getState();
if (getState) {
const currentState = await this.getState();
if (currentState) {
this.logger.log(
`Restoring state from previous run: ${JSON.stringify(
getState,
currentState,
)}`,
);
} else {
this.logger.log('No previous state found. Starting from scratch.');
const state: EsploraOperationState = {
const updatedState: EsploraOperationState = {
currentBlockHeight: 0,
blockCache: {},
indexedBlockHeight:
Expand All @@ -83,7 +83,7 @@ export class EsploraProvider
: 0,
lastProcessedTxIndex: 0, // we dont take coinbase txn in account
};
await this.setState(state);
await this.setState(currentState, updatedState);
}
}

Expand Down Expand Up @@ -161,7 +161,7 @@ export class EsploraProvider
}, this),
);

await this.setState({
await this.setState(state, {
indexedBlockHeight: height,
lastProcessedTxIndex: i + this.batchSize - 1,
blockCache: { [height]: hash },
Expand Down
29 changes: 26 additions & 3 deletions src/configuration.model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,35 @@ import {
IsIn,
IsInt,
IsNotEmpty,
IsOptional,
IsString,
IsUrl,
Max,
Min,
Validate,
ValidateIf,
ValidateNested,
ValidatorConstraint,
ValidatorConstraintInterface,
} from 'class-validator';
import { Type } from 'class-transformer';
import { BitcoinNetwork, ProviderType } from '@/common/enum';
import { isValidCron } from 'cron-validator';

@ValidatorConstraint({ name: 'cronSyntax', async: false })
export class CustomCronSyntax implements ValidatorConstraintInterface {
validate(value: string): boolean {
return isValidCron(value, {
seconds: true,
alias: true,
allowBlankDay: true,
});
}

defaultMessage(): string {
return 'Invalid Cron Pattern';
}
}

class DbConfig {
@IsNotEmpty()
Expand All @@ -40,9 +60,8 @@ class AppConfig {
@Max(65535)
port: number;

@IsInt()
@Min(1)
schedulerInterval: number;
@Validate(CustomCronSyntax)
schedulerInterval: string;

@IsEnum(BitcoinNetwork)
network: BitcoinNetwork;
Expand All @@ -51,6 +70,10 @@ class AppConfig {
@ValidateNested()
@Type(() => AxiosRetryConfig)
requestRetry: AxiosRetryConfig;

@IsOptional()
@IsBoolean()
verbose?: boolean;
}

class EsploraConfig {
Expand Down
11 changes: 11 additions & 0 deletions src/main.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { NestFactory } from '@nestjs/core';
import { AppModule } from '@/app.module';
import { ConfigService } from '@nestjs/config';
import { LogLevel } from '@nestjs/common';

declare const module: any;

Expand All @@ -10,6 +11,16 @@ async function bootstrap() {
const configService = app.get<ConfigService>(ConfigService);
const port = configService.get<number>('app.port');

const isVerbose = configService.get<boolean>('app.verbose') ?? false;

const loggerLevels: LogLevel[] = ['error', 'warn', 'log', 'debug'];

if (isVerbose) {
loggerLevels.push('verbose');
}

app.useLogger(loggerLevels);

await app.listen(port);

if (module.hot) {
Expand Down
1 change: 0 additions & 1 deletion src/operation-state/operation-state.entity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,4 @@ export class OperationState {

@Column('simple-json')
state: any;

}

0 comments on commit 606d73c

Please sign in to comment.