123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405(*****************************************************************************)(* *)(* Open Source License *)(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. <contact@tezos.com> *)(* Copyright (c) 2020 Metastate AG <hello@metastate.dev> *)(* Copyright (c) 2018-2022 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. *)(* *)(*****************************************************************************)openShell_operationmoduletypeCHAIN_STORE=sigtypechain_storevalcontext:chain_store->Store.Block.t->Tezos_protocol_environment.Context.ttzresultLwt.tvalchain_id:chain_store->Chain_id.tendmoduletypeT=sigtypeprotocol_operationtypeconfigvaldefault_config:configvalconfig_encoding:configData_encoding.ttypechain_storetypetvalcreate:chain_store->head:Store.Block.t->timestamp:Time.Protocol.t->ttzresultLwt.tvalflush:chain_store->head:Store.Block.t->timestamp:Time.Protocol.t->t->ttzresultLwt.tvalpre_filter:t->config->protocol_operationShell_operation.operation->[`Passed_prefilterofPrevalidator_pending_operations.priority|Prevalidator_classification.error_classification]Lwt.ttypereplacements=(Operation_hash.t*Prevalidator_classification.error_classification)listtypeadd_result=t*protocol_operationoperation*Prevalidator_classification.classification*replacementsvaladd_operation:t->config->protocol_operationoperation->add_resultLwt.tvalremove_operation:t->Operation_hash.t->tmoduleInternal_for_tests:sigvalget_mempool_operations:t->protocol_operationOperation_hash.Map.ttypemempoolvalset_mempool:t->mempool->ttypebounding_statevalget_bounding_state:t->bounding_statevalset_bounding_state:t->bounding_state->tendendmoduleMakeAbstract(Chain_store:CHAIN_STORE)(Proto:Protocol_plugin.T)(Bounding:Prevalidator_bounding.Twithtypeprotocol_operation=Proto.operation):Twithtypeprotocol_operation=Proto.operationandtypechain_store=Chain_store.chain_storeandtypeInternal_for_tests.mempool=Proto.Mempool.tandtypeInternal_for_tests.bounding_state=Bounding.state=structtypeprotocol_operation=Proto.operationtypeconfig=Proto.Plugin.config*Prevalidator_bounding.configletdefault_config=(Proto.Plugin.default_config,Prevalidator_bounding.default_config)letconfig_encoding=Data_encoding.merge_objsProto.Plugin.config_encodingPrevalidator_bounding.config_encodingtypechain_store=Chain_store.chain_storetypeoperation=protocol_operationShell_operation.operationtypet={validation_info:Proto.Mempool.validation_info;(** Static information needed by [Proto.Mempool.add_operation]. *)mempool:Proto.Mempool.t;(** Protocol representation of currently valid operations. *)bounding_state:Bounding.state;(** Representation of currently valid operations used to enforce
mempool bounds. *)plugin_info:Proto.Plugin.info;(** Static information needed by [Proto.Plugin.pre_filter]. *)conflict_map:Proto.Plugin.Conflict_map.t;(** State needed by
[Proto.Plugin.Conflict_map.fee_needed_to_replace_by_fee] in
order to provide the [needed_fee_in_mutez] field of the
[Operation_conflict] error (see the [translate_proto_add_result]
function below). *)}letcreate_aux?old_statechain_storeheadtimestamp=letopenLwt_result_syntaxinlet*context=Chain_store.contextchain_storeheadinlethead_hash=Store.Block.hashheadinlet*!context=Block_validation.update_testchain_statuscontext~predecessor_hash:head_hashtimestampinletchain_id=Chain_store.chain_idchain_storeinlethead=(Store.Block.headerhead).shellinlet*validation_info,mempool=Proto.Mempool.initcontextchain_id~head_hash~head~cache:`Lazyinlet*plugin_info=matchold_statewith|None->Proto.Plugin.initcontext~head|Someold_state->Proto.Plugin.flushold_state.plugin_info~headinletbounding_state=Bounding.emptyinletconflict_map=Proto.Plugin.Conflict_map.emptyinreturn{validation_info;mempool;bounding_state;plugin_info;conflict_map}letcreatechain_store~head~timestamp=create_auxchain_storeheadtimestampletflushchain_store~head~timestampold_state=create_aux~old_statechain_storeheadtimestampletpre_filterstate(filter_config,(_:Prevalidator_bounding.config))op=Proto.Plugin.pre_filterstate.plugin_infofilter_configop.protocoltypeerror_classification=Prevalidator_classification.error_classificationtypeclassification=Prevalidator_classification.classificationtypereplacement=(Operation_hash.t*error_classification)optiontypereplacements=(Operation_hash.t*error_classification)listtypeadd_result=t*operation*classification*replacementsletclassification_of_tracetrace=matchclassify_tracetracewith|Branch->`Branch_refusedtrace|Permanent->`Refusedtrace|Temporary->`Branch_delayedtrace|Outdated->`Outdatedtrace(* Wrapper around [Proto.Mempool.add_operation]. *)letproto_add_operation~conflict_handlerstateop:(Proto.Mempool.t*Proto.Mempool.add_result)tzresultLwt.t=Proto.Mempool.add_operation~check_signature:(notop.signature_checked)~conflict_handlerstate.validation_infostate.mempool(op.hash,op.protocol)|>Lwt_result.map_error(function|Proto.Mempool.Validation_errortrace->trace|Add_conflict_->(* This cannot happen because we provide a [conflict_handler] to
[Proto.Mempool.add_operation]. See documentation in
[lib_protocol_environment/sigs/v<num>/updater.mli]
with [num >= 7]. *)assertfalse)(* Analyse the output of [Proto.Mempool.add_operation] to extract
the potential replaced operation or return the appropriate error. *)lettranslate_proto_add_result(proto_add_result:Proto.Mempool.add_result)opconflict_mapfilter_config:replacementtzresult=letopenResultinletopenValidation_errorsinmatchproto_add_resultwith|Added->return_none|Replaced{removed}->lettrace=[Operation_replacement{old_hash=removed;new_hash=op.hash}]inreturn_some(removed,classification_of_tracetrace)|Unchanged->(* There was an operation conflict and [op] lost to the
pre-existing operation. The error should indicate the fee
that [op] would need in order to win the conflict and replace
the old operation, if such a fee exists; otherwise the error
should contain [None]. *)letneeded_fee_in_mutez=Proto.Plugin.Conflict_map.fee_needed_to_replace_by_feefilter_config~candidate_op:op.protocol~conflict_mapinerror[Operation_conflict{new_hash=op.hash;needed_fee_in_mutez}]letupdate_bounding_statebounding_statebounding_configop~proto_replacement=letopenResult_syntaxinletbounding_state=matchproto_replacementwith|None->bounding_state|Some(replaced,_)->Bounding.remove_operationbounding_statereplacedinlet*bounding_state,removed_operation_hashes=Result.map_error(funop_to_overtake->letneeded_fee_in_mutez=Option.bindop_to_overtake(funop_to_overtake->Proto.Plugin.fee_needed_to_overtake~op_to_overtake:op_to_overtake.protocol~candidate_op:op.protocol)in[Validation_errors.Rejected_by_full_mempool{hash=op.hash;needed_fee_in_mutez};])(Bounding.add_operationbounding_statebounding_configop)inletbounding_replacements=List.map(funremoved->leterr=[Validation_errors.Removed_from_full_mempoolremoved]in(removed,classification_of_traceerr))removed_operation_hashesinreturn(bounding_state,bounding_replacements)letupdate_conflict_mapconflict_map~mempool_beforeopreplacements=(* [mempool_before] is the protocol's mempool representation
**before calling [Proto.Mempool.add_operation]**, so that it
still contains the replaced operations. Indeed, it is used to
retrieve these operations from their hash. *)letreplacements=ifList.is_emptyreplacementsthen[](* No need to call [Proto.Mempool.operations] when the list is empty. *)elseletops=Proto.Mempool.operationsmempool_beforeinList.filter_map(fun(oph,(_:error_classification))->(* This should always return [Some _]. *)Operation_hash.Map.findophops)replacementsinProto.Plugin.Conflict_map.updateconflict_map~new_operation:op.protocol~replacements(* Implements [add_operation] but inside the [tzresult] monad. *)letadd_operation_resultstate(filter_config,bounding_config)op=letopenLwt_result_syntaxinletconflict_handler=Proto.Plugin.conflict_handlerfilter_configinlet*mempool,proto_add_result=proto_add_operation~conflict_handlerstateopin(* The operation might still be rejected because of a conflict
with a previously validated operation, or if the mempool is
full and the operation does not have enough fees. Nevertheless,
the successful call to [Proto.Mempool.add_operation] guarantees
that the operation is individually valid, in particular its
signature is correct. We record this so that any future
signature check can be skipped. *)letvalid_op=record_successful_signature_checkopinletres=catch_e@@fun()->letopenResult_syntaxinlet*proto_replacement=translate_proto_add_resultproto_add_resultopstate.conflict_mapfilter_configinlet*bounding_state,bounding_replacements=update_bounding_statestate.bounding_statebounding_configop~proto_replacementinletmempool=List.fold_left(funmempool(replaced_oph,_)->Proto.Mempool.remove_operationmempoolreplaced_oph)mempoolbounding_replacementsinletall_replacements=matchproto_replacementwith|None->bounding_replacements|Someproto_replacement->proto_replacement::bounding_replacementsinletconflict_map=update_conflict_mapstate.conflict_map~mempool_before:state.mempoolopall_replacementsinletstate={statewithmempool;bounding_state;conflict_map}inreturn(state,valid_op,`Validated,all_replacements)inmatchreswith|Okadd_result->returnadd_result|Errortrace->(* When [res] is an error, we convert it to an [add_result]
here (instead of letting [add_operation] do it below) so
that we can return the updated [valid_op]. *)return(state,valid_op,classification_of_tracetrace,[])letadd_operationstateconfigop:add_resultLwt.t=letopenLwt_syntaxinlet*res=protect(fun()->add_operation_resultstateconfigop)inmatchreswith|Okadd_result->returnadd_result|Errortrace->return(state,op,classification_of_tracetrace,[])letremove_operationstateoph=letmempool=Proto.Mempool.remove_operationstate.mempoolophinletbounding_state=Bounding.remove_operationstate.bounding_stateophin{statewithmempool;bounding_state}moduleInternal_for_tests=structletget_mempool_operations{mempool;_}=Proto.Mempool.operationsmempooltypemempool=Proto.Mempool.tletset_mempoolstatemempool={statewithmempool}typebounding_state=Bounding.stateletget_bounding_state{bounding_state;_}=bounding_stateletset_bounding_statestatebounding_state={statewithbounding_state}endendmoduleProduction_chain_store:CHAIN_STOREwithtypechain_store=Store.chain_store=structtypechain_store=Store.chain_storeletcontext=Store.Block.contextletchain_id=Store.Chain.chain_idendmoduleMake(Proto:Protocol_plugin.T):Twithtypeprotocol_operation=Proto.operationandtypechain_store=Store.chain_store=MakeAbstract(Production_chain_store)(Proto)(Prevalidator_bounding.Make(Proto))moduleInternal_for_tests=structmoduletypeCHAIN_STORE=CHAIN_STOREmoduleMake=MakeAbstractend