123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268(*****************************************************************************)(* *)(* 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. *)(* *)(*****************************************************************************)typeerror+=No_identity_fileofstringtypeerror+=Insufficient_proof_of_workof{expected:float}typeerror+=|Identity_mismatchof{filename:string;peer_id:Tezos_crypto.Crypto_box.Public_key_hash.t;}typeerror+=|Identity_keys_mismatchof{filename:string;expected_key:Tezos_crypto.Crypto_box.public_key;}let()=register_error_kind`Permanent~id:"main.identity.no_file"~title:"No identity file"~description:"The node identity file cannot be found"~pp:(funppffile->Format.fprintfppf"Cannot read the identity file: `%s`. See `%s identity --help` on how \
to generate an identity."fileSys.argv.(0))Data_encoding.(obj1(req"file"string))(functionNo_identity_filefile->Somefile|_->None)(funfile->No_identity_filefile)let()=register_error_kind`Permanent~id:"main.identity.insufficient_proof_of_work"~title:"Insufficient proof of work"~description:"The proof of work embedded by the current identity is not sufficient"~pp:(funppfexpected->Format.fprintfppf"The current identity does not embed a sufficient stamp of \
proof-of-work. (expected level: %.2f). See `%s identity --help` on \
how to generate a new identity."expectedSys.argv.(0))Data_encoding.(obj1(req"expected"float))(function|Insufficient_proof_of_work{expected}->Someexpected|_->None)(funexpected->Insufficient_proof_of_work{expected})let()=register_error_kind`Permanent~id:"main.identity.identity_mismatch"~title:"Identity mismatch"~description:"The identity (public key hash) does not match the keys provided with it"~pp:(funppf(file,public_key_hash)->Format.fprintfppf"The current identity (public key hash) does not match the keys in %s.\n\
\ Expected identity %a."fileTezos_crypto.Crypto_box.Public_key_hash.pppublic_key_hash)Data_encoding.(obj2(req"file"string)(req"public_key_hash"Tezos_crypto.Crypto_box.Public_key_hash.encoding))(function|Identity_mismatch{filename;peer_id}->Some(filename,peer_id)|_->None)(fun(filename,peer_id)->Identity_mismatch{filename;peer_id})let()=register_error_kind`Permanent~id:"main.identity.identity_keys_mismatch"~title:"Identity keys mismatch"~description:"The current identity file has non-matching keys (secret key/ public key \
pair is not valid)"~pp:(funppf(file,public_key)->Format.fprintfppf"The current identity file %s has non-matching keys (secret key/ \
public key pair is not valid).\n\
\ Expected public key %a."fileTezos_crypto.Crypto_box.pp_pkpublic_key)Data_encoding.(obj2(req"file"string)(req"public_key"Tezos_crypto.Crypto_box.public_key_encoding))(function|Identity_keys_mismatch{filename;expected_key}->Some(filename,expected_key)|_->None)(fun(filename,expected_key)->Identity_keys_mismatch{filename;expected_key})letread?expected_powfilename=letopenLwt_result_syntaxinlet*!file_exists=Lwt_unix.file_existsfilenameinifnotfile_existsthentzfail(No_identity_filefilename)elselet*json=Lwt_utils_unix.Json.read_filefilenameinletid=Data_encoding.Json.destructP2p_identity.encodingjsoninletpkh=Tezos_crypto.Crypto_box.hashid.public_keyin(* check public_key hash *)ifnot(Tezos_crypto.Crypto_box.Public_key_hash.equalpkhid.peer_id)thentzfail(Identity_mismatch{filename;peer_id=pkh})(* check public/private keys correspondence *)elseifnotTezos_crypto.Crypto_box.(equal(neuterizeid.secret_key)id.public_key)thentzfail(Identity_keys_mismatch{filename;expected_key=id.public_key})else(* check PoW level *)matchexpected_powwith|None->returnid|Someexpected->lettarget=Tezos_crypto.Crypto_box.make_pow_targetexpectedinifnot(Tezos_crypto.Crypto_box.check_proof_of_workid.public_keyid.proof_of_work_stamptarget)thentzfail(Insufficient_proof_of_work{expected})elsereturnidtypeerror+=Existent_identity_fileofstringlet()=register_error_kind`Permanent~id:"main.identity.existent_file"~title:"Cannot overwrite identity file"~description:"Cannot implicitly overwrite the current identity file"~pp:(funppffile->Format.fprintfppf"Cannot implicitly overwrite the current identity file: '%s'. See `%s \
identity --help` on how to generate a new identity."fileSys.argv.(0))Data_encoding.(obj1(req"file"string))(functionExistent_identity_filefile->Somefile|_->None)(funfile->Existent_identity_filefile)letwrite~check_data_dirfileidentity=letopenLwt_result_syntaxinifSys.file_existsfilethentzfail(Existent_identity_filefile)elselet*()=check_data_dir~data_dir:(Filename.dirnamefile)inLwt_utils_unix.Json.write_filefile(Data_encoding.Json.constructP2p_identity.encodingidentity)letgenerate_with_animationppftarget=letopenLwt_syntaxinletduration=1200/Animation.number_of_framesinAnimation.make_with_animationppf~make:(funcount->Lwt.catch(fun()->let+id=P2p_identity.generate_with_bound~max:counttargetinOkid)(function|Not_found->Lwt.return@@Errorcount|exc->Lwt.reraiseexc))~on_retry:(funtimecount->letms=int_of_float(Mtime.Span.to_mstime)inletcount=ifms<=1thenmax10(count*10)elsecount*duration/msinlet*()=Lwt.pause()inLwt.returncount)10000letgenerate~check_data_diridentity_fileexpected_pow=letopenLwt_result_syntaxinifSys.file_existsidentity_filethentzfail(Existent_identity_fileidentity_file)elselettarget=Tezos_crypto.Crypto_box.make_pow_targetexpected_powinFormat.eprintf"Generating a new identity... (level: %.2f) "expected_pow;let*!id=generate_with_animationFormat.err_formattertargetinlet*()=write~check_data_diridentity_fileidinFormat.eprintf"Stored the new identity (%a) into '%s'.@."P2p_peer.Id.ppid.peer_ididentity_file;returnidmoduleEvent=structincludeInternal_event.Simpleletsection=["node";"identity"]letread_identity=declare_1~section~name:"read_identity"~msg:"read identity file"~level:Notice("peer_id",P2p_peer.Id.encoding)letgenerating_identity=declare_0~section~name:"generating_identity"~msg:"generating an identity file"~level:Notice()letidentity_generated=declare_1~section~name:"identity_generated"~msg:"identity file generated"~level:Notice("peer_id",P2p_peer.Id.encoding)endletinit~check_data_dir~identity_file~expected_pow=letopenLwt_result_syntaxinifSys.file_existsidentity_filethenlet*identity=readidentity_fileinlet*!()=Event.(emitread_identity)identity.peer_idinreturnidentityelselet*!()=Event.(emitgenerating_identity)()inlet*identity=generate~check_data_diridentity_fileexpected_powinlet*!()=Event.(emitidentity_generated)identity.peer_idinreturnidentity