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
5 changes: 5 additions & 0 deletions .changeset/broad-cats-fetch.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@rosen-bridge/watcher': minor
---

Port Firo watcher from firod JSON-RPC to ElectrumX TCP connector
6 changes: 5 additions & 1 deletion config/default.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ binance:
timeout: 10 # rpc request timeout (in seconds)
# authToken: # rpc auth token
firo:
type: '' # options: rpc
type: '' # options: rpc, electrumx
initial:
height: -1 # initial height of scanning
interval: 180 # scanning interval (in seconds)
Expand All @@ -87,6 +87,10 @@ firo:
timeout: 10 # rpc request timeout (in seconds)
# username: '' # rpc username for authentication required instances
# password: '' # rpc password for authentication required instances
electrumx:
host: '' # electrumx host
port: 50002 # electrumx SSL port
timeout: 10 # electrumx request timeout (in seconds)
handshake:
type: 'rpc' # options: rpc
initial:
Expand Down
7 changes: 7 additions & 0 deletions docker/custom-environment-variables.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,16 @@ binance:
rpc:
authToken: 'BINANCE_RPC_AUTH_TOKEN'
firo:
type: 'FIRO_TYPE'
rpc:
url: 'FIRO_RPC_URL'
timeout: 'FIRO_RPC_TIMEOUT'
username: 'FIRO_RPC_USERNAME'
password: 'FIRO_RPC_PASSWORD'
electrumx:
host: 'FIRO_ELECTRUMX_HOST'
port: 'FIRO_ELECTRUMX_PORT'
timeout: 'FIRO_ELECTRUMX_TIMEOUT'
handshake:
rpc:
username: 'HANDSHAKE_RPC_USERNAME'
Expand Down
12 changes: 11 additions & 1 deletion src/config/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -621,6 +621,11 @@ class FiroConfig {
username?: string;
password?: string;
};
electrumx?: {
host: string;
port: number;
timeout: number;
};

