diff --git a/src/bin_dac_node/RPC_server.ml b/src/bin_dac_node/RPC_server.ml index 90c61b656b18a0a59ebe64ec9e9d50051670ae8c..9d24ae730be4446e838d5943b6c855ac978225da 100644 --- a/src/bin_dac_node/RPC_server.ml +++ b/src/bin_dac_node/RPC_server.ml @@ -27,12 +27,11 @@ open Tezos_rpc_http open Tezos_rpc_http_server -let start configuration cctxt ctxt dac_pks_opt dac_sk_uris = +(* TODO: https://gitlab.com/tezos/tezos/-/issues/4750 + Move this to RPC_server.Legacy once all operating modes are supported. *) +let start_legacy ~rpc_address ~rpc_port ~reveal_data_dir ~threshold cctxt ctxt + dac_pks_opt dac_sk_uris = let open Lwt_syntax in - let Configuration. - {rpc_addr; rpc_port; dac = {reveal_data_dir; threshold; _}; _} = - configuration - in let dir = Tezos_rpc.Directory.register_dynamic_directory Tezos_rpc.Directory.empty @@ -49,10 +48,10 @@ let start configuration cctxt ctxt dac_pks_opt dac_sk_uris = threshold) | Starting -> Lwt.return Tezos_rpc.Directory.empty) in - let rpc_addr = P2p_addr.of_string_exn rpc_addr in - let host = Ipaddr.V6.to_string rpc_addr in + let rpc_address = P2p_addr.of_string_exn rpc_address in + let host = Ipaddr.V6.to_string rpc_address in let node = `TCP (`Port rpc_port) in - let acl = RPC_server.Acl.default rpc_addr in + let acl = RPC_server.Acl.default rpc_address in let server = RPC_server.init_server dir ~acl ~media_types:Media_type.all_media_types in diff --git a/src/bin_dac_node/configuration.ml b/src/bin_dac_node/configuration.ml index f7661dcd37078697b030b03cdd071f54472aeeb2..88f15234582e86d8a36ff051f6d199f4d482212e 100644 --- a/src/bin_dac_node/configuration.ml +++ b/src/bin_dac_node/configuration.ml @@ -1,7 +1,8 @@ (*****************************************************************************) (* *) (* Open Source License *) -(* Copyright (c) 2021-2022 Nomadic Labs, *) +(* Copyright (c) 2022 Nomadic Labs, *) +(* Copyright (c) 2023 TriliTech, *) (* *) (* Permission is hereby granted, free of charge, to any person obtaining a *) (* copy of this software and associated documentation files (the "Software"),*) @@ -23,13 +24,37 @@ (* *) (*****************************************************************************) -type dac = { - addresses : Tezos_crypto.Aggregate_signature.public_key_hash list; +type coordinator = { threshold : int; - reveal_data_dir : string; + dac_members_addresses : Tezos_crypto.Aggregate_signature.public_key_hash list; +} + +type dac_member = { + coordinator_rpc_address : string; + coordinator_rpc_port : int; + address : Tezos_crypto.Aggregate_signature.public_key_hash; +} + +type observer = {coordinator_rpc_address : string; coordinator_rpc_port : int} + +type legacy = { + threshold : int; + dac_members_addresses : Tezos_crypto.Aggregate_signature.public_key_hash list; } -type t = {data_dir : string; rpc_addr : string; rpc_port : int; dac : dac} +type mode = + | Coordinator of coordinator + | Dac_member of dac_member + | Observer of observer + | Legacy of legacy + +type t = { + data_dir : string; + rpc_address : string; + rpc_port : int; + reveal_data_dir : string; + mode : mode; +} let default_data_dir = Filename.concat (Sys.getenv "HOME") ".tezos-dac-node" @@ -39,7 +64,7 @@ let relative_filename data_dir = Filename.concat data_dir "config.json" let filename config = relative_filename config.data_dir -let default_rpc_addr = "127.0.0.1" +let default_rpc_address = "127.0.0.1" let default_rpc_port = 10832 @@ -52,47 +77,113 @@ let default_reveal_data_dir = (Filename.concat (Sys.getenv "HOME") ".tezos-smart-rollup-node") "wasm_2_0_0" -let default_dac = - { - addresses = default_dac_addresses; - threshold = default_dac_threshold; - reveal_data_dir = default_reveal_data_dir; - } - -let dac_encoding : dac Data_encoding.t = - let open Data_encoding in - conv - (fun {addresses; threshold; reveal_data_dir} -> - (addresses, threshold, reveal_data_dir)) - (fun (addresses, threshold, reveal_data_dir) -> - {addresses; threshold; reveal_data_dir}) - (obj3 - (req - "addresses" - (list Tezos_crypto.Aggregate_signature.Public_key_hash.encoding)) - (req "threshold" uint8) - (req "reveal-data-dir" string)) +let coordinator_encoding = + Data_encoding.( + conv_with_guard + (fun ({threshold; dac_members_addresses} : coordinator) -> + (threshold, dac_members_addresses, false)) + (fun (threshold, dac_members_addresses, legacy) -> + if legacy then Error "legacy flag should be set to false" + else Ok {threshold; dac_members_addresses}) + (obj3 + (req "threshold" uint8) + (req + "dac_members" + (list Tezos_crypto.Aggregate_signature.Public_key_hash.encoding)) + (req "legacy" bool))) + +let dac_member_encoding = + Data_encoding.( + conv + (fun {coordinator_rpc_address; coordinator_rpc_port; address} -> + (coordinator_rpc_address, coordinator_rpc_port, address)) + (fun (coordinator_rpc_address, coordinator_rpc_port, address) -> + {coordinator_rpc_address; coordinator_rpc_port; address}) + (obj3 + (req "coordinator_rpc_address" string) + (req "coordinator_rpc_port" int16) + (req + "address" + Tezos_crypto.Aggregate_signature.Public_key_hash.encoding))) + +let observer_encoding = + Data_encoding.( + conv + (fun {coordinator_rpc_address; coordinator_rpc_port} -> + (coordinator_rpc_address, coordinator_rpc_port)) + (fun (coordinator_rpc_address, coordinator_rpc_port) -> + {coordinator_rpc_address; coordinator_rpc_port}) + (obj2 + (req "coordinator_rpc_address" string) + (req "coordinator_rpc_port" int16))) + +let legacy_encoding = + Data_encoding.( + conv_with_guard + (fun {threshold; dac_members_addresses} -> + (threshold, dac_members_addresses, true)) + (fun (threshold, dac_members_addresses, legacy) -> + if legacy then Ok {threshold; dac_members_addresses} + else Error "legacy flag should be set to true") + (obj3 + (dft "threshold" uint8 default_dac_threshold) + (dft + "dac_members" + (list Tezos_crypto.Aggregate_signature.Public_key_hash.encoding) + default_dac_addresses) + (req "legacy" bool))) + +let mode_config_encoding = + Data_encoding.( + union + [ + case + ~title:"coordinator" + (Tag 0) + coordinator_encoding + (function Coordinator config -> Some config | _ -> None) + (function config -> Coordinator config); + case + ~title:"dac_member" + (Tag 1) + dac_member_encoding + (function Dac_member config -> Some config | _ -> None) + (function config -> Dac_member config); + case + ~title:"observer" + (Tag 2) + observer_encoding + (function Observer config -> Some config | _ -> None) + (function config -> Observer config); + case + ~title:"legacy" + (Tag 3) + legacy_encoding + (function Legacy config -> Some config | _ -> None) + (function config -> Legacy config); + ]) let encoding : t Data_encoding.t = let open Data_encoding in conv - (fun {data_dir; rpc_addr; rpc_port; dac} -> - (data_dir, rpc_addr, rpc_port, dac)) - (fun (data_dir, rpc_addr, rpc_port, dac) -> - {data_dir; rpc_addr; rpc_port; dac}) - (obj4 + (fun {data_dir; rpc_address; rpc_port; reveal_data_dir; mode} -> + (data_dir, rpc_address, rpc_port, reveal_data_dir, mode)) + (fun (data_dir, rpc_address, rpc_port, reveal_data_dir, mode) -> + {data_dir; rpc_address; rpc_port; reveal_data_dir; mode}) + (obj5 (dft "data-dir" ~description:"Location of the data dir" string default_data_dir) - (dft "rpc-addr" ~description:"RPC address" string default_rpc_addr) + (dft "rpc-addr" ~description:"RPC address" string default_rpc_address) (dft "rpc-port" ~description:"RPC port" uint16 default_rpc_port) (dft - "dac" - ~description:"Data Availability Committee" - dac_encoding - default_dac)) + "reveal_data_dir" + ~description:"Reveal data directory" + string + default_reveal_data_dir) + (req "mode" ~description:"Running mode" mode_config_encoding)) type error += DAC_node_unable_to_write_configuration_file of string diff --git a/src/bin_dac_node/configuration.mli b/src/bin_dac_node/configuration.mli index 0ba682325f3e01cc7a9bf9f893f76eb849b96249..98b2f633d0abd204e0fb9d171e270f8c3d7fc814 100644 --- a/src/bin_dac_node/configuration.mli +++ b/src/bin_dac_node/configuration.mli @@ -2,6 +2,7 @@ (* *) (* Open Source License *) (* Copyright (c) 2022 Nomadic Labs, *) +(* Copyright (c) 2023 TriliTech, *) (* *) (* Permission is hereby granted, free of charge, to any person obtaining a *) (* copy of this software and associated documentation files (the "Software"),*) @@ -23,25 +24,55 @@ (* *) (*****************************************************************************) -type dac = { - addresses : Tezos_crypto.Aggregate_signature.public_key_hash list; +(** Configuration type for coordinators. *) +type coordinator = { threshold : int; - (** The number of signature needed on root page hashes for the - corresponding reveal preimages to be available. *) - reveal_data_dir : string; - (** The directory where the dac node saves pages computed - from reveal preimages. If the dac node saves the data - directly into the rollup node, this should be - {ROLLUP_NODE_DATA_DIR}/{PVM_NAME}. *) + (** The number of signatures required from DAC members to consider a + message valid. *) + dac_members_addresses : Tezos_crypto.Aggregate_signature.public_key_hash list; + (** The list of tz4 addresses denoting the dac members. *) +} + +(** Configuration type for dac members. *) +type dac_member = { + coordinator_rpc_address : string; (** RPC address of the coordinator. *) + coordinator_rpc_port : int; (** RPC port of the coordinator. *) + address : Tezos_crypto.Aggregate_signature.public_key_hash; + (** Tz4 address of the DAC member. *) } +(** Configuation type for observers. *) +type observer = { + coordinator_rpc_address : string; (** RPC address of the coordinator. *) + coordinator_rpc_port : int; (** RPC port of the coordinator. *) +} + +(** Configuration type for legacy mode. *) +type legacy = { + threshold : int; + (** The number of signatures required from DAC members to consider a + message valid. *) + dac_members_addresses : Tezos_crypto.Aggregate_signature.public_key_hash list; + (** The list of tz4 addresses denoting the dac members. *) +} + +(* TODO: https://gitlab.com/tezos/tezos/-/issues/4707. + Remove legacy mode once other DAC operating modes are fully functional. *) +type mode = + | Coordinator of coordinator + | Dac_member of dac_member + | Observer of observer + | Legacy of legacy + type t = { - data_dir : string; (** The path to the DAC node data directory *) - rpc_addr : string; (** The address the DAC node listens to *) - rpc_port : int; (** The port the DAC node listens to *) - dac : dac; - (** The aggregate account aliases that constitute the Data availability - Committee. *) + data_dir : string; (** The path to the DAC node data directory. *) + rpc_address : string; (** The address the DAC node listens to. *) + rpc_port : int; (** The port the DAC node listens to. *) + reveal_data_dir : string; + (** The directory where the DAC node saves pages. *) + mode : mode; + (** Configuration parameters specific to the operating mode of the + DAC. *) } (** [filename config] gets the path to config file *) @@ -51,18 +82,27 @@ val filename : t -> string [config] *) val data_dir_path : t -> string -> string +(** [default_data_dir] is the data directory that the DAC node + will use, when one is not specified in the configuration: + currently set to "${HOME}/.tezos-dac-node." *) val default_data_dir : string +(** [default_reveal_data_dir] is the directory that the DAC node + will use to store pages on disk. Currently set to + "${HOME}/.tezos_rollup_node/wasm_2_0_0". *) val default_reveal_data_dir : string -val default_rpc_addr : string +(** [default_rpc_address] is the default address of the RPC server + of the DAC node: currently set to "127.0.0.1" *) +val default_rpc_address : string +(** [default_rpc_port] is the default port of the RPC server + of the DAC node: currently set to 10832. *) val default_rpc_port : int -(** Default configuration for the data availability committee. *) -val default_dac : dac - (** [save config] writes config file in [config.data_dir] *) val save : t -> unit tzresult Lwt.t +(** [load ~data_dir] config tries to load the configuration of the DAC node + from [data_dir]. *) val load : data_dir:string -> (t, Error_monad.tztrace) result Lwt.t diff --git a/src/bin_dac_node/dac_manager.ml b/src/bin_dac_node/dac_manager.ml index 1952417ed5632b2c28a5976c0d86ace1899dc952..e73afded36127a9927191f41fcc514d396526d16 100644 --- a/src/bin_dac_node/dac_manager.ml +++ b/src/bin_dac_node/dac_manager.ml @@ -78,7 +78,7 @@ module Keys = struct return_none | Some sk_uri -> return_some (pkh, pk, sk_uri))) - let get_keys cctxt {Configuration.dac = {addresses; threshold; _}; _} = + let get_keys ~addresses ~threshold cctxt = let open Lwt_result_syntax in let* keys = List.map_es (get_address_keys cctxt) addresses in let recovered_keys = List.length @@ List.filter Option.is_some keys in diff --git a/src/bin_dac_node/dac_manager.mli b/src/bin_dac_node/dac_manager.mli index 981b86c395d02dd7e5ea74b506e022ee955f2e1a..45e4dff3882c84016315d2dc097f444a8d110296 100644 --- a/src/bin_dac_node/dac_manager.mli +++ b/src/bin_dac_node/dac_manager.mli @@ -30,11 +30,12 @@ type error += | Cannot_create_reveal_data_dir of string module Keys : sig - (** [get_keys cctxt config] returns the aliases and keys associated with the + (** [get_keys ~addresses ~threshold cctxt config] returns the aliases and keys associated with the aggregate signature addresses in [config] pkh in the tezos wallet of [cctxt]. *) val get_keys : + addresses:Tezos_crypto.Aggregate_signature.public_key_hash trace -> + threshold:int -> #Client_context.wallet -> - Configuration.t -> (Tezos_crypto.Aggregate_signature.public_key_hash * Tezos_crypto.Aggregate_signature.public_key option * Client_keys.aggregate_sk_uri) diff --git a/src/bin_dac_node/daemon.ml b/src/bin_dac_node/daemon.ml index 013363487c21e737cf2266d3cc843397270de4b7..913dba73847403e193ea300943e094111202c42e 100644 --- a/src/bin_dac_node/daemon.ml +++ b/src/bin_dac_node/daemon.ml @@ -23,9 +23,19 @@ (* *) (*****************************************************************************) -type error += - | Reveal_data_path_not_a_directory of string - | Cannot_create_reveal_data_dir of string +type error += Mode_not_supported of string + +let () = + register_error_kind + `Permanent + ~id:"dac.node.operating_mode_not_supported" + ~title:"Operating mode not supported" + ~description:"Operating mode not supported" + ~pp:(fun ppf mode_string -> + Format.fprintf ppf "DAC node cannot run in %s operating mode" mode_string) + Data_encoding.(obj1 (req "mode" string)) + (function Mode_not_supported mode -> Some mode | _ -> None) + (fun mode -> Mode_not_supported mode) module Handler = struct (** [make_stream_daemon handler streamed_call] calls [handler] on each newly @@ -65,8 +75,6 @@ module Handler = struct let* protocols = Tezos_shell_services.Chain_services.Blocks.protocols cctxt () in - (* TODO: https://gitlab.com/tezos/tezos/-/issues/4627 - Register only one plugin according to mode of operation. *) let*! dac_plugin = Dac_manager.resolve_plugin protocols in match dac_plugin with | Some dac_plugin -> @@ -128,12 +136,21 @@ let daemonize handlers = let run ~data_dir cctxt = let open Lwt_result_syntax in let*! () = Event.(emit starting_node) () in - let* config = Configuration.load ~data_dir in - let config = {config with data_dir} in - let* () = - Dac_manager.Storage.ensure_reveal_data_dir_exists config.dac.reveal_data_dir + let* ({rpc_address; rpc_port; reveal_data_dir; mode; _} as config) = + Configuration.load ~data_dir + in + let* () = Dac_manager.Storage.ensure_reveal_data_dir_exists reveal_data_dir in + let* addresses, threshold = + match mode with + | Configuration.Legacy {dac_members_addresses; threshold} -> + return (dac_members_addresses, threshold) + | Configuration.Coordinator _ -> tzfail @@ Mode_not_supported "coordinator" + | Configuration.Dac_member _ -> tzfail @@ Mode_not_supported "dac_member" + | Configuration.Observer _ -> tzfail @@ Mode_not_supported "observer" in - let* dac_accounts = Dac_manager.Keys.get_keys cctxt config in + (* TODO: https://gitlab.com/tezos/tezos/-/issues/4725 + Stop DAC node when in Legacy mode, if threshold is not reached. *) + let* dac_accounts = Dac_manager.Keys.get_keys ~addresses ~threshold cctxt in let dac_pks_opt, dac_sk_uris = dac_accounts |> List.map (fun account_opt -> @@ -143,13 +160,21 @@ let run ~data_dir cctxt = |> List.split in let ctxt = Node_context.init config cctxt in - let* rpc_server = - RPC_server.(start config cctxt ctxt dac_pks_opt dac_sk_uris) + RPC_server.( + start_legacy + ~rpc_address + ~rpc_port + ~reveal_data_dir + ~threshold + cctxt + ctxt + dac_pks_opt + dac_sk_uris) in let _ = RPC_server.install_finalizer rpc_server in let*! () = - Event.(emit rpc_server_is_ready (config.rpc_addr, config.rpc_port)) + Event.(emit rpc_server_is_ready (config.rpc_address, config.rpc_port)) in (* Start daemon to resolve current protocol plugin *) let* () = daemonize [Handler.resolve_plugin_and_set_ready ctxt cctxt] in diff --git a/src/bin_dac_node/main_dac.ml b/src/bin_dac_node/main_dac.ml index a2e8064efbdfb79a35a7d43ecb2dae0d7b299360..704dc7312a878a16c744ecb1397075d0d88da578 100644 --- a/src/bin_dac_node/main_dac.ml +++ b/src/bin_dac_node/main_dac.ml @@ -2,6 +2,7 @@ (* *) (* Open Source License *) (* Copyright (c) 2022 Nomadic Labs, *) +(* Copyright (c) 2023 TriliTech, *) (* *) (* Permission is hereby granted, free of charge, to any person obtaining a *) (* copy of this software and associated documentation files (the "Software"),*) @@ -38,8 +39,8 @@ let data_dir_arg = ~default (Client_config.string_parameter ()) -let rpc_addr_arg = - let default = Configuration.default_rpc_addr in +let rpc_address_arg = + let default = Configuration.default_rpc_address in Tezos_clic.default_arg ~long:"rpc-addr" ~placeholder:"rpc-address|ip" @@ -78,11 +79,19 @@ let config_init_command = command ~group ~desc:"Configure DAC node." - (args3 data_dir_arg rpc_addr_arg rpc_port_arg) + (args3 data_dir_arg rpc_address_arg rpc_port_arg) (prefixes ["init-config"] stop) - (fun (data_dir, rpc_addr, rpc_port) cctxt -> + (fun (data_dir, rpc_address, rpc_port) cctxt -> let open Configuration in - let config = {data_dir; rpc_addr; rpc_port; dac = default_dac} in + let config = + { + data_dir; + rpc_address; + rpc_port; + mode = Legacy {threshold = 0; dac_members_addresses = []}; + reveal_data_dir = default_reveal_data_dir; + } + in let* () = save config in let*! _ = cctxt#message "DAC node configuration written in %s" (filename config) @@ -133,15 +142,20 @@ module Dac_client = struct (args1 data_dir_arg) (prefixes ["add"; "data"; "availability"; "committee"; "member"] @@ tz4_address_param @@ stop) - (fun data_dir address cctxt -> + (fun data_dir dac_member_address cctxt -> let open Configuration in let* config = load ~data_dir in - let old_addresses = config.dac.addresses in + let* ({dac_members_addresses = old_dac_members_addresses; _} as + legacy_config) = + match config.mode with + | Legacy config -> return config + | _ -> failwith "Configuration is not in legacy mode" + in if List.mem ~equal:Tezos_crypto.Aggregate_signature.Public_key_hash.equal - address - old_addresses + dac_member_address + old_dac_members_addresses then let*! _ = cctxt#message @@ -150,9 +164,11 @@ module Dac_client = struct in return_unit else - let addresses = old_addresses @ [address] in - let dac = {config.dac with addresses} in - let* () = save {config with dac} in + let dac_members_addresses = + old_dac_members_addresses @ [dac_member_address] + in + let mode = Legacy {legacy_config with dac_members_addresses} in + let* () = save {config with mode} in let*! _ = cctxt#message "DAC address added to configuration in %s" @@ -173,12 +189,19 @@ module Dac_client = struct (fun (data_dir, threshold, reveal_data_dir) cctxt -> let open Configuration in let* config = load ~data_dir in - let threshold = Option.value threshold ~default:config.dac.threshold in + let* legacy_config = + match config.mode with + | Legacy config -> return config + | _ -> failwith "Only legacy mode supported." + in + let threshold = + Option.value threshold ~default:legacy_config.threshold + in let reveal_data_dir = - Option.value reveal_data_dir ~default:config.dac.reveal_data_dir + Option.value reveal_data_dir ~default:config.reveal_data_dir in - let dac = {config.dac with threshold; reveal_data_dir} in - let config = {config with dac} in + let mode = Legacy {legacy_config with threshold} in + let config = {config with reveal_data_dir; mode} in let* () = save config in let*! _ = cctxt#message