diff --git a/src/client/embedded/alpha/client_proto_context.ml b/src/client/embedded/alpha/client_proto_context.ml index 3be8bf7e7..2dfeb0c56 100644 --- a/src/client/embedded/alpha/client_proto_context.ml +++ b/src/client/embedded/alpha/client_proto_context.ml @@ -148,6 +148,19 @@ let faucet cctxt block ?force ~manager_pkh () = ~net ~id:manager_pkh () >>=? fun bytes -> originate cctxt ?force ~block bytes +let dictate cctxt block command seckey = + Client_node_rpcs.Blocks.net cctxt block >>= fun net -> + Client_proto_rpcs.Helpers.Forge.Dictator.operation + cctxt block ~net command >>=? fun bytes -> + let signature = Ed25519.sign seckey bytes in + let signed_bytes = MBytes.concat bytes signature in + let oph = Operation_hash.hash_bytes [ signed_bytes ] in + Client_node_rpcs.inject_operation cctxt ~wait:true signed_bytes >>=? fun injected_oph -> + assert (Operation_hash.equal oph injected_oph) ; + cctxt.message "Operation successfully injected in the node." >>= fun () -> + cctxt.message "Operation hash is '%a'." Operation_hash.pp oph >>= fun () -> + return () + let group = { Cli_entries.name = "context" ; title = "Block contextual commands (see option -block)" } @@ -275,5 +288,33 @@ let commands () = (fun c -> cctxt.message "New contract %a originated from a smart contract." Contract.pp c) contracts >>= fun () -> return ()) >>= - Client_proto_rpcs.handle_error cctxt) + Client_proto_rpcs.handle_error cctxt) ; + command ~desc: "Activate a protocol" begin + prefixes [ "activate" ; "protocol" ] @@ + param ~name:"version" ~desc:"Protocol version (b58check)" + (fun _ p -> Lwt.return @@ Protocol_hash.of_b58check p) @@ + prefixes [ "with" ; "key" ] @@ + param ~name:"password" ~desc:"Dictator's key" + (fun _ key -> + Lwt.return (Environment.Ed25519.Secret_key.of_b58check key)) + stop + end + (fun hash seckey cctxt -> + let block = Client_config.block () in + dictate cctxt block (Activate hash) seckey >>= + Client_proto_rpcs.handle_error cctxt) ; + command ~desc: "Fork a test protocol" begin + prefixes [ "fork" ; "test" ; "protocol" ] @@ + param ~name:"version" ~desc:"Protocol version (b58check)" + (fun _ p -> Lwt.return (Protocol_hash.of_b58check p)) @@ + prefixes [ "with" ; "key" ] @@ + param ~name:"password" ~desc:"Dictator's key" + (fun _ key -> + Lwt.return (Environment.Ed25519.Secret_key.of_b58check key)) + stop + end + (fun hash seckey cctxt -> + let block = Client_config.block () in + dictate cctxt block (Activate_testnet hash) seckey >>= + Client_proto_rpcs.handle_error cctxt) ; ] diff --git a/src/client/embedded/alpha/client_proto_rpcs.ml b/src/client/embedded/alpha/client_proto_rpcs.ml index 8ac00eccc..fb052ecf7 100644 --- a/src/client/embedded/alpha/client_proto_rpcs.ml +++ b/src/client/embedded/alpha/client_proto_rpcs.ml @@ -236,6 +236,19 @@ module Helpers = struct operations cctxt b ~net ~source Tezos_context.[Endorsement { block ; slot }] end + module Dictator = struct + let operation cctxt + block ~net operation = + let op = Dictator_operation operation in + (call_error_service1 cctxt Services.Helpers.Forge.operations block + ({net_id=net}, Sourced_operations op)) + let activate cctxt + b ~net hash = + operation cctxt b ~net (Activate hash) + let activate_testnet cctxt + b ~net hash = + operation cctxt b ~net (Activate_testnet hash) + end module Anonymous = struct let operations cctxt block ~net operations = (call_error_service1 cctxt Services.Helpers.Forge.operations block diff --git a/src/client/embedded/alpha/client_proto_rpcs.mli b/src/client/embedded/alpha/client_proto_rpcs.mli index c4cc20ba2..da4866c57 100644 --- a/src/client/embedded/alpha/client_proto_rpcs.mli +++ b/src/client/embedded/alpha/client_proto_rpcs.mli @@ -238,6 +238,26 @@ module Helpers : sig public_key_hash option -> MBytes.t tzresult Lwt.t end + module Dictator : sig + val operation: + Client_commands.context -> + block -> + net:Updater.Net_id.t -> + dictator_operation -> + MBytes.t tzresult Lwt.t + val activate: + Client_commands.context -> + block -> + net:Updater.Net_id.t -> + Protocol_hash.t -> + MBytes.t tzresult Lwt.t + val activate_testnet: + Client_commands.context -> + block -> + net:Updater.Net_id.t -> + Protocol_hash.t -> + MBytes.t tzresult Lwt.t + end module Delegate : sig val operations: Client_commands.context -> diff --git a/src/proto/alpha/TEZOS_PROTOCOL b/src/proto/alpha/TEZOS_PROTOCOL index 787ccb742..b011da7eb 100644 --- a/src/proto/alpha/TEZOS_PROTOCOL +++ b/src/proto/alpha/TEZOS_PROTOCOL @@ -1,7 +1,6 @@ { "hash": "ProtoALphaALphaALphaALphaALphaALphaALphaALphaDdp3zK", "modules": [ - "Misc", "Tezos_hash", diff --git a/src/proto/alpha/apply.ml b/src/proto/alpha/apply.ml index c761d2ffa..85efbbc80 100644 --- a/src/proto/alpha/apply.ml +++ b/src/proto/alpha/apply.ml @@ -153,6 +153,17 @@ let apply_sourced_operation ctxt delegate pred_block block_prio content) ctxt contents >>=? fun ctxt -> return (ctxt, origination_nonce) + | Dictator_operation (Activate hash) -> + let dictator_pubkey = Constants.dictator_pubkey ctxt in + Operation.check_signature dictator_pubkey operation >>=? fun () -> + activate ctxt hash >>= fun ctxt -> + return (ctxt, origination_nonce) + | Dictator_operation (Activate_testnet hash) -> + let dictator_pubkey = Constants.dictator_pubkey ctxt in + Operation.check_signature dictator_pubkey operation >>=? fun () -> + set_test_protocol ctxt hash >>= fun ctxt -> + fork_test_network ctxt >>= fun ctxt -> + return (ctxt, origination_nonce) let apply_anonymous_operation ctxt miner_contract origination_nonce kind = match kind with @@ -282,9 +293,12 @@ let compare_operations op1 op2 = | Sourced_operations _, Anonymous_operations _ -> 1 | Sourced_operations op1, Sourced_operations op2 -> match op1, op2 with - | Delegate_operations _, Manager_operations _ -> -1 - | Manager_operations _, Delegate_operations _ -> 1 + | Delegate_operations _, (Manager_operations _ | Dictator_operation _) -> -1 + | Manager_operations _, Dictator_operation _ -> -1 + | Dictator_operation _, Manager_operations _ -> 1 + | (Manager_operations _ | Dictator_operation _), Delegate_operations _ -> 1 | Delegate_operations _, Delegate_operations _ -> 0 + | Dictator_operation _, Dictator_operation _ -> 0 | Manager_operations op1, Manager_operations op2 -> begin (* Manager operations with smaller counter are pre-validated first. *) Int32.compare op1.counter op2.counter diff --git a/src/proto/alpha/constants_repr.ml b/src/proto/alpha/constants_repr.ml index 65f84449e..3c94e977a 100644 --- a/src/proto/alpha/constants_repr.ml +++ b/src/proto/alpha/constants_repr.ml @@ -43,6 +43,7 @@ type constants = { instructions_per_transaction: int ; proof_of_work_threshold: int64 ; bootstrap_keys: Ed25519.Public_key.t list ; + dictator_pubkey: Ed25519.Public_key.t ; } let read_public_key s = @@ -69,7 +70,10 @@ let default = { "9c328bddf6249bbe550121076194d99bbe60e5b1e144da4f426561b5d3bbc6ab" ; "a3db517734e07ace089ad0a2388e7276fb9b114bd79259dd5c93b0c33d57d6a2" ; "6d2d52e62f1d48f3cf9badbc90cfe5f3aa600194bf21eda44b8e64698a82d341" ; - ] + ] ; + dictator_pubkey = + read_public_key + "4d5373455738070434f214826d301a1c206780d7f789fcbf94c2149b2e0718cc"; } let opt (=) def v = if def = v then None else Some v @@ -113,6 +117,9 @@ let constants_encoding = and bootstrap_keys = opt Compare_keys.(=) default.bootstrap_keys c.bootstrap_keys + and dictator_pubkey = + opt Ed25519.Public_key.(=) + default.dictator_pubkey c.dictator_pubkey in (( cycle_length, voting_period_length, @@ -122,7 +129,8 @@ let constants_encoding = max_signing_slot, instructions_per_transaction, proof_of_work_threshold, - bootstrap_keys), ()) ) + bootstrap_keys, + dictator_pubkey), ()) ) (fun (( cycle_length, voting_period_length, time_before_reward, @@ -131,7 +139,8 @@ let constants_encoding = max_signing_slot, instructions_per_transaction, proof_of_work_threshold, - bootstrap_keys), ()) -> + bootstrap_keys, + dictator_pubkey), ()) -> { cycle_length = unopt default.cycle_length cycle_length ; voting_period_length = @@ -152,10 +161,12 @@ let constants_encoding = unopt default.proof_of_work_threshold proof_of_work_threshold ; bootstrap_keys = unopt default.bootstrap_keys bootstrap_keys ; + dictator_pubkey = + unopt default.dictator_pubkey dictator_pubkey ; } ) Data_encoding.( merge_objs - (obj9 + (obj10 (opt "cycle_length" int32) (opt "voting_period_length" int32) (opt "time_before_reward" int64) @@ -164,7 +175,8 @@ let constants_encoding = (opt "max_signing_slot" int31) (opt "instructions_per_transaction" int31) (opt "proof_of_work_threshold" int64) - (opt "bootstrap_keys" (list Ed25519.Public_key.encoding))) + (opt "bootstrap_keys" (list Ed25519.Public_key.encoding)) + (opt "dictator_pubkey" Ed25519.Public_key.encoding)) unit) type error += Constant_read of exn diff --git a/src/proto/alpha/operation_repr.ml b/src/proto/alpha/operation_repr.ml index 249616e95..20c32b9d0 100644 --- a/src/proto/alpha/operation_repr.ml +++ b/src/proto/alpha/operation_repr.ml @@ -42,6 +42,7 @@ and sourced_operations = source: Ed25519.Public_key.t ; operations: delegate_operation list ; } + | Dictator_operation of dictator_operation and manager_operation = | Transaction of { @@ -78,6 +79,10 @@ and delegate_operation = ballot: Vote_repr.ballot ; } +and dictator_operation = + | Activate of Protocol_hash.t + | Activate_testnet of Protocol_hash.t + and counter = Int32.t module Encoding = struct @@ -236,11 +241,40 @@ module Encoding = struct | _ -> None) (fun (source, operations) -> Delegate_operations { source ; operations }) + let dictator_kind_encoding = + let mk_case name args = + let open Data_encoding in + conv + (fun o -> ((), o)) + (fun ((), o) -> o) + (merge_objs + (obj1 (req "network" (constant name))) + args) in + let open Data_encoding in + union ~tag_size:`Uint8 [ + case ~tag:0 + (mk_case "activate" + (obj1 (req "hash" Protocol_hash.encoding))) + (function (Activate hash) -> Some hash | _ -> None) + (fun hash -> Activate hash) ; + case ~tag:1 + (mk_case "activate_testnet" + (obj1 (req "hash" Protocol_hash.encoding))) + (function (Activate_testnet hash) -> Some hash | _ -> None) + (fun hash -> Activate_testnet hash) ; + ] + + let dictator_kind_case tag = + case ~tag dictator_kind_encoding + (function Dictator_operation op -> Some op | _ -> None) + (fun op -> Dictator_operation op) + let signed_operations_case tag = case ~tag (union [ manager_kind_case 0 ; delegate_kind_case 1 ; + dictator_kind_case 2 ; ]) (function Sourced_operations ops -> Some ops | _ -> None) (fun ops -> Sourced_operations ops) diff --git a/src/proto/alpha/operation_repr.mli b/src/proto/alpha/operation_repr.mli index d935daaec..99c425944 100644 --- a/src/proto/alpha/operation_repr.mli +++ b/src/proto/alpha/operation_repr.mli @@ -42,6 +42,7 @@ and sourced_operations = source: Ed25519.Public_key.t ; operations: delegate_operation list ; } + | Dictator_operation of dictator_operation and manager_operation = | Transaction of { @@ -78,6 +79,10 @@ and delegate_operation = ballot: Vote_repr.ballot ; } +and dictator_operation = + | Activate of Protocol_hash.t + | Activate_testnet of Protocol_hash.t + and counter = Int32.t type error += Cannot_parse_operation diff --git a/src/proto/alpha/services_registration.ml b/src/proto/alpha/services_registration.ml index 027ff0b12..0072be745 100644 --- a/src/proto/alpha/services_registration.ml +++ b/src/proto/alpha/services_registration.ml @@ -466,6 +466,10 @@ let check_signature ctxt signature shell contents = | Sourced_operations (Delegate_operations { source }) -> Operation.check_signature source { signature ; shell ; contents ; hash = dummy_hash } + | Sourced_operations (Dictator_operation _) -> + let key = Constants.dictator_pubkey ctxt in + Operation.check_signature key + { signature ; shell ; contents ; hash = dummy_hash } let parse_operations ctxt (shell, bytes, check) = Operation.parse_proto bytes >>=? fun (proto, signature) -> diff --git a/src/proto/alpha/tezos_context.ml b/src/proto/alpha/tezos_context.ml index 99a5fc254..a4a92deb2 100644 --- a/src/proto/alpha/tezos_context.ml +++ b/src/proto/alpha/tezos_context.ml @@ -70,6 +70,9 @@ module Constants = struct let proof_of_work_threshold c = let constants = Storage.constants c in constants.proof_of_work_threshold + let dictator_pubkey c = + let constants = Storage.constants c in + constants.dictator_pubkey end module Public_key = struct diff --git a/src/proto/alpha/tezos_context.mli b/src/proto/alpha/tezos_context.mli index 1c9d820d9..4f1ced13b 100644 --- a/src/proto/alpha/tezos_context.mli +++ b/src/proto/alpha/tezos_context.mli @@ -183,6 +183,7 @@ module Constants : sig val max_signing_slot: context -> int val instructions_per_transaction: context -> int val proof_of_work_threshold: context -> int64 + val dictator_pubkey: context -> Ed25519.Public_key.t end @@ -459,6 +460,7 @@ and sourced_operations = source: public_key ; operations: delegate_operation list ; } + | Dictator_operation of dictator_operation and manager_operation = | Transaction of { @@ -495,6 +497,10 @@ and delegate_operation = ballot: Vote.ballot ; } +and dictator_operation = + | Activate of Protocol_hash.t + | Activate_testnet of Protocol_hash.t + and counter = Int32.t module Operation : sig