123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269(*****************************************************************************)(* *)(* Open Source License *)(* Copyright (c) 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. *)(* *)(*****************************************************************************)openProtocolmoduleS=Dal_slot_reprmoduleSlot_index=Dal_slot_index_reprmoduleP=S.PagemoduleHist=S.HistorymoduleIhist=Hist.Internal_for_tests(** Error used below for functions that don't return their failures in the monad
error. *)typeerror+=Test_failureofstringlet()=letopenData_encodinginregister_error_kind`Permanent~id:(Protocol.name^"_test_failure")~title:"Test failure"~description:"Test failure."~pp:(funppfe->Format.fprintfppf"Test failure: %s"e)(obj1(req"error"string))(functionTest_failuree->Somee|_->None)(fune->Test_failuree)letmk_cryptoboxdal_params=letopenResult_syntaxinletparameters=Cryptobox.Internal_for_tests.parameters_initialisationdal_paramsinlet()=Cryptobox.Internal_for_tests.load_parametersparametersinmatchCryptobox.makedal_paramswith|Okdal->returndal|Error(`Fails)->fail[Test_failures]letderive_dal_parameters(reference:Cryptobox.parameters)~redundancy_factor~constants_divider={S.redundancy_factor;page_size=reference.page_size/constants_divider;slot_size=reference.slot_size/constants_divider;number_of_shards=reference.number_of_shards/constants_divider;}moduleMake(Parameters:sigvaldal_parameters:Alpha_context.Constants.Parametric.dalvalcryptobox:Cryptobox.tLazy.tend)=struct(* Some global constants. *)letparams=Parameters.dal_parameters.cryptobox_parametersletcryptobox=Parameters.cryptoboxletgenesis_history=Hist.genesisletgenesis_history_cache=Hist.History_cache.empty~capacity:3000Lletlevel_one=Raw_level_repr.(succroot)letlevel_ten=Raw_level_repr.(of_int32_exn10l)(* Helper functions. *)letget_historycacheh=Hist.History_cache.findhcache|>Lwt.returnletdal_mk_polynomial_from_slotslot_data=letopenResult_syntaxinletcryptobox=Lazy.forcecryptoboxinmatchCryptobox.polynomial_from_slotcryptoboxslot_datawith|Okp->returnp|Error(`Slot_wrong_sizes)->fail[Test_failure(Format.sprintf"polynomial_from_slot: Slot_wrong_size (%s)"s);]letdal_commitcryptoboxpolynomial=letopenResult_syntaxinmatchCryptobox.commitcryptoboxpolynomialwith|Okcm->returncm|Error(`Invalid_degree_strictly_less_than_expected_ascommit_error)->fail[Test_failure(Cryptobox.string_of_commit_errorcommit_error)]letdal_mk_prove_pagepolynomialpage_id=letopenResult_syntaxinletcryptobox=Lazy.forcecryptoboxinmatchCryptobox.prove_pagecryptoboxpolynomialpage_id.P.page_indexwith|Okp->returnp|Error`Page_index_out_of_range->fail[Test_failure"compute_proof_segment: Page_index_out_of_range"]|Error(`Invalid_degree_strictly_less_than_expected_ascommit_error)->fail[Test_failure(Cryptobox.string_of_commit_errorcommit_error)]letmk_slot?(level=level_one)?(index=Slot_index.zero)?(fill_function=fun_i->'x')()=letopenResult_syntaxinletslot_data=Bytes.initparams.slot_sizefill_functioninlet*polynomial=dal_mk_polynomial_from_slotslot_datainletcryptobox=Lazy.forcecryptoboxinlet*commitment=dal_commitcryptoboxpolynomialinreturn(slot_data,polynomial,S.Header.{id={published_level=level;index};commitment})letmk_page_idpublished_levelslot_indexpage_index=P.{slot_id={published_level;index=slot_index};page_index}letno_data=Some(fun~default_char:__->None)letmk_page_info?(default_char='x')?level?(page_index=P.Index.zero)?(custom_data=None)(slot:S.Header.t)polynomial=letopenResult_syntaxinletlevel=matchlevelwithNone->slot.id.published_level|Somelevel->levelinletpage_id=mk_page_idlevelslot.id.indexpage_indexinlet*page_proof=dal_mk_prove_pagepolynomialpage_idinmatchcustom_datawith|None->letpage_data=Bytes.makeparams.page_sizedefault_charinreturn(Some(page_data,page_proof),page_id)|Somemk_data->(matchmk_data~default_charparams.page_sizewith|None->return(None,page_id)|Somepage_data->return(Some(page_data,page_proof),page_id))letsucc_slot_indexindex=Option.value_fSlot_index.(of_int_opt~number_of_slots:Parameters.dal_parameters.number_of_slots(to_intindex+1))~default:(fun()->Slot_index.zero)letnext_charc=Char.(chr((codec+1)mod255))(** Auxiliary test function used by both unit and PBT tests: This function
produces a proof from the given information and verifies the produced result,
if any. The result of each step is checked with [check_produce_result] and
[check_verify_result], respectively. *)letproduce_and_verify_proof~check_produce?check_verify~get_historyskip_list~page_info~page_id=letopenLwt_result_syntaxinlet*!res=Hist.produce_proofparams~page_infopage_id~get_historyskip_list|>Lwt.mapEnvironment.wrap_tzresultinlet*()=check_producerespage_infoinmatchcheck_verifywith|None->return_unit|Somecheck_verify->let*?proof,_input_opt=resinletres=Hist.verify_proofparamspage_idskip_listproof|>Environment.wrap_tzresultincheck_verifyrespage_info(* Some check functions. *)(** Check that/if the returned content is the expected one. *)letassert_content_is~__LOC__~expectedreturned=Assert.equal~loc:__LOC__(Option.equalBytes.equal)"Returned %s doesn't match the expected one"(funfmtopt->matchoptwith|None->Format.fprintffmt"<None>"|Somebs->Format.fprintffmt"<Some:%s>"(Bytes.to_stringbs))returnedexpectedletexpected_datapage_infoproof_status=match(page_info,proof_status)with|Some(d,_p),`Confirmed->Somed|None,`Confirmed->assertfalse|_->Noneletproof_status_to_string=function|`Confirmed->"CONFIRMED"|`Unconfirmed->"UNCONFIRMED"letsuccessful_check_produce_result~__LOC__proof_statusrespage_info=letopenLwt_result_syntaxinlet*proof,input_opt=Assert.get_ok~__LOC__resinlet*()=ifHist.Internal_for_tests.proof_statement_isproofproof_statusthenreturn_unitelsefailwith"Expected to have a %s page proof. Got %a@."(proof_status_to_stringproof_status)(Hist.pp_proof~serialized:false)proofinassert_content_is~__LOC__input_opt~expected:(expected_datapage_infoproof_status)letfailing_check_produce_result~__LOC__~expected_errorres_page_info=Assert.proto_error~loc:__LOC__res(fune->match(e,expected_error)with|Hist.Dal_proof_errors,Hist.Dal_proof_errorexpected->String.equalsexpected|(Hist.Unexpected_page_size{expected_size=e1;page_size=p1},Hist.Unexpected_page_size{expected_size=e2;page_size=p2})->e1=e2&&p1=p2|_->false)letsuccessful_check_verify_result~__LOC__proof_statusrespage_info=letopenLwt_result_syntaxinlet*content=Assert.get_ok~__LOC__resinletexpected=expected_datapage_infoproof_statusinassert_content_is~__LOC__~expectedcontent(** Checks if the two provided Page.proof are equal. *)leteq_page_proof=letbytes_opt_of_proofpage_proof=Data_encoding.Binary.to_bytes_optP.proof_encodingpage_proofinfunpp1pp2->Option.equalBytes.equal(bytes_opt_of_proofpp1)(bytes_opt_of_proofpp2)letslot_confirmed_but_page_data_not_provided~__LOC__=failing_check_produce_result~__LOC__~expected_error:(Hist.Dal_proof_error"The page ID's slot is confirmed, but no page content and proof are \
provided.")letslot_not_confirmed_but_page_data_provided~__LOC__=failing_check_produce_result~__LOC__~expected_error:(Hist.Dal_proof_error"The page ID's slot is not confirmed, but page content and proof \
are provided.")end