diff --git a/CHANGES.md b/CHANGES.md index 393f5e1202242aa644d2006aefc8b41f3ffb7568..58a5699acd6ca8571862d2426c65059016283f5f 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -19,6 +19,9 @@ here either. - Added a new multisig command to change keys and threshold `set threshold of multisig contract ...`. +- Added a command to perform protocol migrations in persistent mockup mode + `migrate mockup to ` + ## Baker / Endorser / Accuser ## Protocol Compiler And Environment diff --git a/docs/user/mockup.rst b/docs/user/mockup.rst index 43431eabc3959556ae412736b83d63679c85badd..ee8bd284cc429564befdec83638c99ccf106639b 100644 --- a/docs/user/mockup.rst +++ b/docs/user/mockup.rst @@ -205,7 +205,7 @@ operation. The ``cost_per_byte`` is used to compute the amount of tokens to be burnt proportionally to the fresh storage consumed by the execution of an operation. The ``chain_id`` is used to prevent replay of operations between chains. You can pick a chain id for your mockup environment using the following -command: +command: .. code-block:: shell-session @@ -245,7 +245,7 @@ transactions at any point. Let us make that clearer with an example. We will start by creating a mockup directory supporting *asynchronous* transfers, i.e., where transfers do not -immediately bake the block. +immediately bake the block. .. code-block:: shell-session @@ -253,7 +253,7 @@ immediately bake the block. This will create a fresh mockup directory. Notice that, in addition to the ``mockup/context.json`` file, you now also have a ``mockup/mempool.json``, which -is initially empty. +is initially empty. Now, let us add 2 transactions, that we will label respectively ``t1`` and ``t2``, to the mempool. @@ -290,7 +290,7 @@ case by visiting ``mockup/mempool.json``. This should look like "destination": "tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx" } ], "signature": "sigTBpkXw6tC72L2nJ2r2Jm5iB6uidTWqoMNd4oEawUbGBf5mHVfKawFYL8X8MJECpL73oBnfujyUZNLK2LQWD1FaCkYMP4j" } } ] - + Now let's simulate a selective baker, like so .. code-block:: shell-session @@ -300,7 +300,7 @@ Now let's simulate a selective baker, like so The effect of successfully baking the new head will be to include ``t1`` but discard ``t2``. You can check that ``t2`` has been added to the file ``mockup/trashpool.json``, since we know it cannot be added to further -blocks of the mockup chain. +blocks of the mockup chain. .. code-block:: JSON @@ -357,3 +357,23 @@ looks like. "destination": "tz1faswCTDciRzE4oJ9jn2Vm2dvjeyA9fUzU" } ], "signature": "sigeFcabZTE8Y2LXv19Fe7TbRtkjzVpBy2qhABp263Xnj8TJtA6XpRRMfGeD5YxwCJiTr9r6ZFGBdLnpxL9Y9CG3bpbXmu7E" } } ] + +Performing protocol migrations of persistent mockup states +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The persistent state of the mockup mode is highly protocol-dependent. +But Tezos is self-amending: protocols regularly evolve from one to the next. +When a protocol switch happens on-chain, the protocol state is automatically +migrated to the format used by the new protocol. + +A command is provided to do the same on the persistent mockup state: + +:: + + $ mockup-client migrate mockup to + +The protocol corresponding to the hash must know how to migrate from the current protocol. + +This is mostly useful for protocol developers, but also eg for developers +wanting to check the robustness of their application against new features +or breaking changes to the protocol. diff --git a/src/lib_mockup/dune b/src/lib_mockup/dune index 59762402406e76ee336f7a04c5e2aca373d2ee5e..810755de15caf1aec9a69ae767a56bf8d709a971 100644 --- a/src/lib_mockup/dune +++ b/src/lib_mockup/dune @@ -12,7 +12,7 @@ (library (name tezos_mockup) (public_name tezos-mockup) - (modules files local_services persistence RPC_client) + (modules files local_services persistence RPC_client migration) (libraries tezos-base tezos-client-base diff --git a/src/lib_mockup/migration.ml b/src/lib_mockup/migration.ml new file mode 100644 index 0000000000000000000000000000000000000000..c31766c09fe6a436d22179174dd5e7165096e658 --- /dev/null +++ b/src/lib_mockup/migration.ml @@ -0,0 +1,68 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2020 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. *) +(* *) +(*****************************************************************************) + +open Persistence + +let migrate_mockup ~(cctxt : Tezos_client_base.Client_context.full) + ~protocol_hash ~next_protocol_hash = + let base_dir = cctxt#get_base_dir in + let explain_will_not_work explain = + cctxt#error + "@[Base directory %s %a@ This command will not work.@ Please \ + specify a correct mockup base directory.@]" + base_dir + explain + () + >>= fun () -> return_unit + in + classify_base_dir base_dir + >>=? fun base_dir_class -> + ( match base_dir_class with + | Base_dir_does_not_exist -> + explain_will_not_work (fun fmtr () -> + Format.fprintf fmtr "does not exist.") + | Base_dir_is_empty -> + explain_will_not_work (fun fmtr () -> Format.fprintf fmtr "is empty.") + | Base_dir_is_file -> + explain_will_not_work (fun fmtr () -> Format.fprintf fmtr "is a file.") + | Base_dir_is_nonempty -> + explain_will_not_work (fun fmtr () -> + Format.fprintf fmtr "is not a mockup base directory.") + | Base_dir_is_mockup -> + return_unit ) + >>=? fun () -> + get_mockup_context_from_disk ~base_dir ~protocol_hash + >>=? fun ((module Current_mockup_env), (chain_id, rpc_context)) -> + get_registered_mockup (Some next_protocol_hash) + >>=? fun (module Next_mockup_env) -> + Next_mockup_env.migrate (chain_id, rpc_context) + >>=? fun (chain_id, rpc_context) -> + overwrite_mockup + ~protocol_hash:next_protocol_hash + ~chain_id + ~rpc_context + ~base_dir + >>=? fun () -> + cctxt#message "Migration successful." >>= fun () -> return_unit diff --git a/src/lib_mockup/migration.mli b/src/lib_mockup/migration.mli new file mode 100644 index 0000000000000000000000000000000000000000..0cd615c1cdb510b289125fbba54e59c4e1ea61a0 --- /dev/null +++ b/src/lib_mockup/migration.mli @@ -0,0 +1,32 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2020 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. *) +(* *) +(*****************************************************************************) + +(** Migrates the protocol version of an on-disk mockup environment. + The effect is protocol-dependent. *) +val migrate_mockup : + cctxt:Tezos_client_base.Client_context.full -> + protocol_hash:Tezos_base.TzPervasives.Protocol_hash.t option -> + next_protocol_hash:Tezos_base.TzPervasives.Protocol_hash.t -> + unit tzresult Lwt.t diff --git a/src/lib_mockup/mockup_commands.ml b/src/lib_mockup/mockup_commands.ml index 6fe4a75127d5ed804e744b9d88cba1e370076f14..2bc505e41ef847b369084662f8e736f8fdf9992e 100644 --- a/src/lib_mockup/mockup_commands.ml +++ b/src/lib_mockup/mockup_commands.ml @@ -46,4 +46,24 @@ let list_mockup_command : Tezos_client_base.Client_context.full Clic.command = (prefixes ["list"; "mockup"; "protocols"] @@ stop) list_mockup_command_handler -let commands () = [list_mockup_command] +let migrate_mockup_command_handler () next_protococol_hash + (cctxt : Tezos_client_base.Client_context.full) = + match Protocol_hash.of_b58check next_protococol_hash with + | Error _ as result -> + Lwt.return result + | Ok next_protocol_hash -> + Migration.migrate_mockup ~cctxt ~protocol_hash:None ~next_protocol_hash + +let migrate_mockup_command : Tezos_client_base.Client_context.full Clic.command + = + let open Clic in + command + ~group + ~desc:"Migrates an on-disk mockup context from a protocol to another." + no_options + ( prefixes ["migrate"; "mockup"; "to"] + @@ string ~name:"hash" ~desc:"Protocol hash of the next protocol" + @@ stop ) + migrate_mockup_command_handler + +let commands () = [list_mockup_command; migrate_mockup_command] diff --git a/src/lib_mockup/registration.ml b/src/lib_mockup/registration.ml index 513f32383b4100f44448e1c9837178241d855f02..cfbb39bd7c30401a98a1e854d88d962ef57bd26b 100644 --- a/src/lib_mockup/registration.ml +++ b/src/lib_mockup/registration.ml @@ -67,6 +67,8 @@ module type Mockup_sig = sig constants_overrides_json:Data_encoding.json option -> bootstrap_accounts_json:Data_encoding.json option -> mockup_context tzresult Lwt.t + + val migrate : mockup_context -> mockup_context tzresult Lwt.t end type mockup_environment = (module Mockup_sig) diff --git a/src/lib_mockup/registration.mli b/src/lib_mockup/registration.mli index 586b684e46803984fa7cdd536f8b2ef1cb9b88d2..f175d641e8a9349ce88fa517e2566550c2756e65 100644 --- a/src/lib_mockup/registration.mli +++ b/src/lib_mockup/registration.mli @@ -66,6 +66,8 @@ module type Mockup_sig = sig constants_overrides_json:Data_encoding.json option -> bootstrap_accounts_json:Data_encoding.json option -> mockup_context tzresult Lwt.t + + val migrate : mockup_context -> mockup_context tzresult Lwt.t end type mockup_environment = (module Mockup_sig) diff --git a/src/proto_006_PsCARTHA/lib_client/mockup.ml b/src/proto_006_PsCARTHA/lib_client/mockup.ml index f154e3a1246546ec2ece8a807f79a885adf14de7..98a38c4901d5d0a078bb53bacc3738bfb1297533 100644 --- a/src/proto_006_PsCARTHA/lib_client/mockup.ml +++ b/src/proto_006_PsCARTHA/lib_client/mockup.ml @@ -449,6 +449,21 @@ let mem_init : context; } ) +let migrate : + Chain_id.t * Tezos_protocol_environment.rpc_context -> + (Chain_id.t * Tezos_protocol_environment.rpc_context) tzresult Lwt.t = + fun (chain_id, rpc_context) -> + let {Tezos_protocol_environment.block_hash; context; block_header} = + rpc_context + in + Protocol.Main.init context block_header + >|= Protocol.Environment.wrap_error + >>=? fun {context; _} -> + let rpc_context = + {Tezos_protocol_environment.block_hash; block_header; context} + in + return (chain_id, rpc_context) + (* ------------------------------------------------------------------------- *) (* Register mockup *) @@ -477,5 +492,7 @@ let () = let directory = Protocol.rpc_services let init = mem_init + + let migrate = migrate end in register_mockup_environment (module M) diff --git a/src/proto_007_PsDELPH1/lib_client/mockup.ml b/src/proto_007_PsDELPH1/lib_client/mockup.ml index f1dc0d4bc85623dec253df1bf547f3ad6b820c54..87da8405c5caf890c75e1bfdb108fcfe3b578703 100644 --- a/src/proto_007_PsDELPH1/lib_client/mockup.ml +++ b/src/proto_007_PsDELPH1/lib_client/mockup.ml @@ -470,6 +470,21 @@ let mem_init : context; } ) +let migrate : + Chain_id.t * Tezos_protocol_environment.rpc_context -> + (Chain_id.t * Tezos_protocol_environment.rpc_context) tzresult Lwt.t = + fun (chain_id, rpc_context) -> + let {Tezos_protocol_environment.block_hash; context; block_header} = + rpc_context + in + Protocol.Main.init context block_header + >|= Protocol.Environment.wrap_error + >>=? fun {context; _} -> + let rpc_context = + {Tezos_protocol_environment.block_hash; block_header; context} + in + return (chain_id, rpc_context) + (* ------------------------------------------------------------------------- *) (* Register mockup *) @@ -498,5 +513,7 @@ let () = let directory = Protocol.rpc_services let init = mem_init + + let migrate = migrate end in register_mockup_environment (module M) diff --git a/src/proto_008_PtEdoTez/lib_client/mockup.ml b/src/proto_008_PtEdoTez/lib_client/mockup.ml index f1dc0d4bc85623dec253df1bf547f3ad6b820c54..87da8405c5caf890c75e1bfdb108fcfe3b578703 100644 --- a/src/proto_008_PtEdoTez/lib_client/mockup.ml +++ b/src/proto_008_PtEdoTez/lib_client/mockup.ml @@ -470,6 +470,21 @@ let mem_init : context; } ) +let migrate : + Chain_id.t * Tezos_protocol_environment.rpc_context -> + (Chain_id.t * Tezos_protocol_environment.rpc_context) tzresult Lwt.t = + fun (chain_id, rpc_context) -> + let {Tezos_protocol_environment.block_hash; context; block_header} = + rpc_context + in + Protocol.Main.init context block_header + >|= Protocol.Environment.wrap_error + >>=? fun {context; _} -> + let rpc_context = + {Tezos_protocol_environment.block_hash; block_header; context} + in + return (chain_id, rpc_context) + (* ------------------------------------------------------------------------- *) (* Register mockup *) @@ -498,5 +513,7 @@ let () = let directory = Protocol.rpc_services let init = mem_init + + let migrate = migrate end in register_mockup_environment (module M) diff --git a/src/proto_alpha/lib_client/mockup.ml b/src/proto_alpha/lib_client/mockup.ml index 15ba0eb825a3733f16e15e385ef56d86de19a597..34b5ff1f7e9da841833d838a9810cdbad9ad78ff 100644 --- a/src/proto_alpha/lib_client/mockup.ml +++ b/src/proto_alpha/lib_client/mockup.ml @@ -455,6 +455,21 @@ let mem_init : context; } ) +let migrate : + Chain_id.t * Tezos_protocol_environment.rpc_context -> + (Chain_id.t * Tezos_protocol_environment.rpc_context) tzresult Lwt.t = + fun (chain_id, rpc_context) -> + let {Tezos_protocol_environment.block_hash; context; block_header} = + rpc_context + in + Protocol.Main.init context block_header + >|= Protocol.Environment.wrap_error + >>=? fun {context; _} -> + let rpc_context = + {Tezos_protocol_environment.block_hash; block_header; context} + in + return (chain_id, rpc_context) + (* ------------------------------------------------------------------------- *) (* Register mockup *) @@ -483,5 +498,7 @@ let () = let directory = Protocol.rpc_services let init = mem_init + + let migrate = migrate end in register_mockup_environment (module M) diff --git a/tezt/lib_tezos/client.ml b/tezt/lib_tezos/client.ml index aae2029a54fde53c90106ab221d078f66bc33227..c0cdcdeda1a5fad76a284d6921cbaf43efc7212b 100644 --- a/tezt/lib_tezos/client.ml +++ b/tezt/lib_tezos/client.ml @@ -430,6 +430,23 @@ let originate_contract ?node ?wait ?init ?burn_cap ~alias ~amount ~src ~prg | Some hash -> return hash +let spawn_list_mockup_protocols client = + spawn_command client (mode_arg client @ ["list"; "mockup"; "protocols"]) + +let list_mockup_protocols client = + let process = spawn_list_mockup_protocols client in + let* () = Process.check process + and* output = Lwt_io.read (Process.stdout process) in + return (String.split_on_char '\n' output) + +let spawn_migrate_mockup ~next_protocol client = + spawn_command + client + (mode_arg client @ ["migrate"; "mockup"; "to"; Protocol.hash next_protocol]) + +let migrate_mockup ~next_protocol client = + spawn_migrate_mockup ~next_protocol client |> Process.check + let init ?path ?admin_path ?name ?color ?base_dir ?node () = let client = create ?path ?admin_path ?name ?color ?base_dir ?node () in let* () = diff --git a/tezt/lib_tezos/client.mli b/tezt/lib_tezos/client.mli index 74d9c2e2ebc73bc6ac74fa3c6982506b8b2754b6..0e62b612e5ef2ee48485505877e012b790bd21ce 100644 --- a/tezt/lib_tezos/client.mli +++ b/tezt/lib_tezos/client.mli @@ -323,6 +323,19 @@ val spawn_originate_contract : t -> Process.t +(** Run [tezos-client list mockup protocols]. *) +val list_mockup_protocols : t -> string list Lwt.t + +(** Same as [list_mockup_protocols], but do not wait for the process to exit + and do not process stdout. *) +val spawn_list_mockup_protocols : t -> Process.t + +(** Run [tezos-client migrate mockup to]. *) +val migrate_mockup : next_protocol:Protocol.t -> t -> unit Lwt.t + +(** Same as [migrate_mockup], but do not wait for the process to exit. *) +val spawn_migrate_mockup : next_protocol:Protocol.t -> t -> Process.t + (** {2 High-Level Functions} *) (** Create a client with mode [Client] and import all secret keys diff --git a/tezt/lib_tezos/protocol.ml b/tezt/lib_tezos/protocol.ml index ace249d4369d64220b5f44a9c06f647bda5bae6c..3278486f2f4b93835defb658f5a603904c0962a1 100644 --- a/tezt/lib_tezos/protocol.ml +++ b/tezt/lib_tezos/protocol.ml @@ -24,11 +24,13 @@ (* *) (*****************************************************************************) -type t = Alpha | Delphi | Carthage +type t = Alpha | Edo | Delphi | Carthage let name = function | Alpha -> "Alpha" + | Edo -> + "Edo" | Delphi -> "Delphi" | Carthage -> @@ -40,6 +42,8 @@ let tag protocol = String.lowercase_ascii (name protocol) let hash = function | Alpha -> "ProtoALphaALphaALphaALphaALphaALphaALphaALphaDdp3zK" + | Edo -> + "PtEdoTezd3RHSC31mpxxo1npxFjoWWcFgQtxapi51Z8TLu6v6Uq" | Delphi -> "PsDELPH1Kxsxt8f9eWbxQeRxkjfbxoqM52jvs5Y5fBxWWh4ifpo" | Carthage -> @@ -48,6 +52,8 @@ let hash = function let parameter_file = function | Alpha -> "src/proto_alpha/parameters/sandbox-parameters.json" + | Edo -> + "src/proto_008_PtEdoTez/parameters/sandbox-parameters.json" | Delphi -> "src/proto_007_PsDELPH1/parameters/sandbox-parameters.json" | Carthage -> @@ -56,6 +62,8 @@ let parameter_file = function let accuser = function | Alpha -> "./tezos-accuser-alpha" + | Edo -> + "./tezos-accuser-008-PtEdoTez" | Delphi -> "./tezos-accuser-007-PsDELPH1" | Carthage -> @@ -90,3 +98,15 @@ let write_parameter_file : protocol:t -> parameter_overrides -> string Lwt.t = Lwt_io.write overriden_parameters_out @@ JSON.encode_u parameters in Lwt.return overriden_parameters + +let next_protocol = function + | Carthage -> + Some Delphi + | Delphi -> + Some Edo + | Edo -> + Some Alpha + | Alpha -> + None + +let all_protocols = [Alpha; Edo; Delphi; Carthage] diff --git a/tezt/manual_tests/migration.ml b/tezt/manual_tests/migration.ml index 92cd801fbaad8f20dbe67be526c3d3e877ebb4f4..ba04dc208636cfe892559db379ad0f12c17fa69d 100644 --- a/tezt/manual_tests/migration.ml +++ b/tezt/manual_tests/migration.ml @@ -151,7 +151,7 @@ let migration ?yes_node_path ?yes_wallet context protocol = | Protocol.Carthage -> ( RPC.Proto_007.get_current_level, RPC.Proto_007.get_levels_in_current_cycle ) - | Delphi | Alpha -> + | Edo | Delphi | Alpha -> ( RPC.Proto_alpha.get_current_level, RPC.Proto_alpha.get_levels_in_current_cycle ) in diff --git a/tezt/tests/mockup.ml b/tezt/tests/mockup.ml index a79b6826c2100b5821e94960def499443a736eed..d83d1e6f12bab4db4c350d7a3fbab641d5bc2abd 100644 --- a/tezt/tests/mockup.ml +++ b/tezt/tests/mockup.ml @@ -223,10 +223,108 @@ let test_multiple_baking ~protocol = return ()) (range 1 10) +let perform_migration ~protocol ~next_protocol ~pre_migration ~post_migration = + let* client = Client.init_mockup ~protocol () in + let* pre_result = pre_migration client in + Log.info + "Migrating from %s to %s" + (Protocol.hash protocol) + (Protocol.hash next_protocol) ; + let* () = Client.migrate_mockup ~next_protocol client in + post_migration client pre_result + +let get_candidates_to_migration () = + let* mockup_protocols = + let transient = Client.create_with_mode Client.Mockup in + Client.list_mockup_protocols transient + in + (* Find all registered mockup protocols which declare a next protocol *) + let result = + List.filter_map + (fun (protocol : Protocol.t) -> + match Protocol.next_protocol protocol with + | None -> + None + | Some next -> + let next_hash = Protocol.hash next in + if + List.exists + (String.equal (Protocol.hash protocol)) + mockup_protocols + && List.exists (String.equal next_hash) mockup_protocols + then Some (protocol, next) + else None) + Protocol.all_protocols + in + return result + +(* Test mockup migration. *) +let test_migration ?(migration_spec : (Protocol.t * Protocol.t) option) + ~pre_migration ~post_migration ~info () = + Test.register + ~__FILE__ + ~title:(Printf.sprintf "migration (mockup, %s)" info) + ~tags:["mockup"; "migration"] + (fun () -> + match migration_spec with + | None -> ( + Log.info "Searching for protocols to migrate..." ; + let* protocols = get_candidates_to_migration () in + match protocols with + | [] -> + Test.fail "No protocol can be tested for migration!" + | (protocol, next_protocol) :: _ -> + perform_migration + ~protocol + ~next_protocol + ~pre_migration + ~post_migration ) + | Some (protocol, next_protocol) -> + perform_migration + ~protocol + ~next_protocol + ~pre_migration + ~post_migration) + +let test_migration_transfer ?migration_spec () = + let (giver, amount, receiver) = transfer_data in + test_migration + ?migration_spec + ~pre_migration:(fun client -> + Log.info + "About to transfer %s from %s to %s" + (Tez.to_string amount) + giver + receiver ; + let* giver_balance_before = + Client.get_balance_for ~account:giver client + in + let* receiver_balance_before = + Client.get_balance_for ~account:receiver client + in + let* () = Client.transfer ~amount ~giver ~receiver client in + return (giver_balance_before, receiver_balance_before)) + ~post_migration: + (fun client (giver_balance_before, receiver_balance_before) -> + let* giver_balance_after = + Client.get_balance_for ~account:giver client + in + let* receiver_balance_after = + Client.get_balance_for ~account:receiver client + in + test_balances_after_transfer + (giver_balance_before, giver_balance_after) + (Tez.to_float amount) + (receiver_balance_before, receiver_balance_after) ; + return ()) + ~info:"transfer" + () + let register protocol = test_rpc_list ~protocol ; test_same_transfer_twice ~protocol ; test_transfer_same_participants ~protocol ; test_transfer ~protocol ; test_simple_baking_event ~protocol ; - test_multiple_baking ~protocol + test_multiple_baking ~protocol ; + test_migration_transfer ()