Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .env.test
Original file line number Diff line number Diff line change
Expand Up @@ -43,3 +43,6 @@ MAX_FEE_AMOUNT_ALLOWED=5000000

#Dust value (Satoshi)
BURN_DUST_VALUE=2000

SENTRY_DSN=<YOUR_SENTRY_DSN>
SENTRY_ENV=<staging-testnet | staging-mainnet | mainnet | testnet>
870 changes: 860 additions & 10 deletions package-lock.json

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@
"@rsksmart/bridge-state-data-parser": "^2.0.0",
"@rsksmart/bridge-transaction-parser": "^2.0.0",
"@rsksmart/rsk-precompiled-abis": "^8.0.0-REED",
"@sentry/node": "^10.38.0",
"big.js": "^6.1.1",
"bitcoinjs-lib": "^6.0.1",
"bs58": "^5.0.0",
Expand Down
6 changes: 5 additions & 1 deletion src/controllers/addresses-info.controller.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import {getModelSchemaRef, post, requestBody, response} from '@loopback/rest';
import {inject} from '@loopback/core';
import * as Sentry from "@sentry/node";
import {AddressList} from '../models';
import {AddressInfoResponse} from '../models/adddress-info-response.model';
import {ServicesBindings} from '../dependency-injection-bindings';
Expand Down Expand Up @@ -52,7 +53,10 @@ export class AddressesInfoController {
addressesInfo,
}));
})
.catch(reject);
.catch((error) => {
Sentry.captureException(error);
return reject(error);
});
});
}
}
2 changes: 1 addition & 1 deletion src/controllers/api-information.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ export class ApiInformationController {
},
})
getApiInformation():ApiInformation {
const version = packageJson.version;
const {version} = packageJson;
this.logger.debug(`[getApiInformation] current version : ${version}`);
const apiInfo = new ApiInformation();
apiInfo.version = version;
Expand Down
2 changes: 2 additions & 0 deletions src/controllers/broadcast.controller.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import {inject} from '@loopback/core';
import {getModelSchemaRef, post} from '@loopback/rest';
import {getLogger, Logger} from 'log4js';
import * as Sentry from "@sentry/node";
import {BroadcastRequest, BroadcastResponse} from '../models';
import {Broadcast} from '../services';

Expand Down Expand Up @@ -60,6 +61,7 @@ export class BroadcastController {
})
.catch((reason) => {
this.logger.warn(`[sendTx] Something went wrong. error: ${reason}`);
Sentry.captureException(reason);
return reject(reason);
});
});
Expand Down
39 changes: 22 additions & 17 deletions src/controllers/health-check.controller.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { RestBindings, get, getModelSchemaRef, Response } from '@loopback/rest';
import { getLogger, Logger } from 'log4js';
import { inject } from '@loopback/core';
import * as Sentry from "@sentry/node";
import { BitcoinService, BridgeService } from '../services';
import { ServicesBindings } from "../dependency-injection-bindings";
import { HealthInformation } from '../models/health-information.model';
Expand Down Expand Up @@ -50,16 +51,16 @@
},
})
async health(): Promise<Response> {
const version = packageJson.version;
const {version} = packageJson;
this.logger.debug(`[healthCheckController] current version : ${version}`);
const health = new HealthInformation();
health.up = true;
health.apiVersion = version;

let dataBase: HealthInformationChecks = await this.getDataBaseInfo(health);
let blockBook: BlockBoock = await this.getBlockBookInfo(health);
let rskNode: HealthInformationChecks = await this.getRskNodeInfo(health);
let bridgeService: HealthInformationChecks = await this.getBridgeInfo(health);
const dataBase: HealthInformationChecks = await this.getDataBaseInfo(health);
const blockBook: BlockBoock = await this.getBlockBookInfo(health);
const rskNode: HealthInformationChecks = await this.getRskNodeInfo(health);
const bridgeService: HealthInformationChecks = await this.getBridgeInfo(health);

health.dataBase = dataBase;
health.blockBook = blockBook;
Expand All @@ -74,25 +75,26 @@
}

