Legend:
Page
Library
Module
Module type
Parameter
Class
Class type
Source
Source file operation_pool.ml
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397(*****************************************************************************)(* *)(* Open Source License *)(* Copyright (c) 2021 Nomadic Labs <contact@nomadic-labs.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. *)(* *)(*****************************************************************************)openProtocolopenAlpha_context(* Should we use a better ordering ? *)type'collectiont={consensus:'collection;votes:'collection;anonymous:'collection;managers:'collection;}letcompare_opop1op2=tryStdlib.compareop1op2with_->(* FIXME some operations (e.g. tx_rollup_rejection) pack
functional values which could raise an exception. In this
specific case, we default to comparing their hashes. *)Operation_hash.compare(Alpha_context.Operation.hash_packedop1)(Alpha_context.Operation.hash_packedop2)modulePrioritized_operation=struct(* Higher priority operations will be included first *)typet=Prioritizedofint*packed_operation|Lowofpacked_operationletextern?(priority=1)op=Prioritized(priority,op)letnodeop=Lowopletpacked=functionPrioritized(_,op)|Lowop->opletcompare_priorityt1t2=match(t1,t2)with|Prioritized_,Low_->1|Low_,Prioritized_->-1|Low_,Low_->0|Prioritized(p0,_),Prioritized(p1,_)->Compare.Int.comparep0p1letcompareab=letc=compare_priorityabinifc<>0thencelsecompare_op(packeda)(packedb)endmoduleOperation_set=Set.Make(structtypet=packed_operationletcompare=compare_opend)modulePrioritized_operation_set=structincludeSet.Make(structtypet=Prioritized_operation.tletcompare=Prioritized_operation.compareend)letoperationsset=elementsset|>List.mapPrioritized_operation.packedend(* TODO refine this: unpack operations *)typepool=Operation_set.tt(* TODO refine this: unpack operations *)typeordered_pool=packed_operationlisttletordered_pool_encoding=letopenData_encodinginconv(fun{consensus;votes;anonymous;managers}->(consensus,votes,anonymous,managers))(fun(consensus,votes,anonymous,managers)->{consensus;votes;anonymous;managers})(obj4(req"ordered_consensus"(list(dynamic_sizeOperation.encoding)))(req"ordered_votes"(list(dynamic_sizeOperation.encoding)))(req"ordered_anonymouns"(list(dynamic_sizeOperation.encoding)))(req"ordered_managers"(list(dynamic_sizeOperation.encoding))))typepayload={votes_payload:packed_operationlist;anonymous_payload:packed_operationlist;managers_payload:packed_operationlist;}letempty_payload={votes_payload=[];anonymous_payload=[];managers_payload=[]}letpayload_encoding=letopenData_encodinginconv(fun{votes_payload;anonymous_payload;managers_payload}->(votes_payload,anonymous_payload,managers_payload))(fun(votes_payload,anonymous_payload,managers_payload)->{votes_payload;anonymous_payload;managers_payload})(obj3(req"votes_payload"(list(dynamic_sizeOperation.encoding)))(req"anonymous_payload"(list(dynamic_sizeOperation.encoding)))(req"managers_payload"(list(dynamic_sizeOperation.encoding))))letpp_payloadfmt{votes_payload;anonymous_payload;managers_payload}=Format.fprintffmt"[votes: %d, anonymous: %d, managers: %d]"(List.lengthvotes_payload)(List.lengthanonymous_payload)(List.lengthmanagers_payload)letempty={consensus=Operation_set.empty;votes=Operation_set.empty;anonymous=Operation_set.empty;managers=Operation_set.empty;}letempty_ordered={consensus=[];votes=[];anonymous=[];managers=[]}letpp_poolfmt{consensus;votes;anonymous;managers}=Format.fprintffmt"[consensus: %d, votes: %d, anonymous: %d, managers: %d]"(Operation_set.cardinalconsensus)(Operation_set.cardinalvotes)(Operation_set.cardinalanonymous)(Operation_set.cardinalmanagers)letpp_ordered_poolfmt{consensus;votes;anonymous;managers}=Format.fprintffmt"[consensus: %d, votes: %d, anonymous: %d, managers: %d]"(List.lengthconsensus)(List.lengthvotes)(List.lengthanonymous)(List.lengthmanagers)letclassifyop=(* Hypothesis: acceptable passes on an ill-formed operation returns
None. *)letpass=Main.acceptable_passopinmatchpasswith|None->`Bad|Somepass->letopenOperation_reprinifpass=consensus_passthen`Consensus(* TODO filter outdated consensus ops ? *)elseifpass=voting_passthen`Voteselseifpass=anonymous_passthen`Anonymouselseifpass=manager_passthen`Managerselse`Badletadd_operation_to_pooladdclassifypooloperation=matchclassifyoperationwith|`Consensus->letconsensus=addoperationpool.consensusin{poolwithconsensus}|`Votes->letvotes=addoperationpool.votesin{poolwithvotes}|`Anonymous->letanonymous=addoperationpool.anonymousin{poolwithanonymous}|`Managers->letmanagers=addoperationpool.managersin{poolwithmanagers}|`Bad->poolletadd_operation=add_operation_to_poolOperation_set.addclassifyletadd_operationspoolops=List.fold_leftadd_operationpoolopstypeconsensus_filter={level:int32;round:Round.t;payload_hash:Block_payload_hash.t;}(** From a pool of operations [operation_pool], the function filters
out the endorsements that are different from the [current_level],
the [current_round] or the optional [current_block_payload_hash],
as well as preendorsements. *)letfilter_with_relevant_consensus_ops~(endorsement_filter:consensus_filter)~(preendorsement_filter:consensus_filteroption)operation_set=Operation_set.filter(fun{protocol_data;_}->match(protocol_data,preendorsement_filter)with(* 1a. Remove preendorsements. *)|Operation_data{contents=Single(Preendorsement_);_},None->false(* 1b. Filter preendorsements. *)|(Operation_data{contents=Single(Preendorsement{level;round;block_payload_hash;_});_;},Some{level=level';round=round';payload_hash=block_payload_hash'})->Compare.Int32.(Raw_level.to_int32level=level')&&Round.(round=round')&&Block_payload_hash.(block_payload_hash=block_payload_hash')(* 2. Filter endorsements. *)|(Operation_data{contents=Single(Endorsement{level;round;block_payload_hash;_});_;},_)->Compare.Int32.(Raw_level.to_int32level=endorsement_filter.level)&&Round.(round=endorsement_filter.round)&&Block_payload_hash.(block_payload_hash=endorsement_filter.payload_hash)(* 3. Preserve all non-consensus operations. *)|_->true)operation_setletunpack_preendorsementpacked_preendorsement=let{shell;protocol_data=Operation_datadata}=packed_preendorsementinmatchdatawith|{contents=Single(Preendorsement_);_}->Some({shell;protocol_data=data}:Kind.preendorsementOperation.t)|_->Noneletunpack_endorsementpacked_endorsement=let{shell;protocol_data=Operation_datadata}=packed_endorsementinmatchdatawith|{contents=Single(Endorsement_);_}->Some({shell;protocol_data=data}:Kind.endorsementOperation.t)|_->Noneletfilter_preendorsementsops=List.filter_map(function|{shell={branch};protocol_data=Operation_data({contents=Single(Preendorsement_);_}ascontent);_;}->Some({shell={branch};protocol_data=content}:Kind.preendorsementoperation)|_->None)opsletfilter_endorsementsops=List.filter_map(function|{shell={branch};protocol_data=Operation_data({contents=Single(Endorsement_);_}ascontent);_;}->Some({shell={branch};protocol_data=content}:Kind.endorsementoperation)|_->None)opsletordered_to_list_list{consensus;votes;anonymous;managers}=[consensus;votes;anonymous;managers]letordered_of_list_list=function|[consensus;votes;anonymous;managers]->Some{consensus;votes;anonymous;managers}|_->Noneletpayload_of_ordered_pool{votes;anonymous;managers;_}={votes_payload=votes;anonymous_payload=anonymous;managers_payload=managers;}letordered_pool_of_payload~consensus_operations{votes_payload;anonymous_payload;managers_payload}={consensus=consensus_operations;votes=votes_payload;anonymous=anonymous_payload;managers=managers_payload;}letextract_operations_of_list_list=function|[consensus;votes_payload;anonymous_payload;managers_payload]->letpreendorsements,endorsements=List.fold_left(fun((preendorsements:Kind.preendorsementOperation.tlist),(endorsements:Kind.endorsementOperation.tlist))packed_op->let{shell;protocol_data=Operation_datadata}=packed_opinmatchdatawith|{contents=Single(Preendorsement_);_}->({shell;protocol_data=data}::preendorsements,endorsements)|{contents=Single(Endorsement_);_}->(preendorsements,{shell;protocol_data=data}::endorsements)|_->(* unreachable *)(preendorsements,endorsements))([],[])consensus(* N.b. the order doesn't matter *)inletpreendorsements=ifpreendorsements=[]thenNoneelseSomepreendorsementsinletpayload={votes_payload;anonymous_payload;managers_payload}inSome(preendorsements,endorsements,payload)|_->Noneletfilter_poolp{consensus;votes;anonymous;managers}={consensus=Operation_set.filterpconsensus;votes=Operation_set.filterpvotes;anonymous=Operation_set.filterpanonymous;managers=Operation_set.filterpmanagers;}modulePrioritized=structtypenonrect=Prioritized_operation_set.ttletof_operation_set(operation_set:Operation_set.t)=Operation_set.fold(funeltset->Prioritized_operation_set.add(Prioritized_operation.nodeelt)set)operation_setPrioritized_operation_set.emptyletof_pool(pool:pool):t={consensus=of_operation_setpool.consensus;votes=of_operation_setpool.votes;anonymous=of_operation_setpool.anonymous;managers=of_operation_setpool.managers;}letadd_operation=add_operation_to_poolPrioritized_operation_set.add(funop->classify(Prioritized_operation.packedop))letadd_external_operationpoolpriorityoperation=add_operationpool(Prioritized_operation.extern~priorityoperation)letadd_operationsprioritized_pooloperations=List.fold_leftadd_operationprioritized_pooloperations(* [merge_external_operations] considers that the list of operation
represents an ordererd list of operation with the head having the highest
prioritiy.
*)letmerge_external_operationspool(external_operations:packed_operationlist)=List.fold_left_i(funipoolop->add_external_operationpool(-i)op)poolexternal_operationsletfilterp{consensus;votes;anonymous;managers}=letfilter=Prioritized_operation_set.filter(funpop->p(Prioritized_operation.packedpop))in{consensus=filterconsensus;votes=filtervotes;anonymous=filteranonymous;managers=filtermanagers;}end