Revision 5c0277382a82ab3642ddd1de790a362e8c047837 authored by Pierre-Louis on 11 September 2023, 13:01:33 UTC, committed by Pierre-Louis on 25 September 2023, 12:16:22 UTC
1 parent 97eebdf
RPC_test.ml
(*****************************************************************************)
(* *)
(* Open Source License *)
(* Copyright (c) 2020 Metastate AG <hello@metastate.dev> *)
(* Copyright (c) 2021 Nomadic Labs <contact@nomadic-labs.com> *)
(* Copyright (c) 2022 Trili Tech <contact@trili.tech> *)
(* *)
(* 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: RPC regression tests
Invocation: dune exec tezt/tests/main.exe -- -f RPC_test.ml
Note that to reset the regression outputs, one can use
the [--reset-regressions] option. When doing so, it is
recommended to clear the output directory [tezt/_regressions/rpc]
first to remove unused files in case some paths change.
Subject: RPC regression tests capture the output of RPC calls and compare it
with the output from the previous run. The test passes only if the
outputs match exactly.
*)
(* These hooks must be attached to every process that should be captured for
regression testing *)
let hooks = Tezos_regression.hooks
let title_tag_of_test_mode = function
| `Client -> (`Client, "client")
| `Client_data_dir_proxy_server -> (`Client, "proxy_server_data_dir")
| `Client_rpc_proxy_server -> (`Client, "proxy_server_rpc")
| `Light -> (`Light, "light")
| `Proxy -> (`Proxy, "proxy")
let patch_protocol_parameters protocol = function
| None -> Lwt.return_none
| Some overrides ->
let* file =
Protocol.write_parameter_file
~base:(Either.right (protocol, None))
(overrides protocol)
in
Lwt.return_some file
let initialize_chain_for_test client = function
| `Client_data_dir_proxy_server | `Client_rpc_proxy_server ->
(* Because the proxy server doesn't support genesis. *)
Client.bake_for_and_wait client
| `Client | `Light | `Proxy -> unit
let endpoint_of_test_mode_tag node = function
| `Client | `Light | `Proxy -> Lwt.return_some Client.(Node node)
| (`Client_rpc_proxy_server | `Client_data_dir_proxy_server) as
proxy_server_mode ->
let args =
Some
(match proxy_server_mode with
| `Client_rpc_proxy_server -> [Proxy_server.Data_dir]
| `Client_data_dir_proxy_server -> [])
in
let* proxy_server = Proxy_server.init ?args node in
Lwt.return_some Client.(Proxy_server proxy_server)
(* A helper to register a RPC test environment with a node and a client for the
given protocol version.
- [test_mode_tag] specifies the client mode ([`Client], [`Light] or [`Proxy]).
- [test_function] is the function to run to perform RPCs after the test
environment is set up.
- [parameter_overrides] specifies protocol parameters to change from the default
sandbox parameters.
- [nodes_args] specifies additional parameters to pass to the node.
- [event_sections_levels] is passed to the node initialization.
- [sub_group] is a short identifier for your test, used in the test title and as a tag.
Additionally, since this uses [Protocol.register_regression_test], this has an
implicit argument to specify the list of protocols to test. *)
let check_rpc_regression ~test_mode_tag ~test_function ?supports
?parameter_overrides ?nodes_args ?event_sections_levels sub_group =
let client_mode_tag, title_tag = title_tag_of_test_mode test_mode_tag in
Protocol.register_regression_test
~__FILE__
~title:(sf "(mode %s) RPC regression tests: %s" title_tag sub_group)
~tags:["rpc"; title_tag; sub_group]
?supports
@@ fun protocol ->
let* parameter_file =
patch_protocol_parameters protocol parameter_overrides
in
(* Initialize a node with alpha protocol and data to be used for RPC calls.
The log of the node is not captured in the regression output. *)
let* node, client =
Client.init_with_protocol
?parameter_file
?nodes_args
?event_sections_levels
~protocol
client_mode_tag
()
in
let* () = initialize_chain_for_test client test_mode_tag in
let* endpoint = endpoint_of_test_mode_tag node test_mode_tag in
let* _ = test_function test_mode_tag protocol ?endpoint client in
unit
(* Like [check_rpc_regression], but does not register a regression tests *)
let check_rpc ~test_mode_tag ~test_function ?parameter_overrides ?nodes_args
sub_group =
let client_mode_tag, title_tag = title_tag_of_test_mode test_mode_tag in
Protocol.register_test
~__FILE__
~title:(sf "(mode %s) RPC tests: %s" title_tag sub_group)
~tags:["rpc"; title_tag; sub_group]
@@ fun protocol ->
let* parameter_file =
patch_protocol_parameters protocol parameter_overrides
in
(* Initialize a node with alpha protocol and data to be used for RPC calls. *)
let* node, client =
Client.init_with_protocol
?parameter_file
?nodes_args
~protocol
client_mode_tag
()
in
let* () = initialize_chain_for_test client test_mode_tag in
let* endpoint = endpoint_of_test_mode_tag node test_mode_tag in
let* _ = test_function test_mode_tag protocol ?endpoint client in
unit
(* Test the contracts RPC. *)
let test_contracts _test_mode_tag protocol ?endpoint client =
let test_implicit_contract contract_id =
let* _ =
RPC.Client.call ?endpoint ~hooks client
@@ RPC.get_chain_block_context_contract ~id:contract_id ()
in
let* _ =
RPC.Client.call ?endpoint ~hooks client
@@ RPC.get_chain_block_context_contract_balance ~id:contract_id ()
in
let* _ =
RPC.Client.call ?endpoint ~hooks client
@@ RPC.get_chain_block_context_contract_counter ~id:contract_id ()
in
let*! _ =
RPC.Client.spawn ?endpoint ~hooks client
@@ RPC.get_chain_block_context_contract_manager_key ~id:contract_id ()
in
unit
in
let* _contracts =
RPC.Client.call ?endpoint ~hooks client
@@ RPC.get_chain_block_context_contracts ()
in
let* contracts =
RPC.Client.call ?endpoint ~hooks client
@@ RPC.get_chain_block_context_delegates ()
in
Log.info "Test implicit baker contract" ;
let bootstrap = List.hd contracts in
let* () = test_implicit_contract bootstrap in
let* _ =
RPC.Client.call ?endpoint ~hooks client
@@ RPC.get_chain_block_context_contract_delegate ~id:bootstrap ()
in
Log.info "Test un-allocated implicit contract" ;
let unallocated_implicit = "tz1c5BVkpwCiaPHJBzyjg7UHpJEMPTYA1bHG" in
assert (not @@ List.mem unallocated_implicit contracts) ;
let* _ =
RPC.Client.call ?endpoint ~hooks client
@@ RPC.get_chain_block_context_contract ~id:unallocated_implicit ()
in
Log.info "Test non-delegated implicit contract" ;
let simple_implicit = "simple" in
let* simple_implicit_key =
Client.gen_and_show_keys ~alias:simple_implicit client
in
let bootstrap1 = "bootstrap1" in
let* () =
Client.transfer
~amount:Tez.(of_int 100)
~giver:bootstrap1
~receiver:simple_implicit_key.public_key_hash
~burn_cap:Constant.implicit_account_burn
client
in
let* () = Client.bake_for_and_wait client in
let* () = test_implicit_contract simple_implicit_key.public_key_hash in
let* () =
Lwt_list.iter_s
(fun rpc ->
let*? process =
RPC.Client.spawn ?endpoint ~hooks client
@@ rpc
?chain:None
?block:None
~id:simple_implicit_key.public_key_hash
()
in
Process.check ~expect_failure:true process)
[
RPC.get_chain_block_context_contract_delegate;
RPC.get_chain_block_context_contract_entrypoints;
RPC.get_chain_block_context_contract_script;
RPC.get_chain_block_context_contract_storage;
]
in
Log.info "Test delegated implicit contract" ;
let delegated_implicit = "delegated" in
let* delegated_implicit_key =
Client.gen_and_show_keys ~alias:delegated_implicit client
in
let* () =
Client.transfer
~amount:Tez.(of_int 100)
~giver:bootstrap1
~receiver:delegated_implicit
~burn_cap:Constant.implicit_account_burn
client
in
let* () = Client.bake_for_and_wait client in
let*! () =
Client.set_delegate ~src:delegated_implicit ~delegate:bootstrap1 client
in
let* () = Client.bake_for_and_wait client in
let* () = test_implicit_contract delegated_implicit_key.public_key_hash in
let* _ =
RPC.Client.call ?endpoint ~hooks client
@@ RPC.get_chain_block_context_contract_delegate
~id:delegated_implicit_key.public_key_hash
()
in
let* () =
Lwt_list.iter_s
(fun rpc ->
let*? process =
RPC.Client.spawn ?endpoint ~hooks client
@@ rpc
?chain:None
?block:None
~id:delegated_implicit_key.public_key_hash
()
in
Process.check ~expect_failure:true process)
[
RPC.get_chain_block_context_contract_entrypoints;
RPC.get_chain_block_context_contract_script;
RPC.get_chain_block_context_contract_storage;
]
in
let test_originated_contract contract_id =
let* _ =
RPC.Client.call ?endpoint ~hooks client
@@ RPC.get_chain_block_context_contract ~id:contract_id ()
in
let* _ =
RPC.Client.call ?endpoint ~hooks client
@@ RPC.get_chain_block_context_contract_balance ~id:contract_id ()
in
let*? process =
RPC.Client.spawn ?endpoint ~hooks client
@@ RPC.get_chain_block_context_contract_counter ~id:contract_id ()
in
let* () = Process.check ~expect_failure:true process in
let*? process =
RPC.Client.spawn ?endpoint ~hooks client
@@ RPC.get_chain_block_context_contract_manager_key ~id:contract_id ()
in
let* () = Process.check ~expect_failure:true process in
let big_map_key =
Ezjsonm.value_from_string
"{ \"key\": { \"int\": \"0\" }, \"type\": { \"prim\": \"int\" } }"
in
let* _ =
RPC.Client.call ?endpoint ~hooks client
@@ RPC.post_chain_block_context_contract_big_map_get
~id:contract_id
~data:(Data big_map_key)
()
in
let* _ =
RPC.Client.call ?endpoint ~hooks client
@@ RPC.get_chain_block_context_contract_entrypoints ~id:contract_id ()
in
let* _ =
RPC.Client.call ?endpoint ~hooks client
@@ RPC.get_chain_block_context_contract_script ~id:contract_id ()
in
let* _ =
RPC.Client.call ?endpoint ~hooks client
@@ RPC.get_chain_block_context_contract_storage ~id:contract_id ()
in
unit
in
(* A smart contract without any big map or entrypoints *)
Log.info "Test simple originated contract" ;
let* _alias, originated_contract_simple =
Client.originate_contract_at
~amount:Tez.zero
~src:"bootstrap1"
~init:"Some \"initial storage\""
~burn_cap:Tez.(of_int 3)
client
["mini_scenarios"; "str_id"]
protocol
in
let* () = Client.bake_for_and_wait client in
let* () = test_originated_contract originated_contract_simple in
(* A smart contract with a big map and entrypoints *)
Log.info "Test advanced originated contract" ;
let* _alias, originated_contract_advanced =
Client.originate_contract_at
~amount:Tez.zero
~src:"bootstrap1"
~init:"Pair { Elt \"dup\" 0 } { Elt \"dup\" 1 ; Elt \"test\" 5 }"
~burn_cap:Tez.(of_int 3)
client
["mini_scenarios"; "big_map_entrypoints"]
protocol
in
let* () = Client.bake_for_and_wait client in
let* () = test_originated_contract originated_contract_advanced in
let unique_big_map_key =
Ezjsonm.value_from_string
"{ \"key\": { \"string\": \"test\" }, \"type\": { \"prim\": \"string\" } \
}"
in
let* _ =
RPC.Client.call ?endpoint ~hooks client
@@ RPC.post_chain_block_context_contract_big_map_get
~id:originated_contract_advanced
~data:(Data unique_big_map_key)
()
in
let duplicate_big_map_key =
Ezjsonm.value_from_string
"{ \"key\": { \"string\": \"dup\" }, \"type\": { \"prim\": \"string\" } }"
in
let* _ =
RPC.Client.call ?endpoint ~hooks client
@@ RPC.post_chain_block_context_contract_big_map_get
~id:originated_contract_advanced
~data:(Data duplicate_big_map_key)
()
in
unit
let test_delegates_on_registered_alpha ~contracts ?endpoint client =
Log.info "Test implicit baker contract" ;
let bootstrap = List.hd contracts in
let* _ =
RPC.Client.call ?endpoint client ~hooks
@@ RPC.get_chain_block_context_delegate bootstrap
in
let* _ =
RPC.Client.call ?endpoint ~hooks client
@@ RPC.get_chain_block_context_delegate_full_balance bootstrap
in
let* _ =
RPC.Client.call ?endpoint ~hooks client
@@ RPC.get_chain_block_context_delegate_frozen_deposits bootstrap
in
let* _ =
RPC.Client.call ?endpoint ~hooks client
@@ RPC.get_chain_block_context_delegate_deactivated bootstrap
in
let* _ =
RPC.Client.call ?endpoint ~hooks client
@@ RPC.get_chain_block_context_delegate_delegated_balance bootstrap
in
let* _ =
RPC.Client.call ?endpoint ~hooks client
@@ RPC.get_chain_block_context_delegate_delegated_contracts bootstrap
in
let* _ =
RPC.Client.call ?endpoint ~hooks client
@@ RPC.get_chain_block_context_delegate_grace_period bootstrap
in
let* _ =
RPC.Client.call ?endpoint ~hooks client
@@ RPC.get_chain_block_context_delegate_staking_balance bootstrap
in
let* _ =
RPC.Client.call ?endpoint ~hooks client
@@ RPC.get_chain_block_context_delegate_voting_power bootstrap
in
unit
let test_adaptive_issuance_on_alpha ~contracts ?endpoint client =
Log.info "Test adaptive issuance parameters retrieval" ;
let* _ =
RPC.Client.call ?endpoint client ~hooks
@@ RPC.get_chain_block_context_total_supply ()
in
let* _ =
RPC.Client.call ?endpoint client ~hooks
@@ RPC.get_chain_block_context_total_frozen_stake ()
in
let* _ =
RPC.Client.call ?endpoint client ~hooks
@@ RPC.get_chain_block_context_issuance_current_yearly_rate ()
in
let* _ =
RPC.Client.call ?endpoint client ~hooks
@@ RPC.get_chain_block_context_issuance_current_yearly_rate_exact ()
in
let* _ =
RPC.Client.call ?endpoint client ~hooks
@@ RPC.get_chain_block_context_issuance_issuance_per_minute ()
in
let* _ =
RPC.Client.call ?endpoint client ~hooks
@@ RPC.get_chain_block_context_adaptive_issuance_launch_cycle ()
in
let* _ =
RPC.Client.call ?endpoint client ~hooks
@@ RPC.get_chain_block_context_issuance_expected_issuance ()
in
let bootstrap = List.hd contracts in
let* _ =
RPC.Client.call ?endpoint ~hooks client
@@ RPC.get_chain_block_context_delegate_stakers bootstrap
in
unit
let test_delegates_on_registered_hangzhou ~contracts ?endpoint client =
Log.info "Test implicit baker contract" ;
let bootstrap = List.hd contracts in
let* _ =
RPC.Client.call ?endpoint ~hooks client
@@ RPC.get_chain_block_context_delegate bootstrap
in
let* _ =
RPC.Client.call ?endpoint ~hooks client
@@ RPC.get_chain_block_context_delegate_balance bootstrap
in
let* _ =
RPC.Client.call ?endpoint ~hooks client
@@ RPC.get_chain_block_context_delegate_frozen_balance bootstrap
in
let* _ =
RPC.Client.call ?endpoint ~hooks client
@@ RPC.get_chain_block_context_delegate_frozen_balance_by_cycle bootstrap
in
let* _ =
RPC.Client.call ?endpoint ~hooks client
@@ RPC.get_chain_block_context_delegate_staking_balance bootstrap
in
let* _ =
RPC.Client.call ?endpoint ~hooks client
@@ RPC.get_chain_block_context_delegate_delegated_contracts bootstrap
in
let* _ =
RPC.Client.call ?endpoint ~hooks client
@@ RPC.get_chain_block_context_delegate_delegated_balance bootstrap
in
let* _ =
RPC.Client.call ?endpoint ~hooks client
@@ RPC.get_chain_block_context_delegate_deactivated bootstrap
in
let* _ =
RPC.Client.call ?endpoint ~hooks client
@@ RPC.get_chain_block_context_delegate_grace_period bootstrap
in
let* _ =
RPC.Client.call ?endpoint ~hooks client
@@ RPC.get_chain_block_context_delegate_voting_power bootstrap
in
unit
(* Test the delegates RPC with unregistered baker for Tenderbake protocols. *)
let test_delegates_on_unregistered_alpha ~contracts ?endpoint client =
Log.info "Test with a PKH that is not a registered baker contract" ;
let unregistered_baker = "tz1c5BVkpwCiaPHJBzyjg7UHpJEMPTYA1bHG" in
assert (not @@ List.mem unregistered_baker contracts) ;
let check_failure rpc =
let*? process = RPC.Client.spawn ?endpoint ~hooks client @@ rpc in
Process.check ~expect_failure:true process
in
let* () =
check_failure @@ RPC.get_chain_block_context_delegate unregistered_baker
in
let* () =
check_failure
@@ RPC.get_chain_block_context_delegate_full_balance unregistered_baker
in
let* () =
check_failure
@@ RPC.get_chain_block_context_delegate_frozen_deposits unregistered_baker
in
let* () =
check_failure
@@ RPC.get_chain_block_context_delegate_deactivated unregistered_baker
in
let* () =
check_failure
@@ RPC.get_chain_block_context_delegate_delegated_balance unregistered_baker
in
let* () =
check_failure
@@ RPC.get_chain_block_context_delegate_delegated_contracts
unregistered_baker
in
let* () =
check_failure
@@ RPC.get_chain_block_context_delegate_grace_period unregistered_baker
in
let* () =
check_failure
@@ RPC.get_chain_block_context_delegate_staking_balance unregistered_baker
in
let* () =
check_failure
@@ RPC.get_chain_block_context_delegate_voting_power unregistered_baker
in
unit
(* Test the delegates RPC with unregistered baker for Emmy protocols. *)
let test_delegates_on_unregistered_hangzhou ~contracts ?endpoint client =
Log.info "Test with a PKH that is not a registered baker contract" ;
let unregistered_baker = "tz1c5BVkpwCiaPHJBzyjg7UHpJEMPTYA1bHG" in
assert (not @@ List.mem unregistered_baker contracts) ;
let check_failure rpc =
let*? process = RPC.Client.spawn ?endpoint ~hooks client @@ rpc in
Process.check ~expect_failure:true process
in
let* () =
check_failure @@ RPC.get_chain_block_context_delegate unregistered_baker
in
let* () =
check_failure
@@ RPC.get_chain_block_context_delegate_balance unregistered_baker
in
let* () =
check_failure
@@ RPC.get_chain_block_context_delegate_deactivated unregistered_baker
in
let* () =
check_failure
@@ RPC.get_chain_block_context_delegate_delegated_balance unregistered_baker
in
let* () =
check_failure
@@ RPC.get_chain_block_context_delegate_delegated_contracts
unregistered_baker
in
let* () =
check_failure
@@ RPC.get_chain_block_context_delegate_frozen_balance unregistered_baker
in
let* () =
check_failure
@@ RPC.get_chain_block_context_delegate_frozen_balance_by_cycle
unregistered_baker
in
let* () =
check_failure
@@ RPC.get_chain_block_context_delegate_grace_period unregistered_baker
in
let* () =
check_failure
@@ RPC.get_chain_block_context_delegate_staking_balance unregistered_baker
in
let* () =
check_failure
@@ RPC.get_chain_block_context_delegate_voting_power unregistered_baker
in
unit
let get_contracts ?endpoint client =
let* _ =
RPC.Client.call ?endpoint ~hooks client
@@ RPC.get_chain_block_context_contracts ()
in
let* contracts =
RPC.Client.call ?endpoint ~hooks client
@@ RPC.get_chain_block_context_delegates ()
in
Lwt.return contracts
(* Test the delegates RPC for the specified protocol. *)
let test_delegates _test_mode_tag _protocol ?endpoint client =
let* contracts = get_contracts ?endpoint client in
let* () = test_delegates_on_registered_alpha ~contracts ?endpoint client in
test_delegates_on_unregistered_alpha ~contracts ?endpoint client
(* Test the adaptive issuance RPC. *)
let test_adaptive_issuance _test_mode_tag _protocol ?endpoint client =
let* contracts = get_contracts ?endpoint client in
test_adaptive_issuance_on_alpha ~contracts ?endpoint client
(* Test the votes RPC. *)
let test_votes _test_mode_tag _protocol ?endpoint client =
(* initialize data *)
let proto_hash = Protocol.demo_noops_hash in
let* () = Client.submit_proposals ~proto_hash client in
let* () = Client.bake_for_and_wait client in
(* RPC calls *)
let call rpc = RPC.Client.call ?endpoint ~hooks client rpc in
let* _ = call @@ RPC.get_chain_block_votes_ballot_list () in
let* _ = call @@ RPC.get_chain_block_votes_ballots () in
let* _ = call @@ RPC.get_chain_block_votes_current_period () in
let* _ = call @@ RPC.get_chain_block_votes_current_proposal () in
let* _ = call @@ RPC.get_chain_block_votes_current_quorum () in
let* _ = call @@ RPC.get_chain_block_votes_listings () in
let* _ = call @@ RPC.get_chain_block_votes_proposals () in
let* _ = call @@ RPC.get_chain_block_votes_successor_period () in
let* _ = call @@ RPC.get_chain_block_votes_total_voting_power () in
(* bake to testing vote period and submit some ballots *)
let* () = repeat 2 (fun () -> Client.bake_for_and_wait client) in
let* () = Client.submit_ballot ~key:"bootstrap1" ~proto_hash Yay client in
let* () = Client.submit_ballot ~key:"bootstrap2" ~proto_hash Nay client in
let* () = Client.submit_ballot ~key:"bootstrap3" ~proto_hash Pass client in
let* () = Client.bake_for_and_wait client in
(* RPC calls again *)
let* _ = call @@ RPC.get_chain_block_votes_ballot_list () in
let* _ = call @@ RPC.get_chain_block_votes_ballots () in
let* _ = call @@ RPC.get_chain_block_votes_current_period () in
let* _ = call @@ RPC.get_chain_block_votes_current_proposal () in
let* _ = call @@ RPC.get_chain_block_votes_current_quorum () in
let* _ = call @@ RPC.get_chain_block_votes_listings () in
let* _ = call @@ RPC.get_chain_block_votes_proposals () in
let* _ = call @@ RPC.get_chain_block_votes_successor_period () in
let* _ = call @@ RPC.get_chain_block_votes_total_voting_power () in
unit
(* Test the various other RPCs. *)
let test_misc_protocol _test_mode_tag protocol ?endpoint client =
let* _ =
RPC.Client.call ?endpoint ~hooks client
@@ RPC.get_chain_block_context_constants ()
in
let* _ =
RPC.Client.call ?endpoint ~hooks client
@@ RPC.get_chain_block_helper_baking_rights ()
in
let* _ =
RPC.Client.call ?endpoint ~hooks client
@@ RPC.get_chain_block_helper_baking_rights
~delegate:Constant.bootstrap5.public_key_hash
()
in
let* _ =
RPC.Client.call ?endpoint ~hooks client
@@ RPC.get_chain_block_helper_current_level ()
in
let* () =
if Protocol.(number protocol <= number Oxford) then
let* _ =
RPC.Client.call ?endpoint ~hooks client
@@ RPC.get_chain_block_helper_endorsing_rights ()
(* TODO: https://gitlab.com/tezos/tezos/-/issues/6227
This RPC helper should be removed once Oxford will be frozen. *)
in
let* _ =
RPC.Client.call ?endpoint ~hooks client
@@ RPC.get_chain_block_helper_endorsing_rights
~delegate:Constant.bootstrap4.public_key_hash
()
in
unit
else unit
in
let* () =
let* _ =
RPC.Client.call ?endpoint ~hooks client
@@ RPC.get_chain_block_helper_attestation_rights ()
in
let* _ =
RPC.Client.call ?endpoint ~hooks client
@@ RPC.get_chain_block_helper_attestation_rights
~delegate:Constant.bootstrap4.public_key_hash
()
in
unit
in
let* _ =
RPC.Client.call ?endpoint ~hooks client
@@ RPC.get_chain_block_helper_levels_in_current_cycle ()
in
unit
let mempool_hooks =
let replace_variable string =
let replacements =
[
("edsig\\w{94}", "[SIGNATURE]");
("sig\\w{93}", "[SIGNATURE]");
("o\\w{50}", "[OPERATION_HASH]");
("B\\w{50}", "[BRANCH_HASH]");
("vh\\w{50}", "[BLOCK_PAYLOAD_HASH]");
]
in
List.fold_left
(fun string (replace, by) ->
Base.replace_string ~all:true (rex replace) ~by string)
string
replacements
in
{
Tezos_regression.hooks with
on_log = (fun output -> replace_variable output |> hooks.on_log);
}
let get_client_port client =
match
Client.get_mode client |> Client.mode_to_endpoint
|> Option.map Client.rpc_port
with
| Some port -> port
| None ->
Test.fail
"Client for mempool rpc tests should be initialized with a node or a \
proxy server only. Both have an endpoint and hence a RPC port so this \
should not happen."
let mempool_node_flags =
Node.
[
Synchronisation_threshold 0;
(* Node does not need to be synchronized with peers before being
bootstrapped *)
Connections 1
(* Number of connection allowed for each of our 2 nodes used in the
mempool tests *);
]
let bake_empty_block ?endpoint client =
let mempool = Client.empty_mempool_file () in
(* We defer to using a low-level command here since we enforce using protocol
in order to distinguish which form of the option we actually need, since
the name has changed. *)
Client.spawn_command
?endpoint
client
(["bake"; "for"; Constant.bootstrap1.alias; "--minimal-timestamp"]
@
let option_name = "--operations-pool" in
[option_name; mempool])
|> Process.check
(* Test the mempool RPCs: /chains/<chain>/mempool/...
Tested RPCs:
- GET pending_operations
- GET monitor_operations
- GET filter
- POST filter
Testing RPCs monitor_operations and pending_operations:
We create a validated operation and three operations that fail
to be validated. Each one of these failed operations has a different
classification to test every possibility of the monitor_operations and
pending_operations RPCs. The error classifications are the following :
- Branch_refused (Branch error classification in protocol)
- Branch_delayed (Temporary)
- Refused (Permanent)
- Outdated (Outdated)
The main goal is to have a record of the encoding of the different
operations returned by the RPC calls. This allows
us to detect undesired changes. *)
(* TODO: https://gitlab.com/tezos/tezos/-/issues/1900
Test the following RPCs:
- POST request_operations
- POST ban_operation
- POST unban_operation
- POST unban_all_operations
*)
(* [mode] is only useful insofar as it helps adapting the test to specific
* `Proxy mode constraint*)
let test_mempool _test_mode_tag protocol ?endpoint client =
let* node = Node.init mempool_node_flags in
let* () = Client.Admin.trust_address ?endpoint client ~peer:node in
let* () = Client.Admin.connect_address ?endpoint client ~peer:node in
let level = 1 in
let* _ = Node.wait_for_level node level in
let* node1_identity = Node.wait_for_identity node in
let* () = Client.Admin.kick_peer ~peer:node1_identity client in
(* Inject a transfer to increment the counter of bootstrap1. Bake with this
transfer to trigger the counter_in_the_past error for the following
transfer. *)
let* _ =
Operation.Manager.(inject ~force:true [make @@ transfer ()] client)
in
let* _ = Client.bake_for_and_wait ?endpoint client in
let* _ = bake_empty_block ?endpoint client in
(* Outdated operation after the second empty baking. *)
let* () = Client.attest_for ~protocol ~force:true client in
let* _ = bake_empty_block ?endpoint client in
let monitor_path =
(* To test the monitor_operations rpc we use curl since the client does
not support streaming RPCs yet. *)
sf
"http://localhost:%d/chains/main/mempool/monitor_operations?validated=true&outdated=true&branch_delayed=true&refused=true&branch_refused=true"
(get_client_port client)
in
let proc_monitor =
(* monitor_operation rpc must be lanched before adding operations in order
to record them. *)
Process.spawn ~hooks:mempool_hooks "curl" ["-s"; monitor_path]
in
let* counter_json =
RPC.Client.call client
@@ RPC.get_chain_block_context_contract_counter
~id:Constant.bootstrap1.Account.public_key_hash
()
in
let counter = JSON.as_int counter_json in
(* Branch_refused op: counter_in_the_past *)
let* _ =
Operation.Manager.(inject ~force:true [make ~counter @@ transfer ()] client)
in
let* counter_json =
RPC.Client.call client
@@ RPC.get_chain_block_context_contract_counter
~id:Constant.bootstrap2.Account.public_key_hash
()
in
let counter = JSON.as_int counter_json in
(* Branch_delayed op: counter_in_the_future *)
let* _ =
Operation.Manager.(
inject
~force:true
[make ~source:Constant.bootstrap2 ~counter:(counter + 5) @@ transfer ()]
client)
in
(* Refused op: fees_too_low *)
let* _ =
Operation.Manager.(
inject
[
make ~source:Constant.bootstrap3 ~fee:0
@@ transfer ~dest:Constant.bootstrap2 ();
]
client)
in
(* Validated op *)
let* _ =
Operation.Manager.(
inject
[
make ~source:Constant.bootstrap4
@@ transfer ~dest:Constant.bootstrap2 ();
]
client)
in
let* () = Client.Admin.connect_address ?endpoint ~peer:node client in
let flush_waiter = Node_event_level.wait_for_flush node in
let* _ =
Prevalidator.bake_empty_block ~protocol ~endpoint:(Client.Node node) client
in
let* _ = flush_waiter in
let* _output_monitor = Process.check_and_read_stdout proc_monitor in
let* complete_mempool =
Mempool.get_mempool ?endpoint ~hooks:mempool_hooks client
in
let* consensus_mempool =
Mempool.get_mempool
?endpoint
~hooks:mempool_hooks
~validation_passes:[0]
client
in
let expected_consensus_mempool =
{Mempool.empty with outdated = complete_mempool.outdated}
in
Check.(
(expected_consensus_mempool = consensus_mempool)
Mempool.classified_typ
~error_msg:"Expected mempool %L, got %R") ;
let* manager_mempool =
Mempool.get_mempool
?endpoint
~hooks:mempool_hooks
~validation_passes:[3]
client
in
let expected_manager_mempool =
{
Mempool.empty with
validated = complete_mempool.validated;
refused = complete_mempool.refused;
branch_refused = complete_mempool.branch_refused;
branch_delayed = complete_mempool.branch_delayed;
}
in
Check.(
(expected_manager_mempool = manager_mempool)
Mempool.classified_typ
~error_msg:"Expected mempool %L, got %R") ;
let* consensus_manager_mempool =
Mempool.get_mempool
?endpoint
~hooks:mempool_hooks
~validation_passes:[0; 3]
client
in
Check.(
(consensus_manager_mempool = complete_mempool)
Mempool.classified_typ
~error_msg:"Expected mempool %L, got %R") ;
let* voting_anonymous_mempool =
Mempool.get_mempool
?endpoint
~hooks:mempool_hooks
~validation_passes:[1; 2]
client
in
Check.(
(voting_anonymous_mempool = Mempool.empty)
Mempool.classified_typ
~error_msg:"Expected mempool %L, got %R") ;
let* _ =
Lwt_list.iter_s
(fun i ->
let* mempool =
Mempool.get_mempool
?endpoint
~hooks:mempool_hooks
~validated:(i = `Validated)
~refused:(i = `Refused)
~branch_delayed:(i = `Branch_delayed)
~branch_refused:(i = `Branch_refused)
~outdated:(i = `Outdated)
client
in
let may_get_field field ophs = if i = field then ophs else [] in
let expected_mempool =
Mempool.
{
validated = may_get_field `Validated complete_mempool.validated;
refused = may_get_field `Refused complete_mempool.refused;
outdated = may_get_field `Outdated complete_mempool.outdated;
branch_refused =
may_get_field `Branch_refused complete_mempool.branch_refused;
branch_delayed =
may_get_field `Branch_delayed complete_mempool.branch_delayed;
unprocessed = [];
}
in
Check.(
(expected_mempool = mempool)
Mempool.classified_typ
~error_msg:"Expected mempool %L, got %R") ;
unit)
[`Validated; `Refused; `Branch_delayed; `Branch_refused; `Outdated]
in
(* We spawn a second monitor_operation RPC that monitor operations
reclassified with errors. *)
let proc_monitor =
Process.spawn ~hooks:mempool_hooks "curl" ["-s"; monitor_path]
in
let* _ =
Prevalidator.bake_empty_block ~protocol ~endpoint:(Client.Node node) client
in
let* _output_monitor = Process.check_and_read_stdout proc_monitor in
Log.info
~color:Log.Color.BG.yellow
"## Test RPCs [GET|POST /chains/main/mempool/filter]" ;
let open Mempool.Config in
Log.info
"Check that GET filter returns the default configuration (the full default \
configuration when the query parameter [include_default] is either absent \
or set to [true], or an empty configuration when [include_default] is \
[false])." ;
let* () =
check_get_filter_all_variations
~log:true
?endpoint
~hooks:mempool_hooks
default
client
in
Log.info
"For various configurations, call POST filter then check that GET filter \
returns the expected result (for all variations of [include_default)." ;
let set_config_and_check msg config =
Log.info "%s" msg ;
let* output =
post_filter ~log:true ?endpoint ~hooks:mempool_hooks config client
in
check_equal (fill_with_default config) (of_json output) ;
check_get_filter_all_variations
~log:true
?endpoint
~hooks:mempool_hooks
config
client
in
let* () =
set_config_and_check
"Config 1: all fields provided and distinct from default."
{
minimal_fees = Some 1;
minimal_nanotez_per_gas_unit = Some (2, 3);
minimal_nanotez_per_byte = Some (4, 5);
replace_by_fee_factor = Some (6, 7);
max_operations = Some 8;
max_total_bytes = Some 9;
}
in
let* () =
set_config_and_check
"Config 2: omitted fields (which should be set to default)."
{
minimal_fees = Some 25;
minimal_nanotez_per_gas_unit = None;
minimal_nanotez_per_byte = Some (1050, 1);
replace_by_fee_factor = None;
max_operations = Some 2000;
max_total_bytes = None;
}
in
let* () =
set_config_and_check
"Config 3: {} (ie. all fields should be set to default)."
{
minimal_fees = None;
minimal_nanotez_per_gas_unit = None;
minimal_nanotez_per_byte = None;
replace_by_fee_factor = None;
max_operations = None;
max_total_bytes = None;
}
in
let* () =
set_config_and_check
"Config 4: divide by zero. (Should this config be invalid?)"
{
minimal_fees = None;
minimal_nanotez_per_gas_unit = Some (100, 0);
minimal_nanotez_per_byte = None;
replace_by_fee_factor = None;
max_operations = None;
max_total_bytes = None;
}
in
let config5 =
{
minimal_fees = None;
minimal_nanotez_per_gas_unit = Some default_minimal_nanotez_per_gas_unit;
minimal_nanotez_per_byte = Some (max_int, 1);
replace_by_fee_factor = None;
max_operations = Some default_max_operations;
max_total_bytes = Some 0;
}
in
let* () =
set_config_and_check
"Config 5: some fields omitted, some provided and equal to default, some \
with extreme values."
config5
in
Log.info
"Post invalid configurations; check that the config is unchanged and that \
event [invalid_mempool_filter_configuration] is witnessed." ;
let config5_full = fill_with_default config5 in
let endpoint =
match endpoint with
| Some endpoint -> endpoint
| None -> Test.fail "This test requires an actual endpoint at %s" __LOC__
in
let test_invalid_config msg config_str =
Log.info "%s" msg ;
let waiter =
Client.endpoint_wait_for
endpoint
"invalid_mempool_filter_configuration.v0"
(Fun.const (Some ()))
in
let* output_post =
post_filter_str ~log:true ~endpoint ~hooks:mempool_hooks config_str client
in
check_equal config5_full (of_json output_post) ;
let* () = waiter in
let* output_get = call_get_filter ~endpoint ~hooks:mempool_hooks client in
check_equal config5_full (of_json output_get) ;
unit
in
let* () =
test_invalid_config
"Invalid config 1: invalid field name"
{|{ "minimal_fees": "100", "minimal_nanotez_per_gas_unit": [ "1050", "1" ], "minimal_nanotez_per_byte": [ "7", "5" ], "replace_by_fee_factor": ["21", "20"], "max_operations": 10, "max_total_bytes": 10_000_000, "invalid_field_name": 100 }|}
in
let* () =
test_invalid_config
"Invalid config 2: wrong type"
{|{ "minimal_fees": "true" }|}
in
let* () =
test_invalid_config
"Invalid config 3: wrong type bis"
{|{ "max_operations": "1000" }|}
in
let* () =
test_invalid_config
"Invalid config 4: not enough elements in fraction"
{|{ "minimal_nanotez_per_gas_unit": [ "100" ] }|}
in
let* () =
test_invalid_config
"Invalid config 5: too many elements in fraction"
{|{ "minimal_nanotez_per_gas_unit": [ "100", "1", "10" ] }|}
in
let* () =
test_invalid_config
"Invalid config 6: negative"
{|{ "minimal_fees": "-1" }|}
in
test_invalid_config
"Invalid config 7: negative bis"
{|{ "max_operations": -1 }|}
let start_with_acl address acl =
let* node =
Node.init
~rpc_host:address
~patch_config:(JSON.update "rpc" (JSON.put ("acl", acl)))
[]
in
let endpoint = Client.Node node in
Client.init ~endpoint ()
let test_network test_mode_tag _protocol ?endpoint client =
let test peer_id =
let call rpc = RPC.Client.call ?endpoint client rpc in
let* _ = call @@ RPC.get_network_connection peer_id in
let* _ = call RPC.get_network_greylist_clear in
(* Peers *)
let* _ = call RPC.get_network_peers in
let* _ = call @@ RPC.get_network_peer peer_id in
let* _ = call @@ RPC.get_network_peer_ban peer_id in
let* _ = call @@ RPC.get_network_peer_banned peer_id in
let* _ = call @@ RPC.get_network_peer_unban peer_id in
let* _ = call @@ RPC.get_network_peer_untrust peer_id in
let* _ = call @@ RPC.get_network_peer_trust peer_id in
(* Connections *)
let* points = call @@ RPC.get_network_points in
let point_id =
match points with
| (p, _) :: _ -> p
| _ -> Test.fail "Expected at least one point."
in
let* _ = call @@ RPC.get_network_point point_id in
let* _ = call @@ RPC.get_network_point_ban point_id in
let* _ = call @@ RPC.get_network_point_banned point_id in
let* _ = call @@ RPC.get_network_point_unban point_id in
let* _ = call @@ RPC.get_network_point_untrust point_id in
let* _ = call @@ RPC.get_network_point_trust point_id in
let* _ = call RPC.get_network_stat in
let* _ = call RPC.get_network_version in
let* _ = call RPC.get_network_versions in
unit
in
match test_mode_tag with
| `Client_data_dir_proxy_server | `Client_rpc_proxy_server ->
Log.info "Skipping network RPCs" ;
unit
| `Light ->
(* In light mode, the node is already connected to another node: use that as peer *)
let* peers = RPC.Client.call ?endpoint client @@ RPC.get_network_peers in
let peer_id =
match peers with
| (p, _) :: _ -> p
| _ -> Test.fail "Expected at least one peer in light mode."
in
test peer_id
| `Proxy | `Client ->
(* Create a second node to get a peer for testing RPCs that are
parameterized by a point or peer id *)
let* node = Node.init ~name:"node" [Connections 1] in
let* () = Client.Admin.trust_address ?endpoint client ~peer:node in
let* () = Client.Admin.connect_address ?endpoint client ~peer:node in
let* _ = Node.wait_for_level node 1 in
let* client = Client.init ~endpoint:(Node node) () in
let* peer_id =
RPC.Client.call ~endpoint:(Node node) client RPC.get_network_self
in
test peer_id
let test_workers _test_mode_tag _protocol ?endpoint client =
let* _ = RPC.Client.call ?endpoint client @@ RPC.get_worker_block_validator in
let* _ =
RPC.Client.call ?endpoint client @@ RPC.get_workers_chain_validators
in
let* _ =
RPC.Client.call ?endpoint client @@ RPC.get_worker_chain_validator ()
in
let* _ =
RPC.Client.call ?endpoint client @@ RPC.get_worker_chain_validator_ddb ()
in
let* _ =
RPC.Client.call ?endpoint client
@@ RPC.get_worker_chain_validator_peers_validators ()
in
let* _ = RPC.Client.call ?endpoint client @@ RPC.get_workers_prevalidators in
let* _ = RPC.Client.call ?endpoint client @@ RPC.get_worker_prevalidator () in
unit
let test_misc_shell _test_mode_tag protocol ?endpoint client =
let protocol_hash = Protocol.hash protocol in
(* Turn off logging to avoid polluting the logs with the error schema *)
let* _ =
RPC.Client.call ?endpoint ~log_output:false client @@ RPC.get_errors
in
let* _ = RPC.Client.call ?endpoint client @@ RPC.get_protocols in
(* Turn off logging to avoid polluting the logs with full protocol
source code *)
let* _ =
RPC.Client.call ?endpoint ~log_output:false client
@@ RPC.get_protocol protocol_hash
in
let* _ =
RPC.Client.call ?endpoint client @@ RPC.get_fetch_protocol protocol_hash
in
let* _ = RPC.Client.call ?endpoint client @@ RPC.get_stats_gc in
let* _ = RPC.Client.call ?endpoint client @@ RPC.get_stats_memory in
let* _ = RPC.Client.call ?endpoint client @@ RPC.get_config in
unit
let test_chain _test_mode_tag _protocol ?endpoint client =
let block_level = 3 in
let* _ = RPC.Client.call ?endpoint client @@ RPC.get_chain_blocks () in
let* _ = RPC.Client.call ?endpoint client @@ RPC.get_chain_chain_id () in
let* _ =
RPC.Client.call ?endpoint client @@ RPC.get_chain_invalid_blocks ()
in
let* _ = RPC.Client.call ?endpoint client @@ RPC.get_chain_block () in
let* _ =
RPC.Client.call ?endpoint client
@@ RPC.get_chain_block_context_constants_errors ()
in
let* _ =
RPC.Client.call ?endpoint client
@@ RPC.get_chain_block_context_nonce block_level
in
let* _ =
(* Calls [/chains/main/blocks/head/context/raw/bytes] *)
RPC.Client.call ?endpoint client
@@ RPC.get_chain_block_context_raw ~ctxt_type:Bytes ~value_path:[] ()
in
let* delegates =
RPC.Client.call ?endpoint client
@@ RPC.get_chain_block_context_raw
~depth:2
~ctxt_type:Bytes
~value_path:["delegates"]
()
in
Check.(
(JSON.unannotate delegates
= `O
[
( "ed25519",
`O
[
("02298c03ed7d454a101eb7022bc95f7e5f41ac78", `Null);
("a9ceae0f8909125492a7c4700acc59274cc6c846", `Null);
("c55cf02dbeecc978d9c84625dcae72bb77ea4fbd", `Null);
("dac9f52543da1aed0bc1d6b46bf7c10db7014cd6", `Null);
("e7670f32038107a59a2b9cfefae36ea21f5aa63c", `Null);
] );
])
json_u
~__LOC__
~error_msg:"Expected %R, got %L") ;
let* () =
let spawn_get_chain_block_context_raw ?depth ~error_msg value_path =
let*? process =
RPC.Client.spawn ?endpoint client
@@ RPC.get_chain_block_context_raw
?depth
~ctxt_type:Bytes
~value_path
()
in
Process.check_error ~msg:(rex error_msg) process
in
let* () =
spawn_get_chain_block_context_raw
["non-existent"]
~error_msg:"No service found at this URL"
in
let* () =
spawn_get_chain_block_context_raw
~depth:(-1)
[]
~error_msg:"Failed to parse argument 'depth' \\(\"-1\"\\)"
in
spawn_get_chain_block_context_raw
~depth:0
["non-existent"]
~error_msg:"No service found at this URL"
in
let* _ = RPC.Client.call ?endpoint client @@ RPC.get_chain_block_hash () in
let* _ = RPC.Client.call ?endpoint client @@ RPC.get_chain_block_header () in
let* _ =
(* Calls [/chains/main/blocks/head/header/protocol_data] *)
RPC.Client.call ?endpoint client
@@ RPC.get_chain_block_header_protocol_data ()
in
let* _ =
(* Calls [/chains/main/blocks/head/header/protocol_data/raw] *)
RPC.Client.call ?endpoint client
@@ RPC.get_chain_block_header_protocol_data_raw ()
in
let* _ =
RPC.Client.call ?endpoint client @@ RPC.get_chain_block_header_raw ()
in
let* _ =
RPC.Client.call ?endpoint client @@ RPC.get_chain_block_header_raw ()
in
let* _ =
let pkh = Constant.bootstrap1.public_key in
let prefix = String.sub pkh 0 10 in
(* TODO: https://gitlab.com/tezos/tezos/-/issues/3234
The result of this RPC endpoint is empty, but I guess it
should be a list containing [pkh]. The original python
test has the same result. *)
RPC.Client.call ?endpoint client
@@ RPC.get_chain_block_helper_complete prefix
in
let* _ =
let* () = Client.bake_for_and_wait client in
let* head_hash =
RPC.Client.call ?endpoint client @@ RPC.get_chain_block_hash ()
in
let prefix = String.sub head_hash 0 10 in
(* TODO: https://gitlab.com/tezos/tezos/-/issues/3234
The result of this RPC endpoint is empty, but I guess it
should be a list containing [head_hash]. The original python
test has the same result. *)
RPC.Client.call ?endpoint client
@@ RPC.get_chain_block_helper_complete prefix
in
let* _ =
RPC.Client.call ?endpoint client @@ RPC.get_chain_block_live_blocks ()
in
let* _ =
RPC.Client.call ?endpoint client @@ RPC.get_chain_block_metadata ()
in
let* _ =
RPC.Client.call ?endpoint client @@ RPC.get_chain_block_operation_hashes ()
in
let* () =
let validation_pass = 3 in
let operation_offset = 0 in
let* () =
Client.transfer
~amount:Tez.one
~giver:"bootstrap1"
~receiver:"bootstrap2"
client
in
let* () = Client.bake_for_and_wait client in
let* _ =
RPC.Client.call ?endpoint client
@@ RPC.get_chain_block_operation_hashes ()
in
let* _ =
RPC.Client.call ?endpoint client
@@ RPC.get_chain_block_operation_hashes_of_validation_pass validation_pass
in
let* _ =
RPC.Client.call ?endpoint client
@@ RPC.get_chain_block_operation_hash
~validation_pass
~operation_offset
()
in
let* _ =
RPC.Client.call ?endpoint client @@ RPC.get_chain_block_operations ()
in
let* _ =
RPC.Client.call ?endpoint client
@@ RPC.get_chain_block_operations_validation_pass ~validation_pass ()
in
let* _ =
RPC.Client.call ?endpoint client
@@ RPC.get_chain_block_operations_validation_pass
~validation_pass
~operation_offset
()
in
unit
in
unit
let test_deprecated _test_mode_tag protocol ?endpoint client =
let check_rpc_not_found rpc =
let*? process = RPC.Client.spawn ?endpoint ~hooks client @@ rpc in
Process.check_error
~msg:
(rex
"(No service found at this URL|Did not find service|Rpc request \
failed)")
process
in
let implicit_account = Account.Bootstrap.keys.(0).public_key_hash in
let make path =
RPC.make
~get_host:Node.rpc_host
~get_port:Node.rpc_port
~get_scheme:Node.rpc_scheme
GET
path
Fun.id
in
let* () =
check_rpc_not_found
@@ make
[
"chains";
"main";
"blocks";
"head";
"context";
"contracts";
implicit_account;
"delegatable";
]
in
let* _alias, originated_account =
Client.originate_contract_at
~amount:Tez.zero
~src:"bootstrap1"
~init:"Some \"initial storage\""
~burn_cap:Tez.(of_int 3)
client
["mini_scenarios"; "str_id"]
protocol
in
let* () =
Lwt_list.iter_s
(fun contract_id ->
check_rpc_not_found
@@ make
[
"chains";
"main";
"blocks";
"head";
"contracts";
contract_id;
"spendable";
])
[originated_account; implicit_account]
in
unit
(* Test access to RPC regulated with an ACL. *)
let test_whitelist address () =
let whitelist =
JSON.annotate ~origin:"whitelist"
@@ `A
[
`O
[
("address", `String address);
( "whitelist",
`A [`String "GET /describe/**"; `String "GET /chains/**"] );
];
]
in
let* client = start_with_acl address whitelist in
let* success_resp = RPC.Client.call client @@ RPC.get_chain_blocks () in
let block_hash = JSON.geti 0 success_resp |> JSON.geti 0 |> JSON.as_string in
let* () =
if block_hash = "BLockGenesisGenesisGenesisGenesisGenesisf79b5d1CoW2" then
unit
else
Test.fail "Received an unexpected block hash from node: '%s'." block_hash
in
let* () =
Client.spawn_rpc GET ["network"; "connections"] client
|> Process.check_error ~exit_code:1
in
unit
let test_blacklist address () =
let blacklist =
JSON.annotate ~origin:"blacklist"
@@ `A
[
`O
[
("address", `String address);
("blacklist", `A [`String "GET /chains/**"]);
];
]
in
let* client = start_with_acl address blacklist in
let* () =
Client.spawn_rpc GET ["chains"; "main"; "blocks"] client
|> Process.check_error ~exit_code:1
in
let* _success_resp = RPC.Client.call client @@ RPC.get_network_connections in
unit
let binary_regression_test () =
let node = Node.create ~rpc_host:"127.0.0.1" [] in
let endpoint = Client.(Node node) in
let* () = Node.config_init node [] in
let* () = Node.identity_generate node in
let* () = Node.run node [] in
let* () = Node.wait_for_ready node in
let* json_client = Client.init ~endpoint ~media_type:Json () in
let* binary_client = Client.init ~endpoint ~media_type:Binary () in
let call_rpc client =
Client.spawn_rpc
~hooks
GET
["chains"; "main"; "blocks"; "head"; "header"; "shell"]
client
|> Process.check_and_read_stdout
in
let* json_result = call_rpc json_client in
let* binary_result = call_rpc binary_client in
let* decoded_binary_result =
Codec.decode ~name:"block_header.shell" binary_result
in
if JSON.unannotate decoded_binary_result = Ezjsonm.from_string json_result
then Lwt.return_unit
else Test.fail "Unexpected binary answer"
let test_node_binary_mode address () =
let node = Node.create ~rpc_host:address [] in
let endpoint = Client.(Node node) in
let* () = Node.config_init node [] in
let* () = Node.identity_generate node in
let* () = Node.run node [Media_type Binary] in
let* () = Node.wait_for_ready node in
let* client = Client.init ~endpoint ~media_type:Json () in
Client.spawn_rpc GET ["chains"; "main"; "blocks"] client
|> Process.check_error ~exit_code:1
let test_no_service_at_valid_prefix address () =
let node = Node.create ~rpc_host:address [] in
let endpoint = Client.(Node node) in
let* () = Node.config_init node [] in
let* () = Node.identity_generate node in
let* () = Node.run node [] in
let* () = Node.wait_for_ready node in
let* client = Client.init ~endpoint () in
let* () =
Client.spawn_rpc ~better_errors:true GET ["chains"; "main"] client
|> Process.check_error
~exit_code:1
~msg:
(rex
"Fatal error:\n\
\ No service found at this URL (but this is a valid prefix)*\n\
*")
in
unit
let register protocols =
Regression.register
~__FILE__
~title:"Binary RPC regression tests"
~tags:["rpc"; "regression"; "binary"]
binary_regression_test ;
let register protocols test_mode_tag =
let check_rpc_regression ?parameter_overrides ?supports ?nodes_args
?event_sections_levels ~test_function sub_group =
check_rpc_regression
~test_mode_tag
?parameter_overrides
?nodes_args
?event_sections_levels
~test_function
sub_group
?supports
protocols
in
let check_rpc ?parameter_overrides ?nodes_args ~test_function sub_group =
check_rpc
~test_mode_tag
?parameter_overrides
?nodes_args
~test_function
sub_group
protocols
in
let consensus_threshold _protocol = [(["consensus_threshold"], `Int 0)] in
check_rpc_regression
"contracts"
~test_function:test_contracts
~parameter_overrides:consensus_threshold ;
check_rpc_regression
"delegates"
~test_function:test_delegates
~parameter_overrides:consensus_threshold ;
check_rpc_regression
"adaptive_issuance"
~supports:Protocol.(From_protocol (number Nairobi + 1))
~test_function:test_adaptive_issuance ;
check_rpc_regression
"votes"
~test_function:test_votes
~parameter_overrides:(fun protocol ->
(* reduced periods duration to get to testing vote period faster *)
(* We need nonce_revelation_threshold < blocks_per_cycle for sanity
checks *)
[
(["blocks_per_cycle"], `Int 4);
(["cycles_per_voting_period"], `Int 1);
(["nonce_revelation_threshold"], `Int 3);
]
@ consensus_threshold protocol) ;
check_rpc_regression
"misc_protocol"
~test_function:test_misc_protocol
~parameter_overrides:consensus_threshold ;
(match test_mode_tag with
| `Client_data_dir_proxy_server | `Client_rpc_proxy_server | `Light -> ()
| _ ->
check_rpc_regression
"mempool"
~test_function:test_mempool
~nodes_args:mempool_node_flags
~event_sections_levels:[("prevalidator", `Debug)]
(* Level [Debug] is needed to witness prevalidator event
[invalid_mempool_filter_configuration]. *)) ;
check_rpc
"network"
~test_function:test_network
~parameter_overrides:consensus_threshold
~nodes_args:[Connections 1] ;
(match test_mode_tag with
(* No worker RPCs in these modes *)
| `Client_data_dir_proxy_server | `Client_rpc_proxy_server -> ()
| _ ->
check_rpc
"workers"
~test_function:test_workers
~parameter_overrides:consensus_threshold) ;
(match test_mode_tag with
(* No misc shell RPCs in these modes *)
| `Client_data_dir_proxy_server | `Client_rpc_proxy_server -> ()
| _ ->
check_rpc
"misc_shell"
~test_function:test_misc_shell
~parameter_overrides:consensus_threshold) ;
(match test_mode_tag with
(* No chain RPCs in these modes *)
| `Client_data_dir_proxy_server | `Client_rpc_proxy_server -> ()
| _ ->
check_rpc
"chain"
~test_function:test_chain
~parameter_overrides:consensus_threshold) ;
check_rpc "deprecated" ~test_function:test_deprecated
in
List.iter
(register protocols)
[
`Client;
`Light;
`Proxy;
`Client_data_dir_proxy_server;
`Client_rpc_proxy_server;
] ;
let addresses = ["localhost"; "127.0.0.1"] in
let mk_title list_type address =
Format.sprintf "Test RPC %s @@ %s" list_type address
in
List.iter
(fun addr ->
Test.register
~__FILE__
~title:(mk_title "whitelist" addr)
~tags:["rpc"; "acl"]
(test_whitelist addr) ;
Test.register
~__FILE__
~title:(mk_title "blacklist" addr)
~tags:["rpc"; "acl"]
(test_blacklist addr) ;
Test.register
~__FILE__
~title:(mk_title "no_service_at_valid_prefix" addr)
~tags:["rpc"]
(test_no_service_at_valid_prefix addr) ;
Test.register
~__FILE__
~title:(mk_title "node_binary_mode" addr)
~tags:["rpc"; "binary"]
(test_node_binary_mode addr))
addresses
![swh spinner](/static/img/swh-spinner.gif)
Computing file changes ...