import {Injectable} from '@angular/core'; import {Settings} from '@app/_models'; import Web3 from 'web3'; import {CICRegistry, TransactionHelper} from 'cic-client'; import {first} from 'rxjs/operators'; import {TransactionService} from '@app/_services/transaction.service'; import {environment} from '@src/environments/environment'; import {HttpGetter} from '@app/_helpers'; import {LoggingService} from '@app/_services/logging.service'; @Injectable({ providedIn: 'root' }) export class BlockSyncService { readyStateTarget: number = 2; readyState: number = 0; fileGetter = new HttpGetter(); constructor( private transactionService: TransactionService, private loggingService: LoggingService ) { } blockSync(address: string = null, offset: number = 0, limit: number = 100): any { this.transactionService.resetTransactionsList(); const settings = new Settings(this.scan); const provider = environment.web3Provider; const readyStateElements = { network: 2 }; settings.w3.provider = provider; settings.w3.engine = new Web3(provider); settings.registry = new CICRegistry(settings.w3.engine, environment.registryAddress, this.fileGetter, ['../../assets/js/block-sync/data']); settings.registry.declaratorHelper.addTrust(environment.trustedDeclaratorAddress); settings.txHelper = new TransactionHelper(settings.w3.engine, settings.registry); settings.txHelper.ontransfer = async (transaction: any): Promise => { window.dispatchEvent(this.newTransferEvent(transaction)); }; settings.txHelper.onconversion = async (transaction: any): Promise => { window.dispatchEvent(this.newConversionEvent(transaction)); }; settings.registry.onload = (addressReturned: number): void => { this.loggingService.sendInfoLevelMessage(`Loaded network contracts ${addressReturned}`); this.readyStateProcessor(settings, readyStateElements.network, address, offset, limit); }; settings.registry.load(); } readyStateProcessor(settings: Settings, bit: number, address: string, offset: number, limit: number): void { this.readyState |= bit; if (this.readyStateTarget === this.readyState && this.readyStateTarget) { const wHeadSync = new Worker('./../assets/js/block-sync/head.js'); wHeadSync.onmessage = (m) => { settings.txHelper.processReceipt(m.data); }; wHeadSync.postMessage({ w3_provider: settings.w3.provider, }); if (address === null) { this.transactionService.getAllTransactions(offset, limit).pipe(first()).subscribe(res => { this.fetcher(settings, res); }); } else { this.transactionService.getAddressTransactions(address, offset, limit).pipe(first()).subscribe(res => { this.fetcher(settings, res); }); } } } newTransferEvent(tx): any { return new CustomEvent('cic_transfer', { detail: { tx, }, }); } newConversionEvent(tx): any { return new CustomEvent('cic_convert', { detail: { tx, }, }); } async scan(settings, lo, hi, bloomBlockBytes, bloomBlocktxBytes, bloomRounds): Promise { const w = new Worker('./../assets/js/block-sync/ondemand.js'); w.onmessage = (m) => { settings.txHelper.processReceipt(m.data); }; w.postMessage({ w3_provider: settings.w3.provider, lo, hi, filters: [ bloomBlockBytes, bloomBlocktxBytes, ], filter_rounds: bloomRounds, }); } fetcher(settings: Settings, transactionsInfo: any): void { const blockFilterBinstr = window.atob(transactionsInfo.block_filter); const bOne = new Uint8Array(blockFilterBinstr.length); bOne.map((e, i, v) => v[i] = blockFilterBinstr.charCodeAt(i)); const blocktxFilterBinstr = window.atob(transactionsInfo.blocktx_filter); const bTwo = new Uint8Array(blocktxFilterBinstr.length); bTwo.map((e, i, v) => v[i] = blocktxFilterBinstr.charCodeAt(i)); settings.scanFilter(settings, transactionsInfo.low, transactionsInfo.high, bOne, bTwo, transactionsInfo.filter_rounds); } }