2022-08-02 00:37:54 +00:00
import { Component , OnInit , OnDestroy , ViewChild , ElementRef } from '@angular/core' ;
import { ActivatedRoute , ParamMap } from '@angular/router' ;
2024-10-22 21:05:01 +09:00
import { ElectrsApiService } from '@app/services/electrs-api.service' ;
2022-08-03 16:43:47 +00:00
import { switchMap , tap , throttleTime , catchError , shareReplay , startWith , pairwise , filter } from 'rxjs/operators' ;
2023-12-29 14:13:13 +00:00
import { of , Subscription , asyncScheduler , forkJoin } from 'rxjs' ;
2024-10-22 21:05:01 +09:00
import { StateService } from '@app/services/state.service' ;
import { SeoService } from '@app/services/seo.service' ;
import { OpenGraphService } from '@app/services/opengraph.service' ;
2024-10-23 11:09:38 +09:00
import { BlockExtended , TransactionStripped } from '@interfaces/node-api.interface' ;
2024-10-22 21:05:01 +09:00
import { ApiService } from '@app/services/api.service' ;
import { seoDescriptionNetwork } from '@app/shared/common.utils' ;
import { BlockOverviewGraphComponent } from '@components/block-overview-graph/block-overview-graph.component' ;
import { ServicesApiServices } from '@app/services/services-api.service' ;
2022-07-12 22:04:20 +00:00
@Component ( {
selector : 'app-block-preview' ,
templateUrl : './block-preview.component.html' ,
2022-08-02 00:37:54 +00:00
styleUrls : [ './block-preview.component.scss' ]
2022-07-12 22:04:20 +00:00
} )
2022-08-02 00:37:54 +00:00
export class BlockPreviewComponent implements OnInit , OnDestroy {
network = '' ;
block : BlockExtended ;
blockHeight : number ;
blockHash : string ;
2022-08-31 17:24:56 +00:00
rawId : string ;
2022-08-02 00:37:54 +00:00
isLoadingBlock = true ;
strippedTransactions : TransactionStripped [ ] ;
overviewTransitionDirection : string ;
isLoadingOverview = true ;
error : any ;
blockSubsidy : number ;
fees : number ;
overviewError : any = null ;
overviewSubscription : Subscription ;
networkChangedSubscription : Subscription ;
@ViewChild ( 'blockGraph' ) blockGraph : BlockOverviewGraphComponent ;
constructor (
private route : ActivatedRoute ,
private electrsApiService : ElectrsApiService ,
public stateService : StateService ,
private seoService : SeoService ,
private openGraphService : OpenGraphService ,
2024-01-09 12:11:45 +01:00
private apiService : ApiService ,
private servicesApiService : ServicesApiServices ,
2022-08-02 00:37:54 +00:00
) { }
ngOnInit() {
this . network = this . stateService . network ;
const block $ = this . route . paramMap . pipe (
switchMap ( ( params : ParamMap ) = > {
2022-08-31 17:24:56 +00:00
this . rawId = params . get ( 'id' ) || '' ;
this . openGraphService . waitFor ( 'block-viz-' + this . rawId ) ;
this . openGraphService . waitFor ( 'block-data-' + this . rawId ) ;
2022-08-02 00:37:54 +00:00
const blockHash : string = params . get ( 'id' ) || '' ;
this . block = undefined ;
this . error = undefined ;
2022-08-03 16:43:47 +00:00
this . overviewError = undefined ;
2022-08-02 00:37:54 +00:00
this . fees = undefined ;
let isBlockHeight = false ;
if ( /^[0-9]+$/ . test ( blockHash ) ) {
isBlockHeight = true ;
} else {
this . blockHash = blockHash ;
}
this . isLoadingBlock = true ;
this . isLoadingOverview = true ;
if ( isBlockHeight ) {
return this . electrsApiService . getBlockHashFromHeight $ ( parseInt ( blockHash , 10 ) )
. pipe (
switchMap ( ( hash ) = > {
2022-08-03 16:43:47 +00:00
if ( hash ) {
this . blockHash = hash ;
return this . apiService . getBlock $ ( hash ) ;
} else {
return null ;
}
} ) ,
catchError ( ( err ) = > {
this . error = err ;
2023-03-09 02:34:21 -06:00
this . seoService . logSoft404 ( ) ;
2022-08-31 17:24:56 +00:00
this . openGraphService . fail ( 'block-data-' + this . rawId ) ;
this . openGraphService . fail ( 'block-viz-' + this . rawId ) ;
2022-08-03 16:43:47 +00:00
return of ( null ) ;
} ) ,
2022-08-02 00:37:54 +00:00
) ;
}
return this . apiService . getBlock $ ( blockHash ) ;
} ) ,
2022-08-03 16:43:47 +00:00
filter ( ( block : BlockExtended | void ) = > block != null ) ,
2022-08-02 00:37:54 +00:00
tap ( ( block : BlockExtended ) = > {
this . block = block ;
this . blockHeight = block . height ;
this . seoService . setTitle ( $localize ` :@@block.component.browser-title:Block ${ block . height } :BLOCK_HEIGHT:: ${ block . id } :BLOCK_ID: ` ) ;
2023-08-30 20:26:07 +09:00
if ( this . stateService . network === 'liquid' || this . stateService . network === 'liquidtestnet' ) {
this . seoService . setDescription ( $localize ` :@@meta.description.liquid.block:See size, weight, fee range, included transactions, and more for Liquid ${ seoDescriptionNetwork ( this . stateService . network ) } block ${ block . height } :BLOCK_HEIGHT: ( ${ block . id } :BLOCK_ID:). ` ) ;
} else {
this . seoService . setDescription ( $localize ` :@@meta.description.bitcoin.block:See size, weight, fee range, included transactions, audit (expected v actual), and more for Bitcoin ${ seoDescriptionNetwork ( this . stateService . network ) } block ${ block . height } :BLOCK_HEIGHT: ( ${ block . id } :BLOCK_ID:). ` ) ;
}
2022-08-02 00:37:54 +00:00
this . isLoadingBlock = false ;
this . setBlockSubsidy ( ) ;
if ( block ? . extras ? . reward !== undefined ) {
this . fees = block . extras . reward / 100000000 - this . blockSubsidy ;
}
this . stateService . markBlock $ . next ( { blockHeight : this.blockHeight } ) ;
this . isLoadingOverview = true ;
this . overviewError = null ;
2022-08-31 17:24:56 +00:00
this . openGraphService . waitOver ( 'block-data-' + this . rawId ) ;
2022-08-02 00:37:54 +00:00
} ) ,
throttleTime ( 50 , asyncScheduler , { leading : true , trailing : true } ) ,
2025-01-06 18:41:46 +00:00
shareReplay ( { bufferSize : 1 , refCount : true } )
2022-08-02 00:37:54 +00:00
) ;
this . overviewSubscription = block $ . pipe (
startWith ( null ) ,
pairwise ( ) ,
2023-12-29 14:13:13 +00:00
switchMap ( ( [ prevBlock , block ] ) = > {
return forkJoin ( [
this . apiService . getStrippedBlockTransactions $ ( block . id )
. pipe (
catchError ( ( err ) = > {
this . overviewError = err ;
this . openGraphService . fail ( 'block-viz-' + this . rawId ) ;
return of ( [ ] ) ;
} ) ,
switchMap ( ( transactions ) = > {
return of ( transactions ) ;
} )
) ,
2024-05-12 21:15:27 +00:00
this . stateService . env . ACCELERATOR === true && block . height > 819500
2024-08-28 14:38:12 +00:00
? this . servicesApiService . getAllAccelerationHistory $ ( { blockHeight : block.height } )
2024-05-12 21:15:27 +00:00
. pipe ( catchError ( ( ) = > {
return of ( [ ] ) ;
} ) )
: of ( [ ] )
2023-12-29 14:13:13 +00:00
] ) ;
}
2022-08-02 00:37:54 +00:00
) ,
)
2023-12-29 14:13:13 +00:00
. subscribe ( ( [ transactions , accelerations ] ) = > {
2022-08-02 00:37:54 +00:00
this . strippedTransactions = transactions ;
2023-12-29 14:13:13 +00:00
const acceleratedInBlock = { } ;
for ( const acc of accelerations ) {
acceleratedInBlock [ acc . txid ] = acc ;
}
for ( const tx of transactions ) {
if ( acceleratedInBlock [ tx . txid ] ) {
tx . acc = true ;
}
}
2022-08-02 00:37:54 +00:00
this . isLoadingOverview = false ;
if ( this . blockGraph ) {
this . blockGraph . destroy ( ) ;
this . blockGraph . setup ( this . strippedTransactions ) ;
}
} ,
( error ) = > {
this . error = error ;
this . isLoadingOverview = false ;
2023-03-09 02:34:21 -06:00
this . seoService . logSoft404 ( ) ;
2022-08-31 17:24:56 +00:00
this . openGraphService . fail ( 'block-viz-' + this . rawId ) ;
this . openGraphService . fail ( 'block-data-' + this . rawId ) ;
2022-08-02 00:37:54 +00:00
if ( this . blockGraph ) {
this . blockGraph . destroy ( ) ;
}
} ) ;
this . networkChangedSubscription = this . stateService . networkChanged $
. subscribe ( ( network ) = > this . network = network ) ;
}
ngOnDestroy() {
if ( this . overviewSubscription ) {
this . overviewSubscription . unsubscribe ( ) ;
}
if ( this . networkChangedSubscription ) {
this . networkChangedSubscription . unsubscribe ( ) ;
}
}
// TODO - Refactor this.fees/this.reward for liquid because it is not
// used anymore on Bitcoin networks (we use block.extras directly)
setBlockSubsidy() {
this . blockSubsidy = 0 ;
}
onGraphReady ( ) : void {
2022-08-31 17:24:56 +00:00
this . openGraphService . waitOver ( 'block-viz-' + this . rawId ) ;
2022-08-02 00:37:54 +00:00
}
2022-07-12 22:04:20 +00:00
}