123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637(*****************************************************************************)(* *)(* Open Source License *)(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. <contact@tezos.com> *)(* *)(* Permission is hereby granted, free of charge, to any person obtaining a *)(* copy of this software and associated documentation files (the "Software"),*)(* to deal in the Software without restriction, including without limitation *)(* the rights to use, copy, modify, merge, publish, distribute, sublicense, *)(* and/or sell copies of the Software, and to permit persons to whom the *)(* Software is furnished to do so, subject to the following conditions: *)(* *)(* The above copyright notice and this permission notice shall be included *)(* in all copies or substantial portions of the Software. *)(* *)(* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR*)(* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *)(* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *)(* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER*)(* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING *)(* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER *)(* DEALINGS IN THE SOFTWARE. *)(* *)(*****************************************************************************)typecounter=Z.tletcounter=Data_encoding.zlet((+):counter->counter->counter)=Z.addletzero:counter=Z.zeroletone:counter=Z.one(* Distributed DB peer metadata *)typemessages={mutablebranch:counter;mutablehead:counter;mutableblock_header:counter;mutableoperations:counter;mutableprotocols:counter;mutableoperation_hashes_for_block:counter;mutableoperations_for_block:counter;mutablecheckpoint:counter;mutableprotocol_branch:counter;mutablepredecessor_header:counter;mutableother:counter;}letsent_requests_encoding=letopenData_encodingin(conv(fun{branch;head;block_header;operations;protocols;operation_hashes_for_block;operations_for_block;checkpoint;protocol_branch;predecessor_header;other;}->(branch,head,block_header,operations,protocols,operation_hashes_for_block,operations_for_block,checkpoint,protocol_branch,predecessor_header,other))(fun(branch,head,block_header,operations,protocols,operation_hashes_for_block,operations_for_block,checkpoint,protocol_branch,predecessor_header,other)->{branch;head;block_header;operations;protocols;operation_hashes_for_block;operations_for_block;checkpoint;protocol_branch;predecessor_header;other;}))(union[case~title:"peer_metadata.v1"Json_only(merge_objs(obj10(req"branch"counter)(req"head"counter)(req"block_header"counter)(req"operations"counter)(req"protocols"counter)(req"operation_hashes_for_block"counter)(req"operations_for_block"counter)(req"checkpoint"counter)(req"protocol_branch"counter)(req"predecessor_header"counter))(obj1(req"other"counter)))(fun(b,h,bh,ops,p,ophs,opb,cp,pb,ph,o)->Some((b,h,bh,ops,p,ophs,opb,cp,pb,ph),o))(fun((b,h,bh,ops,p,ophs,opb,cp,pb,ph),o)->(b,h,bh,ops,p,ophs,opb,cp,pb,ph,o));(* This legacy encoding may be removed once every node
upgrade to the DDB v1. This encoding is currently only
being used to decode the peers json file. *)case~title:"peer_metadata.legacy_v0"Json_only(obj8(req"branch"counter)(req"head"counter)(req"block_header"counter)(req"operations"counter)(req"protocols"counter)(req"operation_hashes_for_block"counter)(req"operations_for_block"counter)(req"other"counter))(fun_->None)(* Never used for encoding *)(fun(a,b,c,d,e,f,g,h)->(a,b,c,d,e,f,g,zero,zero,zero,h));])typerequests_kind=|Branch|Head|Block_header|Operations|Protocols|Operation_hashes_for_block|Operations_for_block|Checkpoint|Protocol_branch|Predecessor_header|Othertyperequests={sent:messages;(** p2p sent messages of type requests *)received:messages;(** p2p received messages of type requests *)failed:messages;(** p2p messages of type requests that we failed to send *)scheduled:messages;(** p2p messages ent via request scheduler *)}letrequests_encoding=letopenData_encodingin(conv(fun{sent;received;failed;scheduled}->(sent,received,failed,scheduled))(fun(sent,received,failed,scheduled)->{sent;received;failed;scheduled}))(obj4(req"sent"sent_requests_encoding)(req"received"sent_requests_encoding)(req"failed"sent_requests_encoding)(req"scheduled"sent_requests_encoding))(* Prevalidator peer metadata *)typeprevalidator_results={cannot_download:counter;cannot_parse:counter;refused_by_prefilter:counter;refused_by_postfilter:counter;(* prevalidation results *)applied:counter;branch_delayed:counter;branch_refused:counter;refused:counter;duplicate:counter;outdated:counter;}letprevalidator_results_encoding=letopenData_encodinginconv(fun{cannot_download;cannot_parse;refused_by_prefilter;refused_by_postfilter;applied;branch_delayed;branch_refused;refused;duplicate;outdated;}->(cannot_download,cannot_parse,refused_by_prefilter,refused_by_postfilter,applied,branch_delayed,branch_refused,refused,duplicate,outdated))(fun(cannot_download,cannot_parse,refused_by_prefilter,refused_by_postfilter,applied,branch_delayed,branch_refused,refused,duplicate,outdated)->{cannot_download;cannot_parse;refused_by_prefilter;refused_by_postfilter;applied;branch_delayed;branch_refused;refused;duplicate;outdated;})(obj10(req"cannot_download"counter)(req"cannot_parse"counter)(req"refused_by_prefilter"counter)(req"refused_by_postfilter"counter)(req"applied"counter)(req"branch_delayed"counter)(req"branch_refused"counter)(req"refused"counter)(req"duplicate"counter)(req"outdated"counter))typeresource_kind=Block|Operations|Protocoltypeadvertisement=Head|Branchtypemetadata=(* Distributed_db *)|Received_requestofrequests_kind|Sent_requestofrequests_kind|Failed_requestofrequests_kind|Scheduled_requestofrequests_kind|Received_responseofrequests_kind|Sent_responseofrequests_kind|Unexpected_response|Unactivated_chain|Inactive_chain|Future_block|Unadvertisedofresource_kind|Sent_advertisementofadvertisement|Received_advertisementofadvertisement|Outdated_response(* TODO : unused *)(* Peer validator *)|Valid_blocks|Old_heads(* Prevalidation *)|Cannot_download|Cannot_parse|Refused_by_prefilter|Refused_by_postfilter|Applied|Branch_delayed|Branch_refused|Refused|Duplicate|Outdatedtyperesponses={mutablesent:messages;(** p2p sent messages of type responses *)mutablefailed:messages;(** p2p sent messages of type responses *)mutablereceived:messages;(** p2p received responses *)mutableunexpected:counter;(** p2p received responses that were unexpected *)mutableoutdated:counter;(** p2p received responses that are now outdated *)}letresponses_encoding=letopenData_encodingin(conv(fun{sent;failed;received;unexpected;outdated}->(sent,failed,received,unexpected,outdated))(fun(sent,failed,received,unexpected,outdated)->{sent;failed;received;unexpected;outdated}))(obj5(req"sent"sent_requests_encoding)(req"failed"sent_requests_encoding)(req"received"sent_requests_encoding)(req"unexpected"counter)(req"outdated"counter))typeunadvertised={mutableblock:counter;(** requests for unadvertised block *)mutableoperations:counter;(** requests for unadvertised operations *)mutableprotocol:counter;(** requests for unadvertised protocol *)}letunadvertised_encoding=letopenData_encodingin(conv(fun{block;operations;protocol}->(block,operations,protocol))(fun(block,operations,protocol)->{block;operations;protocol}))(obj3(req"block"counter)(req"operations"counter)(req"protocol"counter))typeadvertisements_kind={mutablehead:counter;mutablebranch:counter}letadvertisements_kind_encoding=letopenData_encodingin(conv(fun{head;branch}->(head,branch))(fun(head,branch)->{head;branch}))(obj2(req"head"counter)(req"branch"counter))typeadvertisements={mutablesent:advertisements_kind;mutablereceived:advertisements_kind;}letadvertisements_encoding=letopenData_encodingin(conv(fun{sent;received}->(sent,received))(fun(sent,received)->{sent;received}))(obj2(req"sent"advertisements_kind_encoding)(req"received"advertisements_kind_encoding))typet={mutableresponses:responses;(** responses sent/received *)mutablerequests:requests;(** requests sent/received *)mutablevalid_blocks:counter;(** new valid blocks advertized by a peer *)mutableold_heads:counter;(** previously validated blocks from a peer *)mutableprevalidator_results:prevalidator_results;(** prevalidator metadata *)mutableunactivated_chains:counter;(** requests from unactivated chains *)mutableinactive_chains:counter;(** advertise inactive chains *)mutablefuture_blocks_advertised:counter;(** future blocks *)mutableunadvertised:unadvertised;(** requests for unadvertised resources *)mutableadvertisements:advertisements;(** advertisements sent *)}letempty()=letempty_request()={branch=zero;head=zero;block_header=zero;operations=zero;protocols=zero;operation_hashes_for_block=zero;operations_for_block=zero;checkpoint=zero;protocol_branch=zero;predecessor_header=zero;other=zero;}in{responses={sent=empty_request();failed=empty_request();received=empty_request();unexpected=zero;outdated=zero;};requests={sent=empty_request();failed=empty_request();scheduled=empty_request();received=empty_request();};valid_blocks=zero;old_heads=zero;prevalidator_results={cannot_download=zero;cannot_parse=zero;refused_by_prefilter=zero;refused_by_postfilter=zero;applied=zero;branch_delayed=zero;branch_refused=zero;refused=zero;duplicate=zero;outdated=zero;};unactivated_chains=zero;inactive_chains=zero;future_blocks_advertised=zero;unadvertised={block=zero;operations=zero;protocol=zero};advertisements={sent={head=zero;branch=zero};received={head=zero;branch=zero};};}letencoding=letopenData_encodingin(conv(fun{responses;requests;valid_blocks;old_heads;prevalidator_results;unactivated_chains;inactive_chains;future_blocks_advertised;unadvertised;advertisements;}->((responses,requests,valid_blocks,old_heads,prevalidator_results,unactivated_chains,inactive_chains,future_blocks_advertised),(unadvertised,advertisements)))(fun((responses,requests,valid_blocks,old_heads,prevalidator_results,unactivated_chains,inactive_chains,future_blocks_advertised),(unadvertised,advertisements))->{responses;requests;valid_blocks;old_heads;prevalidator_results;unactivated_chains;inactive_chains;future_blocks_advertised;unadvertised;advertisements;}))(merge_objs(obj8(req"responses"responses_encoding)(req"requests"requests_encoding)(req"valid_blocks"counter)(req"old_heads"counter)(req"prevalidator_results"prevalidator_results_encoding)(req"unactivated_chains"counter)(req"inactive_chains"counter)(req"future_blocks_advertised"counter))(obj2(req"unadvertised"unadvertised_encoding)(req"advertisements"advertisements_encoding)))letincr_requests(msgs:messages)(req:requests_kind)=matchreqwith|Branch->msgs.branch<-msgs.branch+one|Head->msgs.head<-msgs.head+one|Block_header->msgs.block_header<-msgs.block_header+one|Operations->msgs.operations<-msgs.operations+one|Protocols->msgs.protocols<-msgs.protocols+one|Operation_hashes_for_block->msgs.operation_hashes_for_block<-msgs.operation_hashes_for_block+one|Operations_for_block->msgs.operations_for_block<-msgs.operations_for_block+one|Checkpoint->msgs.checkpoint<-msgs.checkpoint+one|Protocol_branch->msgs.protocol_branch<-msgs.protocol_branch+one|Predecessor_header->msgs.predecessor_header<-msgs.predecessor_header+one|Other->msgs.other<-msgs.other+oneletincr_unadvertisedtk=let{unadvertised=u;_}=tinmatchkwith|Block->u.block<-u.block+one|Operations->u.operations<-u.operations+one|Protocol->u.protocol<-u.protocol+oneletincrmmetadata=let{responses=rsps;requests=rqst;_}=minmatchmetadatawith(* requests *)|Received_requestreq->incr_requestsrqst.receivedreq|Sent_requestreq->incr_requestsrqst.sentreq|Scheduled_requestreq->incr_requestsrqst.scheduledreq|Failed_requestreq->incr_requestsrqst.failedreq(* responses *)|Received_responsereq->incr_requestsrsps.receivedreq|Sent_responsereq->incr_requestsrsps.sentreq|Unexpected_response->rsps.unexpected<-rsps.unexpected+one|Outdated_response->rsps.outdated<-rsps.outdated+one(* Advertisements *)|Sent_advertisementad->(matchadwith|Head->m.advertisements.sent.head<-m.advertisements.sent.head+one|Branch->m.advertisements.sent.branch<-m.advertisements.sent.branch+one)|Received_advertisementad->(matchadwith|Head->m.advertisements.received.head<-m.advertisements.received.head+one|Branch->m.advertisements.received.branch<-m.advertisements.received.branch+one)(* Unexpected erroneous msg *)|Unactivated_chain->m.unactivated_chains<-m.unactivated_chains+one|Inactive_chain->m.inactive_chains<-m.inactive_chains+one|Future_block->m.future_blocks_advertised<-m.future_blocks_advertised+one|Unadvertisedu->incr_unadvertisedmu(* Peer validator *)|Valid_blocks->m.valid_blocks<-m.valid_blocks+one|Old_heads->m.old_heads<-m.old_heads+one(* prevalidation *)|Cannot_download->m.prevalidator_results<-{m.prevalidator_resultswithcannot_download=m.prevalidator_results.cannot_download+one;}|Cannot_parse->m.prevalidator_results<-{m.prevalidator_resultswithcannot_parse=m.prevalidator_results.cannot_parse+one;}|Refused_by_prefilter->m.prevalidator_results<-{m.prevalidator_resultswithrefused_by_prefilter=m.prevalidator_results.refused_by_prefilter+one;}|Refused_by_postfilter->m.prevalidator_results<-{m.prevalidator_resultswithrefused_by_postfilter=m.prevalidator_results.refused_by_postfilter+one;}|Applied->m.prevalidator_results<-{m.prevalidator_resultswithapplied=m.prevalidator_results.applied+one;}|Branch_delayed->m.prevalidator_results<-{m.prevalidator_resultswithbranch_delayed=m.prevalidator_results.branch_delayed+one;}|Branch_refused->m.prevalidator_results<-{m.prevalidator_resultswithbranch_refused=m.prevalidator_results.branch_refused+one;}|Refused->m.prevalidator_results<-{m.prevalidator_resultswithrefused=m.prevalidator_results.refused+one;}|Duplicate->m.prevalidator_results<-{m.prevalidator_resultswithduplicate=m.prevalidator_results.duplicate+one;}|Outdated->m.prevalidator_results<-{m.prevalidator_resultswithoutdated=m.prevalidator_results.outdated+one;}(* shortcuts to update sent/failed requests/responses *)letupdate_requeststkindb=let{requests={sent;failed;_};_}=tinmatchbwith|true->incr_requestssentkind|false->incr_requestsfailedkindletupdate_responsestkindb=let{requests={sent;failed;_};_}=tinmatchbwith|true->incr_requestssentkind|false->incr_requestsfailedkind(* Scores computation *)(* TODO:
- scores cannot be kept as integers (use big numbers?)
- they scores should probably be reset frequently (at each block/cycle?)
- we might still need to keep some kind of score history
- store only best/worst/last_value/mean/variance... ?
- do we need to keep "good" scores ?
- maybe "bad" scores are enough to reduce resources
allocated to misbehaving peers *)letdistributed_db_score_=(* TODO *)1.0letprevalidation_score{prevalidator_results=_;_}=(* TODO *)1.0letscore_=(* TODO *)1.0