private async getBridgeInfo(health: HealthInformation): Promise<HealthInformationChecks> {
let bridgeService = new Federation();
const bridgeService = new Federation();
return this.bridgeService.getFederationAddress().then((address: any) => {

Check warning on line 79 in src/controllers/health-check.controller.ts

View workflow job for this annotation

GitHub Actions / checkout-and-build

Unexpected any. Specify a different type

Check warning on line 79 in src/controllers/health-check.controller.ts

View workflow job for this annotation

GitHub Actions / checkout-and-build

Unexpected any. Specify a different type
if(address) {
bridgeService.up = true;
bridgeService.federationAddress = address;
return bridgeService;
} else {
}
throw new Error("Error searching Bridge State");
}

}).catch((e) => {
this.logger.error(`[healthCheckController-BridgeError] error : ${e}`);
Sentry.captureException(e);
bridgeService.up = false;
health.up = false;

Check warning on line 91 in src/controllers/health-check.controller.ts

View workflow job for this annotation

GitHub Actions / checkout-and-build

Assignment to property of function parameter 'health'

Check warning on line 91 in src/controllers/health-check.controller.ts

View workflow job for this annotation

GitHub Actions / checkout-and-build

Assignment to property of function parameter 'health'
return bridgeService;
});
}

private async getBlockBookInfo(health: HealthInformation): Promise<BlockBoock> {
let blockBook = new BlockBoock();
const blockBook = new BlockBoock();
return this.bitcoinService.getLastBlock().then((info: LastBlockInfo) => {
if (info) {
blockBook.up = true;
Expand All @@ -102,48 +104,51 @@
blockBook.syncing = info.inSync;
blockBook.chain = info.chain;
return blockBook;
} else {
}
throw new Error("Error searching BTC Block Number");
}

}).catch((e) => {
this.logger.error(`[healthCheckController-BlockBook] error : ${e}`);
Sentry.captureException(e);
blockBook.up = false;
health.up = false;

Check warning on line 114 in src/controllers/health-check.controller.ts

View workflow job for this annotation

GitHub Actions / checkout-and-build

Assignment to property of function parameter 'health'

Check warning on line 114 in src/controllers/health-check.controller.ts

View workflow job for this annotation

GitHub Actions / checkout-and-build

Assignment to property of function parameter 'health'
return blockBook;
});
}

private async getRskNodeInfo(health: HealthInformation): Promise<HealthInformationChecks> {
let rskNode = this.createNewType();
const rskNode = this.createNewType();
return this.rskNodeService.getBlockNumber().then((blockNumber:number) => {
if(blockNumber) {
rskNode.up = true;
rskNode.lastRskBlockNumber = blockNumber;
return rskNode;
} else {
}
throw new Error("Error searching block number");
}

}).catch((e) => {
this.logger.error(`[healthCheckController-RskNodeInfoError] error : ${e}`);
Sentry.captureException(e);
rskNode.up = false;
health.up = false;

Check warning on line 133 in src/controllers/health-check.controller.ts

View workflow job for this annotation

GitHub Actions / checkout-and-build

Assignment to property of function parameter 'health'

Check warning on line 133 in src/controllers/health-check.controller.ts

View workflow job for this annotation

GitHub Actions / checkout-and-build

Assignment to property of function parameter 'health'
return rskNode;
});
}

private async getDataBaseInfo(health: HealthInformation): Promise<HealthInformationChecks> {
let dataBase = this.createNewType();
const dataBase = this.createNewType();
return this.syncStorageService.getBestBlock().then((syncStatusModel: SyncStatusModel | undefined) => {
if(syncStatusModel) {
dataBase.lastRskBlockNumber = syncStatusModel.rskBlockHeight;
dataBase.lastRskBlockHash = syncStatusModel.rskBlockHash;
dataBase.up = true;
return dataBase;
} else {
}
throw new Error("[healthCheckController-DataBaseError] - Block info not found");
}

}).catch((e) => {
this.logger.error(`[healthCheckController-DataBaseError] error : ${e}`);
Sentry.captureException(e);
health.up = false;
dataBase.up = false;
return dataBase;
Expand Down
2 changes: 2 additions & 0 deletions src/controllers/pegin-configuration.controller.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import {repository} from '@loopback/repository';
import {get, getModelSchemaRef} from '@loopback/rest';
import {getLogger, Logger} from 'log4js';
import * as Sentry from "@sentry/node";
import {PeginConfiguration} from '../models';
import {PeginConfigurationRepository} from '../repositories';
import {BridgeService} from '../services';
Expand Down Expand Up @@ -53,6 +54,7 @@ export class PeginConfigurationController {
})
.catch((e) => {
this.logger.warn(`[get] Got an error: ${e}`);
Sentry.captureException(e);
reject(e);
});
});
Expand Down
2 changes: 2 additions & 0 deletions src/controllers/tx.controller.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import {inject} from '@loopback/core';
import {get, getModelSchemaRef} from '@loopback/rest';
import {getLogger, Logger} from 'log4js';
import * as Sentry from "@sentry/node";
import {Tx} from '../models';
import {TxService} from '../services';

