From e3611a69f34eb9db78ec263cc900809d112d96a0 Mon Sep 17 00:00:00 2001 From: Victor Allombert Date: Mon, 18 Mar 2024 15:13:27 +0100 Subject: [PATCH 1/3] Store: improve liveblocks computation --- src/lib_store/unix/store.ml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib_store/unix/store.ml b/src/lib_store/unix/store.ml index 928bf5a42430..c7c75e47481b 100644 --- a/src/lib_store/unix/store.ml +++ b/src/lib_store/unix/store.ml @@ -933,9 +933,9 @@ module Chain_traversal = struct let open Lwt_syntax in let rec loop acc block_head n = let hashes = Block.all_operation_hashes block_head in - let acc = f acc (Block.hash block_head, hashes) in if n = 0 then Lwt.return acc else + let acc = f acc (Block.hash block_head, hashes) in let* o = Block.read_predecessor_opt chain_store block_head in match o with | None -> Lwt.return acc -- GitLab From 37310868566bf59c816f246d5740b97954999c21 Mon Sep 17 00:00:00 2001 From: Vincent Botbol Date: Mon, 25 Mar 2024 11:23:59 +0100 Subject: [PATCH 2/3] Store/test: introduce operation validation Co-authored-by: Victor Allombert --- src/lib_store/unix/test/alpha_utils.ml | 47 ++++++++++++++++++-------- src/lib_store/unix/test/test_utils.ml | 33 ++++++++++++++++++ 2 files changed, 66 insertions(+), 14 deletions(-) diff --git a/src/lib_store/unix/test/alpha_utils.ml b/src/lib_store/unix/test/alpha_utils.ml index fc52ebe68e55..09abf47dd71f 100644 --- a/src/lib_store/unix/test/alpha_utils.ml +++ b/src/lib_store/unix/test/alpha_utils.ml @@ -553,7 +553,7 @@ let apply pred_resulting_ctxt chain_id ~policy ?(operations = empty_operations) `Lazy element_of_key in - let* validation, block_header_metadata = + let* (validation, block_header_metadata), operations_results = let*! r = let* vstate = begin_validation_and_application @@ -567,15 +567,23 @@ let apply pred_resulting_ctxt chain_id ~policy ?(operations = empty_operations) }) ~predecessor:(Store.Block.shell_header pred) in - let* vstate = + let* vstate, resultll = List.fold_left_es - (List.fold_left_es (fun vstate op -> - let* state, _result = validate_and_apply_operation vstate op in - return state)) - vstate + (fun (vstate, resultll) l -> + let* vstate, resultl = + List.fold_left_es + (fun (vstate, resultl) op -> + let* state, result = validate_and_apply_operation vstate op in + return (state, result :: resultl)) + (vstate, []) + l + in + return (vstate, List.rev resultl :: resultll)) + (vstate, []) operations in - finalize_validation_and_application vstate (Some shell) + let* x = finalize_validation_and_application vstate (Some shell) in + return (x, List.rev resultll) in let*? r = Environment.wrap_tzresult r in return r @@ -618,16 +626,24 @@ let apply pred_resulting_ctxt chain_id ~policy ?(operations = empty_operations) let block_header = {Tezos_base.Block_header.shell = header.shell; protocol_data} in + let operations_results = + List.map + (List.map + (Data_encoding.Binary.to_bytes_exn + Protocol.Main.operation_receipt_encoding)) + operations_results + in let operations_metadata_hashes = Some (List.map (List.map (fun r -> Operation_metadata_hash.hash_bytes [r])) - (WithExceptions.List.init ~loc:__LOC__ 4 (fun _ -> []))) + operations_results) in return ( block_header, block_header_metadata, block_hash_metadata, + operations_results, operations_metadata_hashes, resulting_context_hash, validation ) @@ -643,6 +659,7 @@ let apply_and_store chain_store ?(synchronous_merge = true) ?policy let* ( block_header, block_header_metadata, block_metadata_hash, + ops_metadata, ops_metadata_hashes, resulting_context_hash, validation ) = @@ -655,20 +672,22 @@ let apply_and_store chain_store ?(synchronous_merge = true) ?policy pred_resulting_context_hash in let ops_metadata = - let operations_metadata = - WithExceptions.List.init ~loc:__LOC__ 4 (fun _ -> []) - in match ops_metadata_hashes with | Some metadata_hashes -> let res = WithExceptions.List.map2 ~loc:__LOC__ - (WithExceptions.List.map2 ~loc:__LOC__ (fun x y -> (x, y))) - operations_metadata + (WithExceptions.List.map2 ~loc:__LOC__ (fun x y -> + (Block_validation.Metadata x, y))) + ops_metadata metadata_hashes in Block_validation.Metadata_hash res - | None -> Block_validation.(No_metadata_hash operations_metadata) + | None -> + let operations_metadata = + WithExceptions.List.init ~loc:__LOC__ 4 (fun _ -> []) + in + Block_validation.(No_metadata_hash operations_metadata) in let validation_result = { diff --git a/src/lib_store/unix/test/test_utils.ml b/src/lib_store/unix/test/test_utils.ml index ec4a8c2ae0fe..103027f46adb 100644 --- a/src/lib_store/unix/test/test_utils.ml +++ b/src/lib_store/unix/test/test_utils.ml @@ -559,6 +559,39 @@ let make_raw_block_list ?min_lpbl ?constants ?max_operations_ttl ?(kind = `Full) let blk = List.hd l |> WithExceptions.Option.get ~loc:__LOC__ in Lwt.return (List.rev l, blk) +let make_operation ?(fee = Tezos_protocol_alpha.Protocol.Alpha_context.Tez.zero) + ?(gas_limit = + Tezos_protocol_alpha.Protocol.Alpha_context.Gas.Arith.integral_of_int_exn + 100_000) ?(storage_limit = Z.zero) ~source_pkh ~source_sk ~counter + ~branch operation = + let open Tezos_protocol_alpha.Protocol.Alpha_context in + let branch = Store.Block.hash branch in + let shell, contents = + let contents = + Single + (Manager_operation + { + source = source_pkh; + fee; + counter; + operation; + gas_limit; + storage_limit; + }) + in + ({Tezos_base.Operation.branch}, contents) + in + let b = + Data_encoding.Binary.to_bytes_exn + Operation.unsigned_encoding + (shell, Contents_list contents) + in + let signature = + Signature.sign ~watermark:Signature.Generic_operation source_sk b + in + Operation.pack + {Operation.shell; protocol_data = {contents; signature = Some signature}} + let incr_fitness b = match b with | [] -> -- GitLab From 89c928f57f3ae13582a82182e7d68f38de101d03 Mon Sep 17 00:00:00 2001 From: Vincent Botbol Date: Mon, 25 Mar 2024 13:57:57 +0100 Subject: [PATCH 3/3] Store/test: add a dedicated live_blocks test Co-authored-by: Victor Allombert --- src/lib_store/unix/test/test_store.ml | 179 +++++++++++++++++++++++++- 1 file changed, 178 insertions(+), 1 deletion(-) diff --git a/src/lib_store/unix/test/test_store.ml b/src/lib_store/unix/test/test_store.ml index 729da6efbbb6..6850301d2388 100644 --- a/src/lib_store/unix/test/test_store.ml +++ b/src/lib_store/unix/test/test_store.ml @@ -711,6 +711,180 @@ let test_block_of_identifier_success_savepoint chain_store table = chain_store table +(* Tests the live blocks computation behaviour thanks to a dedicated + block history. + + X - Y - Z ..... ------ -- A --- B + \ + \- A' -- B' + | \- B'' + |- A'' + + level(X) = level(A) - max_op_ttl - 1 = level(B) - max_op_ttl - 2 + level(Y) = level(A) - max_op_ttl = level(B) - max_op_ttl - 1 + level(Z) = level(A) - max_op_ttl + 1 = level(B) - max_op_ttl + + Baking: A, A', B, B', B'' and A''. + + A contains an operation targeting Y (valid) + A contains an operation targeting Z (valid) + + B contains an operation targeting A (valid) + B contains an operation targeting Z (valid) + + A' contains an operation targeting Y (valid) + A' contains an operation targeting Z (valid) + + B' contains an operation targeting A (invalid) + + B'' contains an operation targeting A' (valid) + + A'' contains an operation targeting X (invalid) + A'' contains an operation targeting Y (valid) +*) +let test_live_blocks store_dir = + let open Tezos_protocol_alpha in + let open Lwt_result_syntax in + let accounts = + Stdlib.List.init 50 (fun _ -> Alpha_utils.Account.new_account ()) + in + let max_operations_time_to_live = 4 in + let patch_context ctxt = + let constants : Protocol.Alpha_context.Constants.Parametric.t = + Default_parameters. + { + constants_test with + consensus_threshold = 0; + max_operations_time_to_live; + } + in + let test_parameters = + let open Tezos_protocol_alpha_parameters in + { + Default_parameters.(parameters_of_constants constants) with + bootstrap_accounts = + List.map + (fun acc -> + Alpha_utils.Account.account_to_bootstrap + ( acc, + Protocol.Alpha_context.Tez.of_mutez_exn 100_000_000_000L, + None )) + accounts; + } + in + Alpha_utils.patch_context + ctxt + ~json:(Default_parameters.json_of_parameters test_parameters) + in + let dst_store_dir = store_dir // "store" in + let dst_context_dir = store_dir // "context" in + let* store = + Store.init + ~patch_context + ~readonly:false + ~store_dir:dst_store_dir + ~context_dir:dst_context_dir + ~allow_testchains:false + genesis + in + let infinite_accounts = ref (Stdlib.Seq.cycle (List.to_seq accounts)) in + let mk_op branch = + let open Protocol.Alpha_context in + let c = + match !infinite_accounts () with + | Nil -> assert false + | Cons (c, r) -> + infinite_accounts := r ; + c + in + let counter = Manager_counter.Internal_for_tests.of_int 1 in + let operation = Delegation (Some c.pkh) in + make_operation ~source_pkh:c.pkh ~source_sk:c.sk ~counter ~branch operation + in + let chain_store = Store.main_chain_store store in + let*! genesis = Store.Chain.genesis_block chain_store in + let* block_x = Alpha_utils.bake chain_store genesis in + let* block_y = Alpha_utils.bake chain_store block_x in + let* block_z = Alpha_utils.bake chain_store block_y in + let* _, before_b = + Alpha_utils.bake_n chain_store (max_operations_time_to_live - 1) block_z + in + let mk_operations bl = [[]; []; []; List.map mk_op bl] in + let check ?(should_fail = false) block = + let bh = Store.Block.hash block in + let ops = + Store.Block.operations block + |> List.map (List.map (fun op -> Block_validation.mk_operation op)) + in + let* pred = Store.Block.read_predecessor chain_store block in + let* live_blocks, live_operations = + Store.Chain.compute_live_blocks chain_store ~block:pred + in + let r = + Block_validation.check_liveness ~live_blocks ~live_operations bh ops + in + match r with + | Ok () -> + if should_fail then Assert.fail_msg "Error: unexpected success" + else return_unit + | Error _ -> + if should_fail then return_unit + else Assert.fail_msg "Error: unexpected failure" + in + let* block_a = + Alpha_utils.bake + ~operations:(mk_operations [block_y; block_z]) + chain_store + before_b + in + let* () = check block_a in + let* block_a' = + Alpha_utils.bake + ~operations:(mk_operations [block_y; block_z]) + chain_store + before_b + in + let* () = check block_a' in + let* block_b = + Alpha_utils.bake + ~operations:(mk_operations [block_a; block_z]) + chain_store + block_a + in + let* () = check block_b in + let* block_b' = + Alpha_utils.bake ~operations:(mk_operations [block_a]) chain_store block_a' + in + let* () = check ~should_fail:true block_b' in + let* block_b'' = + Alpha_utils.bake ~operations:(mk_operations [block_a']) chain_store block_a' + in + let* () = check block_b'' in + let* block_a'' = + Alpha_utils.bake + ~operations:(mk_operations [block_x; block_y]) + chain_store + before_b + in + let* () = check ~should_fail:true block_a'' in + return_unit + +let wrap_test_no_store (name, f) = + let open Lwt_syntax in + let prefix_dir = "tezos_indexed_store_test_" in + let run f = + let base_dir = Filename.temp_file prefix_dir "" in + let* () = Lwt_unix.unlink base_dir in + let* () = Lwt_unix.mkdir base_dir 0o700 in + f base_dir + in + Alcotest_lwt.test_case name `Quick (fun _ () -> + let* r = run f in + match r with + | Ok () -> return_unit + | Error err -> + Format.kasprintf Alcotest.fail "error: %a" pp_print_trace err) + let tests = let test_tree_cases = List.map @@ -758,6 +932,9 @@ let tests = test_block_of_identifier_success_savepoint ); ] in - ("store", test_cases @ test_tree_cases) + let test_live_blocks = + List.map wrap_test_no_store [("live_blocks", test_live_blocks)] + in + ("store", test_cases @ test_tree_cases @ test_live_blocks) let () = Lwt_main.run (Alcotest_lwt.run ~__FILE__ "tezos-store" [tests]) -- GitLab