From d1d75e2a7bdfc2ca8c664e646835feb9a6ad2246 Mon Sep 17 00:00:00 2001 From: Andrea Cerone Date: Wed, 26 Apr 2023 13:43:29 +0100 Subject: [PATCH 1/9] Dac/Daemon: remove unused function --- src/lib_dac_node/daemon.ml | 32 -------------------------------- 1 file changed, 32 deletions(-) diff --git a/src/lib_dac_node/daemon.ml b/src/lib_dac_node/daemon.ml index 1589861fd3e4..8ab2405cf781 100644 --- a/src/lib_dac_node/daemon.ml +++ b/src/lib_dac_node/daemon.ml @@ -53,38 +53,6 @@ let daemonize handlers = return_unit) |> lwt_map_error (List.fold_left (fun acc errs -> errs @ acc) []) -let get_all_committee_members_keys pkhs ~threshold wallet_cctxt = - let open Lwt_result_syntax in - let* wallet_accounts = - List.map_es - (fun pkh -> - Wallet_account.Legacy.of_committee_member_address pkh wallet_cctxt) - pkhs - in - let*! valid_wallet_accounts = - List.filter_s - (fun Wallet_account.Legacy.{public_key_hash; secret_key_uri_opt; _} -> - if Option.is_some secret_key_uri_opt then Lwt.return true - else - let*! () = - Event.(emit committee_member_cannot_sign public_key_hash) - in - Lwt.return false) - wallet_accounts - in - let recovered_keys = List.length valid_wallet_accounts in - let*! () = - (* We emit a warning if the threshold of dac accounts needed to sign a - root page hash is not reached. We also emit a warning for each DAC - account whose secret key URI was not recovered. - We do not stop the dac node at this stage. - *) - if recovered_keys < threshold then - Event.(emit dac_threshold_not_reached (recovered_keys, threshold)) - else Event.(emit dac_is_ready) () - in - return wallet_accounts - (* FIXME: https://gitlab.com/tezos/tezos/-/issues/3605 Improve general architecture, handle L1 disconnection etc *) -- GitLab From 90d4b54f4d02fbbed9de4327b9d3bbbb5e7dfee5 Mon Sep 17 00:00:00 2001 From: Andrea Cerone Date: Tue, 14 Mar 2023 17:17:43 +0000 Subject: [PATCH 2/9] Dac/RPC server: improve signature for directory registration functions --- src/lib_dac_node/RPC_server.ml | 88 ++++++++++++++++++++-------------- 1 file changed, 53 insertions(+), 35 deletions(-) diff --git a/src/lib_dac_node/RPC_server.ml b/src/lib_dac_node/RPC_server.ml index 9aa77288cc26..cc8403a98d32 100644 --- a/src/lib_dac_node/RPC_server.ml +++ b/src/lib_dac_node/RPC_server.ml @@ -208,18 +208,12 @@ let register_get_certificate ctx dac_plugin = RPC_services.get_certificate (fun root_hash () () -> handle_get_certificate dac_plugin ctx root_hash) -let register_get_missing_page ctx dac_plugin = - match Node_context.mode ctx with - | Legacy _ | Observer _ -> - add_service - Tezos_rpc.Directory.register1 - RPC_services.get_missing_page - (fun root_hash () () -> - let open Lwt_result_syntax in - let page_store = Node_context.get_page_store ctx in - let*? cctxt = Node_context.get_coordinator_client ctx in - handle_get_missing_page cctxt page_store dac_plugin root_hash) - | Coordinator _ | Committee_member _ -> Fun.id +let register_get_missing_page dac_plugin page_store cctxt = + add_service + Tezos_rpc.Directory.register1 + RPC_services.get_missing_page + (fun root_hash () () -> + handle_get_missing_page cctxt page_store dac_plugin root_hash) module Coordinator = struct let handle_post_preimage dac_plugin page_store hash_streamer payload = @@ -317,9 +311,10 @@ module Coordinator = struct (fun () payload -> handle_post_preimage dac_plugin page_store hash_streamer payload) - let dynamic_rpc_dir dac_plugin (node_ctxt : Node_context.t) = + let dynamic_rpc_dir dac_plugin _ro_store _rw_store page_store cctxt + coordinator_node_ctxt = let modal_node_ctxt = - match Node_context.mode node_ctxt with + match Node_context.mode coordinator_node_ctxt with | Coordinator modal_node_ctxt -> modal_node_ctxt (* We only pass [Node_context.t] values whose mode is [Coordinator _] to this function. *) @@ -332,10 +327,10 @@ module Coordinator = struct let public_keys_opt = Node_context.Coordinator.public_keys_opt modal_node_ctxt in - let page_store = Node_context.get_page_store node_ctxt in - let cctxt = Node_context.get_tezos_node_cctxt node_ctxt in let certificate_streamers = modal_node_ctxt.certificate_streamers in - let ro_store = Node_context.get_node_store node_ctxt Store_sigs.Read_only in + let ro_store = + Node_context.get_node_store coordinator_node_ctxt Store_sigs.Read_only + in let committee_members = modal_node_ctxt.committee_members in Tezos_rpc.Directory.empty |> register_coordinator_post_preimage dac_plugin hash_streamer page_store @@ -347,28 +342,27 @@ module Coordinator = struct ro_store certificate_streamers committee_members - |> register_put_dac_member_signature node_ctxt cctxt - |> register_get_certificate node_ctxt dac_plugin + |> register_put_dac_member_signature coordinator_node_ctxt cctxt + |> register_get_certificate coordinator_node_ctxt dac_plugin end module Committee_member = struct - let dynamic_rpc_dir dac_plugin (node_ctxt : Node_context.t) = - let page_store = Node_context.get_page_store node_ctxt in + let dynamic_rpc_dir dac_plugin page_store = Tezos_rpc.Directory.empty |> register_get_preimage dac_plugin page_store end module Observer = struct - let dynamic_rpc_dir dac_plugin (node_ctxt : Node_context.t) = - let page_store = Node_context.get_page_store node_ctxt in + let dynamic_rpc_dir dac_plugin coordinator_cctxt page_store = Tezos_rpc.Directory.empty |> register_get_preimage dac_plugin page_store - |> register_get_missing_page node_ctxt dac_plugin + |> register_get_missing_page dac_plugin page_store coordinator_cctxt end module Legacy = struct - let dynamic_rpc_dir dac_plugin (node_ctxt : Node_context.t) = + let dynamic_rpc_dir dac_plugin _ro_store _rw_store page_store cctxt + legacy_node_ctxt = let modal_node_ctxt = - match Node_context.mode node_ctxt with + match Node_context.mode legacy_node_ctxt with | Legacy modal_node_ctxt -> modal_node_ctxt (* We only pass [Node_context.t] values whose mode is [Coordinator _] to this function. *) @@ -379,8 +373,13 @@ module Legacy = struct let secret_key_uris_opt = Node_context.Legacy.secret_key_uris_opt modal_node_ctxt in - let page_store = Node_context.get_page_store node_ctxt in - let cctxt = Node_context.get_tezos_node_cctxt node_ctxt in + let register_get_missing_page = + match modal_node_ctxt.coordinator_cctxt with + | None -> fun dir -> dir + | Some cctxt -> + fun dir -> + dir |> register_get_missing_page dac_plugin page_store cctxt + in Tezos_rpc.Directory.empty |> register_post_store_preimage dac_plugin @@ -391,20 +390,39 @@ module Legacy = struct |> register_get_verify_signature dac_plugin public_keys_opt |> register_get_preimage dac_plugin page_store |> register_monitor_root_hashes hash_streamer - |> register_put_dac_member_signature node_ctxt cctxt - |> register_get_certificate node_ctxt dac_plugin - |> register_get_missing_page node_ctxt dac_plugin + |> register_put_dac_member_signature legacy_node_ctxt cctxt + |> register_get_certificate legacy_node_ctxt dac_plugin + |> register_get_missing_page end let start ~rpc_address ~rpc_port node_ctxt = let open Lwt_syntax in + let ro_store = Node_context.get_node_store node_ctxt Store_sigs.Read_only in + let rw_store = Node_context.get_node_store node_ctxt Store_sigs.Read_write in + let page_store = Node_context.get_page_store node_ctxt in + let cctxt = Node_context.get_tezos_node_cctxt node_ctxt in let register_dynamic_rpc dac_plugin = match Node_context.mode node_ctxt with - | Coordinator _ -> Coordinator.dynamic_rpc_dir dac_plugin node_ctxt + | Coordinator _ -> + Coordinator.dynamic_rpc_dir + dac_plugin + ro_store + rw_store + page_store + cctxt + node_ctxt | Committee_member _ -> - Committee_member.dynamic_rpc_dir dac_plugin node_ctxt - | Observer _ -> Observer.dynamic_rpc_dir dac_plugin node_ctxt - | Legacy _ -> Legacy.dynamic_rpc_dir dac_plugin node_ctxt + Committee_member.dynamic_rpc_dir dac_plugin page_store + | Observer {coordinator_cctxt; _} -> + Observer.dynamic_rpc_dir dac_plugin coordinator_cctxt page_store + | Legacy _ -> + Legacy.dynamic_rpc_dir + dac_plugin + ro_store + rw_store + page_store + cctxt + node_ctxt in let dir = Tezos_rpc.Directory.register_dynamic_directory -- GitLab From c24314ec8f584db06f1c4b3b27b9eba01d5b78f5 Mon Sep 17 00:00:00 2001 From: Andrea Cerone Date: Tue, 14 Mar 2023 17:21:19 +0000 Subject: [PATCH 3/9] Dac/Signature manager: move errors out of Coordinator module --- src/lib_dac_node/signature_manager.ml | 164 +++++++++++-------------- src/lib_dac_node/signature_manager.mli | 21 ++-- 2 files changed, 83 insertions(+), 102 deletions(-) diff --git a/src/lib_dac_node/signature_manager.ml b/src/lib_dac_node/signature_manager.ml index 5fef6f9aa1d2..ba80579937b5 100644 --- a/src/lib_dac_node/signature_manager.ml +++ b/src/lib_dac_node/signature_manager.ml @@ -24,10 +24,17 @@ (* *) (*****************************************************************************) +module Aggregate_signature = Tezos_crypto.Aggregate_signature + type error += | Cannot_convert_root_page_hash_to_bytes of string | Cannot_compute_aggregate_signature of string | Public_key_for_witness_not_available of int * string + | Public_key_is_non_dac_member of Aggregate_signature.public_key_hash + | Signature_verification_failed of + (Aggregate_signature.public_key * Aggregate_signature.t * string) + | Public_key_for_dac_member_not_available of + Aggregate_signature.public_key_hash let () = register_error_kind @@ -78,7 +85,72 @@ let () = (function | Public_key_for_witness_not_available (index, hash) -> Some (index, hash) | _ -> None) - (fun (index, hash) -> Public_key_for_witness_not_available (index, hash)) + (fun (index, hash) -> Public_key_for_witness_not_available (index, hash)) ; + register_error_kind + `Permanent + ~id:"Public_key_is_non_dac_member" + ~title:"Public key hash is not a valid dac member" + ~description: + "Public key hash is not associated with any Dac member registered with \ + this Dac coordinator." + ~pp:(fun ppf dac_member_pkh -> + Format.fprintf + ppf + "Expected public key to be an active Dac committee member but was not: \ + %s" + (Tezos_crypto.Aggregate_signature.Public_key_hash.to_short_b58check + dac_member_pkh)) + Data_encoding.( + obj1 + (req + "public_key_hash" + Tezos_crypto.Aggregate_signature.Public_key_hash.encoding)) + (function + | Public_key_is_non_dac_member dac_member_pkh -> Some dac_member_pkh + | _ -> None) + (fun dac_member_pkh -> Public_key_is_non_dac_member dac_member_pkh) ; + register_error_kind + `Permanent + ~id:"signature_verification_failed" + ~title:"Signature verification failed" + ~description:"Signature verification failed." + ~pp:(fun ppf (pk, signature, root_hash) -> + let pk = Aggregate_signature.Public_key.to_short_b58check pk in + let signature = Aggregate_signature.to_short_b58check signature in + Format.fprintf + ppf + "Could not verify signature \"%s\" given public key \"%s\" and \ + root_hash \"%s\": Signature verification failed." + pk + signature + root_hash) + Data_encoding.( + obj3 + (req "public_key" Aggregate_signature.Public_key.encoding) + (req "signature" Aggregate_signature.encoding) + (req "root_hash" (string' Plain))) + (function + | Signature_verification_failed (pk, signature, root_hash) -> + Some (pk, signature, root_hash) + | _ -> None) + (function + | pk, signature, root_hash -> + Signature_verification_failed (pk, signature, root_hash)) ; + register_error_kind + `Permanent + ~id:"public_key_of_dac_member_not_available" + ~title:"Public key of dac member not available." + ~description:"Public key of dac member not available." + ~pp:(fun ppf b58_hash -> + Format.fprintf ppf "Public key of dac member %s not available." b58_hash) + Data_encoding.(obj1 (req "hash" (string' Plain))) + (function + | Public_key_for_dac_member_not_available hash -> + Some (Aggregate_signature.Public_key_hash.to_b58check hash) + | _ -> None) + (fun hash -> + Public_key_for_dac_member_not_available + (Aggregate_signature.Public_key_hash.of_b58check_exn hash)) let bind_es (f : 'a -> 'b option tzresult Lwt.t) v_opt = let open Lwt_result_syntax in @@ -169,96 +241,6 @@ let verify dac_plugin ~public_keys_opt root_page_hash signature witnesses = @@ Tezos_crypto.Aggregate_signature.aggregate_check pk_msg_list signature module Coordinator = struct - module Aggregate_signature = Tezos_crypto.Aggregate_signature - - type error += - | Public_key_is_non_dac_member of Aggregate_signature.public_key_hash - | Signature_verification_failed of - (Aggregate_signature.public_key * Aggregate_signature.t * string) - | Public_key_for_dac_member_not_available of - Aggregate_signature.public_key_hash - | Unknown_root_hash of string - - let () = - register_error_kind - `Permanent - ~id:"Public_key_is_non_dac_member" - ~title:"Public key hash is not a valid dac member" - ~description: - "Public key hash is not associated with any Dac member registered with \ - this Dac coordinator." - ~pp:(fun ppf dac_member_pkh -> - Format.fprintf - ppf - "Expected public key to be an active Dac committee member but was \ - not: %s" - (Tezos_crypto.Aggregate_signature.Public_key_hash.to_short_b58check - dac_member_pkh)) - Data_encoding.( - obj1 - (req - "public_key_hash" - Tezos_crypto.Aggregate_signature.Public_key_hash.encoding)) - (function - | Public_key_is_non_dac_member dac_member_pkh -> Some dac_member_pkh - | _ -> None) - (fun dac_member_pkh -> Public_key_is_non_dac_member dac_member_pkh) ; - register_error_kind - `Permanent - ~id:"signature_verification_failed" - ~title:"Signature verification failed" - ~description:"Signature verification failed." - ~pp:(fun ppf (pk, signature, root_hash) -> - let pk = Aggregate_signature.Public_key.to_short_b58check pk in - let signature = Aggregate_signature.to_short_b58check signature in - Format.fprintf - ppf - "Could not verify signature \"%s\" given public key \"%s\" and \ - root_hash \"%s\": Signature verification failed." - pk - signature - root_hash) - Data_encoding.( - obj3 - (req "public_key" Aggregate_signature.Public_key.encoding) - (req "signature" Aggregate_signature.encoding) - (req "root_hash" (string' Plain))) - (function - | Signature_verification_failed (pk, signature, root_hash) -> - Some (pk, signature, root_hash) - | _ -> None) - (function - | pk, signature, root_hash -> - Signature_verification_failed (pk, signature, root_hash)) ; - register_error_kind - `Permanent - ~id:"public_key_of_dac_member_not_available" - ~title:"Public key of dac member not available." - ~description:"Public key of dac member not available." - ~pp:(fun ppf b58_hash -> - Format.fprintf ppf "Public key of dac member %s not available." b58_hash) - Data_encoding.(obj1 (req "hash" (string' Plain))) - (function - | Public_key_for_dac_member_not_available hash -> - Some (Aggregate_signature.Public_key_hash.to_b58check hash) - | _ -> None) - (fun hash -> - Public_key_for_dac_member_not_available - (Aggregate_signature.Public_key_hash.of_b58check_exn hash)) ; - register_error_kind - `Permanent - ~id:"unknown_root_hash" - ~title:"No data associated to the provided root hash" - ~description:"There is no data in storage for this root hash" - ~pp:(fun ppf hash -> - Format.fprintf - ppf - "There is no data available for the root page hash %s" - hash) - Data_encoding.(obj1 (req "hash" (string' Plain))) - (function Unknown_root_hash hash -> Some hash | _ -> None) - (fun hash -> Unknown_root_hash hash) - let verify_signature ((module Plugin) : Dac_plugin.t) pk signature root_hash = let root_hash_bytes = Dac_plugin.hash_to_bytes root_hash in fail_unless diff --git a/src/lib_dac_node/signature_manager.mli b/src/lib_dac_node/signature_manager.mli index 5e9288cc2c11..33f89827c3c0 100644 --- a/src/lib_dac_node/signature_manager.mli +++ b/src/lib_dac_node/signature_manager.mli @@ -29,6 +29,14 @@ type error += | Cannot_convert_root_page_hash_to_bytes of string | Cannot_compute_aggregate_signature of string | Public_key_for_witness_not_available of int * string + | Public_key_is_non_dac_member of + Tezos_crypto.Aggregate_signature.public_key_hash + | Signature_verification_failed of + (Tezos_crypto.Aggregate_signature.public_key + * Tezos_crypto.Aggregate_signature.t + * string) + | Public_key_for_dac_member_not_available of + Tezos_crypto.Aggregate_signature.public_key_hash (* [sign_root_hash dac_pliugin cctx dac_sk_uris_opt root_hash] is legacy function that returns an aggregate signature over [root_hash] and a bitmap of witnesses where @@ -55,17 +63,8 @@ val verify : (** Module that exposes signature operations necsesary when running in [Configuration.Coordinator] mode.*) module Coordinator : sig - type error += - | Public_key_is_non_dac_member of - Tezos_crypto.Aggregate_signature.public_key_hash - | Signature_verification_failed of - (Tezos_crypto.Aggregate_signature.public_key - * Tezos_crypto.Aggregate_signature.t - * string) - | Public_key_for_dac_member_not_available of - Tezos_crypto.Aggregate_signature.public_key_hash - | Unknown_root_hash of string - + (* TODO: https://gitlab.com/tezos/tezos/-/issues/4997 + Verify that root hash is one that the coordinator has *) (** [handle_put_dac_member_signature ctxt cctxt dac_members_pkh dac_member_signature] does the following procedure: 1. Checks that the [root_hash] provided inside [Signature_repr.t] is known. Fails if unknown -- GitLab From 219ad220f3fee2d7a0b2d1a771ada18016a9d91f Mon Sep 17 00:00:00 2001 From: Andrea Cerone Date: Tue, 14 Mar 2023 17:26:15 +0000 Subject: [PATCH 4/9] Dac/Node context: retrieve committee members by operating mode --- src/lib_dac_node/node_context.ml | 10 ++++++++++ src/lib_dac_node/node_context.mli | 6 ++++++ 2 files changed, 16 insertions(+) diff --git a/src/lib_dac_node/node_context.ml b/src/lib_dac_node/node_context.ml index 47416656e5b0..9499cb4da711 100644 --- a/src/lib_dac_node/node_context.ml +++ b/src/lib_dac_node/node_context.ml @@ -63,6 +63,11 @@ module Coordinator = struct List.map (fun Wallet_account.Coordinator.{public_key_opt; _} -> public_key_opt) t.committee_members + + let committee_members t = + List.map + (fun Wallet_account.Coordinator.{public_key_hash; _} -> public_key_hash) + t.committee_members end module Committee_member = struct @@ -196,6 +201,11 @@ module Legacy = struct List.map (fun Wallet_account.Legacy.{secret_key_uri_opt; _} -> secret_key_uri_opt) t.committee_members + + let committee_members t = + List.map + (fun Wallet_account.Legacy.{public_key_hash; _} -> public_key_hash) + t.committee_members end type mode = diff --git a/src/lib_dac_node/node_context.mli b/src/lib_dac_node/node_context.mli index 132354bfaebc..f04902d0b090 100644 --- a/src/lib_dac_node/node_context.mli +++ b/src/lib_dac_node/node_context.mli @@ -50,6 +50,9 @@ module Coordinator : sig data availability committee of [t]. *) val public_keys_opt : t -> Tezos_crypto.Aggregate_signature.public_key option list + + val committee_members : + t -> Tezos_crypto.Aggregate_signature.public_key_hash list end (** [Committee_member] defines a partial [Node_context.t] that is available @@ -111,6 +114,9 @@ module Legacy : sig (** [secret_key_uris_opt] return the list of optional secret key URIs of the committee members of [t]. *) val secret_key_uris_opt : t -> Client_keys.aggregate_sk_uri option list + + val committee_members : + t -> Tezos_crypto.Aggregate_signature.public_key_hash list end (** Operating mode specific fraction of a [Node_context.t] *) -- GitLab From b52522e0506a9dfdcb3e1d567ee8a8144309c8ba Mon Sep 17 00:00:00 2001 From: Andrea Cerone Date: Tue, 14 Mar 2023 17:49:59 +0000 Subject: [PATCH 5/9] Dac node/Rpc server: operating mode specific signature update registration --- src/lib_dac_node/RPC_server.ml | 83 ++++++++++++++++---------- src/lib_dac_node/signature_manager.ml | 25 ++------ src/lib_dac_node/signature_manager.mli | 17 ++++-- 3 files changed, 68 insertions(+), 57 deletions(-) diff --git a/src/lib_dac_node/RPC_server.ml b/src/lib_dac_node/RPC_server.ml index cc8403a98d32..5d0060ea8c24 100644 --- a/src/lib_dac_node/RPC_server.ml +++ b/src/lib_dac_node/RPC_server.ml @@ -192,16 +192,6 @@ let register_monitor_root_hashes hash_streamer dir = Monitor_services.S.root_hashes (fun () () () -> handle_monitor_root_hashes hash_streamer) -let register_put_dac_member_signature ctx cctxt = - add_service - Tezos_rpc.Directory.register0 - RPC_services.put_dac_member_signature - (fun () dac_member_signature -> - Signature_manager.Coordinator.handle_put_dac_member_signature - ctx - cctxt - dac_member_signature) - let register_get_certificate ctx dac_plugin = add_service Tezos_rpc.Directory.register1 @@ -304,15 +294,31 @@ module Coordinator = struct | Ok (next, shutdown) -> Tezos_rpc.Answer.return_stream {next; shutdown} | Error e -> Tezos_rpc.Answer.fail e) - let register_coordinator_post_preimage dac_plugin hash_streamer page_store = + let register_post_preimage dac_plugin hash_streamer page_store = add_service Tezos_rpc.Directory.register0 RPC_services.Coordinator.post_preimage (fun () payload -> handle_post_preimage dac_plugin page_store hash_streamer payload) - let dynamic_rpc_dir dac_plugin _ro_store _rw_store page_store cctxt - coordinator_node_ctxt = + let register_put_dac_member_signature ctx dac_plugin certificate_streamers_opt + rw_node_store page_store cctxt = + add_service + Tezos_rpc.Directory.register0 + RPC_services.put_dac_member_signature + (fun () dac_member_signature -> + Signature_manager.Coordinator.handle_put_dac_member_signature + Node_context.Coordinator.committee_members + ctx + dac_plugin + certificate_streamers_opt + rw_node_store + page_store + cctxt + dac_member_signature) + + let dynamic_rpc_dir dac_plugin rw_store page_store cctxt + (coordinator_node_ctxt : Node_context.t) = let modal_node_ctxt = match Node_context.mode coordinator_node_ctxt with | Coordinator modal_node_ctxt -> modal_node_ctxt @@ -328,21 +334,24 @@ module Coordinator = struct Node_context.Coordinator.public_keys_opt modal_node_ctxt in let certificate_streamers = modal_node_ctxt.certificate_streamers in - let ro_store = - Node_context.get_node_store coordinator_node_ctxt Store_sigs.Read_only - in let committee_members = modal_node_ctxt.committee_members in Tezos_rpc.Directory.empty - |> register_coordinator_post_preimage dac_plugin hash_streamer page_store + |> register_post_preimage dac_plugin hash_streamer page_store |> register_get_verify_signature dac_plugin public_keys_opt |> register_get_preimage dac_plugin page_store |> register_monitor_root_hashes hash_streamer |> register_monitor_certificate dac_plugin - ro_store + rw_store certificate_streamers committee_members - |> register_put_dac_member_signature coordinator_node_ctxt cctxt + |> register_put_dac_member_signature + modal_node_ctxt + dac_plugin + (Some certificate_streamers) + rw_store + page_store + cctxt |> register_get_certificate coordinator_node_ctxt dac_plugin end @@ -359,8 +368,23 @@ module Observer = struct end module Legacy = struct - let dynamic_rpc_dir dac_plugin _ro_store _rw_store page_store cctxt - legacy_node_ctxt = + let register_put_dac_member_signature ctx dac_plugin rw_node_store page_store + cctxt = + add_service + Tezos_rpc.Directory.register0 + RPC_services.put_dac_member_signature + (fun () dac_member_signature -> + Signature_manager.Coordinator.handle_put_dac_member_signature + Node_context.Legacy.committee_members + ctx + dac_plugin + None + rw_node_store + page_store + cctxt + dac_member_signature) + + let dynamic_rpc_dir dac_plugin rw_store page_store cctxt legacy_node_ctxt = let modal_node_ctxt = match Node_context.mode legacy_node_ctxt with | Legacy modal_node_ctxt -> modal_node_ctxt @@ -390,14 +414,18 @@ module Legacy = struct |> register_get_verify_signature dac_plugin public_keys_opt |> register_get_preimage dac_plugin page_store |> register_monitor_root_hashes hash_streamer - |> register_put_dac_member_signature legacy_node_ctxt cctxt + |> register_put_dac_member_signature + modal_node_ctxt + dac_plugin + rw_store + page_store + cctxt |> register_get_certificate legacy_node_ctxt dac_plugin |> register_get_missing_page end let start ~rpc_address ~rpc_port node_ctxt = let open Lwt_syntax in - let ro_store = Node_context.get_node_store node_ctxt Store_sigs.Read_only in let rw_store = Node_context.get_node_store node_ctxt Store_sigs.Read_write in let page_store = Node_context.get_page_store node_ctxt in let cctxt = Node_context.get_tezos_node_cctxt node_ctxt in @@ -406,7 +434,6 @@ let start ~rpc_address ~rpc_port node_ctxt = | Coordinator _ -> Coordinator.dynamic_rpc_dir dac_plugin - ro_store rw_store page_store cctxt @@ -416,13 +443,7 @@ let start ~rpc_address ~rpc_port node_ctxt = | Observer {coordinator_cctxt; _} -> Observer.dynamic_rpc_dir dac_plugin coordinator_cctxt page_store | Legacy _ -> - Legacy.dynamic_rpc_dir - dac_plugin - ro_store - rw_store - page_store - cctxt - node_ctxt + Legacy.dynamic_rpc_dir dac_plugin rw_store page_store cctxt node_ctxt in let dir = Tezos_rpc.Directory.register_dynamic_directory diff --git a/src/lib_dac_node/signature_manager.ml b/src/lib_dac_node/signature_manager.ml index ba80579937b5..7cf248793181 100644 --- a/src/lib_dac_node/signature_manager.ml +++ b/src/lib_dac_node/signature_manager.ml @@ -373,27 +373,12 @@ module Coordinator = struct return () else return () - let handle_put_dac_member_signature ctx cctxt committee_member_signature = + let handle_put_dac_member_signature get_committee_members ctx dac_plugin + certificate_streamers_opt rw_node_store page_store cctxt + committee_member_signature = + let committee_members = get_committee_members ctx in let open Lwt_result_syntax in - let* certificate_streamers_opt = - match Node_context.mode ctx with - (* TODO: https://gitlab.com/tezos/tezos/-/issues/5292 - Make type non optional when Legacy mode has been removed. *) - | Node_context.Coordinator {certificate_streamers; _} -> - return @@ Some certificate_streamers - | Legacy _ -> return None - | _ -> - (* TODO: https://gitlab.com/tezos/tezos/-/issues/5370 - This line will never be executed as - [handle_put_dac_member_signature] is only invoked when the - DAC node is running in either coordinator or legacy mode. - *) - failwith "Operation not supported for operating mode" - in - let*? dac_plugin = Node_context.get_dac_plugin ctx in - let page_store = Node_context.get_page_store ctx in - let*? committee_members = Node_context.get_committee_members ctx in - let rw_node_store = Node_context.get_node_store ctx Store_sigs.Read_write in + let ((module Plugin) : Dac_plugin.t) = dac_plugin in let Signature_repr.{root_hash; _} = committee_member_signature in let* () = check_coordinator_knows_root_hash dac_plugin page_store root_hash diff --git a/src/lib_dac_node/signature_manager.mli b/src/lib_dac_node/signature_manager.mli index 33f89827c3c0..73c202a8b32d 100644 --- a/src/lib_dac_node/signature_manager.mli +++ b/src/lib_dac_node/signature_manager.mli @@ -65,19 +65,24 @@ val verify : module Coordinator : sig (* TODO: https://gitlab.com/tezos/tezos/-/issues/4997 Verify that root hash is one that the coordinator has *) - (** [handle_put_dac_member_signature ctxt cctxt dac_members_pkh dac_member_signature] - does the following procedure: + (** [handle_put_dac_member_signature dac_plugin ro_store rw_store page_store + cctxt dac_members_pkh dac_member_signature] does the following procedure: 1. Checks that the [root_hash] provided inside [Signature_repr.t] is known. Fails if unknown - 1. Checks that the [dac_member_signature.signer_pkh] is currently a Dac member. - 2. Checks that the dac member has not yet signed. If already signed, then noop + 2. Checks that the [dac_member_signature.signer_pkh] is currently a Dac member. + 3. Checks that the dac member has not yet signed. If already signed, then noop and return. - 3. Otherwise: + 4. Otherwise: 1. Verify the signature against the root hash and signer's public key. 2. Add signature to [Signature_store] 3. Update the aggregate signature in [Aggregate_signature_store] *) val handle_put_dac_member_signature : - Node_context.t -> + ('a -> Tezos_crypto.Aggregate_signature.public_key_hash list) -> + 'a -> + Dac_plugin.t -> + Certificate_streamers.t option -> + Store_sigs.rw Store.Irmin_store.t -> + Page_store.Filesystem.t -> #Client_context.wallet -> Signature_repr.t -> unit tzresult Lwt.t -- GitLab From 21902200d46687070a76ec95deced07af1034793 Mon Sep 17 00:00:00 2001 From: Andrea Cerone Date: Tue, 14 Mar 2023 18:00:50 +0000 Subject: [PATCH 6/9] Dac/Signature manager: improve state of modules --- src/lib_dac_node/RPC_server.ml | 17 +- src/lib_dac_node/signature_manager.ml | 426 +++++++++++++------------ src/lib_dac_node/signature_manager.mli | 56 ++-- 3 files changed, 271 insertions(+), 228 deletions(-) diff --git a/src/lib_dac_node/RPC_server.ml b/src/lib_dac_node/RPC_server.ml index 5d0060ea8c24..0e372df99ba0 100644 --- a/src/lib_dac_node/RPC_server.ml +++ b/src/lib_dac_node/RPC_server.ml @@ -90,7 +90,11 @@ let handle_post_store_preimage dac_plugin cctxt dac_sk_uris page_store data in let* signature, witnesses = - Signature_manager.sign_root_hash dac_plugin cctxt dac_sk_uris root_hash + Signature_manager.Legacy.sign_root_hash + dac_plugin + cctxt + dac_sk_uris + root_hash in let raw_root_hash = Dac_plugin.hash_to_raw root_hash in let*! external_message = @@ -301,17 +305,15 @@ module Coordinator = struct (fun () payload -> handle_post_preimage dac_plugin page_store hash_streamer payload) - let register_put_dac_member_signature ctx dac_plugin certificate_streamers_opt - rw_node_store page_store cctxt = + let register_put_dac_member_signature ctx dac_plugin rw_node_store page_store + cctxt = add_service Tezos_rpc.Directory.register0 RPC_services.put_dac_member_signature (fun () dac_member_signature -> Signature_manager.Coordinator.handle_put_dac_member_signature - Node_context.Coordinator.committee_members ctx dac_plugin - certificate_streamers_opt rw_node_store page_store cctxt @@ -348,7 +350,6 @@ module Coordinator = struct |> register_put_dac_member_signature modal_node_ctxt dac_plugin - (Some certificate_streamers) rw_store page_store cctxt @@ -374,11 +375,9 @@ module Legacy = struct Tezos_rpc.Directory.register0 RPC_services.put_dac_member_signature (fun () dac_member_signature -> - Signature_manager.Coordinator.handle_put_dac_member_signature - Node_context.Legacy.committee_members + Signature_manager.Legacy.handle_put_dac_member_signature ctx dac_plugin - None rw_node_store page_store cctxt diff --git a/src/lib_dac_node/signature_manager.ml b/src/lib_dac_node/signature_manager.ml index 7cf248793181..8b35e08a5299 100644 --- a/src/lib_dac_node/signature_manager.ml +++ b/src/lib_dac_node/signature_manager.ml @@ -30,10 +30,10 @@ type error += | Cannot_convert_root_page_hash_to_bytes of string | Cannot_compute_aggregate_signature of string | Public_key_for_witness_not_available of int * string - | Public_key_is_non_dac_member of Aggregate_signature.public_key_hash + | Public_key_is_non_committee_member of Aggregate_signature.public_key_hash | Signature_verification_failed of (Aggregate_signature.public_key * Aggregate_signature.t * string) - | Public_key_for_dac_member_not_available of + | Public_key_for_committee_member_not_available of Aggregate_signature.public_key_hash let () = @@ -70,14 +70,16 @@ let () = `Permanent ~id:"public_key_of_witness_not_available" ~title: - "Public key of witness dac member not available for verifying signature" + "Public key of witness committee member not available for verifying \ + signature" ~description: - "Public key of witness dac member not available for verifying signature" + "Public key of witness committee member not available for verifying \ + signature" ~pp:(fun ppf (witness_index, b58_hash) -> Format.fprintf ppf - "Public key of dac member %d not available for verifying signature of \ - root page hash %s" + "Public key of committee member %d not available for verifying \ + signature of root page hash %s" witness_index b58_hash) Data_encoding.( @@ -88,27 +90,28 @@ let () = (fun (index, hash) -> Public_key_for_witness_not_available (index, hash)) ; register_error_kind `Permanent - ~id:"Public_key_is_non_dac_member" - ~title:"Public key hash is not a valid dac member" + ~id:"Public_key_is_non_committee_member" + ~title:"Public key hash is not a committee member" ~description: - "Public key hash is not associated with any Dac member registered with \ - this Dac coordinator." - ~pp:(fun ppf dac_member_pkh -> + "Public key hash is not associated with any committee member registered \ + with this Dac coordinator." + ~pp:(fun ppf committee_member_pkh -> Format.fprintf ppf - "Expected public key to be an active Dac committee member but was not: \ - %s" + "Expected public key to be an active committee member but was not: %s" (Tezos_crypto.Aggregate_signature.Public_key_hash.to_short_b58check - dac_member_pkh)) + committee_member_pkh)) Data_encoding.( obj1 (req "public_key_hash" Tezos_crypto.Aggregate_signature.Public_key_hash.encoding)) (function - | Public_key_is_non_dac_member dac_member_pkh -> Some dac_member_pkh + | Public_key_is_non_committee_member committee_member_pkh -> + Some committee_member_pkh | _ -> None) - (fun dac_member_pkh -> Public_key_is_non_dac_member dac_member_pkh) ; + (fun committee_member_pkh -> + Public_key_is_non_committee_member committee_member_pkh) ; register_error_kind `Permanent ~id:"signature_verification_failed" @@ -138,18 +141,21 @@ let () = Signature_verification_failed (pk, signature, root_hash)) ; register_error_kind `Permanent - ~id:"public_key_of_dac_member_not_available" - ~title:"Public key of dac member not available." - ~description:"Public key of dac member not available." + ~id:"public_key_of_committee_member_not_available" + ~title:"Public key of committee member not available." + ~description:"Public key of committee member not available." ~pp:(fun ppf b58_hash -> - Format.fprintf ppf "Public key of dac member %s not available." b58_hash) + Format.fprintf + ppf + "Public key of committee member %s not available." + b58_hash) Data_encoding.(obj1 (req "hash" (string' Plain))) (function - | Public_key_for_dac_member_not_available hash -> + | Public_key_for_committee_member_not_available hash -> Some (Aggregate_signature.Public_key_hash.to_b58check hash) | _ -> None) (fun hash -> - Public_key_for_dac_member_not_available + Public_key_for_committee_member_not_available (Aggregate_signature.Public_key_hash.of_b58check_exn hash)) let bind_es (f : 'a -> 'b option tzresult Lwt.t) v_opt = @@ -189,28 +195,6 @@ let compute_signatures_with_witnesses rev_indexed_signatures = ([], Z.zero) rev_indexed_signatures -let sign_root_hash ((module Plugin) : Dac_plugin.t) cctxt dac_sk_uris root_hash - = - let open Lwt_result_syntax in - let bytes_to_sign = - Data_encoding.Binary.to_bytes_opt Plugin.encoding root_hash - in - let root_hash = Plugin.to_hex root_hash in - match bytes_to_sign with - | None -> tzfail @@ Cannot_convert_root_page_hash_to_bytes root_hash - | Some bytes_to_sign -> ( - let* rev_indexed_signatures = - rev_collect_indexed_signatures cctxt dac_sk_uris bytes_to_sign - in - let* signatures, witnesses = - compute_signatures_with_witnesses rev_indexed_signatures - in - match - Tezos_crypto.Aggregate_signature.aggregate_signature_opt signatures - with - | None -> tzfail @@ Cannot_compute_aggregate_signature root_hash - | Some signature -> return @@ (signature, witnesses)) - let verify dac_plugin ~public_keys_opt root_page_hash signature witnesses = let open Lwt_result_syntax in let ((module Plugin) : Dac_plugin.t) = dac_plugin in @@ -240,176 +224,218 @@ let verify dac_plugin ~public_keys_opt root_page_hash signature witnesses = return @@ Tezos_crypto.Aggregate_signature.aggregate_check pk_msg_list signature -module Coordinator = struct - let verify_signature ((module Plugin) : Dac_plugin.t) pk signature root_hash = - let root_hash_bytes = Dac_plugin.hash_to_bytes root_hash in - fail_unless - (Aggregate_signature.check pk signature root_hash_bytes) - (Signature_verification_failed (pk, signature, Plugin.to_hex root_hash)) +let verify_signature ((module Plugin) : Dac_plugin.t) pk signature root_hash = + let root_hash_bytes = Dac_plugin.hash_to_bytes root_hash in + fail_unless + (Aggregate_signature.check pk signature root_hash_bytes) + (Signature_verification_failed (pk, signature, Plugin.to_hex root_hash)) - let add_dac_member_signature dac_plugin signature_store - Signature_repr.{root_hash; signer_pkh; signature} = - let open Lwt_result_syntax in - let*? root_hash = Dac_plugin.raw_to_hash dac_plugin root_hash in - Store.Signature_store.add - signature_store - ~primary_key:root_hash - ~secondary_key:signer_pkh - signature +let add_dac_member_signature dac_plugin signature_store + Signature_repr.{root_hash; signer_pkh; signature} = + let open Lwt_result_syntax in + let*? root_hash = Dac_plugin.raw_to_hash dac_plugin root_hash in + Store.Signature_store.add + signature_store + ~primary_key:root_hash + ~secondary_key:signer_pkh + signature - let rev_find_indexed_signatures node_store dac_members_pk root_hash = - let open Lwt_result_syntax in - List.rev_mapi_es - (fun index dac_member_pk -> - let+ (signature_opt : Aggregate_signature.t option) = - Store.Signature_store.find - node_store - ~primary_key:root_hash - ~secondary_key:dac_member_pk - in - Option.map (fun signature -> (index, signature)) signature_opt) - dac_members_pk +let rev_find_indexed_signatures node_store dac_members_pkh root_hash = + let open Lwt_result_syntax in + List.rev_mapi_es + (fun index dac_member_pk -> + let+ (signature_opt : Aggregate_signature.t option) = + Store.Signature_store.find + node_store + ~primary_key:root_hash + ~secondary_key:dac_member_pk + in + Option.map (fun signature -> (index, signature)) signature_opt) + dac_members_pkh - let update_aggregate_sig_store node_store dac_members_pk_opt root_hash = - let open Lwt_result_syntax in - let* rev_indexed_signature = - rev_find_indexed_signatures node_store dac_members_pk_opt root_hash - in - let* signatures, witnesses = - compute_signatures_with_witnesses rev_indexed_signature - in - match - Tezos_crypto.Aggregate_signature.aggregate_signature_opt signatures - with - | None -> - tzfail - @@ Cannot_compute_aggregate_signature - (Hex.show @@ Dac_plugin.hash_to_hex root_hash) - | Some aggregate_signature -> - let* () = - Store.Certificate_store.add - node_store - root_hash - Store.{aggregate_signature; witnesses} - in - return @@ (aggregate_signature, witnesses) +let update_aggregate_sig_store node_store dac_members_pk_opt root_hash = + let open Lwt_result_syntax in + let* rev_indexed_signature = + rev_find_indexed_signatures node_store dac_members_pk_opt root_hash + in + let* signatures, witnesses = + compute_signatures_with_witnesses rev_indexed_signature + in + let final_signature = + Tezos_crypto.Aggregate_signature.aggregate_signature_opt signatures + in + match final_signature with + | None -> + tzfail + @@ Cannot_compute_aggregate_signature + (Hex.show @@ Dac_plugin.hash_to_hex root_hash) + | Some aggregate_signature -> + let* () = + Store.Certificate_store.add + node_store + root_hash + Store.{aggregate_signature; witnesses} + in + return @@ (aggregate_signature, witnesses) - let check_dac_member_has_signed signature_store root_hash dac_member_pkh = - let open Lwt_result_syntax in - let* dac_member_has_signed = - Store.Signature_store.mem - signature_store - ~primary_key:root_hash - ~secondary_key:dac_member_pkh - in - return dac_member_has_signed +let check_dac_member_has_signed signature_store root_hash dac_member_pkh = + Store.Signature_store.mem + signature_store + ~primary_key:root_hash + ~secondary_key:dac_member_pkh - let check_is_dac_member dac_committee signer_pkh = - Option.is_some - @@ List.find - (fun pkh -> Aggregate_signature.Public_key_hash.equal signer_pkh pkh) - dac_committee +let check_is_dac_member dac_committee signer_pkh = + Option.is_some + @@ List.find + (fun pkh -> Aggregate_signature.Public_key_hash.equal signer_pkh pkh) + dac_committee - let check_coordinator_knows_root_hash dac_plugin page_store raw_root_hash = - let open Lwt_result_syntax in - let ((module Plugin) : Dac_plugin.t) = dac_plugin in - let*? root_hash = Dac_plugin.raw_to_hash dac_plugin raw_root_hash in - let*! has_payload = - Page_store.Filesystem.mem (module Plugin) page_store root_hash +let check_coordinator_knows_root_hash dac_plugin page_store root_hash = + let open Lwt_result_syntax in + let ((module Plugin) : Dac_plugin.t) = dac_plugin in + let*! has_payload = + Page_store.Filesystem.mem (module Plugin) page_store root_hash + in + match has_payload with + | Error _ -> + tzfail + @@ Page_store.Cannot_read_page_from_page_storage (Plugin.to_hex root_hash) + (* Return an HTTP 404 error when hash provided in signature is unknown *) + | Ok false -> raise Not_found + | Ok true -> return () + +let should_update_certificate dac_plugin cctxt ro_node_store committee_members + Signature_repr.{signer_pkh; root_hash; signature} = + let open Lwt_result_syntax in + let ((module Plugin) : Dac_plugin.t) = dac_plugin in + let*? root_hash = Dac_plugin.raw_to_hash dac_plugin root_hash in + let* () = + fail_unless + (check_is_dac_member committee_members signer_pkh) + (Public_key_is_non_committee_member signer_pkh) + in + let* pub_key_opt = Wallet_cctxt_helpers.get_public_key cctxt signer_pkh in + let* pub_key = + Option.fold_f + ~none:(fun () -> + tzfail (Public_key_for_committee_member_not_available signer_pkh)) + ~some:return + pub_key_opt + in + let* dac_member_has_signed = + check_dac_member_has_signed ro_node_store root_hash signer_pkh + in + if dac_member_has_signed then return false + else + let* () = verify_signature dac_plugin pub_key signature root_hash in + return true + +let stream_certificate_update dac_plugin committee_members + (Certificate_repr.{root_hash; _} as certificate) certificate_streamers = + let open Result_syntax in + let* () = + Certificate_streamers.push + dac_plugin + certificate_streamers + root_hash + certificate + in + if + Certificate_repr.all_committee_members_have_signed + committee_members + certificate + then + let _ = + Certificate_streamers.close dac_plugin certificate_streamers root_hash in - match has_payload with - | Error _ -> - tzfail - @@ Page_store.Cannot_read_page_from_page_storage - (Plugin.to_hex root_hash) - (* Return an HTTP 404 error when hash provided in signature is unknown *) - | Ok false -> raise Not_found - | Ok true -> return () + return () + else return () - let should_update_certificate dac_plugin cctxt ro_node_store committee_members - Signature_repr.{signer_pkh; root_hash; signature} = - let ((module Plugin) : Dac_plugin.t) = dac_plugin in - let open Lwt_result_syntax in - let*? root_hash = Dac_plugin.raw_to_hash dac_plugin root_hash in +let handle_put_dac_member_signature dac_plugin certificate_streamers_opt + rw_node_store page_store cctxt committee_members committee_member_signature + = + let open Lwt_result_syntax in + let ((module Plugin) : Dac_plugin.t) = dac_plugin in + let Signature_repr.{root_hash = raw_root_hash; _} = + committee_member_signature + in + let*? root_hash = Dac_plugin.raw_to_hash dac_plugin raw_root_hash in + let* () = check_coordinator_knows_root_hash dac_plugin page_store root_hash in + let* should_update_certificate = + should_update_certificate + dac_plugin + cctxt + rw_node_store + committee_members + committee_member_signature + in + if should_update_certificate then let* () = - fail_unless - (check_is_dac_member committee_members signer_pkh) - (Public_key_is_non_dac_member signer_pkh) + add_dac_member_signature + dac_plugin + rw_node_store + committee_member_signature in - let* pub_key_opt = Wallet_cctxt_helpers.get_public_key cctxt signer_pkh in - let* pub_key = - Option.fold_f - ~none:(fun () -> - tzfail (Public_key_for_dac_member_not_available signer_pkh)) - ~some:return - pub_key_opt + let* aggregate_signature, witnesses = + update_aggregate_sig_store rw_node_store committee_members root_hash in - let* dac_member_has_signed = - check_dac_member_has_signed ro_node_store root_hash signer_pkh + let*? () = + Option.iter_e + (stream_certificate_update + dac_plugin + committee_members + Certificate_repr. + {root_hash = raw_root_hash; aggregate_signature; witnesses}) + certificate_streamers_opt in - if dac_member_has_signed then return false - else - let* () = verify_signature dac_plugin pub_key signature root_hash in - return true + return () + else return () - let stream_certificate_update dac_plugin committee_members - (Certificate_repr.{root_hash; _} as certificate) certificate_streamers = - let open Result_syntax in - let* () = - Certificate_streamers.push - dac_plugin - certificate_streamers - root_hash - certificate - in - if - Certificate_repr.all_committee_members_have_signed - committee_members - certificate - then - let _ = - Certificate_streamers.close dac_plugin certificate_streamers root_hash - in - return () - else return () +module Coordinator = struct + let handle_put_dac_member_signature ctx dac_plugin rw_node_store page_store + cctxt dac_member_signature = + let committee_members = Node_context.Coordinator.committee_members ctx in + handle_put_dac_member_signature + dac_plugin + (Some ctx.certificate_streamers) + rw_node_store + page_store + cctxt + committee_members + dac_member_signature +end - let handle_put_dac_member_signature get_committee_members ctx dac_plugin - certificate_streamers_opt rw_node_store page_store cctxt - committee_member_signature = - let committee_members = get_committee_members ctx in +module Legacy = struct + let sign_root_hash ((module P) : Dac_plugin.t) cctxt dac_sk_uris root_hash = let open Lwt_result_syntax in - let ((module Plugin) : Dac_plugin.t) = dac_plugin in - let Signature_repr.{root_hash; _} = committee_member_signature in - let* () = - check_coordinator_knows_root_hash dac_plugin page_store root_hash + let bytes_to_sign = + Data_encoding.Binary.to_bytes_opt P.encoding root_hash in - let* should_update_certificate = - should_update_certificate - dac_plugin - cctxt - rw_node_store - committee_members - committee_member_signature - in - if should_update_certificate then - let* () = - add_dac_member_signature - dac_plugin - rw_node_store - committee_member_signature - in - let*? root_hash' = Dac_plugin.raw_to_hash dac_plugin root_hash in - let* aggregate_signature, witnesses = - update_aggregate_sig_store rw_node_store committee_members root_hash' - in - let*? () = - Option.iter_e - (stream_certificate_update - dac_plugin - committee_members - Certificate_repr.{root_hash; aggregate_signature; witnesses}) - certificate_streamers_opt - in - return () - else return () + let root_hash = P.to_hex root_hash in + match bytes_to_sign with + | None -> tzfail @@ Cannot_convert_root_page_hash_to_bytes root_hash + | Some bytes_to_sign -> ( + let* rev_indexed_signatures = + rev_collect_indexed_signatures cctxt dac_sk_uris bytes_to_sign + in + let* signatures, witnesses = + compute_signatures_with_witnesses rev_indexed_signatures + in + match + Tezos_crypto.Aggregate_signature.aggregate_signature_opt signatures + with + | None -> tzfail @@ Cannot_compute_aggregate_signature root_hash + | Some signature -> return @@ (signature, witnesses)) + + let handle_put_dac_member_signature ctx dac_plugin rw_node_store page_store + cctxt dac_member_signature = + let committee_members = Node_context.Legacy.committee_members ctx in + handle_put_dac_member_signature + dac_plugin + None + rw_node_store + page_store + cctxt + committee_members + dac_member_signature end diff --git a/src/lib_dac_node/signature_manager.mli b/src/lib_dac_node/signature_manager.mli index 73c202a8b32d..9afa9f5bb76a 100644 --- a/src/lib_dac_node/signature_manager.mli +++ b/src/lib_dac_node/signature_manager.mli @@ -29,25 +29,15 @@ type error += | Cannot_convert_root_page_hash_to_bytes of string | Cannot_compute_aggregate_signature of string | Public_key_for_witness_not_available of int * string - | Public_key_is_non_dac_member of + | Public_key_is_non_committee_member of Tezos_crypto.Aggregate_signature.public_key_hash | Signature_verification_failed of (Tezos_crypto.Aggregate_signature.public_key * Tezos_crypto.Aggregate_signature.t * string) - | Public_key_for_dac_member_not_available of + | Public_key_for_committee_member_not_available of Tezos_crypto.Aggregate_signature.public_key_hash -(* [sign_root_hash dac_pliugin cctx dac_sk_uris_opt root_hash] is legacy function that - returns an aggregate signature over [root_hash] and a bitmap of witnesses where - empty elements of [dac_sk_uris_opt] are 0 and non-empty elements are 1. *) -val sign_root_hash : - Dac_plugin.t -> - #Client_context.wallet -> - Client_keys.aggregate_sk_uri option trace -> - Dac_plugin.hash -> - (Tezos_crypto.Aggregate_signature.signature * Z.t, tztrace) result Lwt.t - (** [verify dac_plugin public_keys_opt root_hash aggregate_signature witnesses] verifies the [aggregate_signature] signed by the witnessed dac members. The witnessed dac members is given by applying the [witnesses] bitmap against [public_keys_opt] @@ -63,10 +53,40 @@ val verify : (** Module that exposes signature operations necsesary when running in [Configuration.Coordinator] mode.*) module Coordinator : sig - (* TODO: https://gitlab.com/tezos/tezos/-/issues/4997 - Verify that root hash is one that the coordinator has *) - (** [handle_put_dac_member_signature dac_plugin ro_store rw_store page_store - cctxt dac_members_pkh dac_member_signature] does the following procedure: + (** [handle_put_dac_member_signature ctx dac_plugin ro_store rw_store page_store + cctxt dac_member_signature] does the following procedure: + 1. Checks that the [root_hash] provided inside [Signature_repr.t] is known. Fails if unknown + 2. Checks that the [dac_member_signature.signer_pkh] is currently a Dac member. + 3. Checks that the dac member has not yet signed. If already signed, then noop + and return. + 4. Otherwise: + 1. Verify the signature against the root hash and signer's public key. + 2. Add signature to [Signature_store] + 3. Update the aggregate signature in [Aggregate_signature_store] + *) + val handle_put_dac_member_signature : + Node_context.Coordinator.t -> + Dac_plugin.t -> + Store_sigs.rw Store.Irmin_store.t -> + Page_store.Filesystem.t -> + #Client_context.wallet -> + Signature_repr.t -> + unit tzresult Lwt.t +end + +module Legacy : sig + (* [sign_root_hash dac_pliugin cctx dac_sk_uris_opt root_hash] is legacy function that + returns an aggregate signature over [root_hash] and a bitmap of witnesses where + empty elements of [dac_sk_uris_opt] are 0 and non-empty elements are 1. *) + val sign_root_hash : + Dac_plugin.t -> + #Client_context.wallet -> + Client_keys.aggregate_sk_uri option trace -> + Dac_plugin.hash -> + (Tezos_crypto.Aggregate_signature.signature * Z.t, tztrace) result Lwt.t + + (** [handle_put_dac_member_signature ctx dac_plugin ro_store rw_store page_store + cctxt dac_member_signature] does the following procedure: 1. Checks that the [root_hash] provided inside [Signature_repr.t] is known. Fails if unknown 2. Checks that the [dac_member_signature.signer_pkh] is currently a Dac member. 3. Checks that the dac member has not yet signed. If already signed, then noop @@ -77,10 +97,8 @@ module Coordinator : sig 3. Update the aggregate signature in [Aggregate_signature_store] *) val handle_put_dac_member_signature : - ('a -> Tezos_crypto.Aggregate_signature.public_key_hash list) -> - 'a -> + Node_context.Legacy.t -> Dac_plugin.t -> - Certificate_streamers.t option -> Store_sigs.rw Store.Irmin_store.t -> Page_store.Filesystem.t -> #Client_context.wallet -> -- GitLab From 51db3e0d5857900787d298fd4b8f4104098f0f0f Mon Sep 17 00:00:00 2001 From: Andrea Cerone Date: Tue, 14 Mar 2023 18:04:25 +0000 Subject: [PATCH 7/9] Dac Node/Rpc Server: Improve type safety --- src/lib_dac_node/RPC_server.ml | 79 ++++++++++++++----------------- src/lib_dac_node/handler.ml | 2 +- src/lib_dac_node/node_context.ml | 2 +- src/lib_dac_node/node_context.mli | 4 +- 4 files changed, 40 insertions(+), 47 deletions(-) diff --git a/src/lib_dac_node/RPC_server.ml b/src/lib_dac_node/RPC_server.ml index 0e372df99ba0..2e9f1602afd6 100644 --- a/src/lib_dac_node/RPC_server.ml +++ b/src/lib_dac_node/RPC_server.ml @@ -138,10 +138,10 @@ let handle_monitor_root_hashes hash_streamer = let* () = Event.(emit handle_new_subscription_to_hash_streamer ()) in Tezos_rpc.Answer.return_stream {next; shutdown} -let handle_get_certificate dac_plugin ctx raw_root_hash = +let handle_get_certificate dac_plugin node_store raw_root_hash = let open Lwt_result_syntax in let*? root_hash = Dac_plugin.raw_to_hash dac_plugin raw_root_hash in - let node_store = Node_context.get_node_store ctx Store_sigs.Read_only in + let+ value_opt = Store.Certificate_store.find node_store root_hash in Option.map (fun Store.{aggregate_signature; witnesses} -> @@ -196,11 +196,12 @@ let register_monitor_root_hashes hash_streamer dir = Monitor_services.S.root_hashes (fun () () () -> handle_monitor_root_hashes hash_streamer) -let register_get_certificate ctx dac_plugin = +let register_get_certificate node_store dac_plugin = add_service Tezos_rpc.Directory.register1 RPC_services.get_certificate - (fun root_hash () () -> handle_get_certificate dac_plugin ctx root_hash) + (fun root_hash () () -> + handle_get_certificate dac_plugin node_store root_hash) let register_get_missing_page dac_plugin page_store cctxt = add_service @@ -226,7 +227,7 @@ module Coordinator = struct in return @@ Dac_plugin.hash_to_raw root_hash - let handle_monitor_certificate dac_plugin ro_store certificate_streamers + let handle_monitor_certificate dac_plugin ro_node_store certificate_streamers raw_root_hash committee_members = let open Lwt_result_syntax in let*? stream, stopper = @@ -243,7 +244,7 @@ module Coordinator = struct a certificate is returned even in the case that no updates to the certificate happen for a long time. *) let*! current_certificate_store_value_res = - Store.Certificate_store.find ro_store root_hash + Store.Certificate_store.find ro_node_store root_hash in match current_certificate_store_value_res with | Ok current_certificate_store_value -> @@ -279,8 +280,8 @@ module Coordinator = struct return (next, shutdown) | Error e -> fail e - let register_monitor_certificate dac_plugin ro_store certificate_streamers - committee_members dir = + let register_monitor_certificate dac_plugin ro_node_store + certificate_streamers committee_members dir = Tezos_rpc.Directory.gen_register dir Monitor_services.S.certificate @@ -289,7 +290,7 @@ module Coordinator = struct let*! handler = handle_monitor_certificate dac_plugin - ro_store + ro_node_store certificate_streamers root_hash committee_members @@ -319,24 +320,16 @@ module Coordinator = struct cctxt dac_member_signature) - let dynamic_rpc_dir dac_plugin rw_store page_store cctxt - (coordinator_node_ctxt : Node_context.t) = - let modal_node_ctxt = - match Node_context.mode coordinator_node_ctxt with - | Coordinator modal_node_ctxt -> modal_node_ctxt - (* We only pass [Node_context.t] values whose mode is [Coordinator _] to - this function. *) - | _ -> assert false - in - + let dynamic_rpc_dir dac_plugin rw_store page_store cctxt coordinator_node_ctxt + = let hash_streamer = - modal_node_ctxt.Node_context.Coordinator.hash_streamer + coordinator_node_ctxt.Node_context.Coordinator.hash_streamer in let public_keys_opt = - Node_context.Coordinator.public_keys_opt modal_node_ctxt + Node_context.Coordinator.public_keys_opt coordinator_node_ctxt in - let certificate_streamers = modal_node_ctxt.certificate_streamers in - let committee_members = modal_node_ctxt.committee_members in + let certificate_streamers = coordinator_node_ctxt.certificate_streamers in + let committee_members = coordinator_node_ctxt.committee_members in Tezos_rpc.Directory.empty |> register_post_preimage dac_plugin hash_streamer page_store |> register_get_verify_signature dac_plugin public_keys_opt @@ -348,12 +341,12 @@ module Coordinator = struct certificate_streamers committee_members |> register_put_dac_member_signature - modal_node_ctxt + coordinator_node_ctxt dac_plugin rw_store page_store cctxt - |> register_get_certificate coordinator_node_ctxt dac_plugin + |> register_get_certificate rw_store dac_plugin end module Committee_member = struct @@ -384,20 +377,15 @@ module Legacy = struct dac_member_signature) let dynamic_rpc_dir dac_plugin rw_store page_store cctxt legacy_node_ctxt = - let modal_node_ctxt = - match Node_context.mode legacy_node_ctxt with - | Legacy modal_node_ctxt -> modal_node_ctxt - (* We only pass [Node_context.t] values whose mode is [Coordinator _] to - this function. *) - | _ -> assert false + let hash_streamer = legacy_node_ctxt.Node_context.Legacy.hash_streamer in + let public_keys_opt = + Node_context.Legacy.public_keys_opt legacy_node_ctxt in - let hash_streamer = modal_node_ctxt.Node_context.Legacy.hash_streamer in - let public_keys_opt = Node_context.Legacy.public_keys_opt modal_node_ctxt in let secret_key_uris_opt = - Node_context.Legacy.secret_key_uris_opt modal_node_ctxt + Node_context.Legacy.secret_key_uris_opt legacy_node_ctxt in let register_get_missing_page = - match modal_node_ctxt.coordinator_cctxt with + match legacy_node_ctxt.coordinator_cctxt with | None -> fun dir -> dir | Some cctxt -> fun dir -> @@ -414,12 +402,12 @@ module Legacy = struct |> register_get_preimage dac_plugin page_store |> register_monitor_root_hashes hash_streamer |> register_put_dac_member_signature - modal_node_ctxt + legacy_node_ctxt dac_plugin rw_store page_store cctxt - |> register_get_certificate legacy_node_ctxt dac_plugin + |> register_get_certificate rw_store dac_plugin |> register_get_missing_page end @@ -429,20 +417,25 @@ let start ~rpc_address ~rpc_port node_ctxt = let page_store = Node_context.get_page_store node_ctxt in let cctxt = Node_context.get_tezos_node_cctxt node_ctxt in let register_dynamic_rpc dac_plugin = - match Node_context.mode node_ctxt with - | Coordinator _ -> + match Node_context.get_mode node_ctxt with + | Coordinator coordinator_node_ctxt -> Coordinator.dynamic_rpc_dir dac_plugin rw_store page_store cctxt - node_ctxt - | Committee_member _ -> + coordinator_node_ctxt + | Committee_member _committee_member_node_ctxt -> Committee_member.dynamic_rpc_dir dac_plugin page_store | Observer {coordinator_cctxt; _} -> Observer.dynamic_rpc_dir dac_plugin coordinator_cctxt page_store - | Legacy _ -> - Legacy.dynamic_rpc_dir dac_plugin rw_store page_store cctxt node_ctxt + | Legacy legacy_node_ctxt -> + Legacy.dynamic_rpc_dir + dac_plugin + rw_store + page_store + cctxt + legacy_node_ctxt in let dir = Tezos_rpc.Directory.register_dynamic_directory diff --git a/src/lib_dac_node/handler.ml b/src/lib_dac_node/handler.ml index 05e3869e2bec..472fea25d6af 100644 --- a/src/lib_dac_node/handler.ml +++ b/src/lib_dac_node/handler.ml @@ -362,7 +362,7 @@ let handlers node_ctxt = let*? plugin = Node_context.get_dac_plugin node_ctxt in let page_store = Node_context.get_page_store node_ctxt in let wallet_cctxt = Node_context.get_tezos_node_cctxt node_ctxt in - match Node_context.mode node_ctxt with + match Node_context.get_mode node_ctxt with | Coordinator _ -> return [new_head node_ctxt] | Committee_member ctxt -> return diff --git a/src/lib_dac_node/node_context.ml b/src/lib_dac_node/node_context.ml index 9499cb4da711..a8accc68215e 100644 --- a/src/lib_dac_node/node_context.ml +++ b/src/lib_dac_node/node_context.ml @@ -261,7 +261,7 @@ let init config cctxt = mode; } -let mode node_ctxt = node_ctxt.mode +let get_mode node_ctxt = node_ctxt.mode let set_ready ctxt dac_plugin = match ctxt.status with diff --git a/src/lib_dac_node/node_context.mli b/src/lib_dac_node/node_context.mli index f04902d0b090..bfb03fd75d53 100644 --- a/src/lib_dac_node/node_context.mli +++ b/src/lib_dac_node/node_context.mli @@ -162,9 +162,9 @@ val get_ready : t -> ready_ctxt tzresult (** [get_status ctxt] returns the dac node status. *) val get_status : t -> status -(** [mode node_ctxt] returns the operating mode specific fraction of a +(** [get_mode node_ctxt] returns the operating mode specific fraction of a [Node_context.t]. *) -val mode : t -> mode +val get_mode : t -> mode (** [get_tezos_node_cctxt ctxt] returns the Tezos node's client context. *) val get_tezos_node_cctxt : t -> Client_context.full -- GitLab From ee200b94fc09a65662cd7b997e963fd6265b4c13 Mon Sep 17 00:00:00 2001 From: Andrea Cerone Date: Fri, 17 Mar 2023 17:49:10 +0000 Subject: [PATCH 8/9] Dac/Node: consistent naming for operating modes --- src/lib_dac_node/configuration.ml | 31 ++++++++++++++++++++++-------- src/lib_dac_node/configuration.mli | 4 ++++ src/lib_dac_node/daemon.ml | 2 ++ src/lib_dac_node/event.ml | 8 ++++++++ 4 files changed, 37 insertions(+), 8 deletions(-) diff --git a/src/lib_dac_node/configuration.ml b/src/lib_dac_node/configuration.ml index 6c034400a5f9..5712cd8c7c4b 100644 --- a/src/lib_dac_node/configuration.ml +++ b/src/lib_dac_node/configuration.ml @@ -68,6 +68,8 @@ module Coordinator = struct (list Tezos_crypto.Aggregate_signature.Public_key_hash.encoding)))) let committee_members_addresses t = t.committee_members_addresses + + let name = "Coordinator" end module Committee_member = struct @@ -93,6 +95,8 @@ module Committee_member = struct (req "address" Tezos_crypto.Aggregate_signature.Public_key_hash.encoding))) + + let name = "Committee_member" end module Observer = struct @@ -111,6 +115,8 @@ module Observer = struct (obj2 (req "coordinator_rpc_address" string) (req "coordinator_rpc_port" uint16))) + + let name = "Observer" end module Legacy = struct @@ -180,6 +186,8 @@ module Legacy = struct (opt "committee_member_address_opt" Tezos_crypto.Aggregate_signature.Public_key_hash.encoding))) + + let name = "Legacy" end type mode = @@ -222,6 +230,13 @@ type t = { DAC. *) } +let mode_name t = + match t.mode with + | Coordinator _ -> Coordinator.name + | Committee_member _ -> Committee_member.name + | Observer _ -> Observer.name + | Legacy _ -> Legacy.name + let make ~data_dir ~reveal_data_dir rpc_address rpc_port mode = {data_dir; reveal_data_dir; rpc_address; rpc_port; mode} @@ -240,26 +255,26 @@ let mode_encoding = union [ case - ~title:"Coordinator" - (Tag (0, "coordinator")) + ~title:Coordinator.name + (Tag (0, Coordinator.name)) Coordinator.encoding (function Coordinator t -> Some t | _ -> None) (fun t -> Coordinator t); case - ~title:"Committee_member" - (Tag (1, "committee_member")) + ~title:Committee_member.name + (Tag (1, Committee_member.name)) Committee_member.encoding (function Committee_member t -> Some t | _ -> None) (fun t -> Committee_member t); case - ~title:"Observer" - (Tag (2, "observer")) + ~title:Observer.name + (Tag (2, Observer.name)) Observer.encoding (function Observer t -> Some t | _ -> None) (fun t -> Observer t); case - ~title:"Legacy" - (Tag (3, "legacy")) + ~title:Legacy.name + (Tag (3, Legacy.name)) Legacy.encoding (function Legacy t -> Some t | _ -> None) (fun t -> Legacy t); diff --git a/src/lib_dac_node/configuration.mli b/src/lib_dac_node/configuration.mli index 172b9fe44f8c..abd344f29e2c 100644 --- a/src/lib_dac_node/configuration.mli +++ b/src/lib_dac_node/configuration.mli @@ -108,6 +108,10 @@ type t = private { DAC. *) } +(** [mode_name t] returns a string representation of the operating mode + for the configuration [t]. *) +val mode_name : t -> string + (** [make_coordinator threshold dac_members_addresses] creates a new coordinator configuration mode using the given [threshold] and [dac_members_addresses]. *) diff --git a/src/lib_dac_node/daemon.ml b/src/lib_dac_node/daemon.ml index 8ab2405cf781..8ba9dc68a44f 100644 --- a/src/lib_dac_node/daemon.ml +++ b/src/lib_dac_node/daemon.ml @@ -64,6 +64,8 @@ let run ~data_dir cctxt = config) = Configuration.load ~data_dir in + let operating_mode_string = Configuration.mode_name config in + let*! () = Event.(emit operating_mode operating_mode_string) in let* () = Page_store.ensure_reveal_data_dir_exists reveal_data_dir in let* ctxt = Node_context.init config cctxt in (* TODO: https://gitlab.com/tezos/tezos/-/issues/4725 diff --git a/src/lib_dac_node/event.ml b/src/lib_dac_node/event.ml index 081d816c84c4..943ef6006b19 100644 --- a/src/lib_dac_node/event.ml +++ b/src/lib_dac_node/event.ml @@ -52,6 +52,14 @@ let store_is_ready = ~level:Notice () +let operating_mode = + declare_1 + ~section + ~name:"dac_node_running_mode" + ~msg:"The DAC node is running in mode {mode}" + ~level:Notice + ("mode", Data_encoding.string) + let rpc_server_is_ready = declare_2 ~section -- GitLab From f40117b830891555f58b95279416584c0c4c4508 Mon Sep 17 00:00:00 2001 From: Andrea Cerone Date: Tue, 14 Mar 2023 18:07:09 +0000 Subject: [PATCH 9/9] Dac Node/Node context: remove type unsafe functions --- src/lib_dac_node/node_context.ml | 67 +------------------------------ src/lib_dac_node/node_context.mli | 10 ----- 2 files changed, 2 insertions(+), 75 deletions(-) diff --git a/src/lib_dac_node/node_context.ml b/src/lib_dac_node/node_context.ml index a8accc68215e..15a2306d9c6d 100644 --- a/src/lib_dac_node/node_context.ml +++ b/src/lib_dac_node/node_context.ml @@ -273,10 +273,7 @@ let set_ready ctxt dac_plugin = ctxt.status <- Ready {dac_plugin} | Ready _ -> raise Status_already_ready -type error += - | Node_not_ready - | Invalid_operation_for_mode of {mode : string; operation : string} - | Coordinator_client_not_defined_in_config +type error += Node_not_ready let () = register_error_kind @@ -290,39 +287,7 @@ let () = "DAC node is starting. It's not ready to respond to RPCs.") Data_encoding.(unit) (function Node_not_ready -> Some () | _ -> None) - (fun () -> Node_not_ready) ; - register_error_kind - `Permanent - ~id:"dac_unexpected_mode" - ~title:"Invalid operation for the current mode of Dac node." - ~description: - "An operation was called that it not supported by the current Dac node." - ~pp:(fun ppf (mode, operation) -> - Format.fprintf - ppf - "An operation was called that it not supported by the current Dac \ - node. Mode: %s; Unsupported_operation: %s" - mode - operation) - Data_encoding.( - obj2 (req "mode" (string' Plain)) (req "operation" (string' Plain))) - (function - | Invalid_operation_for_mode {mode; operation} -> Some (mode, operation) - | _ -> None) - (fun (mode, operation) -> Invalid_operation_for_mode {mode; operation}) ; - register_error_kind - `Permanent - ~id:"dac_coordinator_client_not_defined_in_config" - ~title:"Coordinator client was not defined in config." - ~description: - "Coordinator client configuration was expected but not defined." - ~pp:(fun ppf () -> - Format.fprintf - ppf - "Coordinator client configuration was expected but not defined.") - Data_encoding.unit - (function Coordinator_client_not_defined_in_config -> Some () | _ -> None) - (fun () -> Coordinator_client_not_defined_in_config) + (fun () -> Node_not_ready) let get_ready ctxt = let open Result_syntax in @@ -347,31 +312,3 @@ let get_node_store (type a) ctxt (access_mode : a Store_sigs.mode) : match access_mode with | Store_sigs.Read_only -> Store.Irmin_store.readonly ctxt.node_store | Store_sigs.Read_write -> ctxt.node_store - -let get_committee_members ctxt = - let open Result_syntax in - match ctxt.mode with - | Legacy legacy -> - Ok - (List.map - (fun Wallet_account.Legacy.{public_key_hash; _} -> public_key_hash) - legacy.committee_members) - | Coordinator coordinator -> - Ok - ((List.map (fun Wallet_account.Coordinator.{public_key_hash; _} -> - public_key_hash)) - coordinator.committee_members) - | Observer _ -> - tzfail - @@ Invalid_operation_for_mode - {mode = "observer"; operation = "get_committee_members"} - | Committee_member _ -> - tzfail - @@ Invalid_operation_for_mode - {mode = "dac_member"; operation = "get_committee_members"} - -let get_coordinator_client ctxt = - match ctxt.mode with - | Observer observer_ctxt -> Ok observer_ctxt.coordinator_cctxt - | Legacy {coordinator_cctxt = Some cctxt; _} -> Ok cctxt - | _ -> Result_syntax.tzfail Coordinator_client_not_defined_in_config diff --git a/src/lib_dac_node/node_context.mli b/src/lib_dac_node/node_context.mli index bfb03fd75d53..bcd6a697c66d 100644 --- a/src/lib_dac_node/node_context.mli +++ b/src/lib_dac_node/node_context.mli @@ -180,13 +180,3 @@ val get_page_store : t -> Page_store.Filesystem.t (** [get_node_store ctxt access_mode] returns the [Store.Irmin_store.t] with [access_mode] used by Dac components. *) val get_node_store : t -> 'a Store_sigs.mode -> 'a Store.Irmin_store.t - -(** [get_committee_members ctxt] returns the Dac committee public key hashes from - [Configuration.Legacy.dac_members_addresses] or - [Configuration.Coordinator.dac_members_addresses] *) -val get_committee_members : - t -> Tezos_crypto.Aggregate_signature.public_key_hash list tzresult - -(** [get_coordinator_client ctx] returns the Coordinator client if it - is available. *) -val get_coordinator_client : t -> Dac_node_client.cctxt tzresult -- GitLab