constructor(network: string) {
this.type = config.get<string>('firo.type');
Expand All @@ -633,9 +638,14 @@ class FiroConfig {
const username = getOptionalString('firo.rpc.username', undefined);
const password = getOptionalString('firo.rpc.password', undefined);
this.rpc = { url, timeout, username, password };
} else if (this.type === Constants.ELECTRUMX_TYPE) {
const host = getRequiredString('firo.electrumx.host');
const port = getRequiredNumber('firo.electrumx.port');
const timeout = getRequiredNumber('firo.electrumx.timeout');
this.electrumx = { host, port, timeout };
} else {
throw new Error(
`Improperly configured. firo configuration type is invalid available choices are '${Constants.RPC_TYPE}'`
`Improperly configured. firo configuration type is invalid available choices are '${Constants.RPC_TYPE}', '${Constants.ELECTRUMX_TYPE}'`
);
}
}
Expand Down
1 change: 1 addition & 0 deletions src/config/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ export const TRIGGER_EXTRACTOR_NAME = 'watcher-trigger-extractor';
export const COLLATERAL_EXTRACTOR_NAME = 'watcher-collateral-extractor';
export const ESPLORA_TYPE = 'esplora';
export const RPC_TYPE = 'rpc';
export const ELECTRUMX_TYPE = 'electrumx';
export const EVM_RPC_TYPE = 'rpc';
export const OGMIOS_TYPE = 'ogmios';
export const KOIOS_TYPE = 'koios';
Expand Down
28 changes: 22 additions & 6 deletions src/utils/healthCheck.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import {
} from '@rosen-bridge/permit-check';
import {
CardanoOgmiosScannerHealthCheck,
FiroElectrumXScannerHealthCheck,
ScannerSyncHealthCheckParam,
} from '@rosen-bridge/scanner-sync-check';
import {
Expand All @@ -37,6 +38,7 @@ import {
ERGO_CHAIN_NAME,
ERGO_DECIMALS,
ERGO_NATIVE_ASSET,
ELECTRUMX_TYPE,
ETHEREUM_BLOCK_TIME,
ETHEREUM_CHAIN_NAME,
EXPLORER_TYPE,
Expand Down Expand Up @@ -201,7 +203,8 @@ class HealthCheckSingleton {
const currentConfig = getConfig();
let scannerSyncCheck:
| ScannerSyncHealthCheckParam
| CardanoOgmiosScannerHealthCheck;
| CardanoOgmiosScannerHealthCheck
| FiroElectrumXScannerHealthCheck;
if (
currentConfig.general.networkWatcher === CARDANO_CHAIN_NAME &&
currentConfig.cardano.type === OGMIOS_TYPE
Expand All @@ -216,6 +219,19 @@ class HealthCheckSingleton {
// TODO: Fix configuration: local/health-check/-/issues/29
currentConfig.cardano.ogmios!.connectionRetrialInterval * 15
);
} else if (
currentConfig.general.networkWatcher === FIRO_CHAIN_NAME &&
currentConfig.firo.type === ELECTRUMX_TYPE
) {
scannerSyncCheck = new FiroElectrumXScannerHealthCheck(
this.observingNetworkLastBlock(scanner.getObservationScanner().name()),
currentConfig.healthCheck.scannerWarnDiff,
currentConfig.healthCheck.scannerCriticalDiff,
currentConfig.firo.electrumx!.host,
currentConfig.firo.electrumx!.port,
FIRO_BLOCK_TIME,
currentConfig.firo.interval
);
} else {
let chainName: string;
let chainBlockTime: number;
Expand All @@ -242,6 +258,11 @@ class HealthCheckSingleton {
chainBlockTime = DOGE_BLOCK_TIME;
updateInterval = currentConfig.doge.interval;
break;
case FIRO_CHAIN_NAME:
chainName = FIRO_CHAIN_NAME;
chainBlockTime = FIRO_BLOCK_TIME;
updateInterval = currentConfig.firo.interval;
break;
case ETHEREUM_CHAIN_NAME:
chainName = ETHEREUM_CHAIN_NAME;
chainBlockTime = ETHEREUM_BLOCK_TIME;
Expand All @@ -252,11 +273,6 @@ class HealthCheckSingleton {
chainBlockTime = BINANCE_BLOCK_TIME;
updateInterval = currentConfig.binance.interval;
break;
case FIRO_CHAIN_NAME:
chainName = FIRO_CHAIN_NAME;
chainBlockTime = FIRO_BLOCK_TIME;
updateInterval = currentConfig.firo.interval;
break;
case HANDSHAKE_CHAIN_NAME:
chainName = HANDSHAKE_CHAIN_NAME;
chainBlockTime = HANDSHAKE_BLOCK_TIME;
Expand Down
33 changes: 32 additions & 1 deletion src/utils/networkConnectorManagers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,11 @@ import {
ErgoNodeNetwork,
} from '@rosen-bridge/ergo-scanner';
import { EvmRpcNetwork } from '@rosen-bridge/evm-scanner';
import { FiroRpcNetwork, FiroRpcTransaction } from '@rosen-bridge/firo-scanner';
import {
FiroElectrumXNetwork,
FiroRpcNetwork,
FiroRpcTransaction,
} from '@rosen-bridge/firo-scanner';
import {
HandshakeRpcNetwork,
HandshakeRpcTransaction,
Expand Down Expand Up @@ -310,6 +314,33 @@ export const createFiroRpcNetworkConnectorManager = () => {
return networkConnectorManager;
};

/**
* Creates and configures a NetworkConnectorManager instance for Firo ElectrumX scanner
*/
export const createFiroElectrumXNetworkConnectorManager = () => {
const networkConnectorManager =
new NetworkConnectorManager<FiroRpcTransaction>(
new FailoverStrategy(),
firoLogger
);

if (config.firo.electrumx) {
networkConnectorManager.addConnector(
new FiroElectrumXNetwork(
config.firo.electrumx.host,
config.firo.electrumx.port,
config.firo.electrumx.timeout * 1000
)
);
} else {
throw new Error(
'ElectrumX configuration must be provided for Firo ElectrumX network'
);
}

return networkConnectorManager;
};

/**
* Creates and configures a NetworkConnectorManager instance for Handshake RPC scanner
*/
Expand Down
29 changes: 27 additions & 2 deletions src/utils/scanner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,14 @@ import {
EthereumRpcObservationExtractor,
} from '@rosen-bridge/evm-observation-extractor';
import { EvmRpcScanner } from '@rosen-bridge/evm-scanner';
import { FiroRpcObservationExtractor } from '@rosen-bridge/firo-observation-extractor';
import { FiroRpcScanner } from '@rosen-bridge/firo-scanner';
import {
FiroObservationExtractor,
FiroRpcObservationExtractor,
} from '@rosen-bridge/firo-observation-extractor';
import {
FiroElectrumXScanner,
FiroRpcScanner,
} from '@rosen-bridge/firo-scanner';
import { dataSource } from '../../config/dataSource';
import {
BinanceConfig,
Expand All @@ -74,6 +80,7 @@ import {
createErgoExplorerNetworkConnectorManager,
createErgoNodeNetworkConnectorManager,
createEvmNetworkConnectorManager,
createFiroElectrumXNetworkConnectorManager,
createFiroRpcNetworkConnectorManager,
createHandshakeRpcNetworkConnectorManager,
} from './networkConnectorManagers';
Expand Down Expand Up @@ -111,6 +118,7 @@ class CreateScanner {
| DogeRpcScanner
| EvmRpcScanner
| FiroRpcScanner
| FiroElectrumXScanner
| HandshakeRpcScanner;

private constructor() {
Expand Down Expand Up @@ -239,6 +247,7 @@ class CreateScanner {
| DogeRpcScanner
| EvmRpcScanner
| FiroRpcScanner
| FiroElectrumXScanner
| HandshakeRpcScanner => {
if (!CreateScanner.instance) {
throw new Error('Scanner is not initialized');
Expand Down Expand Up @@ -623,6 +632,22 @@ class CreateScanner {
observationStoreRawData
);
this.observationScanner.registerExtractor(observationExtractor);
} else if (firoConfig.electrumx) {
this.observationScanner = new FiroElectrumXScanner({
dataSource,
initialHeight: firoConfig.initialHeight,
network: createFiroElectrumXNetworkConnectorManager(),
logger: loggers.observationScannerLogger,
});

const observationExtractor = new FiroObservationExtractor(
rosenConfig.lockAddress,
dataSource,
TokensConfig.getInstance().getTokenMap(),
loggers.observationExtractorLogger,
observationStoreRawData
);
this.observationScanner.registerExtractor(observationExtractor);
}
}
};
Expand Down