123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167(*****************************************************************************)(* *)(* Open Source License *)(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. <contact@tezos.com> *)(* Copyright (c) 2020-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. *)(* *)(*****************************************************************************)(* Tezos Protocol Implementation - Error Monad *)(*-- Error classification ----------------------------------------------------*)typeerror_category=[`Branch|`Temporary|`Permanent]include(TzCore:moduletypeofTzCorewithtypeerror_category:=error_category)includeTzMonadmoduleTzTrace=TzTrace(* We offer shorter names for monads. These short names only make sense in the
context of Tezos' error-monads which is why it is defined here. *)moduleTzresult_syntax=Traced_result_syntaxmoduleLwt_tzresult_syntax=Lwt_traced_result_syntaxtype'errortrace='errorTzTrace.tracetypeerror+=Exnofexnlet()=register_error_kind`Temporary~id:"failure"~title:"Exception"~description:"Exception safely wrapped in an error"~pp:(funppfs->Format.fprintfppf"@[<h 0>%a@]"Format.pp_print_texts)Data_encoding.(obj1(req"msg"string))(function|Exn(Failuremsg)->Somemsg|Exnexn->Some(Printexc.to_stringexn)|_->None)(funmsg->Exn(Failuremsg))leterror_withfmt=Format.kasprintf(funs->error(Exn(Failures)))fmtletfailwithfmt=Format.kasprintf(funs->fail(Exn(Failures)))fmtleterror_of_exne=Exnelettrace_of_exne=TzTrace.make@@error_of_exneleterror_with_exne=Error(trace_of_exne)letfail_with_exne=Lwt.return(error_with_exne)leterror_of_fmtfmt=Format.kasprintf(funstr->Exn(Failurestr))fmttypeerror+=Canceledlet()=register_error_kind`Temporary~id:"canceled"~title:"Canceled"~description:"A promise was unexpectedly canceled"~pp:(funf()->Format.pp_print_stringf"The promise was unexpectedly canceled")Data_encoding.unit(functionCanceled->Some()|_->None)(fun()->Canceled)letprotect_no_canceler?on_errort=letres=Lwt.catcht(funexn->fail(Exnexn))inres>>=function|Ok_->res|Errortrace->(matchon_errorwith|None->res|Someon_error->Lwt.catch(fun()->on_errortrace)(funexn->fail(Exnexn)))letprotect_canceler?on_errorcancelert=letcancellation=Lwt_canceler.when_cancelingcanceler>>=fun()->failCanceledinletres=Lwt.pick[cancellation;Lwt.catcht(funexn->fail(Exnexn))]inres>>=function|Ok_->res|Errortrace->(lettrace=ifLwt_canceler.canceledcancelerthenTzTrace.makeCanceledelsetraceinmatchon_errorwith|None->Lwt.return_errortrace|Someon_error->Lwt.catch(fun()->on_errortrace)(funexn->fail(Exnexn)))letprotect?on_error?cancelert=matchcancelerwith|None->protect_no_canceler?on_errort|Somecanceler->protect_canceler?on_errorcancelerttypeerror+=Timeoutlet()=register_error_kind`Temporary~id:"utils.Timeout"~title:"Timeout"~description:"Timeout"~pp:(funf()->Format.pp_print_stringf"The request has timed out")Data_encoding.unit(functionTimeout->Some()|_->None)(fun()->Timeout)letwith_timeout?(canceler=Lwt_canceler.create())timeoutf=lettarget=fcancelerinLwt.choose[timeout;(target>|=fun_->())]>>=fun()->ifLwt.statetarget<>Lwt.Sleepthen(Lwt.canceltimeout;target)elseLwt_canceler.cancelcanceler>>=function|Ok()|Error[]->failTimeout|Error(h::_)->raisehleterrs_tag=Tag.def~doc:"Errors""errs"pp_print_traceletcancel_with_exceptionscanceler=Lwt_canceler.cancelcanceler>>=function|Ok()|Error[]->Lwt.return_unit|Error(h::_)->raisehletcatch?catch_onlyf=TzLwtreslib.Result.catch_f?catch_onlyftrace_of_exnletcatch_e?catch_onlyf=TzLwtreslib.Result.catch_f?catch_onlyftrace_of_exn|>Result.joinletcatch_f?catch_onlyfexc_mapper=TzLwtreslib.Result.catch_f?catch_onlyf(funexc->TzTrace.make(exc_mapperexc))letcatch_s?catch_onlyf=TzLwtreslib.Result.catch_s?catch_onlyf>|=Result.map_errortrace_of_exnletcatch_es?catch_onlyf=TzLwtreslib.Result.catch_s?catch_onlyf>|=Result.map_errortrace_of_exn>|=Result.join