123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401(*****************************************************************************)(* *)(* 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. *)(* *)(*****************************************************************************)(* FIXME: https://gitlab.com/tezos/tezos/-/issues/4113
This file is part of the implementation of the new mempool, which
uses features of the protocol that only exist since Lima.
When you modify this file, consider whether you should also change
the files that implement the legacy mempool for Kathmandu. They all
start with the "legacy" prefix and will be removed when Lima is
activated on Mainnet. *)openShell_operationtypeerror+=|Operation_replacementof{old_hash:Operation_hash.t;new_hash:Operation_hash.t;}|Operation_conflictof{new_hash:Operation_hash.t}let()=register_error_kind`Temporary~id:"prevalidation.operation_replacement"~title:"Operation replacement"~description:"The operation has been replaced."~pp:(funppf(old_hash,new_hash)->Format.fprintfppf"The operation %a has been replaced with %a."Operation_hash.ppold_hashOperation_hash.ppnew_hash)(Data_encoding.obj2(Data_encoding.req"old_hash"Operation_hash.encoding)(Data_encoding.req"new_hash"Operation_hash.encoding))(function|Operation_replacement{old_hash;new_hash}->Some(old_hash,new_hash)|_->None)(fun(old_hash,new_hash)->Operation_replacement{old_hash;new_hash});register_error_kind`Temporary~id:"prevalidation.operation_conflict"~title:"Operation conflict"~description:"The operation cannot be added because the mempool already contains a \
conflicting operation."~pp:(funppfnew_hash->Format.fprintfppf"The operation %a cannot be added because the mempool already contains \
a conflicting operation that should not be replaced (e.g. an \
operation from the same manager with better fees)."Operation_hash.ppnew_hash)(Data_encoding.obj1(Data_encoding.req"new_hash"Operation_hash.encoding))(functionOperation_conflict{new_hash}->Somenew_hash|_->None)(funnew_hash->Operation_conflict{new_hash})moduletypeCHAIN_STORE=sigtypechain_storevalcontext:chain_store->Store.Block.t->Tezos_protocol_environment.Context.ttzresultLwt.tvalchain_id:chain_store->Chain_id.tendmoduletypeT=sigtypeprotocol_operationtypevalidation_statetypefilter_statetypefilter_configtypechain_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->filter_config->protocol_operationShell_operation.operation->[`Passed_prefilterofPrevalidator_pending_operations.priority|Prevalidator_classification.error_classification]Lwt.ttypereplacement=(Operation_hash.t*Prevalidator_classification.error_classification)optiontypeadd_result=t*protocol_operationoperation*Prevalidator_classification.classification*replacementvaladd_operation:t->filter_config->protocol_operationoperation->add_resultLwt.tvalremove_operation:t->Operation_hash.t->tmoduleInternal_for_tests:sigvalget_valid_operations:t->protocol_operationOperation_hash.Map.tvalget_filter_state:t->filter_statetypevalidation_infovalset_validation_info:t->validation_info->tendendmoduleMakeAbstract(Chain_store:CHAIN_STORE)(Filter:Shell_plugin.FILTER):Twithtypeprotocol_operation=Filter.Proto.operationandtypevalidation_state=Filter.Proto.validation_stateandtypefilter_state=Filter.Mempool.stateandtypefilter_config=Filter.Mempool.configandtypechain_store=Chain_store.chain_storeandtypeInternal_for_tests.validation_info=Filter.Proto.Mempool.validation_info=structmoduleProto=Filter.Prototypeprotocol_operation=Proto.operationtypevalidation_state=Proto.validation_statetypefilter_state=Filter.Mempool.statetypefilter_config=Filter.Mempool.configtypechain_store=Chain_store.chain_storetypeoperation=protocol_operationShell_operation.operationtypecreate_aux_t={validation_info:Proto.Mempool.validation_info;mempool:Proto.Mempool.t;head:Block_header.shell_header;context:Tezos_protocol_environment.Context.t;}letcreate_auxchain_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:`Lazyinreturn{validation_info;mempool;head;context}typet={validation_info:Proto.Mempool.validation_info;mempool:Proto.Mempool.t;filter_state:Filter.Mempool.state;}letcreatechain_store~head~timestamp=letopenLwt_result_syntaxinlet*{validation_info;mempool;head;context}=create_auxchain_storeheadtimestampinlet*filter_state=Filter.Mempool.initcontext~headinreturn{validation_info;mempool;filter_state}letflushchain_store~head~timestampold_state=letopenLwt_result_syntaxinlet*{validation_info;mempool;head;context=_}=create_auxchain_storeheadtimestampinlet*filter_state=Filter.Mempool.flushold_state.filter_state~headinreturn{validation_info;mempool;filter_state}letpre_filterstatefilter_configop=Filter.Mempool.pre_filter~filter_state:state.filter_statefilter_configop.protocoltypeerror_classification=Prevalidator_classification.error_classificationtypeclassification=Prevalidator_classification.classificationtypereplacement=(Operation_hash.t*error_classification)optiontypeadd_result=t*operation*classification*replacementletclassification_of_tracetrace=matchclassify_tracetracewith|Branch->`Branch_refusedtrace|Permanent->`Refusedtrace|Temporary->`Branch_delayedtrace|Outdated->`Outdatedtraceletproto_add_operation~conflict_handlerstateop:(Proto.Mempool.t*Proto.Mempool.add_result)tzresultLwt.t=Proto.Mempool.add_operation~check_signature:Compare.Int.(op.count_successful_prechecks<=0)~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)lettranslate_proto_add_result(proto_add_result:Proto.Mempool.add_result)op:(replacement,error_classification)result=letopenResultinmatchproto_add_resultwith|Added->return_none|Replaced{removed}->lettrace=[Operation_replacement{old_hash=removed;new_hash=op.hash}]inreturn_some(removed,`Outdatedtrace)|Unchanged->error(classification_of_trace[Operation_conflict{new_hash=op.hash}])(** Call [Filter.Mempool.add_operation_and_enforce_mempool_bound],
which ensures that the number of manager operations in the
mempool is bounded as specified in [filter_config].
The [state] argument is the prevalidation state (which has not
been modified yet). The [mempool] and [proto_add_result] are the
results of the protocol's [add_operation].
Maintaining this bound may require the removal of an operation
when the mempool was already full. In this case, this operation,
called [full_mempool_replacement], must also be removed from the
protocol's abstract [mempool].
Return the updated [state] (containing the updated protocol
[mempool]) and [filter_state], and the final [replacement], which
may have been mandated either by the protocol's [add_operation]
or by [Filter.Mempool.add_operation_and_enforce_mempool_bound]
(but not both: if the protocol already causes a replacement, then
the mempool is no longer full so there cannot be a
[full_mempool_replacement]. *)letenforce_mempool_bound_and_update_statesstatefilter_config(mempool,proto_add_result)op:(t*replacement,error_classification)resultLwt.t=letopenLwt_result_syntaxinlet*?proto_replacement=translate_proto_add_resultproto_add_resultopinlet*filter_state,full_mempool_replacement=Filter.Mempool.add_operation_and_enforce_mempool_bound?replace:(Option.mapfstproto_replacement)filter_configstate.filter_state(op.hash,op.protocol)inletmempool=matchfull_mempool_replacementwith|`No_replace->mempool|`Replace(replace_oph,_)->Proto.Mempool.remove_operationmempoolreplace_ophinletreplacement=match(proto_replacement,full_mempool_replacement)with|_,`No_replace->proto_replacement|None,`Replacerepl->Somerepl|Some_,`Replace_->(* If there is a [proto_replacement], it gets removed from the
mempool before adding [op] so the mempool cannot be full. *)assertfalseinreturn({statewithmempool;filter_state},replacement)letadd_operation_resultstatefilter_configop:(t*operation*classification*replacement)tzresultLwt.t=letopenLwt_result_syntaxinletconflict_handler=Filter.Mempool.conflict_handlerfilter_configinlet*proto_output=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. Therefore we increment its successful
precheck counter, so that any future signature check can be
skipped. *)letop=increment_successful_precheckopinlet*!res=enforce_mempool_bound_and_update_statesstatefilter_configproto_outputopinmatchreswith|Ok(state,replacement)->return(state,op,`Prechecked,replacement)|Errorerr_class->return(state,op,(err_class:>classification),None)letadd_operationstatefilter_configop:add_resultLwt.t=letopenLwt_syntaxinlet*res=protect(fun()->add_operation_resultstatefilter_configop)inmatchreswith|Okadd_result->returnadd_result|Errortrace->return(state,op,classification_of_tracetrace,None)letremove_operationstateoph=letmempool=Proto.Mempool.remove_operationstate.mempoolophinletfilter_state=Filter.Mempool.remove~filter_state:state.filter_stateophin{statewithmempool;filter_state}moduleInternal_for_tests=structletget_valid_operations{mempool;_}=Proto.Mempool.operationsmempoolletget_filter_state{filter_state;_}=filter_statetypevalidation_info=Proto.Mempool.validation_infoletset_validation_infostatevalidation_info={statewithvalidation_info}endendmoduleProduction_chain_store:CHAIN_STOREwithtypechain_store=Store.chain_store=structtypechain_store=Store.chain_storeletcontext=Store.Block.contextletchain_id=Store.Chain.chain_idendmoduleMake(Filter:Shell_plugin.FILTER):Twithtypeprotocol_operation=Filter.Proto.operationandtypevalidation_state=Filter.Proto.validation_stateandtypefilter_state=Filter.Mempool.stateandtypefilter_config=Filter.Mempool.configandtypechain_store=Store.chain_store=MakeAbstract(Production_chain_store)(Filter)moduleInternal_for_tests=structmoduletypeCHAIN_STORE=CHAIN_STOREmoduleMake=MakeAbstractend