import { Block , BlockHeader , BlockBody } from './block' ; import { ValidatorSet , Consensus } from './consensus' ; import { Hash } from '@uniqys/signature' ; import { BlockStore } from './block-store' ; export class Blockchain { private isReady = false ; constructor ( public readonly blockStore , public readonly genesisBlock ) { } public async ready ( ) { if ( this . isReady ) { return Promise . resolve ( ) ; } await this . blockStore . mutex . use ( async ( ) => { const height = await this . blockStore . getHeight ( ) ; if ( height === 0 ) { await Promise . all ( [ this . blockStore . setHeader ( 1 , this . genesisBlock . header ) , this . blockStore . setBody ( 1 , this . genesisBlock . body ) ] ) ; } } ) ; if ( ! ( await this . blockStore . getHeader ( 1 ) ) . hash . equals ( this . genesisBlock . hash ) ) { throw new Error ( 'Stored genesis block is invalid. You need to reset store.' ) ; } this . isReady = true ; } public async hashOf ( height ) { return ( await this . blockStore . getHeader ( height ) ) . hash ; } public async headerOf ( height ) { return this . blockStore . getHeader ( height ) ; } public async bodyOf ( height ) { return this . blockStore . getBody ( height ) ; } public async blockOf ( height ) { this . checkReady ( ) ; const [ header , body ] = await Promise . all ( [ this . blockStore . getHeader ( height ) , this . blockStore . getBody ( height ) ] ) ; return new Block ( header , body ) ; } public async validatorSetOf ( height ) { this . checkReady ( ) ; return ( await this . blockOf ( Math . max ( height - 1 , 1 ) ) ) . body . nextValidatorSet ; } public async consensusOf ( height ) { this . checkReady ( ) ; return this . blockStore . mutex . use ( async ( ) => { const chainHeight = await this . blockStore . getHeight ( ) ; if ( chainHeight === height ) { return this . blockStore . getLastConsensus ( ) ; } else { const block = await this . blockStore . getBody ( height + 1 ) ; return block . lastBlockConsensus ; } } ) ; } public get height ( ) : Promise < number > { return ( async ( ) => { this . checkReady ( ) ; return this . blockStore . getHeight ( ) ; } ) ( ) ; } private checkReady ( ) { if ( ! this . isReady ) { throw new Error ( 'blockchain is not ready' ) ; } } }