diff --git a/src/lib_dac/RPC_services.ml b/src/lib_dac/RPC_services.ml index 646fd80ba10f3e7c01cb659b9052941eda502f52..00d0f6a88ec964892856911d5c23e1ab10d69dfe 100644 --- a/src/lib_dac/RPC_services.ml +++ b/src/lib_dac/RPC_services.ml @@ -30,11 +30,7 @@ module V0 = struct (* A variant of [Sc_rollup_reveal_hash.encoding] that prefers hex encoding over b58check encoding for JSON. *) let store_preimage_request_encoding = - let pagination_scheme_encoding = Pagination_scheme.encoding in - Data_encoding.( - obj2 - (req "payload" Data_encoding.(bytes' Hex)) - (req "pagination_scheme" pagination_scheme_encoding)) + Data_encoding.(obj1 (req "payload" Data_encoding.(bytes' Hex))) let store_preimage_response_encoding = Data_encoding.( diff --git a/src/lib_dac/RPC_services.mli b/src/lib_dac/RPC_services.mli index 0e9ae4419d84143a0ee5935d7a477cfd24286941..47cea45c02d73fa97559cae3f3b584e93905d6ff 100644 --- a/src/lib_dac/RPC_services.mli +++ b/src/lib_dac/RPC_services.mli @@ -28,15 +28,14 @@ 1M/tps demo. The plan is to remove it once we get rid of the [Legacy] mode. Use at your own risk! *) module V0 : sig - (** "POST v0/store_preimage" stores a payload using a given - [pagination_scheme]. It returns the base58 encoded root page hash - and the raw bytes. *) + (** "POST v0/store_preimage" stores a payload. It returns the + base58 encoded root page hash and the raw bytes. *) val post_store_preimage : ( [`POST], unit, unit, unit, - Bytes.t * Pagination_scheme.t, + Bytes.t, Dac_plugin.raw_hash * Bytes.t ) Tezos_rpc.Service.service diff --git a/src/lib_dac/pagination_scheme.ml b/src/lib_dac/pagination_scheme.ml deleted file mode 100644 index e11caf882a25d1250804ce53778c90818c4bcdff..0000000000000000000000000000000000000000 --- a/src/lib_dac/pagination_scheme.ml +++ /dev/null @@ -1,30 +0,0 @@ -(*****************************************************************************) -(* *) -(* Open Source License *) -(* Copyright (c) 2023 TriliTech *) -(* *) -(* 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. *) -(* *) -(*****************************************************************************) - -type t = Merkle_tree_V0 | Hash_chain_V0 - -let encoding = - Data_encoding.string_enum - [("Merkle_tree_V0", Merkle_tree_V0); ("Hash_chain_V0", Hash_chain_V0)] diff --git a/src/lib_dac/pagination_scheme.mli b/src/lib_dac/pagination_scheme.mli deleted file mode 100644 index 48707bcdb5699603f377c7b5744880df821d337f..0000000000000000000000000000000000000000 --- a/src/lib_dac/pagination_scheme.mli +++ /dev/null @@ -1,31 +0,0 @@ -(*****************************************************************************) -(* *) -(* Open Source License *) -(* Copyright (c) 2023 TriliTech *) -(* *) -(* 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. *) -(* *) -(*****************************************************************************) - -(** The pagination schemes that are supported by the DAC node for converting - a payload in a set of pages of 4096 bytes each. *) -type t = Merkle_tree_V0 | Hash_chain_V0 - -(** The encoding for pagination schemes. *) -val encoding : t Data_encoding.t diff --git a/src/lib_dac_client/dac_node_client.ml b/src/lib_dac_client/dac_node_client.ml index b678bb3256cf20a635073939842190e7fdb88e6a..0d3cc85031a5131933acad679985421829a92ecb 100644 --- a/src/lib_dac_client/dac_node_client.ml +++ b/src/lib_dac_client/dac_node_client.ml @@ -54,12 +54,8 @@ module V0 = struct let get_preimage (cctxt : #cctxt) ~page_hash = cctxt#call_service RPC_services.V0.get_preimage ((), page_hash) () () - let post_store_preimage (cctxt : #cctxt) ~payload ~pagination_scheme = - cctxt#call_service - RPC_services.V0.post_store_preimage - () - () - (payload, pagination_scheme) + let post_store_preimage (cctxt : #cctxt) ~payload = + cctxt#call_service RPC_services.V0.post_store_preimage () () payload let get_verify_signature (cctxt : #cctxt) ~external_message = cctxt#call_service diff --git a/src/lib_dac_client/dac_node_client.mli b/src/lib_dac_client/dac_node_client.mli index 1c63d68c46e0e5229c83fe05f39626f062a0db2f..db2ea4646f512afdab3741fa9a3e501daaab24d6 100644 --- a/src/lib_dac_client/dac_node_client.mli +++ b/src/lib_dac_client/dac_node_client.mli @@ -49,14 +49,11 @@ module V0 : sig val get_preimage : #cctxt -> page_hash:Dac_plugin.raw_hash -> bytes tzresult Lwt.t - (** [post_store_preimage cctxt ~payload ~pagination_scheme] posts a [payload] - to v0/store_preimage using a given [pagination_scheme]. It returns the hex - encoded root page hash and the raw bytes. *) + (** [post_store_preimage cctxt ~payload] posts a [payload] + to v0/store_preimage. It returns the hex encoded root page hash + and the raw bytes. *) val post_store_preimage : - #cctxt -> - payload:bytes -> - pagination_scheme:Pagination_scheme.t -> - (Dac_plugin.raw_hash * bytes) tzresult Lwt.t + #cctxt -> payload:bytes -> (Dac_plugin.raw_hash * bytes) tzresult Lwt.t (** [get_verify_signature cctxt ~external_message] requests the DAC node to verify the signature of the external message [external_message] via diff --git a/src/lib_dac_node/RPC_handlers.ml b/src/lib_dac_node/RPC_handlers.ml index 8853ea81226156a341789831ca0c82a17920e537..2105a42793e7ffaa6c3acc94819ad16eeac8277f 100644 --- a/src/lib_dac_node/RPC_handlers.ml +++ b/src/lib_dac_node/RPC_handlers.ml @@ -83,38 +83,20 @@ end module V0 = struct let handle_post_store_preimage dac_plugin cctxt dac_sk_uris page_store - hash_streamer (data, pagination_scheme) = + hash_streamer data = let open Lwt_result_syntax in let open Pages_encoding in let* root_hash = - match pagination_scheme with - | Pagination_scheme.Merkle_tree_V0 -> - (* FIXME: https://gitlab.com/tezos/tezos/-/issues/4897 - Once new "PUT /preimage" endpoint is implemented, pushing - a new root hash to the data streamer should be moved there. - Tezt for testing streaming of root hashes should also use - the new endpoint. *) - let* root_hash = - Merkle_tree.V0.Filesystem.serialize_payload - dac_plugin - ~page_store - data - in - let () = - Data_streamer.publish - hash_streamer - (Dac_plugin.hash_to_raw root_hash) - in - let*! () = - Event.emit_root_hash_pushed_to_data_streamer dac_plugin root_hash - in - return root_hash - | Pagination_scheme.Hash_chain_V0 -> - Hash_chain.V0.serialize_payload - dac_plugin - ~for_each_page:(fun (hash, content) -> - Page_store.Filesystem.save dac_plugin page_store ~hash ~content) - data + let* root_hash = + Merkle_tree.V0.Filesystem.serialize_payload dac_plugin ~page_store data + in + let () = + Data_streamer.publish hash_streamer (Dac_plugin.hash_to_raw root_hash) + in + let*! () = + Event.emit_root_hash_pushed_to_data_streamer dac_plugin root_hash + in + return root_hash in let* signature, witnesses = Signature_manager.Legacy.sign_root_hash diff --git a/src/lib_dac_node/RPC_handlers.mli b/src/lib_dac_node/RPC_handlers.mli index d0834ffac04552f4ef546cbc19a288f060e894d9..686d348227b8d2b082c6a2e09683da04d79cd06a 100644 --- a/src/lib_dac_node/RPC_handlers.mli +++ b/src/lib_dac_node/RPC_handlers.mli @@ -59,7 +59,7 @@ module V0 : sig Client_keys.aggregate_sk_uri option trace -> Page_store.Filesystem.t -> Dac_plugin.raw_hash Data_streamer.t -> - bytes * Pagination_scheme.t -> + bytes -> (Dac_plugin.raw_hash * bytes, tztrace) result Lwt.t (** [handle_get_verify_signature] is a handler for "GET v0/verify_signature". *) diff --git a/src/lib_dac_node/pages_encoding.ml b/src/lib_dac_node/pages_encoding.ml index 7c090bea980bac744d0b8d4b2d092e89dfdf7885..96b0d19f497eac266c659bea2c5b55b8c4a76a7c 100644 --- a/src/lib_dac_node/pages_encoding.ml +++ b/src/lib_dac_node/pages_encoding.ml @@ -567,56 +567,3 @@ module Merkle_tree = struct module Make = Make end end - -module Hash_chain = struct - module V0 = struct - type page = {succ_hash : Dac_plugin.hash; content : string} - - let hash ((module Plugin) : Dac_plugin.t) bytes = - Plugin.hash_bytes ~scheme:Blake2B [bytes] - - let content_limit = - (4 * 1024) - 100 (* We reserve 100 bytes for the continuation hash. *) - - let serialize_page ((module Plugin) : Dac_plugin.t) page = - Format.asprintf "%s hash:%s" page.content (Plugin.to_hex page.succ_hash) - - let link_chunks dac_plugin chunks : (Dac_plugin.hash * bytes) list = - let rec link_chunks_rev linked_pages rev_pages = - match rev_pages with - | [] -> linked_pages - | chunk :: rev_chunks -> - let page = - match linked_pages with - | [] -> chunk - | (succ_hash, _) :: _ -> - serialize_page dac_plugin {succ_hash; content = chunk} - in - let page = Bytes.of_string page in - let hash = hash dac_plugin page in - (link_chunks_rev [@tailcall]) - ((hash, page) :: linked_pages) - rev_chunks - in - let rev_chunks = List.rev chunks in - link_chunks_rev [] rev_chunks - - let make_hash_chain dac_plugin data = - let open Result_syntax in - let+ chunks = String.chunk_bytes content_limit data in - link_chunks dac_plugin chunks - - (** Main function for computing a hash chain from a byte sequence. Returns the - chain head hash.[for_each_page] may be supplied to run post processing - tasks on each page, for example, to persisit a serialized page to disk. - *) - let serialize_payload dac_plugin ~for_each_page payload = - let open Lwt_result_syntax in - let* () = - fail_unless (Bytes.length payload > 0) Payload_cannot_be_empty - in - let*? hash_chain = make_hash_chain dac_plugin payload in - let+ () = List.iter_es for_each_page hash_chain in - Stdlib.List.hd hash_chain |> fst - end -end diff --git a/src/lib_dac_node/pages_encoding.mli b/src/lib_dac_node/pages_encoding.mli index 662d27731ff8372a9e442a41325d99b8bd95eac8..02242a1673663e91725719073d1d6c931610e360 100644 --- a/src/lib_dac_node/pages_encoding.mli +++ b/src/lib_dac_node/pages_encoding.mli @@ -168,18 +168,3 @@ module Merkle_tree : sig Dac_codec with type page_store := B.page_store end end - -(** Encoding of DAC payload as a Hash Chain/Merkle List. The encoding - implementation is specific to the Arith PVM. *) -module Hash_chain : sig - module V0 : sig - val serialize_payload : - Dac_plugin.t -> - for_each_page:(Dac_plugin.hash * bytes -> unit tzresult Lwt.t) -> - bytes -> - Dac_plugin.hash tzresult Lwt.t - - val make_hash_chain : - Dac_plugin.t -> bytes -> ((Dac_plugin.hash * bytes) list, 'a) result - end -end diff --git a/src/proto_017_PtNairob/lib_dac_plugin/test/test_dac_pages_encoding.ml b/src/proto_017_PtNairob/lib_dac_plugin/test/test_dac_pages_encoding.ml index a9483a551538dbf4837de8678c675074601cc3e8..814efbb706bb8e12a874c8cc74cfd717a7da243d 100644 --- a/src/proto_017_PtNairob/lib_dac_plugin/test/test_dac_pages_encoding.ml +++ b/src/proto_017_PtNairob/lib_dac_plugin/test/test_dac_pages_encoding.ml @@ -543,112 +543,6 @@ module Merkle_tree = struct end end -module Hash_chain = struct - (* Return substring of [str] after the first [n] char. Returns the original string - if n <= 0. Returns an empty string if n > String.length str *) - let take_after str n = - let n = max 0 n in - String.sub str (min (String.length str) n) (max 0 (String.length str - n)) - - module V0 = struct - module Pagination_scheme = Pages_encoding.Hash_chain.V0 - - let deserialize_page page : - [`Node of Dac_plugin.hash * string | `Leaf of string] = - if String.length page > 3996 then - let content = String.sub page 0 3996 in - let (module Plugin) = dac_plugin in - let hash = - Stdlib.Option.get - @@ Plugin.of_hex (take_after page (3996 + String.length " hash:")) - in - `Node (hash, content) - else `Leaf page - - let rec retrieve_content ~get_page ?(result = "") hash = - let open Lwt_result_syntax in - let* page = get_page hash in - let* res = return @@ deserialize_page (Bytes.to_string page) in - match res with - | `Node (succ_hash, content) -> - (retrieve_content [@tailcall]) - ~get_page - ~result:(String.cat result content) - succ_hash - | `Leaf content -> return @@ String.cat result content - - let test_make_chain_hash_one_page () = - let open Lwt_result_syntax in - let payload = Bytes.of_string "simple payload" in - let*? pages = Pagination_scheme.make_hash_chain dac_plugin payload in - let* () = Assert.equal_int ~loc:__LOC__ 1 (List.length pages) in - let actual_hash, content = Stdlib.List.hd pages in - let* () = - assert_equal_bytes ~loc:__LOC__ "Contents not equal" payload content - in - let (module Plugin) = dac_plugin in - let expected_hash = - Plugin.to_hex @@ Plugin.hash_bytes ~scheme:Blake2B [content] - in - Assert.equal_string ~loc:__LOC__ expected_hash (Plugin.to_hex actual_hash) - - let test_make_chain_hash_long () = - let open Lwt_result_syntax in - let payload = Bytes.of_string long_payload in - let*? pages = Pagination_scheme.make_hash_chain dac_plugin payload in - let* () = Assert.equal_int ~loc:__LOC__ 2 (List.length pages) in - let head_succ = - Stdlib.List.hd pages |> snd |> fun byt -> - take_after (String.of_bytes byt) (3996 + String.length " hash:") - in - let (module Plugin) = dac_plugin in - let next_hash, content = Stdlib.List.nth pages 1 in - let* () = - Assert.equal_string ~loc:__LOC__ (Plugin.to_hex next_hash) head_succ - in - Assert.equal_string - ~loc:__LOC__ - (Plugin.to_hex next_hash) - (Plugin.to_hex @@ Plugin.hash_bytes ~scheme:Blake2B [content]) - - let test_serialize () = - let open Lwt_result_syntax in - let payload = Bytes.of_string long_payload in - let page_store = Hashes_map_backend.init () in - let* root_hash = - Pagination_scheme.serialize_payload - dac_plugin - ~for_each_page:(fun (hash, content) -> - Hashes_map_backend.save dac_plugin page_store ~hash ~content) - payload - in - let* () = - Assert.equal_int - ~loc:__LOC__ - (Hashes_map_backend.number_of_pages page_store) - 2 - in - let get_page hash = Hashes_map_backend.load dac_plugin page_store hash in - let* content = retrieve_content ~get_page root_hash in - Assert.equal_string ~loc:__LOC__ long_payload content - - let test_serialize_empty_payload_fails () = - let page_store = Hashes_map_backend.init () in - let payload = Bytes.of_string "" in - let result = - Pagination_scheme.serialize_payload - ~for_each_page:(fun (hash, content) -> - Hashes_map_backend.save dac_plugin page_store ~hash ~content) - dac_plugin - payload - in - assert_fails_with - ~loc:__LOC__ - result - Pages_encoding.Payload_cannot_be_empty - end -end - let tests = [ Tztest.tztest @@ -683,23 +577,6 @@ let tests = "Hashes pages are not larger than expected" `Quick Merkle_tree.V0.multiple_pages_roundtrip_do_not_exceed_page_size; - Tztest.tztest - "Constructing hash chain (V0) for single page content is correct" - `Quick - Hash_chain.V0.test_make_chain_hash_one_page; - Tztest.tztest - "Constructing hash chain (V0) for multi page content is correct" - `Quick - Hash_chain.V0.test_make_chain_hash_long; - Tztest.tztest - "Serializing an empty payload returns an error (Hash chain)" - `Quick - Hash_chain.V0.test_serialize_empty_payload_fails; - Tztest.tztest - "Contents fitting in more pages can be retrieved after being saved - \ - repeated pages (Hash chain, V0)" - `Quick - Hash_chain.V0.test_serialize; Tztest.tztest "Deserialization with integrity check fails if page contents are corrupt" `Quick diff --git a/src/proto_018_Proxford/lib_dac_plugin/test/test_dac_pages_encoding.ml b/src/proto_018_Proxford/lib_dac_plugin/test/test_dac_pages_encoding.ml index 7af792bdb0722628f0984219313ca918905578b1..505db318370588324ba888fcc64f39e2a9d26727 100644 --- a/src/proto_018_Proxford/lib_dac_plugin/test/test_dac_pages_encoding.ml +++ b/src/proto_018_Proxford/lib_dac_plugin/test/test_dac_pages_encoding.ml @@ -589,112 +589,6 @@ module Merkle_tree = struct end end -module Hash_chain = struct - (* Return substring of [str] after the first [n] char. Returns the original string - if n <= 0. Returns an empty string if n > String.length str *) - let take_after str n = - let n = max 0 n in - String.sub str (min (String.length str) n) (max 0 (String.length str - n)) - - module V0 = struct - module Pagination_scheme = Pages_encoding.Hash_chain.V0 - - let deserialize_page page : - [`Node of Dac_plugin.hash * string | `Leaf of string] = - if String.length page > 3996 then - let content = String.sub page 0 3996 in - let (module Plugin) = dac_plugin in - let hash = - Stdlib.Option.get - @@ Plugin.of_hex (take_after page (3996 + String.length " hash:")) - in - `Node (hash, content) - else `Leaf page - - let rec retrieve_content ~get_page ?(result = "") hash = - let open Lwt_result_syntax in - let* page = get_page hash in - let* res = return @@ deserialize_page (Bytes.to_string page) in - match res with - | `Node (succ_hash, content) -> - (retrieve_content [@tailcall]) - ~get_page - ~result:(String.cat result content) - succ_hash - | `Leaf content -> return @@ String.cat result content - - let test_make_chain_hash_one_page () = - let open Lwt_result_syntax in - let payload = Bytes.of_string "simple payload" in - let*? pages = Pagination_scheme.make_hash_chain dac_plugin payload in - let* () = Assert.equal_int ~loc:__LOC__ 1 (List.length pages) in - let actual_hash, content = Stdlib.List.hd pages in - let* () = - assert_equal_bytes ~loc:__LOC__ "Contents not equal" payload content - in - let (module Plugin) = dac_plugin in - let expected_hash = - Plugin.to_hex @@ Plugin.hash_bytes ~scheme:Blake2B [content] - in - Assert.equal_string ~loc:__LOC__ expected_hash (Plugin.to_hex actual_hash) - - let test_make_chain_hash_long () = - let open Lwt_result_syntax in - let payload = Bytes.of_string long_payload in - let*? pages = Pagination_scheme.make_hash_chain dac_plugin payload in - let* () = Assert.equal_int ~loc:__LOC__ 2 (List.length pages) in - let head_succ = - Stdlib.List.hd pages |> snd |> fun byt -> - take_after (String.of_bytes byt) (3996 + String.length " hash:") - in - let (module Plugin) = dac_plugin in - let next_hash, content = Stdlib.List.nth pages 1 in - let* () = - Assert.equal_string ~loc:__LOC__ (Plugin.to_hex next_hash) head_succ - in - Assert.equal_string - ~loc:__LOC__ - (Plugin.to_hex next_hash) - (Plugin.to_hex @@ Plugin.hash_bytes ~scheme:Blake2B [content]) - - let test_serialize () = - let open Lwt_result_syntax in - let payload = Bytes.of_string long_payload in - let page_store = Hashes_map_backend.init () in - let* root_hash = - Pagination_scheme.serialize_payload - dac_plugin - ~for_each_page:(fun (hash, content) -> - Hashes_map_backend.save dac_plugin page_store ~hash ~content) - payload - in - let* () = - Assert.equal_int - ~loc:__LOC__ - (Hashes_map_backend.number_of_pages page_store) - 2 - in - let get_page hash = Hashes_map_backend.load dac_plugin page_store hash in - let* content = retrieve_content ~get_page root_hash in - Assert.equal_string ~loc:__LOC__ long_payload content - - let test_serialize_empty_payload_fails () = - let page_store = Hashes_map_backend.init () in - let payload = Bytes.of_string "" in - let result = - Pagination_scheme.serialize_payload - ~for_each_page:(fun (hash, content) -> - Hashes_map_backend.save dac_plugin page_store ~hash ~content) - dac_plugin - payload - in - assert_fails_with - ~loc:__LOC__ - result - Pages_encoding.Payload_cannot_be_empty - end -end - let tests = [ Tztest.tztest @@ -729,23 +623,6 @@ let tests = "Hashes pages are not larger than expected" `Quick Merkle_tree.V0.multiple_pages_roundtrip_do_not_exceed_page_size; - Tztest.tztest - "Constructing hash chain (V0) for single page content is correct" - `Quick - Hash_chain.V0.test_make_chain_hash_one_page; - Tztest.tztest - "Constructing hash chain (V0) for multi page content is correct" - `Quick - Hash_chain.V0.test_make_chain_hash_long; - Tztest.tztest - "Serializing an empty payload returns an error (Hash chain)" - `Quick - Hash_chain.V0.test_serialize_empty_payload_fails; - Tztest.tztest - "Contents fitting in more pages can be retrieved after being saved - \ - repeated pages (Hash chain, V0)" - `Quick - Hash_chain.V0.test_serialize; Tztest.tztest "Deserialization with integrity check fails if page contents are corrupt" `Quick diff --git a/src/proto_alpha/lib_dac_plugin/test/test_dac_pages_encoding.ml b/src/proto_alpha/lib_dac_plugin/test/test_dac_pages_encoding.ml index 2a6018905deccb04d4f06bcbf7aa9cd8c1df572a..4fc0eab684fdd113793643007102927a18494587 100644 --- a/src/proto_alpha/lib_dac_plugin/test/test_dac_pages_encoding.ml +++ b/src/proto_alpha/lib_dac_plugin/test/test_dac_pages_encoding.ml @@ -589,112 +589,6 @@ module Merkle_tree = struct end end -module Hash_chain = struct - (* Return substring of [str] after the first [n] char. Returns the original string - if n <= 0. Returns an empty string if n > String.length str *) - let take_after str n = - let n = max 0 n in - String.sub str (min (String.length str) n) (max 0 (String.length str - n)) - - module V0 = struct - module Pagination_scheme = Pages_encoding.Hash_chain.V0 - - let deserialize_page page : - [`Node of Dac_plugin.hash * string | `Leaf of string] = - if String.length page > 3996 then - let content = String.sub page 0 3996 in - let (module Plugin) = dac_plugin in - let hash = - Stdlib.Option.get - @@ Plugin.of_hex (take_after page (3996 + String.length " hash:")) - in - `Node (hash, content) - else `Leaf page - - let rec retrieve_content ~get_page ?(result = "") hash = - let open Lwt_result_syntax in - let* page = get_page hash in - let* res = return @@ deserialize_page (Bytes.to_string page) in - match res with - | `Node (succ_hash, content) -> - (retrieve_content [@tailcall]) - ~get_page - ~result:(String.cat result content) - succ_hash - | `Leaf content -> return @@ String.cat result content - - let test_make_chain_hash_one_page () = - let open Lwt_result_syntax in - let payload = Bytes.of_string "simple payload" in - let*? pages = Pagination_scheme.make_hash_chain dac_plugin payload in - let* () = Assert.equal_int ~loc:__LOC__ 1 (List.length pages) in - let actual_hash, content = Stdlib.List.hd pages in - let* () = - assert_equal_bytes ~loc:__LOC__ "Contents not equal" payload content - in - let (module Plugin) = dac_plugin in - let expected_hash = - Plugin.to_hex @@ Plugin.hash_bytes ~scheme:Blake2B [content] - in - Assert.equal_string ~loc:__LOC__ expected_hash (Plugin.to_hex actual_hash) - - let test_make_chain_hash_long () = - let open Lwt_result_syntax in - let payload = Bytes.of_string long_payload in - let*? pages = Pagination_scheme.make_hash_chain dac_plugin payload in - let* () = Assert.equal_int ~loc:__LOC__ 2 (List.length pages) in - let head_succ = - Stdlib.List.hd pages |> snd |> fun byt -> - take_after (String.of_bytes byt) (3996 + String.length " hash:") - in - let (module Plugin) = dac_plugin in - let next_hash, content = Stdlib.List.nth pages 1 in - let* () = - Assert.equal_string ~loc:__LOC__ (Plugin.to_hex next_hash) head_succ - in - Assert.equal_string - ~loc:__LOC__ - (Plugin.to_hex next_hash) - (Plugin.to_hex @@ Plugin.hash_bytes ~scheme:Blake2B [content]) - - let test_serialize () = - let open Lwt_result_syntax in - let payload = Bytes.of_string long_payload in - let page_store = Hashes_map_backend.init () in - let* root_hash = - Pagination_scheme.serialize_payload - dac_plugin - ~for_each_page:(fun (hash, content) -> - Hashes_map_backend.save dac_plugin page_store ~hash ~content) - payload - in - let* () = - Assert.equal_int - ~loc:__LOC__ - (Hashes_map_backend.number_of_pages page_store) - 2 - in - let get_page hash = Hashes_map_backend.load dac_plugin page_store hash in - let* content = retrieve_content ~get_page root_hash in - Assert.equal_string ~loc:__LOC__ long_payload content - - let test_serialize_empty_payload_fails () = - let page_store = Hashes_map_backend.init () in - let payload = Bytes.of_string "" in - let result = - Pagination_scheme.serialize_payload - ~for_each_page:(fun (hash, content) -> - Hashes_map_backend.save dac_plugin page_store ~hash ~content) - dac_plugin - payload - in - assert_fails_with - ~loc:__LOC__ - result - Pages_encoding.Payload_cannot_be_empty - end -end - let tests = [ Tztest.tztest @@ -729,23 +623,6 @@ let tests = "Hashes pages are not larger than expected" `Quick Merkle_tree.V0.multiple_pages_roundtrip_do_not_exceed_page_size; - Tztest.tztest - "Constructing hash chain (V0) for single page content is correct" - `Quick - Hash_chain.V0.test_make_chain_hash_one_page; - Tztest.tztest - "Constructing hash chain (V0) for multi page content is correct" - `Quick - Hash_chain.V0.test_make_chain_hash_long; - Tztest.tztest - "Serializing an empty payload returns an error (Hash chain)" - `Quick - Hash_chain.V0.test_serialize_empty_payload_fails; - Tztest.tztest - "Contents fitting in more pages can be retrieved after being saved - \ - repeated pages (Hash chain, V0)" - `Quick - Hash_chain.V0.test_serialize; Tztest.tztest "Deserialization with integrity check fails if page contents are corrupt" `Quick diff --git a/tezt/lib_tezos/dac_helper.ml b/tezt/lib_tezos/dac_helper.ml index 7471da0333b04abd66146e00d7eae81c874e0dde..b957cc2eb747e6fcd6f901b31aed122bd6b95cc8 100644 --- a/tezt/lib_tezos/dac_helper.ml +++ b/tezt/lib_tezos/dac_helper.ml @@ -460,10 +460,8 @@ module Call_endpoint = struct let get_preimage dac_node page_hash = RPC.call dac_node (Dac_rpc.V0.get_preimage page_hash) - let post_store_preimage dac_node ~payload ~pagination_scheme = - RPC.call - dac_node - (Dac_rpc.V0.post_store_preimage ~payload ~pagination_scheme) + let post_store_preimage dac_node ~payload = + RPC.call dac_node (Dac_rpc.V0.post_store_preimage ~payload) let get_verify_signature dac_node external_message = RPC.call dac_node (Dac_rpc.V0.get_verify_signature external_message) diff --git a/tezt/lib_tezos/dac_helper.mli b/tezt/lib_tezos/dac_helper.mli index e87f18edb4856a1db1663a5bfb087fa9a1dbbb25..9a30ac39a4e773c09188f4d2377b3d8a21a6005f 100644 --- a/tezt/lib_tezos/dac_helper.mli +++ b/tezt/lib_tezos/dac_helper.mli @@ -200,12 +200,9 @@ module Call_endpoint : sig (** Call GET v0/preimage/page_hash for the provided [page_hash]. *) val get_preimage : Dac_node.t -> string -> string Lwt.t - (** Call POST v0/store_preimage with provided payload and pagination_scheme. *) + (** Call POST v0/store_preimage with provided payload. *) val post_store_preimage : - Dac_node.t -> - payload:string -> - pagination_scheme:string -> - (string * string) Lwt.t + Dac_node.t -> payload:string -> (string * string) Lwt.t (** Call GET v0/verify_signature for the provided payload. *) val get_verify_signature : Dac_node.t -> string -> bool Lwt.t diff --git a/tezt/lib_tezos/dac_rpc.ml b/tezt/lib_tezos/dac_rpc.ml index 5e203719ebc7e344cbe4b22cea5bc97b83b953be..ca5dccdf668c5da13ceadb3ebd1bd95d11f223ee 100644 --- a/tezt/lib_tezos/dac_rpc.ml +++ b/tezt/lib_tezos/dac_rpc.ml @@ -46,14 +46,11 @@ module V0 = struct let get_preimage page_hash = make GET [api_prefix; "preimage"; page_hash] JSON.as_string - let post_store_preimage ~payload ~pagination_scheme = + let post_store_preimage ~payload = let preimage = JSON.parse ~origin:"dal_node_dac_store_preimage_rpc" - (Format.sprintf - {|{"payload":%s,"pagination_scheme":"%s"}|} - (encode_bytes_to_hex_string payload) - pagination_scheme) + (Format.sprintf {|{"payload":%s}|} (encode_bytes_to_hex_string payload)) in let data : RPC_core.data = Data (JSON.unannotate preimage) in make ~data POST [api_prefix; "store_preimage"] @@ fun json -> diff --git a/tezt/lib_tezos/dac_rpc.mli b/tezt/lib_tezos/dac_rpc.mli index 05fca80686ae854cb1332204e327ee35f9099105..14b6f46daa8c4511e50048e7b237e99214546633 100644 --- a/tezt/lib_tezos/dac_rpc.mli +++ b/tezt/lib_tezos/dac_rpc.mli @@ -33,15 +33,12 @@ module V0 : sig returned as a sequence of bytes. *) val get_preimage : string -> (Dac_node.t, string) RPC_core.t - (** [post_store_preimage cctxt ~payload ~pagination_scheme] posts a - [payload] to "v0/store_preimage" using a given [pagination_scheme]. - It returns the hex encoded root page hash and the raw bytes that can be used - as contents of a rollup message to trigger the request of the payload in a - WASM rollup. *) + (** [post_store_preimage cctxt ~payload] posts a + [payload] to "v0/store_preimage". It returns the hex encoded root page hash + and the raw bytes that can be used as contents of a rollup message + to trigger the request of the payload in a WASM rollup. *) val post_store_preimage : - payload:string -> - pagination_scheme:string -> - (Dac_node.t, string * string) RPC_core.t + payload:string -> (Dac_node.t, string * string) RPC_core.t (** [get_verify_signature cctxt external_message] requests the DAC node to verify the signature of the external message [external_message] via diff --git a/tezt/tests/dac.ml b/tezt/tests/dac.ml index b7d92a15097b8c101fc12c6b0297635622c7ef92..eb576f0265d1831c8f7272574daac22b016df4c5 100644 --- a/tezt/tests/dac.ml +++ b/tezt/tests/dac.ml @@ -47,10 +47,7 @@ let assert_lwt_failure ?__LOC__ msg lwt_under_inspection = let init_hex_root_hash ?payload coordinator_node = let payload = Option.value payload ~default:"hello test message" in let* root_hash, _l1_op = - Dac_helper.Call_endpoint.V0.post_store_preimage - coordinator_node - ~payload - ~pagination_scheme:"Merkle_tree_V0" + Dac_helper.Call_endpoint.V0.post_store_preimage coordinator_node ~payload in let hex_root_hash = `Hex root_hash in return hex_root_hash @@ -176,15 +173,6 @@ let pp fmt = function let status_typ = Check.equalable pp ( = ) -let send_messages ?(src = Constant.bootstrap2.alias) ?(alter_final_msg = Fun.id) - client msgs = - let msg = - alter_final_msg - @@ Ezjsonm.(to_string ~minify:true @@ list Ezjsonm.string msgs) - in - let* () = Client.Sc_rollup.send_message ~hooks ~src ~msg client in - Client.bake_for_and_wait client - let bake_levels n client = repeat n (fun () -> Client.bake_for_and_wait client) let check_valid_root_hash expected_rh actual_rh = @@ -314,6 +302,15 @@ let sample_payload example_filename = let decode_hex_string_to_bytes s = Hex.to_string (`Hex s) +let assert_state_changed ?block sc_rollup_client prev_state_hash = + let*! state_hash = + Sc_rollup_client.state_hash ?block ~hooks sc_rollup_client + in + Check.(state_hash <> prev_state_hash) + Check.string + ~error_msg:"State hash has not changed (%L <> %R)" ; + Lwt.return_unit + (** This modules encapsulate tests for DAC nodes when running in legacy node. It includes tests where we have two dac nodes running in the legacy mode interacting with each other. As such one node normally tries @@ -342,10 +339,7 @@ module Legacy = struct let coordinator_serializes_payload coordinator ~payload ~expected_rh = let* actual_rh, _l1_operation = - Dac_helper.Call_endpoint.V0.post_store_preimage - coordinator - ~payload - ~pagination_scheme:"Merkle_tree_V0" + Dac_helper.Call_endpoint.V0.post_store_preimage coordinator ~payload in return @@ check_valid_root_hash expected_rh actual_rh @@ -1773,15 +1767,6 @@ module Tx_kernel_e2e = struct @@ [multiaccount_tx_of accounts_ops] end - let assert_state_changed ?block sc_rollup_client prev_state_hash = - let*! state_hash = - Sc_rollup_client.state_hash ?block ~hooks sc_rollup_client - in - Check.(state_hash <> prev_state_hash) - Check.string - ~error_msg:"State hash has not changed (%L <> %R)" ; - Lwt.return_unit - let assert_ticks_advanced ?block sc_rollup_client prev_ticks = let*! ticks = Sc_rollup_client.total_ticks ?block ~hooks sc_rollup_client in Check.(ticks > prev_ticks) diff --git a/tezt/tests/sc_rollup.ml b/tezt/tests/sc_rollup.ml index 379da6d2e6bb57d1af026362e791026723a7d8c0..e6ef16693380b013e0352f6eabb3e80dedfda395 100644 --- a/tezt/tests/sc_rollup.ml +++ b/tezt/tests/sc_rollup.ml @@ -2719,6 +2719,48 @@ let test_reveals_fails_on_wrong_hash = in Lwt.choose [error_promise; should_not_sync] +let test_reveals_fails_on_unknown_hash = + let kind = "arith" in + test_full_scenario + ~supports:(Protocol.From_protocol 17) + ~timeout:120 + ~kind + { + tags = ["reveals"; "unknown"]; + variant = None; + description = "reveal data fails with unknown hash"; + } + @@ fun _protocol sc_rollup_node _sc_rollup_client sc_rollup node client -> + let unknown_hash = + "0027782d2a7020be332cc42c4e66592ec50305f559a4011981f1d5af81428ecafe" + in + let* () = Sc_rollup_node.run sc_rollup_node sc_rollup [] in + let error_promise = + Sc_rollup_node.wait_for sc_rollup_node "sc_rollup_daemon_error.v0" (fun e -> + let id = JSON.(e |=> 0 |-> "id" |> as_string) in + if id =~ rex "could_not_open_reveal_preimage_file" then Some () + else None) + in + (* We need to check that the rollup has entered the degraded mode, + so we wait for 60 blocks (commitment period) + 2. *) + let* {commitment_period_in_blocks; _} = get_sc_rollup_constants client in + let* () = + repeat (commitment_period_in_blocks + 2) (fun () -> + Client.bake_for_and_wait client) + in + (* Then, we finally send the message with the unknown hash. *) + let* () = send_text_messages client ["hash:" ^ unknown_hash] in + let should_not_sync = + let* _level = + Sc_rollup_node.wait_for_level + ~timeout:10. + sc_rollup_node + (Node.get_level node) + in + Test.fail "The rollup node processed the unknown reveal without failing" + in + Lwt.choose [error_promise; should_not_sync] + let test_reveals_4k = let kind = "arith" in test_full_scenario @@ -5613,6 +5655,7 @@ let register ~protocols = ~kind:"arith" protocols ; test_reveals_fails_on_wrong_hash protocols ; + test_reveals_fails_on_unknown_hash protocols ; test_reveals_4k protocols ; test_reveals_above_4k protocols ; (* Specific Wasm PVM tezts *)