import * as Debug from "debug" ; const debug = Debug ( "blockchain:handler" ) ; import Blockchain from "./Blockchain" ; import Database from "./db/Database" ; import { getSHA256Hash } from "./utils" ; import BlockInterface from "./interfaces/BlockInterface" ; import TransactionInterface from "./interfaces/TransactionInterface" ; export default class BlockHandler { private blockchain : Blockchain ; private db : Database ; private proofRegex : any ; constructor ( blockchain , db , difficulty ? ) { this . blockchain = blockchain ; this . db = db ; this . proofRegex = this . buildRegex ( difficulty || 4 ) ; } param block public hash ( block ) { if ( block === null ) { throw new Error ( "Cannot hash block that is null." ) ; } const blockString = JSON . stringify ( block ) ; return getSHA256Hash ( blockString ) ; } param proof param previousHash public async newBlock ( proof , previousHash ) { const block = { index : await this . blockchain . getNextBlockIndex ( ) , previousHash : previousHash || this . hash ( await this . lastBlock ( ) ) , proof , timestamp : Date . now ( ) , transactions : this . blockchain . getCurrentTransactions ( ) , } ; debug ( "creating new block" ) ; this . blockchain . clearTransactions ( ) ; await this . blockchain . storeBlock ( block ) ; return block ; } /**
     * gets the last block of the chain
     */ public async lastBlock ( ) { return await this . blockchain . getLastBlock ( ) ; } param lastProof public proofOfWork ( lastProof ) { debug ( "searching for proof for" , lastProof ) ; const startT = Date . now ( ) ; let proof = 0 ; while ( ! this . isProofValid ( lastProof , proof ) ) { proof ++ ; } const duration = Date . now ( ) - startT ; debug ( "found proof" , proof , "for previous" , lastProof , "in" , duration , "ms" ) ; return proof ; } param lastProof param proof public isProofValid ( lastProof , proof ) { const guess = `${ lastProof }:${ proof }` ; const guessHash = getSHA256Hash ( guess ) ; return this . proofRegex . test ( guessHash ) ; } param block public isBlockValid ( block ) { if ( ! block || ! block . previousHash || ! block . proof || ! block . transactions || ! block . transactions . length ) { return false ; } let invalidTransactionFound = false ; block . transactions . forEach ( ( transaction ) => { if ( ! this . blockchain . signature . verifyTransactionSignature ( transaction ) ) { invalidTransactionFound = true ; } } ) ; if ( invalidTransactionFound ) { debug ( "block contains invalid transaction" ) ; return false ; } return true ; } /**
     * checks if the current chain is valid
     */ public async isChainValid ( chain ) { let index = 1 ; while ( index < chain . length ) { const previousBlock = chain [ index - 1 ] ; const block = chain [ index ] ; if ( block . previousHash !== this . hash ( previousBlock ) ) { return false ; } if ( ! this . isProofValid ( previousBlock . proof , block . proof ) ) { return false ; } index ++ ; } return true ; } param difficulty private buildRegex ( difficulty ) { const regHashStart = [ ] ; for ( let i = 0 ; i < difficulty ; i ++ ) { regHashStart . push ( "0" ) ; } return new RegExp ( `^${ regHashStart . join ( "" ) }` ) ; } }