Expand Down Expand Up @@ -47,6 +48,7 @@ export class TxController {
})
.catch((reason) => {
this.logger.warn(`[getTx] Got an error: ${reason}`);
Sentry.captureException(reason);
return reject(reason);
});
});
Expand Down
2 changes: 2 additions & 0 deletions src/controllers/utxo.controller.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import {inject} from '@loopback/core';
import {getModelSchemaRef, post, requestBody, response} from '@loopback/rest';
import {getLogger, Logger} from 'log4js';
import * as Sentry from "@sentry/node";
import {ServicesBindings} from '../dependency-injection-bindings';
import {AddressList, Utxo} from '../models';
import {UtxoResponse} from '../models/utxo-response.model';
Expand Down Expand Up @@ -59,6 +60,7 @@ export class UtxoController {
})
.catch(reason => {
this.logger.warn(`[getUtxos] Got an error: ${reason}`);
Sentry.captureException(reason);
reject(reason);
});
});
Expand Down
1 change: 1 addition & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import {configure, getLogger} from 'log4js';
import {ApplicationConfig, TwpapiApplication} from './application';
import {DaemonRunner} from './daemon-runner';
import { ENVIRONMENT_PRODUCTION } from './constants';
import './instrument';

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

move this import to after config() runs


export * from './application';

Expand Down
12 changes: 12 additions & 0 deletions src/instrument.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
const Sentry = require("@sentry/node");

const dsn = process.env.SENTRY_DSN;
if (!dsn) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

will crash on missing DSN

throw new Error('SENTRY_DSN is not set');
}

Sentry.init({
dsn,
environment: process.env.SENTRY_ENV || 'staging-testnet',
sendDefaultPii: true,
});
6 changes: 4 additions & 2 deletions src/services/bridge.service.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import * as precompiledAbis from '@rsksmart/rsk-precompiled-abis';
import {getLogger, Logger} from 'log4js';
import * as Sentry from "@sentry/node";
import {ethers} from 'ethers';
import BridgeTransactionParser, {Transaction} from '@rsksmart/bridge-transaction-parser';
import { getBridgeState, BridgeState } from '@rsksmart/bridge-state-data-parser';
Expand Down Expand Up @@ -33,6 +34,7 @@ export class BridgeService {
})
.catch((reason: any) => {
this.logger.warn(`[getFederationAddress] Got an error: ${reason}`);
Sentry.captureException(reason);
reject(reason);
});
});
Expand Down Expand Up @@ -108,11 +110,11 @@ export class BridgeService {
}

public async getBridgeTransactionByHash(txHash: string): Promise<Transaction> {
return await this.bridgeTransactionParser.getBridgeTransactionByTxHash(txHash);
return this.bridgeTransactionParser.getBridgeTransactionByTxHash(txHash);
}

