123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303(*****************************************************************************)(* *)(* 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. *)(* *)(*****************************************************************************)openProtocolmoduleProto_Nonce=Nonce(* Renamed otherwise is masked by Alpha_context *)openAlpha_contexttypet={predecessor:Block.t;state:validation_state*application_state;rev_operations:Operation.packedlist;rev_tickets:operation_receiptlist;header:Block_header.t;delegate:Account.t;constants:Constants.Parametric.t;}typeincremental=tletpredecessor{predecessor;_}=predecessorletheader{header;_}=headerletrev_tickets{rev_tickets;_}=rev_ticketsletvalidation_state{state=vs,_;_}=vsletlevelst=st.header.shell.levelletalpha_ctxt{state=_,application_state;_}=application_state.ctxtletrpc_contextst=letfitness=(headerst).shell.fitnessinletresult=Alpha_context.finalize(alpha_ctxtst)fitnessin{Environment.Updater.block_hash=Block_hash.zero;block_header={st.header.shellwithfitness=result.fitness};context=result.context;}letrpc_ctxt=newEnvironment.proto_rpc_context_of_directoryrpc_contextPlugin.RPC.rpc_servicesletset_alpha_ctxtstctxt={stwithstate=(fstst.state,{(sndst.state)withctxt})}letbegin_validation_and_applicationctxtchain_idmode~predecessor=letopenLwt_result_syntaxinlet*validation_state=begin_validationctxtchain_idmode~predecessorinlet*application_state=begin_applicationctxtchain_idmode~predecessorinreturn(validation_state,application_state)letbegin_construction?timestamp?seed_nonce_hash?(mempool_mode=false)?(policy=Block.By_round0)(predecessor:Block.t)=Block.get_next_baker~policypredecessor>>=?fun(delegate,_consensus_key,round,real_timestamp)->Account.finddelegate>>=?fundelegate->Round.of_intround|>Environment.wrap_tzresult>>?=funpayload_round->lettimestamp=Option.value~default:real_timestamptimestampin(matchseed_nonce_hashwith|Some_hash->returnseed_nonce_hash|None->(Plugin.RPC.current_level~offset:1lBlock.rpc_ctxtpredecessor>|=?function|{expected_commitment=true;_}->Some(fst(Proto_Nonce.generate()))|{expected_commitment=false;_}->None))>>=?funseed_nonce_hash->letshell:Block_header.shell_header={predecessor=predecessor.hash;proto_level=predecessor.header.shell.proto_level;validation_passes=predecessor.header.shell.validation_passes;fitness=predecessor.header.shell.fitness;timestamp;level=predecessor.header.shell.level;context=Context_hash.zero;operations_hash=Operation_list_list_hash.zero;}inBlock.Forge.contents?seed_nonce_hash~payload_hash:Block_payload_hash.zero~payload_roundshell>>=?funcontents->letmode=ifmempool_modethenPartial_construction{predecessor_hash=predecessor.hash;timestamp}elseletblock_header_data={Block_header.contents;signature=Signature.zero}inConstruction{predecessor_hash=predecessor.hash;timestamp;block_header_data}inletheader={Block_header.shell;protocol_data={contents;signature=Signature.zero}}inbegin_validation_and_applicationpredecessor.contextChain_id.zeromode~predecessor:predecessor.header.shell>|=funstate->Environment.wrap_tzresultstate>|?funstate->{predecessor;state;rev_operations=[];rev_tickets=[];header;delegate;constants=predecessor.constants;}letdetect_script_failure:typekind.kindApply_results.operation_metadata->_=letrecdetect_script_failure:typekind.kindApply_results.contents_result_list->_=letopenApply_resultsinletopenApply_operation_resultinletopenApply_internal_resultsinletdetect_script_failure_single(typekind)(Manager_operation_result{operation_result;internal_operation_results;_}:kindKind.managerApply_results.contents_result)=letdetect_script_failure(typekind)(result:(kind,_,_)operation_result)=matchresultwith|Applied_->Ok()|Skipped_->assertfalse|Backtracked(_,None)->(* there must be another error for this to happen *)Ok()|Backtracked(_,Someerrs)->Error(Environment.wrap_tztraceerrs)|Failed(_,errs)->Error(Environment.wrap_tztraceerrs)indetect_script_failureoperation_result>>?fun()->List.iter_e(fun(Internal_operation_result(_,r))->detect_script_failurer)internal_operation_resultsinfunction|Single_result(Manager_operation_result_asres)->detect_script_failure_singleres|Single_result_->Ok()|Cons_result(res,rest)->detect_script_failure_singleres>>?fun()->detect_script_failurerestinfun{contents}->detect_script_failurecontentsletcheck_operation_size?(check_size=true)op=ifcheck_sizethenletoperation_size=Data_encoding.Binary.lengthOperation.encoding_with_legacy_attestation_nameopinifoperation_size>Constants_repr.max_operation_data_lengththenraise(invalid_arg(Format.sprintf"The operation size is %d: it exceeds the constant maximum size \
%d."operation_sizeConstants_repr.max_operation_data_length))letvalidate_operation?expect_failure?check_sizestop=letopenLwt_result_syntaxincheck_operation_size?check_sizeop;letvalidation_state,application_state=st.stateinletoph=Operation.hash_packedopinlet*!res=validate_operationvalidation_stateophopinmatch(expect_failure,Environment.wrap_tzresultres)with|Some_,Ok_->failwith"Error expected while validating operation"|Somef,Errorerr->let*()=ferrinreturnst|None,Errorerr->failerr|None,Okvalidation_state->return{stwithstate=(validation_state,application_state)}letadd_operation?expect_failure?expect_apply_failure?allow_manager_failure?check_sizestop=letopenLwt_result_syntaxinletopenApply_resultsinlet*st=validate_operation?expect_failure?check_sizestopinmatchexpect_failurewith|Some_->(* The expected failure has already been observed in
[validate_operation]. *)returnst|None->(letvalidation_state,application_state=st.stateinletoph=Operation.hash_packedopinlet*!res=apply_operationapplication_stateophopinlet*?application_state,metadata=Environment.wrap_tzresultresinletst={stwithstate=(validation_state,application_state);rev_operations=op::st.rev_operations;rev_tickets=metadata::st.rev_tickets;}inmatchallow_manager_failurewith|Sometrue->returnst|None|Somefalse->(match(expect_apply_failure,metadata)with|None,No_operation_metadata->returnst|None,Operation_metadataresult->let*?()=detect_script_failureresultinreturnst|Some_,No_operation_metadata->failwith"Error expected while adding operation"|Somef,Operation_metadataresult->(matchdetect_script_failureresultwith|Ok_->failwith"Error expected while adding operation"|Errorerr->let*()=ferrinreturnst)))letfinalize_validation_and_application(validation_state,application_state)shell_header=letopenLwt_result_syntaxinlet*()=finalize_validationvalidation_stateinfinalize_applicationapplication_stateshell_headerletfinalize_blockst=letopenLwt_result_syntaxinletoperations=List.revst.rev_operationsinletoperations_hash=Operation_list_list_hash.compute[Operation_list_hash.compute(List.mapOperation.hash_packedoperations)]inletshell_header={st.header.shellwithlevel=Int32.succst.header.shell.level;operations_hash;}inlet*!res=finalize_validation_and_applicationst.state(Someshell_header)inlet*?validation_result,_=Environment.wrap_tzresultresinletoperations=List.revst.rev_operationsinletoperations_hash=Operation_list_list_hash.compute[Operation_list_hash.compute(List.mapOperation.hash_packedoperations)]inletheader={st.headerwithshell={st.header.shellwithlevel=Int32.succst.header.shell.level;operations_hash;fitness=validation_result.fitness;};}inlethash=Block_header.hashheaderinreturn{Block.hash;header;operations;context=validation_result.context;constants=st.constants;}letassert_validate_operation_failsexpect_failureopblock=letopenLwt_result_syntaxinlet*i=begin_constructionblockinlet*(_i:incremental)=validate_operation~expect_failureiopinreturn_unit