123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322(*****************************************************************************)(* *)(* Open Source License *)(* Copyright (c) 2021 Nomadic Labs <contact@nomadic-labs.com> *)(* Copyright (c) 2022 Trili Tech, <contact@trili.tech> *)(* *)(* 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. *)(* *)(*****************************************************************************)openSc_rollup_reprtypet={state_hash:State_hash.toption;tick:Sc_rollup_tick_repr.t}letequal{state_hash;tick}chunk2=Option.equalState_hash.equalstate_hashchunk2.state_hash&&Sc_rollup_tick_repr.equaltickchunk2.tickletencoding=letopenData_encodinginconv(fun{state_hash;tick}->(state_hash,tick))(fun(state_hash,tick)->{state_hash;tick})(obj2(opt"state"State_hash.encoding)(req"tick"Sc_rollup_tick_repr.encoding))typeerror+=|(* `Temporary *)Dissection_number_of_sections_mismatchof{expected:Z.t;given:Z.t;}|(* `Permanent *)Dissection_invalid_number_of_sectionsofZ.t|(* `Temporary *)Dissection_start_hash_mismatchof{expected:Sc_rollup_repr.State_hash.toption;given:Sc_rollup_repr.State_hash.toption;}|(* `Temporary *)Dissection_stop_hash_mismatchofSc_rollup_repr.State_hash.toption|(* `Temporary *)Dissection_edge_ticks_mismatchof{dissection_start_tick:Sc_rollup_tick_repr.t;dissection_stop_tick:Sc_rollup_tick_repr.t;chunk_start_tick:Sc_rollup_tick_repr.t;chunk_stop_tick:Sc_rollup_tick_repr.t;}|(* `Permanent *)Dissection_ticks_not_increasing|(* `Permanent *)Dissection_invalid_distributionofZ.t|(* `Permanent *)Dissection_invalid_successive_states_shapeletpp_state_hash=letopenFormatinpp_print_option~none:(funppf()->fprintfppf"None")State_hash.ppletpp_hash_optfmt=function|None->Format.fprintffmt"None"|Somex->Sc_rollup_repr.State_hash.ppfmtxletppppf{state_hash;tick}=letopenFormatinfprintfppf"State hash:%a@ Tick: %a"pp_state_hashstate_hashSc_rollup_tick_repr.pptickletdefault_check_sections_number~default_number_of_sections~number_of_sections~dist=letopenResult_syntaxinletnumber_of_sections=Z.of_intnumber_of_sectionsinletdefault_number_of_sections=Z.of_intdefault_number_of_sectionsinletshould_be_equal_toexpected=Dissection_number_of_sections_mismatch{expected;given=number_of_sections}inifCompare.Z.(default_number_of_sections<=dist)thenerror_unlessCompare.Z.(number_of_sections=default_number_of_sections)(should_be_equal_todefault_number_of_sections)elseifCompare.Z.(dist>Z.one)thenerror_unlessCompare.Z.(number_of_sections=dist)(should_be_equal_todist)elsetzfail(Dissection_invalid_number_of_sectionsnumber_of_sections)letdefault_check~section_maximum_size~check_sections_number~default_number_of_sections~start_chunk~stop_chunkdissection=letopenResult_syntaxinletnumber_of_sections=Compare.Int.max0(List.lengthdissection-1)inletdist=Sc_rollup_tick_repr.distancestart_chunk.tickstop_chunk.tickinlet*()=check_sections_number~default_number_of_sections~number_of_sections~distinlet*()=match(List.hddissection,List.last_optdissection)with|Some{state_hash=a;tick=a_tick},Some{state_hash=b;tick=b_tick}->let*()=error_unless(Option.equalState_hash.equalastart_chunk.state_hash&¬(Option.is_nonea))(Dissection_start_hash_mismatch{expected=start_chunk.state_hash;given=a})inlet*()=error_unless(not(Option.equalState_hash.equalbstop_chunk.state_hash))((* If the [b] state is equal to [stop_chunk], that means we
agree on the after state of the section. But, we're trying
to dispute it, it doesn't make sense. *)Dissection_stop_hash_mismatchstop_chunk.state_hash)inSc_rollup_tick_repr.(error_unless(a_tick=start_chunk.tick&&b_tick=stop_chunk.tick)(Dissection_edge_ticks_mismatch{dissection_start_tick=a_tick;dissection_stop_tick=b_tick;chunk_start_tick=start_chunk.tick;chunk_stop_tick=stop_chunk.tick;}))|_->(* This case is probably already handled by the
[Dissection_invalid_number_of_sections] returned above *)tzfail(Dissection_invalid_number_of_sections(Z.of_intnumber_of_sections))inletrectraversestates=matchstateswith|{state_hash=None;_}::{state_hash=Some_;_}::_->tzfailDissection_invalid_successive_states_shape|{tick;_}::({tick=next_tick;state_hash=_}asnext)::others->ifSc_rollup_tick_repr.(tick<next_tick)thenletincr=Sc_rollup_tick_repr.distanceticknext_tickinifZ.(leqincrsection_maximum_size)thentraverse(next::others)elsetzfail(Dissection_invalid_distributionsection_maximum_size)elsetzfailDissection_ticks_not_increasing|_->return()intraversedissectionlet()=letdescription="Mismatch in the number of sections in the dissection"inregister_error_kind`Temporary~id:"smart_rollup_dissection_number_of_sections_mismatch"~title:description~description~pp:(funppf(expected,given)->Format.fprintfppf"The number of sections must be equal to %a instead of %a"Z.pp_printexpectedZ.pp_printgiven)Data_encoding.(obj2(req"expected"n)(req"given"n))(function|Dissection_number_of_sections_mismatch{expected;given}->Some(expected,given)|_->None)(fun(expected,given)->Dissection_number_of_sections_mismatch{expected;given});letdescription="Invalid number of sections in the dissection"inregister_error_kind`Permanent~id:"smart_rollup_dissection_invalid_number_of_sections"~title:description~description~pp:(funppfn->Format.fprintfppf"A dissection with %a sections can never be valid"Z.pp_printn)Data_encoding.(obj1(req"value"n))(functionDissection_invalid_number_of_sectionsn->Somen|_->None)(funn->Dissection_invalid_number_of_sectionsn);letdescription="Mismatch in the start hash of the dissection"inregister_error_kind`Temporary~id:"smart_rollup_dissection_start_hash_mismatch"~title:description~description~pp:(funppf(given,expected)->matchgivenwith|None->Format.fprintfppf"The start hash must not be None"|Some_->Format.fprintfppf"The start hash should be equal to %a, but the provided hash is %a"pp_hash_optexpectedpp_hash_optgiven)Data_encoding.(obj2(req"expected"(optionSc_rollup_repr.State_hash.encoding))(req"given"(optionSc_rollup_repr.State_hash.encoding)))(function|Dissection_start_hash_mismatch{expected;given}->Some(expected,given)|_->None)(fun(expected,given)->Dissection_start_hash_mismatch{expected;given});letdescription="Mismatch in the stop hash of the dissection"inregister_error_kind`Temporary~id:"smart_rollup_dissection_stop_hash_mismatch"~title:description~description~pp:(funppfh->Format.fprintfppf"The stop hash should not be equal to %a"pp_hash_opth)Data_encoding.(obj1(req"hash"(optionSc_rollup_repr.State_hash.encoding)))(functionDissection_stop_hash_mismatchhopt->Somehopt|_->None)(funhopt->Dissection_stop_hash_mismatchhopt);letdescription="Mismatch in the edge ticks of the dissection"inregister_error_kind`Temporary~id:"smart_rollup_dissection_edge_ticks_mismatch"~title:description~description~pp:(funppf(dissection_start_tick,dissection_stop_tick,chunk_start_tick,chunk_stop_tick)->Sc_rollup_tick_repr.(Format.fprintfppf"We should have dissection_start_tick(%a) = %a and \
dissection_stop_tick(%a) = %a"ppdissection_start_tickppchunk_start_tickppdissection_stop_tickppchunk_stop_tick))Data_encoding.(obj4(req"dissection_start_tick"Sc_rollup_tick_repr.encoding)(req"dissection_stop_tick"Sc_rollup_tick_repr.encoding)(req"chunk_start_tick"Sc_rollup_tick_repr.encoding)(req"chunk_stop_tick"Sc_rollup_tick_repr.encoding))(function|Dissection_edge_ticks_mismatche->Some(e.dissection_start_tick,e.dissection_stop_tick,e.chunk_start_tick,e.chunk_stop_tick)|_->None)(fun(dissection_start_tick,dissection_stop_tick,chunk_start_tick,chunk_stop_tick)->Dissection_edge_ticks_mismatch{dissection_start_tick;dissection_stop_tick;chunk_start_tick;chunk_stop_tick;});letdescription="Ticks should only increase in dissection"inregister_error_kind`Permanent~id:"smart_rollup_dissection_ticks_not_increasing"~title:description~description~pp:(funppf()->Format.pp_print_stringppfdescription)Data_encoding.empty(functionDissection_ticks_not_increasing->Some()|_->None)(fun()->Dissection_ticks_not_increasing);register_error_kind`Permanent~id:"smart_rollup_dissection_invalid_distribution"~title:description~description~pp:(funppfmax->Format.fprintfppf"Maximum tick increment in a section cannot be more than %a ticks"Z.pp_printmax)Data_encoding.(obj1(req"section_max_size"n))(functionDissection_invalid_distributionmax->Somemax|_->None)(funmax->Dissection_invalid_distributionmax);letdescription="Cannot recover from a blocked state in a dissection"inregister_error_kind`Permanent~id:"smart_rollup_dissection_invalid_successive_states_shape"~title:description~description~pp:(funppf()->Format.pp_print_stringppfdescription)Data_encoding.empty(function|Dissection_invalid_successive_states_shape->Some()|_->None)(fun()->Dissection_invalid_successive_states_shape)