public async getBridgeState(defaultBlock: string | number = 'latest'): Promise<BridgeState> {
return await getBridgeState(this.host, defaultBlock);
return getBridgeState(this.host, defaultBlock);
}

}
4 changes: 4 additions & 0 deletions src/services/pegin-status/bitcoin.service.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import {inject} from '@loopback/core';
import {getLogger, Logger} from 'log4js';
import * as Sentry from "@sentry/node";
import {AddressService, TxV2Service} from '..';
import {ServicesBindings} from '../../dependency-injection-bindings';
import {BitcoinAddress} from '../../models/bitcoin-address.model';
Expand Down Expand Up @@ -48,6 +49,7 @@ export class BitcoinService {
})
.catch(reason => {
this.logger.warn(`[getTx] Got an error: ${reason}`);
Sentry.captureException(reason);
reject(`Error getting tx ${txId}`);
});
});
Expand All @@ -74,6 +76,7 @@ export class BitcoinService {
resolve(responseAddress);
})
.catch(() => {
Sentry.captureException(`Error getting address ${address}`);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sentry here should capture reason too, like on line 52

reject(`Error getting address ${address}`);
});
});
Expand All @@ -95,6 +98,7 @@ export class BitcoinService {
resolve(lastBlockInfo);
})
.catch((e) => {
Sentry.captureException(`Error getting last block ${e}`);
reject(`Error getting last block ${e}`);
});
});
Expand Down
18 changes: 10 additions & 8 deletions src/services/pegin-status/pegin-status.service.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import {inject} from '@loopback/core';
import {getLogger, Logger} from 'log4js';
import * as Sentry from "@sentry/node";
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
import peginAddressVerifier from 'pegin-address-verificator';
Expand Down Expand Up @@ -56,26 +57,27 @@ export class PeginStatusService {
peginStatusInfo.setRskPeginStatus(rskStatus);
this.logger.debug(`Tx: ${btcTxId} includes rsk info. RskAddress: ${rskStatus.recipientAddress} Pegin status: ${peginStatusInfo.status}`);
return peginStatusInfo;
} else {
}
const peginRskInfo = new RskPeginStatus();
peginRskInfo.recipientAddress = this.destinationAddress;
peginStatusInfo.status = Status.NOT_IN_RSK_YET;
this.logger.debug(`Tx: ${btcTxId} not in RSK yet. Pegin status: ${peginStatusInfo.status}`);
peginStatusInfo.setRskPeginStatus(peginRskInfo);
return peginStatusInfo;
}

});
} else {
}
const peginRskInfo = new RskPeginStatus();
peginRskInfo.recipientAddress = this.destinationAddress;
peginStatusInfo.status = Status.WAITING_CONFIRMATIONS;
this.logger.debug(`Tx: ${btcTxId} waiting confirmations. Pegin status: ${peginStatusInfo.status}`);
peginStatusInfo.setRskPeginStatus(peginRskInfo);
return peginStatusInfo;
}

})
.catch((e) => {
this.logger.warn(`TxId:${btcTxId} Unexpected error trying to obtain information. Error: ${e}`);
Sentry.captureException(e);
return new PeginStatusError(btcTxId);
})
};
Expand Down Expand Up @@ -109,7 +111,7 @@ export class PeginStatusService {
if (!this.canBeAPeginSender(btcTx)) {
throw new Error(`Is not a pegin. Tx was not processed in Bitcoin network.`);
}
const vout = btcTx.vout;
const {vout} = btcTx;
const fedDestinationAddress = await this.getTxDestinationFedAddress(vout);
if (!fedDestinationAddress) {
throw new Error('Is not a pegin. Tx was not sent to valid Federation address.');
Expand Down Expand Up @@ -244,11 +246,11 @@ export class PeginStatusService {
if (data.length === 96 || data.length === 54) { //Contain refund address
this.logger.debug(`Tx contains OPT_RETURN value: ${txId}`);
return (true);
} else {
}
const errorMessage = `Can not parse OP_RETURN parameter. Invalid transaction: ${txId}`;
this.logger.warn(errorMessage);
return false; //RSK will return invalid
}

}
return (false);
}
Expand All @@ -257,7 +259,7 @@ export class PeginStatusService {
try {
if (peginAddressVerifier.canPegIn(peginAddressVerifier.getAddressInformation(btcTx.vin[0].addresses[0]))) {
return true;
} else if (this.getxDestinationRskAddress(btcTx).length > 0) {
} if (this.getxDestinationRskAddress(btcTx).length > 0) {
return true;
}
} catch {
Expand Down
Loading
Loading