From 64ad95741276e3195ee27bba96241b2a8843784b Mon Sep 17 00:00:00 2001 From: Albin Coquereau Date: Tue, 2 May 2023 18:11:45 +0200 Subject: [PATCH 1/8] proto_alpha/plugin: add versioning to forge operation rpc --- src/proto_alpha/lib_plugin/RPC.ml | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/src/proto_alpha/lib_plugin/RPC.ml b/src/proto_alpha/lib_plugin/RPC.ml index 63cdadee13cb..e7c2c1109edf 100644 --- a/src/proto_alpha/lib_plugin/RPC.ml +++ b/src/proto_alpha/lib_plugin/RPC.ml @@ -2623,11 +2623,28 @@ module Forge = struct let path = RPC_path.(path / "forge") + let operations_encoding = + union + [ + case + ~title:"operations_encoding" + (Tag 0) + Operation.unsigned_encoding + Option.some + Fun.id; + case + ~title:"operations_encoding_with_legacy_attestation_name" + Json_only + Operation.unsigned_encoding_with_legacy_attestation_name + Option.some + Fun.id; + ] + let operations = RPC_service.post_service ~description:"Forge an operation" ~query:RPC_query.empty - ~input:Operation.unsigned_encoding_with_legacy_attestation_name + ~input:operations_encoding ~output:(bytes Hex) RPC_path.(path / "operations") @@ -2662,11 +2679,11 @@ module Forge = struct Registration.register0_noctxt ~chunked:true S.operations - (fun () (shell, proto) -> + (fun () operation -> return (Data_encoding.Binary.to_bytes_exn Operation.unsigned_encoding_with_legacy_attestation_name - (shell, proto))) ; + operation)) ; Registration.register0_noctxt ~chunked:true S.protocol_data -- GitLab From b9d682313dd5b01ec9a3460e51872f63f179c6b0 Mon Sep 17 00:00:00 2001 From: Albin Coquereau Date: Mon, 15 May 2023 12:25:41 +0200 Subject: [PATCH 2/8] tezt/lib_tezos: rename endorsement helper in attestation --- tezt/lib_tezos/operation_core.ml | 31 ++++++++++------- tezt/lib_tezos/operation_core.mli | 56 ++++++++++++++++++++++++------- tezt/tests/dal.ml | 7 ++-- tezt/tests/double_consensus.ml | 14 +++++--- 4 files changed, 77 insertions(+), 31 deletions(-) diff --git a/tezt/lib_tezos/operation_core.ml b/tezt/lib_tezos/operation_core.ml index 1dffee051e51..df78dbbd8572 100644 --- a/tezt/lib_tezos/operation_core.ml +++ b/tezt/lib_tezos/operation_core.ml @@ -25,7 +25,7 @@ open Runnable.Syntax -type consensus_kind = Endorsement | Preendorsement +type consensus_kind = Attestation | Preattestation type kind = | Consensus of {kind : consensus_kind; chain_id : string} @@ -97,7 +97,7 @@ let sign ?protocol ({kind; signer; _} as t) client = (Tezos_crypto.Hashed.Chain_id.of_b58check_exn chain_id) in let prefix = - match kind with Preendorsement -> "\x12" | Endorsement -> "\x13" + match kind with Preattestation -> "\x12" | Attestation -> "\x13" in Tezos_crypto.Signature.Custom (Bytes.cat (Bytes.of_string prefix) (Bytes.of_string chain_id)) @@ -207,6 +207,7 @@ module Consensus = struct type t = | Consensus of { kind : consensus_kind; + use_legacy_name : bool; slot : int; level : int; round : int; @@ -214,23 +215,27 @@ module Consensus = struct } | Dal_attestation of {attestation : bool array; level : int} - let preendorsement ~slot ~level ~round ~block_payload_hash = - Consensus {kind = Preendorsement; slot; level; round; block_payload_hash} + let consensus ~use_legacy_name ~kind ~slot ~level ~round ~block_payload_hash = + Consensus {kind; use_legacy_name; slot; level; round; block_payload_hash} - let endorsement ~slot ~level ~round ~block_payload_hash = - Consensus {kind = Endorsement; slot; level; round; block_payload_hash} + let attestation = consensus ~kind:Attestation + + let preattestation = consensus ~kind:Preattestation let dal_attestation ~attestation ~level = Dal_attestation {attestation; level} + let kind_to_string kind use_legacy_name = + let name = function true -> "endorsement" | false -> "attestation" in + match kind with + | Attestation -> name use_legacy_name + | Preattestation -> Format.sprintf "pre%s" (name use_legacy_name) + let json signer = function - | Consensus {kind; slot; level; round; block_payload_hash} -> + | Consensus {kind; use_legacy_name; slot; level; round; block_payload_hash} + -> `O [ - ( "kind", - Ezjsonm.string - (match kind with - | Preendorsement -> "preendorsement" - | Endorsement -> "endorsement") ); + ("kind", Ezjsonm.string (kind_to_string kind use_legacy_name)); ("slot", Ezjsonm.int slot); ("level", Ezjsonm.int level); ("round", Ezjsonm.int round); @@ -267,7 +272,7 @@ module Consensus = struct let kind = match consensus_operation with | Consensus {kind; _} -> kind - | Dal_attestation _ -> Endorsement + | Dal_attestation _ -> Attestation in return (make ~branch ~signer ~kind:(Consensus {kind; chain_id}) json) diff --git a/tezt/lib_tezos/operation_core.mli b/tezt/lib_tezos/operation_core.mli index adf96ab939af..bc87d78731bc 100644 --- a/tezt/lib_tezos/operation_core.mli +++ b/tezt/lib_tezos/operation_core.mli @@ -61,7 +61,7 @@ type t type operation := t -type consensus_kind = Endorsement | Preendorsement +type consensus_kind = Attestation | Preattestation (** The kind is necessary because it determines the watermark of an operation which is necessary for signing an operation. This type @@ -188,17 +188,49 @@ module Consensus : sig booleans indicates whether the data is deemed available. *) val dal_attestation : attestation:bool array -> level:int -> t - (* [preendorsement ~level ~round ~slot ~block_payload_hash] craft a - preendorsement operation at [level] on the [round] with the [slot] and - [block_payload_hash]. *) - val preendorsement : - slot:int -> level:int -> round:int -> block_payload_hash:string -> t - - (* [endorsement ~level ~round ~slot ~block_payload_hash] craft an - endorsement operation at [level] on the [round] with the [slot] and - [block_payload_hash]. *) - val endorsement : - slot:int -> level:int -> round:int -> block_payload_hash:string -> t + (** [consensus ~kind ~use_legacy_name ~level ~round ~slot ~block_payload_hash] + crafts a consensus operation with the [kind] at [level] on the [round] + with the [slot] and [block_payload_hash]. If [use_legacy_name] is set, the + [kind] field in the crafted JSON will be "(pre)endorsement" instead of + "(pre)attestation". *) + val consensus : + use_legacy_name:bool -> + kind:consensus_kind -> + slot:int -> + level:int -> + round:int -> + block_payload_hash:string -> + t + + (** [preattestation ?use_legacy_name ~level ~round ~slot ~block_payload_hash] + crafts a preattestation operation at [level] on the [round] with the + [slot] and [block_payload_hash]. If [use_legacy_name] is set, the [kind] + field in the crafted JSON will be "preendorsement" instead of + "preattestation". *) + val preattestation : + use_legacy_name:bool -> + slot:int -> + level:int -> + round:int -> + block_payload_hash:string -> + t + + (** [attestation ?use_legacy_name ~level ~round ~slot ~block_payload_hash] + crafts an attestation operation at [level] on the [round] with the [slot] + and [block_payload_hash]. If [use_legacy_name] is set, the [kind] field in + the crafted JSON will be "endorsement" instead of "attestation". *) + val attestation : + use_legacy_name:bool -> + slot:int -> + level:int -> + round:int -> + block_payload_hash:string -> + t + + (** [kind_to_string kind use_legacy_name] return the name of the [kind]. If + [use_legacy_name] is set, the name corresponding to the [kind] will be + "(pre)endorsement" instead of "(pre)attestation". *) + val kind_to_string : consensus_kind -> bool -> string (** [operation] constructs an operation from a consensus operation. the [client] is used to fetch the branch and the diff --git a/tezt/tests/dal.ml b/tezt/tests/dal.ml index 86c6c265a604..42f93733199a 100644 --- a/tezt/tests/dal.ml +++ b/tezt/tests/dal.ml @@ -496,8 +496,11 @@ let dal_attestation ?level ?(force = false) ~signer ~nb_slots availability let* level = Client.level client in return @@ (level + 1) in - Operation.Consensus.( - inject ~force ~signer (dal_attestation ~level ~attestation) client) + Operation.Consensus.inject + ~force + ~signer + (Operation.Consensus.dal_attestation ~level ~attestation) + client let dal_attestations ?level ?force ?(signers = Array.to_list Account.Bootstrap.keys) ~nb_slots availability diff --git a/tezt/tests/double_consensus.ml b/tezt/tests/double_consensus.ml index 8d7199723420..c2e156852315 100644 --- a/tezt/tests/double_consensus.ml +++ b/tezt/tests/double_consensus.ml @@ -136,13 +136,13 @@ let double_consensus_wrong_slot let endorse_utils = ( Client.endorse_for, - Operation.Consensus.endorsement, + Operation.Consensus.attestation ~use_legacy_name:true, double_endorsement_waiter, "endorsement" ) let preendorse_utils = ( Client.preendorse_for, - Operation.Consensus.preendorsement, + Operation.Consensus.preattestation ~use_legacy_name:true, double_preendorsement_waiter, "preendorsement" ) @@ -332,7 +332,12 @@ let operation_too_old = "Craft and inject an endorsement 1 level in the past and wait for \ [consensus_operation_too_old.v0] event from the accuser." ; let op = - Operation.Consensus.endorsement ~slot ~level ~round:3 ~block_payload_hash + Operation.Consensus.attestation + ~use_legacy_name:true + ~slot + ~level + ~round:3 + ~block_payload_hash in let waiter = consensus_operation_too_old_waiter accuser in let* _ = @@ -403,7 +408,8 @@ let operation_too_far_in_future = "Craft and inject an endorsement 3 levels in the future and wait for \ [consensus_operation_too_far_in_future.v0] event from the accuser." ; let op = - Operation.Consensus.endorsement + Operation.Consensus.attestation + ~use_legacy_name:true ~slot:(List.hd slots) ~level ~round:0 -- GitLab From 986550d40dd32bf2a597a265b01f2efb4061e61b Mon Sep 17 00:00:00 2001 From: Albin Coquereau Date: Tue, 30 May 2023 11:19:59 +0200 Subject: [PATCH 3/8] tezt/lib_tezos: make the signer optional --- tezt/lib_tezos/operation_core.ml | 41 +++++++++++++++++-------------- tezt/lib_tezos/operation_core.mli | 11 +++++---- 2 files changed, 28 insertions(+), 24 deletions(-) diff --git a/tezt/lib_tezos/operation_core.ml b/tezt/lib_tezos/operation_core.ml index df78dbbd8572..a026772fe914 100644 --- a/tezt/lib_tezos/operation_core.ml +++ b/tezt/lib_tezos/operation_core.ml @@ -36,7 +36,7 @@ type t = { branch : string; contents : JSON.u; kind : kind; - signer : Account.key; + signer : Account.key option; mutable raw : Hex.t option; (* This is mutable to avoid computing the raw representation several times. *) } @@ -45,7 +45,7 @@ let get_branch ?(offset = 2) client = let block = sf "head~%d" offset in RPC.Client.call client @@ RPC.get_chain_block_hash ~block () -let make ~branch ~signer ~kind contents = +let make ~branch ?signer ~kind contents = {branch; contents; kind; signer; raw = None} let json t = `O [("branch", Ezjsonm.string t.branch); ("contents", t.contents)] @@ -89,23 +89,26 @@ let hex ?protocol ?signature t client = return (`Hex (raw ^ signature)) let sign ?protocol ({kind; signer; _} as t) client = - let watermark = - match kind with - | Consensus {kind; chain_id} -> - let chain_id = - Tezos_crypto.Hashed.Chain_id.to_string - (Tezos_crypto.Hashed.Chain_id.of_b58check_exn chain_id) - in - let prefix = - match kind with Preattestation -> "\x12" | Attestation -> "\x13" - in - Tezos_crypto.Signature.Custom - (Bytes.cat (Bytes.of_string prefix) (Bytes.of_string chain_id)) - | Voting | Manager -> Tezos_crypto.Signature.Generic_operation - in - let* hex = hex ?protocol t client in - let bytes = Hex.to_bytes hex in - return (Account.sign_bytes ~watermark ~signer bytes) + match signer with + | None -> return Tezos_crypto.Signature.zero + | Some signer -> + let watermark = + match kind with + | Consensus {kind; chain_id} -> + let chain_id = + Tezos_crypto.Hashed.Chain_id.to_string + (Tezos_crypto.Hashed.Chain_id.of_b58check_exn chain_id) + in + let prefix = + match kind with Preattestation -> "\x12" | Attestation -> "\x13" + in + Tezos_crypto.Signature.Custom + (Bytes.cat (Bytes.of_string prefix) (Bytes.of_string chain_id)) + | Voting | Manager -> Tezos_crypto.Signature.Generic_operation + in + let* hex = hex ?protocol t client in + let bytes = Hex.to_bytes hex in + return (Account.sign_bytes ~watermark ~signer bytes) module Tezos_operation = Tezos_base.TzPervasives.Operation diff --git a/tezt/lib_tezos/operation_core.mli b/tezt/lib_tezos/operation_core.mli index bc87d78731bc..8e2a4def561b 100644 --- a/tezt/lib_tezos/operation_core.mli +++ b/tezt/lib_tezos/operation_core.mli @@ -72,9 +72,9 @@ type kind = | Voting | Manager -(** [make ~branch ~signer ~kind json client] builds the representation +(** [make ~branch ?signer ~kind json client] builds the representation of an unsigned operation. *) -val make : branch:string -> signer:Account.key -> kind:kind -> JSON.u -> t +val make : branch:string -> ?signer:Account.key -> kind:kind -> JSON.u -> t (** [json t] gives the json representation of an unsigned operation. *) val json : t -> JSON.u @@ -100,9 +100,10 @@ val hex : Client.t -> Hex.t Lwt.t -(** [sign t client] signs the raw representation of operation [t] by - its signer (see {!val:make}). [client] is used to construct the - binary representation of [t]. *) +(** [sign t client] signs the raw representation of operation [t] by its signer + (see {!val:make}). [client] is used to construct the binary representation + of [t]. Note that if no signer have been given to [t] the function returns + [Tezos_crypto.Signature.zero]. *) val sign : ?protocol:Protocol.t -> t -> Client.t -> Tezos_crypto.Signature.t Lwt.t -- GitLab From d8003e720b9f82fc2872111c344ee56f884003d7 Mon Sep 17 00:00:00 2001 From: Albin Coquereau Date: Mon, 15 May 2023 18:05:28 +0200 Subject: [PATCH 4/8] tezt/lib_tezos: add anonymous helper for double_consensus_evidence operations --- tezt/lib_tezos/operation_core.ml | 79 ++++++++++++++++++++++++++++++- tezt/lib_tezos/operation_core.mli | 64 +++++++++++++++++++++++++ 2 files changed, 142 insertions(+), 1 deletion(-) diff --git a/tezt/lib_tezos/operation_core.ml b/tezt/lib_tezos/operation_core.ml index a026772fe914..4bd48201f0c4 100644 --- a/tezt/lib_tezos/operation_core.ml +++ b/tezt/lib_tezos/operation_core.ml @@ -29,6 +29,7 @@ type consensus_kind = Attestation | Preattestation type kind = | Consensus of {kind : consensus_kind; chain_id : string} + | Anonymous | Voting | Manager @@ -104,7 +105,8 @@ let sign ?protocol ({kind; signer; _} as t) client = in Tezos_crypto.Signature.Custom (Bytes.cat (Bytes.of_string prefix) (Bytes.of_string chain_id)) - | Voting | Manager -> Tezos_crypto.Signature.Generic_operation + | Anonymous | Voting | Manager -> + Tezos_crypto.Signature.Generic_operation in let* hex = hex ?protocol t client in let bytes = Hex.to_bytes hex in @@ -284,6 +286,81 @@ module Consensus = struct inject ?request ?force ?error op client end +module Anonymous = struct + type double_consensus_evidence_kind = + | Double_attestation_evidence + | Double_preattestation_evidence + + type nonrec t = + | Double_consensus_evidence of { + kind : double_consensus_evidence_kind; + use_legacy_name : bool; + op1 : t * Tezos_crypto.Signature.t; + op2 : t * Tezos_crypto.Signature.t; + } + + let double_consensus_evidence ~kind ~use_legacy_name + (({kind = op1_kind; _}, _) as op1) (({kind = op2_kind; _}, _) as op2) = + match (kind, op1_kind, op2_kind) with + | ( Double_attestation_evidence, + Consensus {kind = Attestation; _}, + Consensus {kind = Attestation; _} ) -> + Double_consensus_evidence {kind; use_legacy_name; op1; op2} + | ( Double_preattestation_evidence, + Consensus {kind = Preattestation; _}, + Consensus {kind = Preattestation; _} ) -> + Double_consensus_evidence {kind; use_legacy_name; op1; op2} + | _, _, _ -> + Test.fail "Invalid arguments to create a double_consensus_evidence" + + let double_attestation_evidence = + double_consensus_evidence ~kind:Double_attestation_evidence + + let double_preattestation_evidence = + double_consensus_evidence ~kind:Double_preattestation_evidence + + let kind_to_string kind use_legacy_name = + sf + "double_%s_evidence" + (Consensus.kind_to_string + (match kind with + | Double_attestation_evidence -> Attestation + | Double_preattestation_evidence -> Preattestation) + use_legacy_name) + + let denunced_op_json (op, signature) = + `O + [ + ("branch", `String op.branch); + ("operations", List.hd (Ezjsonm.get_list Fun.id op.contents)); + ("signature", `String (Tezos_crypto.Signature.to_b58check signature)); + ] + + let json = function + | Double_consensus_evidence {kind; use_legacy_name; op1; op2} -> + let op1 = denunced_op_json op1 in + let op2 = denunced_op_json op2 in + `O + [ + ("kind", Ezjsonm.string (kind_to_string kind use_legacy_name)); + ("op1", op1); + ("op2", op2); + ] + + let operation ?branch anonymous_operation client = + let json = `A [json anonymous_operation] in + let* branch = + match branch with + | None -> get_branch ~offset:0 client + | Some branch -> return branch + in + return (make ~branch ~kind:Anonymous json) + + let inject ?request ?force ?branch ?error consensus client = + let* op = operation ?branch consensus client in + inject ?request ?force ?error op client +end + module Voting = struct type t = | Proposals of { diff --git a/tezt/lib_tezos/operation_core.mli b/tezt/lib_tezos/operation_core.mli index 8e2a4def561b..f9ba93be0ec3 100644 --- a/tezt/lib_tezos/operation_core.mli +++ b/tezt/lib_tezos/operation_core.mli @@ -69,6 +69,7 @@ type consensus_kind = Attestation | Preattestation this module. *) type kind = | Consensus of {kind : consensus_kind; chain_id : string} + | Anonymous | Voting | Manager @@ -260,6 +261,69 @@ module Consensus : sig [`OpHash of string] Lwt.t end +module Anonymous : sig + (** A representation of an anonymous operation. *) + type t + + type double_consensus_evidence_kind = + | Double_attestation_evidence + | Double_preattestation_evidence + + (** [double_consensus_evidence ~kind ~use_legacy_name op1 op2] crafts a double + consensus evidence operation with the [kind], [op1] and [op2]. Both + operations should be of the same kind and the same as the one expected by + [kind]. If [use_legacy_name] is set, the [kind] field in the crafted JSON + will be "(pre)endorsement" instead of "(pre)attestation". *) + val double_consensus_evidence : + kind:double_consensus_evidence_kind -> + use_legacy_name:bool -> + operation * Tezos_crypto.Signature.t -> + operation * Tezos_crypto.Signature.t -> + t + + (** [double_attestation_evidence ~use_legacy_name op1 op2] crafts a double + attestation evidence operation with op1 and op2. Both operations should be + attestations. If [use_legacy_name] is set, the [kind] field in the crafted + JSON will be "endorsement" instead of "attestation". *) + val double_attestation_evidence : + use_legacy_name:bool -> + operation * Tezos_crypto.Signature.t -> + operation * Tezos_crypto.Signature.t -> + t + + (** [double_preattestation_evidence ~use_legacy_name op1 op2] crafts a double + attestation evidence operation with op1 and op2. Both operations should be + preattestations. If [use_legacy_name] is set, the [kind] field in the + crafted JSON will be "preendorsement" instead of "preattestation". *) + val double_preattestation_evidence : + use_legacy_name:bool -> + operation * Tezos_crypto.Signature.t -> + operation * Tezos_crypto.Signature.t -> + t + + (** [kind_to_string kind use_legacy_name] return the name of the [kind]. If + [use_legacy_name] is set, the name corresponding to the [kind] will be + "double_(pre)endorsement_evidence" instead of + "double_(pre)attestation_evidence". *) + val kind_to_string : double_consensus_evidence_kind -> bool -> string + + (** [operation] constructs an operation from an anonymous operation. the + [client] is used to fetch the branch and the [chain_id]. *) + val operation : ?branch:string -> t -> Client.t -> operation Lwt.t + + (** A wrapper for {!val:inject} with anonymous operations. The client is used + to get all the data that was not provided if it can be recovered via RPCs. + Mainly those are the [branch] and the [chain_id]. *) + val inject : + ?request:[`Inject | `Notify] -> + ?force:bool -> + ?branch:string -> + ?error:rex -> + t -> + Client.t -> + [`OpHash of string] Lwt.t +end + (** Voting operations (validation pass [1]): [proposals] and [ballot]. Only the [proposals] operation is currently supported. Feel free to -- GitLab From 5ecc07eb3670cb6234c27bcb58fdcc150ceb7a6f Mon Sep 17 00:00:00 2001 From: Albin Coquereau Date: Mon, 15 May 2023 18:11:38 +0200 Subject: [PATCH 5/8] tezt/tests: add forging tests for consensus operations using both the `attestation` and `endorsement` naming --- tezt/tests/main.ml | 1 + tezt/tests/rpc_versioning_attestation.ml | 112 +++++++++++++++++++++++ 2 files changed, 113 insertions(+) create mode 100644 tezt/tests/rpc_versioning_attestation.ml diff --git a/tezt/tests/main.ml b/tezt/tests/main.ml index cd85b650330e..c3ddb11d6256 100644 --- a/tezt/tests/main.ml +++ b/tezt/tests/main.ml @@ -172,6 +172,7 @@ let register_protocol_tests_that_use_supports_correctly () = Proxy.register ~protocols ; Proxy_server_test.register ~protocols ; RPC_test.register protocols ; + Rpc_versioning_attestation.register ~protocols ; Reject_malformed_micheline.register ~protocols ; Replace_by_fees.register ~protocols ; Retro.register ~protocols ; diff --git a/tezt/tests/rpc_versioning_attestation.ml b/tezt/tests/rpc_versioning_attestation.ml new file mode 100644 index 000000000000..bd9a2946b4ef --- /dev/null +++ b/tezt/tests/rpc_versioning_attestation.ml @@ -0,0 +1,112 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2023 Nomadic Labs *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +(* Testing + ------- + Component: RPCs + Invocation: dune exec tezt/tests/main.exe -- --file rpc_versioning.ml + Subject: rpc versioning +*) + +let register_test ~title ?(additionnal_tags = []) f = + Protocol.register_test + ~__FILE__ + ~title + ~supports:(Protocol.From_protocol 18) + ~tags:(["rpc"; "versioning"] @ additionnal_tags) + f + +let mk_consensus ?(slot = 1) ?(level = 1) ?(round = 0) + ?(block_payload_hash = + "vh1g87ZG6scSYxKhspAUzprQVuLAyoa5qMBKcUfjgnQGnFb3dJcG") kind + use_legacy_name = + Operation.Consensus.consensus + ~kind + ~use_legacy_name + ~slot + ~level + ~round + ~block_payload_hash + +let check_kind json kind = + let json_kind = + JSON.(json |-> "contents" |> as_list |> List.hd |-> "kind" |> as_string) + in + if not (String.equal json_kind kind) then + Test.fail ~__LOC__ "Operation should have %s kind, got: %s" kind json_kind + +let check_hex_from_ops op1 op2 client = + Log.info + "Ensures that Bytes returned from calling the forge RPC on both operations \ + are identical" ; + let* (`Hex op1_raw) = Operation.hex op1 client in + let* (`Hex op2_raw) = Operation.hex op2 client in + if not (String.equal op1_raw op2_raw) then + Test.fail ~__LOC__ "Bytes are not equal, got: %s and: %s" op1_raw op2_raw + else unit + +let test_consensus kind protocol = + let* _node, client = Client.init_with_protocol ~protocol `Client () in + let signer = Constant.bootstrap1 in + + let create_consensus_op ~use_legacy_name = + let consensus_name = + Operation.Consensus.kind_to_string kind use_legacy_name + in + Log.info "Create an %s operation" consensus_name ; + let consensus = mk_consensus kind use_legacy_name in + let* consensus_op = + Operation.Consensus.operation ~signer consensus client + in + + Log.info + "Ensures that the generated JSON contains the %s kind" + consensus_name ; + let consensus_json = + JSON.annotate ~origin:__LOC__ @@ Operation.json consensus_op + in + check_kind consensus_json consensus_name ; + Lwt.return consensus_op + in + + let* legacy_consensus_op = create_consensus_op ~use_legacy_name:true in + let* consensus_op = create_consensus_op ~use_legacy_name:false in + check_hex_from_ops legacy_consensus_op consensus_op client + +let test_forge_consensus = + register_test + ~title:"Forge consensus operations" + ~additionnal_tags:["forge"; "operations"; "consensus"] + @@ fun protocol -> test_consensus Operation.Attestation protocol + +let test_forge_preconsensus = + register_test + ~title:"Forge pre-consensus operations" + ~additionnal_tags:["forge"; "operations"; "consensus"; "pre"] + @@ fun protocol -> test_consensus Operation.Preattestation protocol + +let register ~protocols = + test_forge_consensus protocols ; + test_forge_preconsensus protocols -- GitLab From 9a9c17104b85637036d8c33d1848c4290eb250fe Mon Sep 17 00:00:00 2001 From: Albin Coquereau Date: Mon, 15 May 2023 18:13:12 +0200 Subject: [PATCH 6/8] tezt/tests: add forging tests for double consensus evidence operations using both the `attestation` and `endorsement` naming --- tezt/tests/rpc_versioning_attestation.ml | 87 +++++++++++++++++++++++- 1 file changed, 86 insertions(+), 1 deletion(-) diff --git a/tezt/tests/rpc_versioning_attestation.ml b/tezt/tests/rpc_versioning_attestation.ml index bd9a2946b4ef..1b2b8db53539 100644 --- a/tezt/tests/rpc_versioning_attestation.ml +++ b/tezt/tests/rpc_versioning_attestation.ml @@ -107,6 +107,91 @@ let test_forge_preconsensus = ~additionnal_tags:["forge"; "operations"; "consensus"; "pre"] @@ fun protocol -> test_consensus Operation.Preattestation protocol +let mk_double_consensus_evidence kind use_legacy_name op1 op2 client = + let* op1_sign = Operation.sign op1 client in + let* op2_sign = Operation.sign op2 client in + return + (Operation.Anonymous.double_consensus_evidence + ~kind + ~use_legacy_name + (op1, op1_sign) + (op2, op2_sign)) + +let test_double_consensus_evidence double_evidence_kind protocol = + let* _node, client = Client.init_with_protocol ~protocol `Client () in + + let create_double_consensus_evidence ~use_legacy_name = + let consensus_kind = + match double_evidence_kind with + | Operation.Anonymous.Double_attestation_evidence -> Operation.Attestation + | Operation.Anonymous.Double_preattestation_evidence -> + Operation.Preattestation + in + let consensus_name = + Operation.Anonymous.kind_to_string double_evidence_kind use_legacy_name + in + Log.info "Create an %s operation" consensus_name ; + + let signer = Constant.bootstrap1 in + let consensus1 = mk_consensus consensus_kind use_legacy_name in + let* op1 = Operation.Consensus.operation ~signer consensus1 client in + let consensus2 = mk_consensus ~slot:2 consensus_kind use_legacy_name in + let* op2 = Operation.Consensus.operation ~signer consensus2 client in + let* double_consensus_evidence = + mk_double_consensus_evidence + double_evidence_kind + use_legacy_name + op1 + op2 + client + in + let* double_consensus_evidence_op = + Operation.Anonymous.operation double_consensus_evidence client + in + + Log.info + "Ensures that the generated JSON contains the %s kind" + consensus_name ; + let consensus_json = + JSON.annotate ~origin:__LOC__ + @@ Operation.json double_consensus_evidence_op + in + check_kind consensus_json consensus_name ; + Lwt.return double_consensus_evidence_op + in + + let* legacy_double_consensus_evidence_op = + create_double_consensus_evidence ~use_legacy_name:true + in + let* double_consensus_evidence_op = + create_double_consensus_evidence ~use_legacy_name:false + in + check_hex_from_ops + legacy_double_consensus_evidence_op + double_consensus_evidence_op + client + +let test_forge_double_consensus_evidence = + register_test + ~title:"Forge double consensus evidence operations" + ~additionnal_tags:["forge"; "operations"; "consensus"; "double"; "evidence"] + @@ fun protocol -> + test_double_consensus_evidence + Operation.Anonymous.Double_attestation_evidence + protocol + +let test_forge_double_preconsensus_evidence = + register_test + ~title:"Forge double pre-consensus evidence operations" + ~additionnal_tags: + ["forge"; "operations"; "consensus"; "pre"; "double"; "evidence"] + @@ fun protocol -> + test_double_consensus_evidence + Operation.Anonymous.Double_preattestation_evidence + protocol + let register ~protocols = test_forge_consensus protocols ; - test_forge_preconsensus protocols + test_forge_preconsensus protocols ; + test_forge_double_consensus_evidence protocols ; + test_forge_double_preconsensus_evidence protocols -- GitLab From d63b97c3694bbacf8fab3e0bfe7f8c44f333d31a Mon Sep 17 00:00:00 2001 From: Albin Coquereau Date: Mon, 15 May 2023 19:10:25 +0200 Subject: [PATCH 7/8] tezt/tests: add some test for double_consensus_evidence with invalid contents --- tezt/tests/rpc_versioning_attestation.ml | 87 +++++++++++++++++++++++- 1 file changed, 86 insertions(+), 1 deletion(-) diff --git a/tezt/tests/rpc_versioning_attestation.ml b/tezt/tests/rpc_versioning_attestation.ml index 1b2b8db53539..79bb68a81c1a 100644 --- a/tezt/tests/rpc_versioning_attestation.ml +++ b/tezt/tests/rpc_versioning_attestation.ml @@ -190,8 +190,93 @@ let test_forge_double_preconsensus_evidence = Operation.Anonymous.Double_preattestation_evidence protocol +let test_invalid_double_consensus_evidence double_evidence_kind protocol = + let* _node, client = Client.init_with_protocol ~protocol `Client () in + + let create_double_consensus_evidence ~use_legacy_name = + let consensus_kind = + match double_evidence_kind with + | Operation.Anonymous.Double_attestation_evidence -> Operation.Attestation + | Operation.Anonymous.Double_preattestation_evidence -> + Operation.Preattestation + in + let consensus_name = + Operation.Anonymous.kind_to_string double_evidence_kind use_legacy_name + in + Log.info "Create an %s operation" consensus_name ; + + let signer = Constant.bootstrap1 in + let consensus1 = mk_consensus consensus_kind use_legacy_name in + let* op1 = Operation.Consensus.operation ~signer consensus1 client in + let consensus2 = + mk_consensus ~slot:2 consensus_kind (not use_legacy_name) + in + let* op2 = Operation.Consensus.operation ~signer consensus2 client in + let* double_consensus_evidence = + mk_double_consensus_evidence + double_evidence_kind + use_legacy_name + op1 + op2 + client + in + let* double_consensus_evidence_op = + Operation.Anonymous.operation double_consensus_evidence client + in + + Log.info + "Ensures that the generated JSON contains the %s kind" + consensus_name ; + let consensus_json = Operation.json double_consensus_evidence_op in + let annotated_json = JSON.annotate ~origin:__LOC__ @@ consensus_json in + check_kind annotated_json consensus_name ; + + Log.info "Ensures that the generated JSON cannot be parsed by the forge RPC" ; + let*? t = + RPC.Client.spawn client + @@ RPC.post_chain_block_helpers_forge_operations + ~data:(Data consensus_json) + () + in + let msg = rex "Failed to parse the request body: No case matched:" in + Process.check_error ~msg t + in + + let* () = create_double_consensus_evidence ~use_legacy_name:true in + create_double_consensus_evidence ~use_legacy_name:false + +let test_forge_invalid_double_consensus_evidence = + register_test + ~title:"Forge invalid double consensus evidence operations" + ~additionnal_tags: + ["forge"; "operations"; "consensus"; "double"; "evidence"; "invalid"] + @@ fun protocol -> + test_invalid_double_consensus_evidence + Operation.Anonymous.Double_attestation_evidence + protocol + +let test_forge_invalid_double_preconsensus_evidence = + register_test + ~title:"Forge invalid double pre-consensus evidence operations" + ~additionnal_tags: + [ + "forge"; + "operations"; + "consensus"; + "pre"; + "double"; + "evidence"; + "invalid"; + ] + @@ fun protocol -> + test_invalid_double_consensus_evidence + Operation.Anonymous.Double_preattestation_evidence + protocol + let register ~protocols = test_forge_consensus protocols ; test_forge_preconsensus protocols ; test_forge_double_consensus_evidence protocols ; - test_forge_double_preconsensus_evidence protocols + test_forge_double_preconsensus_evidence protocols ; + test_forge_invalid_double_consensus_evidence protocols ; + test_forge_invalid_double_preconsensus_evidence protocols -- GitLab From 9791f64b116a45930860dd777a8a2d413de7acb4 Mon Sep 17 00:00:00 2001 From: Albin Coquereau Date: Mon, 15 May 2023 18:33:01 +0200 Subject: [PATCH 8/8] changes: add entry for newly accepted kinds in forge rpc --- CHANGES.rst | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGES.rst b/CHANGES.rst index 879a9845ae52..8db6c0bcad17 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -68,6 +68,12 @@ Node mempool (however, we are working on providing this information again). (MR :gl:`!6787`) +- RPC ``/helpers/forge/operations`` can now take JSON formatted operations with + ``attestation``, ``preattestation``, ``double_attestation_evidence`` and + ``double_preattestation_evidence`` kinds. Note that the existing kinds + ``endorsement``, ``preendorsement``, ``double_endorsement_evidence``, and + ``double_preendorsement_evidence`` are still accepted. (MR :gl:`!8746`) + Client ------ - Adding client commands to generate, open and verify a time-lock. -- GitLab