123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158(*****************************************************************************)(* *)(* Open Source License *)(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. <contact@tezos.com> *)(* Copyright (c) 2020 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]includeTzCoreincludeTzMonadmoduleTzTrace=TzTracetype'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))letgeneric_errorfmt=Format.kasprintf(funs->error(Exn(Failures)))fmtletfailwithfmt=Format.kasprintf(funs->fail(Exn(Failures)))fmtleterror_of_exne=TzTrace.make@@Exneleterror_exns=Error(TzTrace.make@@Exns)lettrace_exnexnf=trace(Exnexn)fletgeneric_tracefmt=Format.kasprintf(funstr->trace_exn(Failurestr))fmtletrecord_trace_exnexnf=record_trace(Exnexn)fletfailurefmt=Format.kasprintf(funstr->Exn(Failurestr))fmtletpp_exnppfexn=ppppf(Exnexn)typeerror+=Canceledlet()=register_error_kind`Temporary~id:"utils.Canceled"~title:"Canceled"~description:"Canceled"Data_encoding.unit(functionCanceled->Some()|_->None)(fun()->Canceled)let()=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_errorletcancel_with_exceptionscanceler=Lwt_canceler.cancelcanceler>>=function|Ok()|Error[]->Lwt.return_unit|Error(h::_)->raiseh