diff options
| -rw-r--r-- | bin/dune | 1 | ||||
| -rw-r--r-- | bin/main.ml | 3 | ||||
| -rw-r--r-- | deps/libressl.nix | 2 | ||||
| -rw-r--r-- | deps/merklecpp.nix | 21 | ||||
| -rw-r--r-- | deps/relational_engine_lib.nix | 30 | ||||
| -rw-r--r-- | flake.nix | 266 | ||||
| -rw-r--r-- | lib/core_functions.ml | 6 | ||||
| -rw-r--r-- | lib/disk.ml | 73 | ||||
| -rw-r--r-- | lib/dune | 7 | ||||
| -rw-r--r-- | lib/interop.ml | 3 | ||||
| -rw-r--r-- | shared/librelational_engine/flake.nix | 0 | ||||
| -rw-r--r-- | shared/librelational_engine/library.cpp | 47 | ||||
| -rw-r--r-- | shared/librelational_engine/library.h | 1 | ||||
| -rw-r--r-- | test/dune | 8 | ||||
| -rw-r--r-- | test/test_relational_engine.ml | 8 |
15 files changed, 290 insertions, 186 deletions
@@ -2,4 +2,3 @@ (public_name relational_engine) (name main) (libraries relational_engine)) - diff --git a/bin/main.ml b/bin/main.ml index 289b4dd..3b718ee 100644 --- a/bin/main.ml +++ b/bin/main.ml @@ -2,5 +2,6 @@ open Relational_engine let () = begin - print_endline @@ Interop.Merkle.merkle_generate_root [Disk.Executor._EMPTY_SHA_HASH_; Disk.Executor._EMPTY_SHA_HASH_] + (* print_endline @@ Interop.Merkle.merkle_generate_root [Disk.Executor._EMPTY_SHA_HASH_] *) + Interop.Merkle.register_to_merkle Disk.Executor._EMPTY_SHA_HASH_; end diff --git a/deps/libressl.nix b/deps/libressl.nix index ad33870..a517dab 100644 --- a/deps/libressl.nix +++ b/deps/libressl.nix @@ -2,7 +2,7 @@ pkgs.stdenv.mkDerivation { name = "libressl-lib"; src = ./.; - buildInputs = with pkgs; [libressl.dev pkg-config]; + buildInputs = with pkgs; [ libressl.dev pkg-config ]; installPhase = '' mkdir -p $out/lib mkdir -p $out/include diff --git a/deps/merklecpp.nix b/deps/merklecpp.nix index 459a957..d130be6 100644 --- a/deps/merklecpp.nix +++ b/deps/merklecpp.nix @@ -2,19 +2,16 @@ pkgs.stdenv.mkDerivation rec { name = "merklecpp"; - src = pkgs.fetchFromGitHub { - owner = "microsoft"; - repo = "merklecpp"; - rev = "master"; - sha256 = "jJJ6FEn+AkMknqun0GkXh5DSXsJnFbdE7U8BQ7Dd/Fw="; - }; + src = pkgs.fetchFromGitHub { + owner = "microsoft"; + repo = "merklecpp"; + rev = "master"; + sha256 = "jJJ6FEn+AkMknqun0GkXh5DSXsJnFbdE7U8BQ7Dd/Fw="; + }; - prePatch = '' - ''; - configurePhase = '' - ''; - buildPhase = '' - ''; + prePatch = ""; + configurePhase = ""; + buildPhase = ""; installPhase = '' mkdir -p $out/include mv merklecpp.h $out/include/merklecpp.h diff --git a/deps/relational_engine_lib.nix b/deps/relational_engine_lib.nix index b1d0488..a3ea22a 100644 --- a/deps/relational_engine_lib.nix +++ b/deps/relational_engine_lib.nix @@ -1,28 +1,24 @@ -{ pkgs, libressl ? pkgs.callPackage ./libressl.nix {}, merklecpp ? pkgs.callPackage ./merklecpp.nix {}, ... }: -let - shared_lib_extension = if pkgs.stdenv.isDarwin then "dylib" else "so"; -in -pkgs.stdenv.mkDerivation { +{ pkgs, libressl ? pkgs.callPackage ./libressl.nix { } +, merklecpp ? pkgs.callPackage ./merklecpp.nix { }, ... }: +let shared_lib_extension = if pkgs.stdenv.isDarwin then "dylib" else "so"; +in pkgs.stdenv.mkDerivation { name = "librelational_engine"; src = ../shared/librelational_engine; - nativeBuildInputs = [ - pkgs.cmake - pkgs.gcc - ]; + nativeBuildInputs = [ pkgs.cmake pkgs.gcc ]; buildInputs = [ libressl merklecpp ]; env = { - MERKLECPP_INCLUDE_PATH="${merklecpp}/include"; - LIBRESSL_INCLUDE_PATH="${libressl}/include"; - LIBRESSL_LIB_PATH="${libressl}/lib"; + MERKLECPP_INCLUDE_PATH = "${merklecpp}/include"; + LIBRESSL_INCLUDE_PATH = "${libressl}/include"; + LIBRESSL_LIB_PATH = "${libressl}/lib"; OS_LIB_EXTENSION = shared_lib_extension; }; buildPhase = '' - mkdir -p $out/lib - mkdir -p $out/include - cmake --build . --target relational_engine + mkdir -p $out/lib + mkdir -p $out/include + cmake --build . --target relational_engine ''; installPhase = '' - mv librelational_engine.${shared_lib_extension} $out/lib/librelational_engine.${shared_lib_extension} - cp $src/library.h $out/include/library.h + mv librelational_engine.${shared_lib_extension} $out/lib/librelational_engine.${shared_lib_extension} + cp $src/library.h $out/include/library.h ''; } @@ -29,9 +29,13 @@ ocamlPackages = legacyPackages.ocamlPackages; # Library functions from nixpkgs lib = legacyPackages.lib; - merklecpp = legacyPackages.callPackage ./deps/merklecpp.nix {}; - libressl = legacyPackages.callPackage ./deps/libressl.nix {}; - librelational_engine = legacyPackages.callPackage ./deps/relational_engine_lib.nix { libressl = libressl; merklecpp = merklecpp; }; + merklecpp = legacyPackages.callPackage ./deps/merklecpp.nix { }; + libressl = legacyPackages.callPackage ./deps/libressl.nix { }; + librelational_engine = + legacyPackages.callPackage ./deps/relational_engine_lib.nix { + libressl = libressl; + merklecpp = merklecpp; + }; # Filtered sources (prevents unecessary rebuilds) sources = { @@ -48,13 +52,10 @@ nix = nix-filter.lib { root = ./.; - include = [ - (nix-filter.lib.matchExt "nix") - ]; + include = [ (nix-filter.lib.matchExt "nix") ]; }; }; - in - { + in { # Exposed packages that can be built or run with `nix build` or # `nix run` respectively: # @@ -67,127 +68,138 @@ # $ nix build # $ nix run -- <args?> # - default = self.packages.${system}.relational_engine; - - relational_engine = ocamlPackages.buildDunePackage { - pname = "relational_engine"; - version = "0.1.0"; - duneVersion = "3"; - src = sources.ocaml; + default = self.packages.${system}.relational_engine; - env = { - MERKLECPP_INCLUDE_PATH="${merklecpp}/include"; - LIBRESSL_INCLUDE_PATH="${libressl}/include"; - LIBRESSL_LIB_PATH="${libressl}/lib"; - OS_LIB_EXTENSION = if legacyPackages.stdenv.isDarwin then "dylib" else "so"; - LIBRELATIONAL_ENGINE_LIB_PATH="${librelational_engine}/lib"; - LIBRELATIONAL_ENGINE_INCLUDE_PATH="${librelational_engine}/include"; - }; + relational_engine = ocamlPackages.buildDunePackage { + pname = "relational_engine"; + version = "0.1.0"; + duneVersion = "3"; + src = sources.ocaml; + + env = { + MERKLECPP_INCLUDE_PATH = "${merklecpp}/include"; + LIBRESSL_INCLUDE_PATH = "${libressl}/include"; + LIBRESSL_LIB_PATH = "${libressl}/lib"; + OS_LIB_EXTENSION = + if legacyPackages.stdenv.isDarwin then "dylib" else "so"; + LIBRELATIONAL_ENGINE_LIB_PATH = "${librelational_engine}/lib"; + LIBRELATIONAL_ENGINE_INCLUDE_PATH = + "${librelational_engine}/include"; + }; - nativeInputs = []; + nativeInputs = [ ]; - buildInputs = with ocamlPackages; [ - ctypes - ctypes-foreign - data-encoding - ]; + buildInputs = with ocamlPackages; [ + ctypes + ctypes-foreign + data-encoding + ppx_inline_test + ]; - strictDeps = true; + strictDeps = true; - preBuild = '' - dune build relational_engine.opam - ''; - }; + preBuild = '' + dune build relational_engine.opam + ''; }; + }; # Flake checks # # $ nix flake check # checks = { # Run tests for the `relational_engine` package - relational_engine = - let - # Patches calls to dune commands to produce log-friendly output - # when using `nix ... --print-build-log`. Ideally there would be - # support for one or more of the following: - # - # In Dune: - # - # - have workspace-specific dune configuration files - # - # In NixPkgs: - # - # - allow dune flags to be set in in `ocamlPackages.buildDunePackage` - # - alter `ocamlPackages.buildDunePackage` to use `--display=short` - # - alter `ocamlPackages.buildDunePackage` to allow `--config-file=FILE` to be set - patchDuneCommand = - let - subcmds = [ "build" "test" "runtest" "install" ]; - in - lib.replaceStrings - (lib.lists.map (subcmd: "dune ${subcmd}") subcmds) - (lib.lists.map (subcmd: "dune ${subcmd} --display=short") subcmds); - in + relational_engine = let + # Patches calls to dune commands to produce log-friendly output + # when using `nix ... --print-build-log`. Ideally there would be + # support for one or more of the following: + # + # In Dune: + # + # - have workspace-specific dune configuration files + # + # In NixPkgs: + # + # - allow dune flags to be set in in `ocamlPackages.buildDunePackage` + # - alter `ocamlPackages.buildDunePackage` to use `--display=short` + # - alter `ocamlPackages.buildDunePackage` to allow `--config-file=FILE` to be set + patchDuneCommand = + let subcmds = [ "build" "test" "runtest" "install" ]; + in lib.replaceStrings + (lib.lists.map (subcmd: "dune ${subcmd}") subcmds) + (lib.lists.map (subcmd: "dune ${subcmd} --display=short") + subcmds); - self.packages.${system}.relational_engine.overrideAttrs - (oldAttrs: { - name = "check-${oldAttrs.name}"; - doCheck = true; - buildPhase = patchDuneCommand oldAttrs.buildPhase; - checkPhase = patchDuneCommand oldAttrs.checkPhase; - # skip installation (this will be tested in the `relational_engine-app` check) - installPhase = "touch $out"; - }); + in self.packages.${system}.relational_engine.overrideAttrs + (oldAttrs: { + name = "check-${oldAttrs.name}"; + doCheck = true; + buildPhase = patchDuneCommand oldAttrs.buildPhase; + checkPhase = patchDuneCommand oldAttrs.checkPhase; + # skip installation (this will be tested in the `relational_engine-app` check) + installPhase = "touch $out"; + }); # Check Dune and OCaml formatting - dune-fmt = legacyPackages.runCommand "check-dune-fmt" - { - nativeBuildInputs = [ - ocamlPackages.dune_3 - ocamlPackages.ocaml - legacyPackages.ocamlformat - ]; - } - '' - echo "checking dune and ocaml formatting" - dune build \ - --display=short \ - --no-print-directory \ - --root="${sources.ocaml}" \ - --build-dir="$(pwd)/_build" \ - @fmt - touch $out - ''; + dune-fmt = legacyPackages.runCommand "check-dune-fmt" { + nativeBuildInputs = [ + ocamlPackages.dune_3 + ocamlPackages.ocaml + legacyPackages.ocamlformat + ]; + } '' + echo "checking dune and ocaml formatting" + dune build \ + --display=short \ + --no-print-directory \ + --root="${sources.ocaml}" \ + --build-dir="$(pwd)/_build" \ + @fmt + touch $out + ''; + + dune-test = legacyPackages.runCommand "check-dune-test" { + nativeBuildInputs = [ + ocamlPackages.dune_3 + ocamlPackages.ocaml + legacyPackages.ocamlformat + ocamlPackages.ppx_inline_test + ]; + } '' + echo "checking dune and ocaml formatting" + dune build \ + --display=short \ + --no-print-directory \ + --root="${sources.ocaml}" \ + --build-dir="$(pwd)/_build" \ + @fmt + touch $out + ''; # Check documentation generation - dune-doc = legacyPackages.runCommand "check-dune-doc" - { - ODOC_WARN_ERROR = "true"; - nativeBuildInputs = [ - ocamlPackages.dune_3 - ocamlPackages.ocaml - ocamlPackages.odoc - ]; - } - '' - echo "checking ocaml documentation" - dune build \ - --display=short \ - --no-print-directory \ - --root="${sources.ocaml}" \ - --build-dir="$(pwd)/_build" \ - @doc - touch $out - ''; + dune-doc = legacyPackages.runCommand "check-dune-doc" { + ODOC_WARN_ERROR = "true"; + nativeBuildInputs = + [ ocamlPackages.dune_3 ocamlPackages.ocaml ocamlPackages.odoc ]; + } '' + echo "checking ocaml documentation" + dune build \ + --display=short \ + --no-print-directory \ + --root="${sources.ocaml}" \ + --build-dir="$(pwd)/_build" \ + @doc + touch $out + ''; # Check Nix formatting - nixpkgs-fmt = legacyPackages.runCommand "check-nixpkgs-fmt" - { nativeBuildInputs = [ legacyPackages.nixpkgs-fmt ]; } - '' - echo "checking nix formatting" - nixpkgs-fmt --check ${sources.nix} - touch $out - ''; + # nixpkgs-fmt = legacyPackages.runCommand "check-nixpkgs-fmt" { + # nativeBuildInputs = [ legacyPackages.nixpkgs-fmt ]; + # } '' + # echo "checking nix formatting" + # nixpkgs-fmt --check ${sources.nix} + # touch $out + # ''; }; # Development shells @@ -205,14 +217,16 @@ default = legacyPackages.mkShell { env = { - MERKLECPP_INCLUDE_PATH="${merklecpp}/include"; - LIBRESSL_INCLUDE_PATH="${libressl}/include"; - LIBRESSL_LIB_PATH="${libressl}/lib"; - OS_LIB_EXTENSION = if legacyPackages.stdenv.isDarwin then "dylib" else "so"; - LIBRELATIONAL_ENGINE_LIB_PATH="${librelational_engine}/lib"; - LIBRELATIONAL_ENGINE_INCLUDE_PATH="${librelational_engine}/include"; + MERKLECPP_INCLUDE_PATH = "${merklecpp}/include"; + LIBRESSL_INCLUDE_PATH = "${libressl}/include"; + LIBRESSL_LIB_PATH = "${libressl}/lib"; + OS_LIB_EXTENSION = + if legacyPackages.stdenv.isDarwin then "dylib" else "so"; + LIBRELATIONAL_ENGINE_LIB_PATH = "${librelational_engine}/lib"; + LIBRELATIONAL_ENGINE_INCLUDE_PATH = + "${librelational_engine}/include"; }; - + # Development tools packages = [ # Source file formatting @@ -233,23 +247,23 @@ ocamlPackages.ctypes ocamlPackages.ctypes-foreign ocamlPackages.data-encoding + ocamlPackages.ppx_inline_test legacyPackages.cmake legacyPackages.gcc + legacyPackages.nixfmt ]; shellHook = '' - echo MERKLECPP_INCLUDE_PATH=$MERKLECPP_INCLUDE_PATH - echo LIBRESSL_INCLUDE_PATH=$LIBRESSL_INCLUDE_PATH - echo LIBRESSL_LIB_PATH=$LIBRESSL_LIB_PATH - echo OS_LIB_EXTENSION=$OS_LIB_EXTENSION - echo LIBRELATIONAL_ENGINE_LIB_PATH=$LIBRELATIONAL_ENGINE_LIB_PATH - echo LIBRELATIONAL_ENGINE_INCLUDE_PATH=$LIBRELATIONAL_ENGINE_INCLUDE_PATH + echo MERKLECPP_INCLUDE_PATH=$MERKLECPP_INCLUDE_PATH + echo LIBRESSL_INCLUDE_PATH=$LIBRESSL_INCLUDE_PATH + echo LIBRESSL_LIB_PATH=$LIBRESSL_LIB_PATH + echo OS_LIB_EXTENSION=$OS_LIB_EXTENSION + echo LIBRELATIONAL_ENGINE_LIB_PATH=$LIBRELATIONAL_ENGINE_LIB_PATH + echo LIBRELATIONAL_ENGINE_INCLUDE_PATH=$LIBRELATIONAL_ENGINE_INCLUDE_PATH ''; # Tools from packages - inputsFrom = [ - self.packages.${system}.relational_engine - ]; + inputsFrom = [ self.packages.${system}.relational_engine ]; }; }; }); diff --git a/lib/core_functions.ml b/lib/core_functions.ml index 1e1af37..3d1cd35 100644 --- a/lib/core_functions.ml +++ b/lib/core_functions.ml @@ -14,8 +14,12 @@ module Functions (F : Ctypes.FOREIGN) = struct "dylib" else "so" else "dll" - let libmerklecpp = Dl.dlopen ~flags:[RTLD_GLOBAL; RTLD_NOW] ~filename:((Sys.getenv "LIBRELATIONAL_ENGINE_LIB_PATH") ^ "/librelational_engine." ^ os_extension) + let libmerklecpp = + Dl.dlopen + ~flags:[RTLD_GLOBAL; RTLD_NOW] + ~filename:((Sys.getenv "LIBRELATIONAL_ENGINE_LIB_PATH") ^ "/librelational_engine." ^ os_extension) let compute_hash = Foreign.foreign ~from:libmerklecpp "compute_hash" (ptr char @-> Ctypes.string @-> returning void) let merkle_generate_root = Foreign.foreign ~from:libmerklecpp "merkle_generate_root" (ptr Ctypes.string @-> int @-> ptr char @-> returning void) + let register_to_merkle = Foreign.foreign ~from:libmerklecpp "register_to_merkle" (Ctypes.string @-> Ctypes.string @-> returning void) end diff --git a/lib/disk.ml b/lib/disk.ml index 3c5157b..aa971dd 100644 --- a/lib/disk.ml +++ b/lib/disk.ml @@ -56,18 +56,33 @@ module Executor = struct hash: string } end module Hashes = struct - type t = string list + type t = { values: string list; + hash: string } + type history = t list end - type files = Hashes.t StringMap.t + type commit = { state: string; files: Hashes.history StringMap.t } + type history = commit list type locations = Location.t StringMap.t let _EMPTY_SHA_HASH_ = "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" (** Initializes the virtual file or opens it. *) - let init_file (files: Hashes.t StringMap.t) filename: Hashes.t StringMap.t = + let init_file (files: Hashes.history StringMap.t) filename: Hashes.history StringMap.t = match StringMap.find_opt filename files with - | None -> StringMap.add filename [_EMPTY_SHA_HASH_] files - | Some _ -> files - let write (files: files) (locations: locations) filename ?hash_to_replace (content: Bytes.t) = + | None -> + let default: Hashes.t = { values = []; hash = _EMPTY_SHA_HASH_} in + let new_files = StringMap.add filename [default] files + in new_files + | Some _ -> + files + + let compose_new_state files = + let history = StringMap.to_list files in + let all_hashes = List.concat + @@ List.map (fun (_, (history:Hashes.history)) -> + List.map (fun ({hash; _}: Hashes.t) -> hash) history) history + in Interop.Merkle.merkle_generate_root all_hashes + + let write ({files;_} as commit: commit) (locations: locations) ~filename ?hash_to_replace (content: Bytes.t) = let files = init_file files filename in let computed_hash: string = Interop.Sha256.compute_hash content in match StringMap.find_opt computed_hash locations with @@ -79,38 +94,58 @@ module Executor = struct let files = StringMap.update filename - (function Some file_hashes -> Some (computed_hash::file_hashes) | None -> Some [computed_hash]) + (function + | Some (file_hashes: Hashes.history) -> + let {values; _}: Hashes.t = List.hd file_hashes in + let new_state = Interop.Merkle.merkle_generate_root (computed_hash::values) in + Some ({values = computed_hash::values; hash = new_state}::file_hashes) + | None -> Some [{values = [computed_hash]; hash = computed_hash}]) files in let open Extensions.Result in let+ (size, offset) = FS.append Storage content in let locations = StringMap.add computed_hash ({size; offset; hash = computed_hash}: Location.t) locations in - Ok (files, locations) + let commit = {state = compose_new_state files; files} + in Ok (commit, locations) end | Some hash_to_replace -> - let files = StringMap.update filename (function Some file_hashes -> Some (List.map (fun hash -> if hash = hash_to_replace then computed_hash else hash) file_hashes) | None -> Some [computed_hash]) files in + let update_fun = function + | Some (file_hashes: Hashes.history) -> + let {values; _}: Hashes.t = List.hd file_hashes in + let updated_entry = List.map (fun hash -> if hash = hash_to_replace then computed_hash else hash) values in + let new_entry: Hashes.t = {values = updated_entry; hash = Interop.Merkle.merkle_generate_root updated_entry} in + Some (new_entry::file_hashes) + | None -> Some [{values = [computed_hash]; hash = computed_hash}] + in + let files = StringMap.update filename update_fun files in let open Extensions.Result in let+ (size, offset) = FS.append Storage content in let locations = StringMap.add computed_hash ({size; offset; hash = computed_hash}: Location.t) locations in - Ok (files, locations) + let commit = {state = compose_new_state files; files} + in Ok (commit, locations) end | Some _ -> begin match hash_to_replace with | Some hash_to_replace -> - let files = - StringMap.update filename - (function - | Some file_hashes -> Some (List.map (fun hash -> if hash = hash_to_replace then computed_hash else hash) file_hashes) - | None -> Some [computed_hash]) - files in - Ok (files, locations) + let update_fun = function + | Some (file_hashes: Hashes.history) -> + let {values; _}: Hashes.t = List.hd file_hashes in + let updated_entry = List.map (fun hash -> if hash = hash_to_replace then computed_hash else hash) values in + let new_entry: Hashes.t = {values = updated_entry; hash = Interop.Merkle.merkle_generate_root updated_entry} in + Some (new_entry::file_hashes) + | None -> Some [{values = [computed_hash]; hash = computed_hash}] + in + let files = StringMap.update filename update_fun files in + let commit = {state = compose_new_state files; files} + in Ok (commit, locations) | None -> - Ok (files, locations) + Ok (commit, locations) end end module Startup = struct - let () = DevelopmentConfiguration.assure() + (* TODO: Weird behavior with a system error on the dir /tmp/relational-engine opening. Disabling for now *) + (* let () = DevelopmentConfiguration.assure() *) end module Command = struct @@ -10,14 +10,13 @@ ;; (-L %{env:LIBRESSL_LIB_PATH=}) ;; (-I %{env:LIBRESSL_INCLUDE_PATH=}) ;; (-I %{env:MERKLECPP_INCLUDE_PATH=}))) - (ctypes (external_library_name relational_engine) - (headers (include %{env:LIBRELATIONAL_ENGINE_INCLUDE_PATH=}/library.h)) + (headers + (include %{env:LIBRELATIONAL_ENGINE_INCLUDE_PATH=}/library.h)) (build_flags_resolver (vendored - (c_flags - -L %{env:LIBRELATIONAL_ENGINE_LIB_PATH=}))) + (c_flags -L %{env:LIBRELATIONAL_ENGINE_LIB_PATH=}))) (type_description (instance Types) (functor core_types)) diff --git a/lib/interop.ml b/lib/interop.ml index fdfde5f..28b4fb9 100644 --- a/lib/interop.ml +++ b/lib/interop.ml @@ -16,4 +16,7 @@ module Merkle = struct let hashes = CArray.of_list string hashes in C.Functions.merkle_generate_root (CArray.start hashes) len buf; Ctypes.coerce (ptr char) Ctypes.string buf + + let register_to_merkle content = + C.Functions.register_to_merkle "/tmp/relational-engine/tree" content end diff --git a/shared/librelational_engine/flake.nix b/shared/librelational_engine/flake.nix deleted file mode 100644 index e69de29..0000000 --- a/shared/librelational_engine/flake.nix +++ /dev/null diff --git a/shared/librelational_engine/library.cpp b/shared/librelational_engine/library.cpp index 8048486..cab8f93 100644 --- a/shared/librelational_engine/library.cpp +++ b/shared/librelational_engine/library.cpp @@ -2,8 +2,51 @@ #include <merklecpp.h> #include <openssl/sha.h> #include <iomanip> +#include <fstream> +#include <iterator> + +#include <sys/stat.h> + +std::vector<uint8_t> read_tree(const char* tree_path) { + std::ifstream file(tree_path, std::ios::binary); + file.unsetf(std::ios::skipws); + file.seekg(0, std::ios::end); + const std::streampos file_size = file.tellg(); + file.seekg(0, std::ios::beg); + std::vector<uint8_t> v; + v.reserve(file_size); + v.insert(v.begin(), std::istream_iterator<uint8_t>(file), std::istream_iterator<uint8_t>()); + return v; +} + +void write_tree(const char* tree_path, const std::vector<uint8_t>& serialized_tree) { + std::ofstream out(tree_path, std::ios::out | std::ios::binary); + out.write(reinterpret_cast<const char*>(serialized_tree.data()), serialized_tree.size()); + out.close(); +} + extern "C" { #include "library.h" + extern void register_to_merkle(const char* tree_path, const char* computed_hash) { + struct stat st; + if (stat(tree_path, &st) == 0) { + const std::vector<uint8_t> tree_bytes = read_tree(tree_path); + merkle::Tree tree; + tree.deserialise(tree_bytes); + const merkle::Tree::Hash hash(computed_hash); + tree.insert(hash); + std::vector<uint8_t> target; + tree.serialise(target); + write_tree(tree_path, target); + } else { + merkle::Tree::Hash hash(computed_hash); + merkle::Tree tree; + tree.insert(hash); + std::vector<uint8_t> target; + tree.serialise(target); + write_tree(tree_path, target); + } + } extern void merkle_generate_root(char** hashes, const int n, char* root) { merkle::Tree tree; for (int i = 0; i < n; i++){ @@ -23,8 +66,8 @@ extern "C" { ss << std::hex << std::setw(2) << std::setfill('0') << static_cast<int>(hash[i]); std::memcpy(computed_hash, ss.str().c_str(), HASH_SIZE); - std::cout << "⚙️ COMPUTED HASH: " << computed_hash << std::endl; + // std::cout << "⚙️ COMPUTED HASH: " << computed_hash << std::endl; } extern int trash() { return 100; } -}
\ No newline at end of file +} diff --git a/shared/librelational_engine/library.h b/shared/librelational_engine/library.h index ebf8497..16734be 100644 --- a/shared/librelational_engine/library.h +++ b/shared/librelational_engine/library.h @@ -5,5 +5,6 @@ extern void merkle_generate_root(char**, const int, char*); extern void compute_hash(char*, const char*); +extern void register_to_merkle(const char*, const char*); #endif //MERKLECPP_STUB_LIBRARY_H @@ -1,2 +1,6 @@ -(test - (name test_relational_engine)) +(library + (name test_relational_engine) + (libraries relational_engine) + (inline_tests) + (preprocess + (pps ppx_inline_test))) diff --git a/test/test_relational_engine.ml b/test/test_relational_engine.ml index e69de29..69a7df2 100644 --- a/test/test_relational_engine.ml +++ b/test/test_relational_engine.ml @@ -0,0 +1,8 @@ + +let%test _ = + let open Relational_engine.Disk.Executor in + let stream: history = [{state = _EMPTY_SHA_HASH_; files = StringMap.empty}] in + let locations: locations = StringMap.empty in + let (new_commit, _) = Result.get_ok @@ write (List.hd stream) locations ~filename:"trash" @@ Bytes.of_string "abc" in + let expected_state_hash = "bca39cc55b19274133ce57d0bea1ff794589f025d4bcf670c44d5d2811837830" in + new_commit.state = expected_state_hash |
