import * as Debug from "debug" ; const debug = Debug ( "blockchain:peer" ) ; import BlockHandler from "./BlockHandler" ; import ConfigInterface from "./interfaces/ConfigInterface" ; import BlockInterface from "./interfaces/BlockInterface" ; import TransactionInterface from "./interfaces/TransactionInterface" ; import HttpClient from "./http/HttpClient" ; import { parseHost } from "./utils" ; import TransferInterface from "./interfaces/TransferInterface" ; export default class Peer { public nodes : Set < string > ; public proto : string ; private config : ConfigInterface ; private client : HttpClient ; constructor ( config ) { this . config = config ; this . client = new HttpClient ( ) ; this . nodes = new Set ( ) ; this . proto = this . config . blockchain . protocol ; } param address public registerNode ( address ) { const host = parseHost ( address ) ; this . nodes . add ( host ) ; debug ( "registering" , host , "as new node" ) ; } param address public removeNode ( address ) { debug ( "removing node" , address ) ; this . nodes . delete ( address ) ; } param host public async fetchChainFromNode ( host ) { debug ( "fetching chain from" , host ) ; try { const { status , body } = await this . client . call ( { method : "GET" , url : `${ this . proto }${ host }/api/peer/chain` , timeout : 5000 , } ) ; if ( status === 200 ) { return body ; } debug ( "failed to fetch chain from node" , host , status ) ; return [ ] ; } catch ( error ) { debug ( "failed to fetch chain from node" , host , error . message ) ; return [ ] ; } } param host public async fetchChainLengthFromNode ( host ) { try { const { status , body } = await this . client . call ( { method : "GET" , url : `${ this . proto }${ host }/api/stats` , timeout : 5000 , } ) ; if ( status === 200 ) { debug ( "fetched chain length from" , host , "is" , body . length ) ; return body . length ; } debug ( "failed to fetch chain lengthfrom node" , host , status ) ; return - 1 ; } catch ( error ) { debug ( "failed to fetch chain length node" , host , error . message ) ; return - 1 ; } } param url public async registerSelfAtOtherNode ( url ) { const host = parseHost ( url ) ; debug ( "registering at other node" , host ) ; try { const { status , body } = await this . client . call ( { body : JSON . stringify ( { nodes : [ this . config . advertisedHost ] , } ) , headers : { "content-type" : "application/json" , } , method : "POST" , url : `${ this . proto }${ host }/api/nodes/register` , timeout : 5000 , } ) ; if ( status === 200 ) { debug ( "registered self at other node" , host ) ; return true ; } debug ( "failed to register on node" , host , status ) ; return false ; } catch ( error ) { debug ( "failed to register on node" , host , error . message ) ; return false ; } } param transaction param host public async publishTransaction ( transaction , host ) { try { const { status , body } = await this . client . call ( { body : JSON . stringify ( { transaction , } ) , headers : { "content-type" : "application/json" , } , method : "POST" , url : `${ this . proto }${ host }/api/peer/transaction` , timeout : 5000 , } ) ; if ( status === 200 ) { debug ( "published transaction to other node" , host ) ; return true ; } else if ( status === 503 ) { debug ( "other node is busy" , host ) ; return false ; } debug ( "failed to publish transaction to other node" , host , status ) ; this . removeNode ( host ) ; return false ; } catch ( error ) { debug ( "failed to publish transaction to other node, with error" , host , error . message ) ; this . removeNode ( host ) ; return false ; } } param block param host public async publishBlock ( block , host ) { try { const { status , body } = await this . client . call ( { body : JSON . stringify ( { block , } ) , headers : { "content-type" : "application/json" , } , method : "POST" , url : `${ this . proto }${ host }/api/peer/block` , timeout : 5000 , } ) ; if ( status === 200 ) { debug ( "published block to other node" , host ) ; return true ; } else if ( status === 503 ) { debug ( "other node is busy" , host ) ; return false ; } debug ( "failed to publish block to other node" , host , status ) ; this . removeNode ( host ) ; return false ; } catch ( error ) { debug ( "failed to publish block to other node, with error" , host , error . message ) ; this . removeNode ( host ) ; return false ; } } }