diff --git a/src/proto_alpha/lib_delegate/baking_actions.ml b/src/proto_alpha/lib_delegate/baking_actions.ml index 2d2b9be42351b871251a82ad06c66f5f0c877029..cfa3b1ab5135ee60b6f87dc64645a0fab913d312 100644 --- a/src/proto_alpha/lib_delegate/baking_actions.ml +++ b/src/proto_alpha/lib_delegate/baking_actions.ml @@ -678,10 +678,17 @@ let forge_and_sign_consensus_vote global_state ~branch unsigned_consensus_vote : | Attestation -> `Attestation in let unsigned_operation = (shell, Contents_list contents) in + let bls_mode = + match delegate.consensus_key.public_key with + | Bls _ -> global_state.constants.parametric.aggregate_attestation + | _ -> false + in + let encoding = + if bls_mode then Operation.bls_mode_unsigned_encoding + else Operation.unsigned_encoding + in let unsigned_operation_bytes = - Data_encoding.Binary.to_bytes_exn - Operation.unsigned_encoding - unsigned_operation + Data_encoding.Binary.to_bytes_exn encoding unsigned_operation in let sk_uri = delegate.consensus_key.secret_key_uri in let* signature = diff --git a/src/proto_alpha/lib_protocol/alpha_context.ml b/src/proto_alpha/lib_protocol/alpha_context.ml index 40940a956160962462503cc0ce2792942f32bd64..3ea45f381fc80eb2e67bf2fcbcae6d24050e138d 100644 --- a/src/proto_alpha/lib_protocol/alpha_context.ml +++ b/src/proto_alpha/lib_protocol/alpha_context.ml @@ -189,6 +189,21 @@ module Entrypoint = Entrypoint_repr module Manager_counter = Manager_counter_repr include Operation_repr +module Constants = struct + include Constants_repr + include Constants_storage + + module Parametric = struct + include Constants_parametric_repr + + module Internal_for_tests = struct + include Internal_for_tests + + let update_sc_rollup_parameter = update_sc_rollup_parameter + end + end +end + module Operation = struct type 'kind t = 'kind operation = { shell : Operation.shell_header; @@ -203,7 +218,17 @@ module Operation = struct include Operation_repr - let check_signature _ctxt = check_signature unsigned_encoding + let check_signature (type kind) ctxt (key : Signature.Public_key.t) chain_id + (op : kind operation) = + let encoding = + if Constants.aggregate_attestation ctxt then + (* attestations signed by BLS keys uses a dedicated serialization encoding *) + match (op.protocol_data.contents, key) with + | Single (Attestation _), Bls _ -> bls_mode_unsigned_encoding + | _ -> unsigned_encoding + else unsigned_encoding + in + check_signature encoding key chain_id op module Internal_for_tests = struct let serialize_unsigned_operation _ctxt branch contents = @@ -268,21 +293,6 @@ type public_key_hash = Signature.Public_key_hash.t type signature = Signature.t -module Constants = struct - include Constants_repr - include Constants_storage - - module Parametric = struct - include Constants_parametric_repr - - module Internal_for_tests = struct - include Internal_for_tests - - let update_sc_rollup_parameter = update_sc_rollup_parameter - end - end -end - module Voting_period = struct include Voting_period_repr include Voting_period_storage diff --git a/tezt/lib_tezos/RPC.ml b/tezt/lib_tezos/RPC.ml index 53b260c73bd85eb2713c9af253d4831bd754ad63..a23206215f4fd7071541655231f82333b8ea0764 100644 --- a/tezt/lib_tezos/RPC.ml +++ b/tezt/lib_tezos/RPC.ml @@ -591,6 +591,22 @@ let post_chain_block_helpers_forge_operations ?(chain = "main") ["chains"; chain; "blocks"; block; "helpers"; "forge"; "operations"] Fun.id +let post_chain_block_helpers_forge_bls_consensus_operations ?(chain = "main") + ?(block = "head") ~data () = + make + ~data + POST + [ + "chains"; + chain; + "blocks"; + block; + "helpers"; + "forge"; + "bls_consensus_operations"; + ] + Fun.id + let post_chain_block_helpers_forge_block_header ?(chain = "main") ?(block = "head") ~data () = make diff --git a/tezt/lib_tezos/RPC.mli b/tezt/lib_tezos/RPC.mli index 7fa3bba5be4c18dd1b9985d6adf56c3f44998ae8..d9742b3b2ce2a449a19fcf13c287dc1bef6cd1c2 100644 --- a/tezt/lib_tezos/RPC.mli +++ b/tezt/lib_tezos/RPC.mli @@ -571,6 +571,14 @@ val post_chain_block_helpers_preapply_operations : val post_chain_block_helpers_forge_operations : ?chain:string -> ?block:string -> data:data -> unit -> JSON.t t +(** RPC: [POST /chains//blocks//helpers/forge/consensus_operations] + + [chain] defaults to ["main"]. + [block] defaults to ["head"]. +*) +val post_chain_block_helpers_forge_bls_consensus_operations : + ?chain:string -> ?block:string -> data:data -> unit -> JSON.t t + (** RPC: [POST /chains//blocks//helpers/forge_block_header] [chain] defaults to ["main"]. diff --git a/tezt/lib_tezos/operation_core.ml b/tezt/lib_tezos/operation_core.ml index 95172391ae520ced0c09bd104d7e31312bece4d1..b963710ae32062d072015e6d56051d936cfe1c03 100644 --- a/tezt/lib_tezos/operation_core.ml +++ b/tezt/lib_tezos/operation_core.ml @@ -68,7 +68,7 @@ let raw ?protocol t client = t.raw <- Some (`Hex raw) ; return (`Hex raw) | Some p -> ( - let name = Protocol.daemon_name p ^ ".operation.unsigned" in + let name = Protocol.encoding_prefix p ^ ".operation.unsigned" in match Data_encoding.Registration.find name with | None -> Test.fail "%s encoding was not found" name | Some registered -> ( @@ -91,35 +91,61 @@ let hex ?protocol ?signature t client = let (`Hex signature) = Tezos_crypto.Signature.to_hex signature in return (`Hex (raw ^ signature)) +let bls_mode_raw t client : Hex.t Lwt.t = + let* json = + Client.RPC.call client + @@ RPC.post_chain_block_helpers_forge_bls_consensus_operations + ~data:(Data (json t)) + () + in + let sign_bytes = JSON.(json |-> "sign" |> as_string) in + let inject_bytes = JSON.(json |-> "inject" |> as_string) in + t.raw <- Some (`Hex inject_bytes) ; + return (`Hex sign_bytes) + let sign ?protocol ({kind; signer; _} as t) client = + let is_tz4 = String.starts_with ~prefix:"tz4" in 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 + | Some signer -> ( + 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 + let watermark = Tezos_crypto.Signature.Custom (Bytes.cat (Bytes.of_string prefix) (Bytes.of_string chain_id)) - | Anonymous | 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) + in + let* hex = + match protocol with + | Some p + when Protocol.number p >= 023 && is_tz4 signer.public_key_hash -> + let* constants = + Client.RPC.call client + @@ RPC.get_chain_block_context_constants () + in + if JSON.(constants |-> "aggregate_attestation" |> as_bool) then + bls_mode_raw t client + else hex ?protocol t client + | _ -> hex ?protocol t client + in + let bytes = Hex.to_bytes hex in + return (Account.sign_bytes ~watermark ~signer bytes) + | Anonymous | Voting | Manager -> + let watermark = 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)) let signed_hex ?protocol ?signature t client = let* signature = match signature with - | None -> sign t client + | None -> sign ?protocol t client | Some signature -> return signature in hex ?protocol ~signature t client @@ -354,9 +380,10 @@ module Consensus = struct in return (make ~branch ~signer ~kind:(Consensus {kind; chain_id}) json) - let inject ?request ?force ?branch ?chain_id ?error ~signer consensus client = + let inject ?request ?force ?branch ?chain_id ?error ~protocol ~signer + consensus client = let* op = operation ?branch ?chain_id ~signer consensus client in - inject ?request ?force ?error op client + inject ?request ?force ?error ~protocol op client let get_slots ~level client = Client.RPC.call client @@ RPC.get_chain_block_helper_validators ~level () diff --git a/tezt/lib_tezos/operation_core.mli b/tezt/lib_tezos/operation_core.mli index 9938c6be508e751586bd3231523fa82a6a93540a..0b9ce4de7df0b8e394c4011ae7491fce43842c5a 100644 --- a/tezt/lib_tezos/operation_core.mli +++ b/tezt/lib_tezos/operation_core.mli @@ -300,6 +300,7 @@ module Consensus : sig ?branch:string -> ?chain_id:string -> ?error:rex -> + protocol:Protocol.t -> signer:Account.key -> t -> Client.t -> diff --git a/tezt/tests/double_consensus.ml b/tezt/tests/double_consensus.ml index a95b6fec9fdb77e4d487151c500e1154718c907d..37f715a0fa1fee10e9b45b5db354b89f51a2cc1e 100644 --- a/tezt/tests/double_consensus.ml +++ b/tezt/tests/double_consensus.ml @@ -120,7 +120,12 @@ let double_consensus_wrong_slot in let waiter = consensus_waiter accuser in let* _ = - Operation.Consensus.inject ~branch ~signer:Constant.bootstrap1 op client + Operation.Consensus.inject + ~protocol + ~branch + ~signer:Constant.bootstrap1 + op + client in let* () = waiter in Log.info @@ -134,7 +139,12 @@ let double_consensus_wrong_slot double_consensus_already_denounced_waiter accuser oph in let* _ = - Operation.Consensus.inject ~branch ~signer:Constant.bootstrap1 op client + Operation.Consensus.inject + ~protocol + ~branch + ~signer:Constant.bootstrap1 + op + client in let* () = waiter_already_denounced in unit @@ -185,6 +195,7 @@ let double_consensus_wrong_block_payload_hash let* _ = Operation.Consensus.inject ~force:true + ~protocol ~branch ~signer:Constant.bootstrap1 op @@ -208,6 +219,7 @@ let double_consensus_wrong_block_payload_hash let* _ = Operation.Consensus.inject ~force:true + ~protocol ~branch ~signer:Constant.bootstrap1 op @@ -264,6 +276,7 @@ let double_consensus_wrong_branch let* _ = Operation.Consensus.inject ~force:true + ~protocol ~branch ~signer:Constant.bootstrap1 op @@ -284,6 +297,7 @@ let double_consensus_wrong_branch let* _ = Operation.Consensus.inject ~force:true + ~protocol ~branch ~signer:Constant.bootstrap1 op @@ -361,6 +375,7 @@ let operation_too_old = let* _ = Operation.Consensus.inject ~force:true + ~protocol ~branch ~signer:Constant.bootstrap1 op @@ -438,6 +453,7 @@ let operation_too_far_in_future = let* _ = Operation.Consensus.inject ~force:true + ~protocol ~branch ~signer:Constant.bootstrap1 op diff --git a/tezt/tests/prevalidator.ml b/tezt/tests/prevalidator.ml index 86ef77d4f1def570230270de5ae47b25a4f82f84..d86fde531f89b26717bdfffa33aec5dab9c44a5a 100644 --- a/tezt/tests/prevalidator.ml +++ b/tezt/tests/prevalidator.ml @@ -1917,6 +1917,7 @@ module Revamped = struct ~round:0 ~block_payload_hash ()) + ~protocol ~signer:delegate client in @@ -2429,6 +2430,7 @@ module Revamped = struct ~round:0 ~block_payload_hash ()) + ~protocol ~signer:account client in @@ -2541,6 +2543,7 @@ module Revamped = struct ~round:0 ~block_payload_hash ()) + ~protocol ~signer:account client in @@ -2672,6 +2675,7 @@ module Revamped = struct ~round:0 ~block_payload_hash ()) + ~protocol ~signer client in @@ -2916,6 +2920,7 @@ module Revamped = struct let* _ = Operation.Consensus.inject ~force:true + ~protocol ~branch:branch_future1 ~signer:Constant.bootstrap1 op_future1 @@ -2924,6 +2929,7 @@ module Revamped = struct let* _ = Operation.Consensus.inject ~force:true + ~protocol ~branch:branch_future2 ~signer:Constant.bootstrap1 op_future2