aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--bin/dune1
-rw-r--r--bin/main.ml3
-rw-r--r--deps/libressl.nix2
-rw-r--r--deps/merklecpp.nix21
-rw-r--r--deps/relational_engine_lib.nix30
-rw-r--r--flake.nix266
-rw-r--r--lib/core_functions.ml6
-rw-r--r--lib/disk.ml73
-rw-r--r--lib/dune7
-rw-r--r--lib/interop.ml3
-rw-r--r--shared/librelational_engine/flake.nix0
-rw-r--r--shared/librelational_engine/library.cpp47
-rw-r--r--shared/librelational_engine/library.h1
-rw-r--r--test/dune8
-rw-r--r--test/test_relational_engine.ml8
15 files changed, 290 insertions, 186 deletions
diff --git a/bin/dune b/bin/dune
index f0cdc01..0888311 100644
--- a/bin/dune
+++ b/bin/dune
@@ -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
'';
}
diff --git a/flake.nix b/flake.nix
index 9f0c182..54740f1 100644
--- a/flake.nix
+++ b/flake.nix
@@ -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
diff --git a/lib/dune b/lib/dune
index a5d0378..0ef1c18 100644
--- a/lib/dune
+++ b/lib/dune
@@ -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
diff --git a/test/dune b/test/dune
index 8f2e6a4..2f3e5eb 100644
--- a/test/dune
+++ b/test/dune
@@ -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