import SHA256 from "crypto-js/sha256" ; import { trampoline } from "./utils" ; type BlockChain = Block [ ] ; type Hash = string ; export interface Block { timestamp : string ; data : any ; previousHash : Hash ; hash : Hash ; nonce : number ; } function param { Block } a returns { string } export function calculateHash ( { previousHash , timestamp , data , nonce } ) { return SHA256 ( previousHash + timestamp + JSON . stringify ( data ) + nonce ) . toString ( ) ; } function returns { Block } export function generateGenesisBlock ( ) { const block = { timestamp : "" , data : "Genesis Block" , previousHash : "0" , } ; return { ... block , hash : calculateHash ( block ) } ; } function param { BlockChain } chain returns { Block } export function getLatestBlock ( chain ) { return chain [ chain . length - 1 ] ; } function param { BlockChain } chain param { Block } block returns { BlockChain } export function addBlock ( chain , { timestamp , data } ) { const latestBlock = getLatestBlock ( chain ) ; const previousHash = latestBlock . hash ; const block = { timestamp , data , previousHash , nonce : 0 } ; const newBlock = mineBlock ( 4 , block ) ; return chain . concat ( newBlock ) ; } function param { number } difficulty param { string } hash returns { boolean } export function checkDifficulty ( difficulty , hash ) { return hash . substr ( 0 , difficulty ) === "0" . repeat ( difficulty ) ; } function param { Block } block returns { Block } export function nextNonce ( block ) { return updateHash ( { ... block , nonce : block . nonce + 1 } ) ; } function param { Block } block returns { Block } function updateHash ( block ) { return { ... block , hash : calculateHash ( block ) } ; } function param { number } difficulty param { Block } block returns { Block } export function mineBlock ( difficulty , block ) { function mine ( block ) { const newBlock = nextNonce ( block ) ; return checkDifficulty ( difficulty , newBlock . hash ) ? newBlock : ( ) => mine ( nextNonce ( block ) ) ; } return trampoline ( mine ( nextNonce ( block ) ) ) ; } function param { BlockChain } chain returns { boolean } description export function validateChain ( chain ) { function tce ( chain , index ) { if ( index === 0 ) return true ; const { hash , ... currentBlockWithoutHash } = chain [ index ] ; const currentBlock = chain [ index ] ; const previousBlock = chain [ index - 1 ] ; const isValidHash = ( hash === calculateHash ( currentBlockWithoutHash ) ) ; const isPreviousHashValid = ( currentBlock . previousHash === previousBlock . hash ) ; const isValidChain = ( isValidHash && isPreviousHashValid ) ; if ( ! isValidChain ) return false ; return tce ( chain , index - 1 ) ; } return tce ( chain , chain . length - 1 ) ; }