diff --git a/.gitignore b/.gitignore index bedab7b9..ac621e19 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ /proof.json +monitor/priv/native/libverifier.so diff --git a/monitor/.formatter.exs b/monitor/.formatter.exs new file mode 100644 index 00000000..d2cda26e --- /dev/null +++ b/monitor/.formatter.exs @@ -0,0 +1,4 @@ +# Used by "mix format" +[ + inputs: ["{mix,.formatter}.exs", "{config,lib,test}/**/*.{ex,exs}"] +] diff --git a/monitor/.gitignore b/monitor/.gitignore new file mode 100644 index 00000000..b28b72b3 --- /dev/null +++ b/monitor/.gitignore @@ -0,0 +1,26 @@ +# The directory Mix will write compiled artifacts to. +/_build/ + +# If you run "mix test --cover", coverage assets end up here. +/cover/ + +# The directory Mix downloads your dependencies sources to. +/deps/ + +# Where third-party dependencies like ExDoc output generated docs. +/doc/ + +# Ignore .fetch files in case you like to edit your project deps locally. +/.fetch + +# If the VM crashes, it generates a dump, let's ignore it too. +erl_crash.dump + +# Also ignore archive artifacts (built via "mix archive.build"). +*.ez + +# Ignore package tarball (built via "mix hex.build"). +monitor-*.tar + +# Temporary files, for example, from tests. +/tmp/ diff --git a/monitor/README.md b/monitor/README.md new file mode 100644 index 00000000..94a50fc4 --- /dev/null +++ b/monitor/README.md @@ -0,0 +1,13 @@ +# Monitor + +To run the project, you need to have Elixir installed. Then, run the following commands: + +```bash +iex -S mix +``` + +To update the dependencies, run: + +```bash +mix deps.get +``` diff --git a/monitor/lib/monitor.ex b/monitor/lib/monitor.ex new file mode 100644 index 00000000..0ef567c6 --- /dev/null +++ b/monitor/lib/monitor.ex @@ -0,0 +1,18 @@ +defmodule Monitor do + @moduledoc """ + Documentation for `Monitor`. + """ + + @doc """ + Hello world. + + ## Examples + + iex> Monitor.hello() + :world + + """ + def hello do + :world + end +end diff --git a/monitor/lib/monitor/application.ex b/monitor/lib/monitor/application.ex new file mode 100644 index 00000000..df2af7d4 --- /dev/null +++ b/monitor/lib/monitor/application.ex @@ -0,0 +1,21 @@ +defmodule Monitor.Application do + # See https://hexdocs.pm/elixir/Application.html + # for more information on OTP Applications + @moduledoc false + + use Application + + @impl true + def start(_type, _args) do + children = [ + # Starts a worker by calling: Monitor.Worker.start_link(arg) + # {Monitor.Worker, arg} + Monitor.Watcher + ] + + # See https://hexdocs.pm/elixir/Supervisor.html + # for other strategies and supported options + opts = [strategy: :one_for_one, name: Monitor.Supervisor] + Supervisor.start_link(children, opts) + end +end diff --git a/monitor/lib/verifier.ex b/monitor/lib/verifier.ex new file mode 100644 index 00000000..36a71965 --- /dev/null +++ b/monitor/lib/verifier.ex @@ -0,0 +1,5 @@ +defmodule Verifier do + use Rustler, otp_app: :monitor, crate: "verifier" + def add(_a, _b), do: :erlang.nif_error(:nif_not_loaded) + def run_program_and_get_proof(_file_name), do: :erlang.nif_error(:nif_not_loaded) +end diff --git a/monitor/lib/watcher.ex b/monitor/lib/watcher.ex new file mode 100644 index 00000000..d7d7a290 --- /dev/null +++ b/monitor/lib/watcher.ex @@ -0,0 +1,48 @@ +defmodule Monitor.Watcher do + use GenServer + require Logger + + @polling_frequency_ms 5_000 + @number_of_blocks_for_confirmation 0 + + def start_link(args) do + GenServer.start_link(__MODULE__, args, name: __MODULE__) + end + + @impl true + def init(_opts) do + state = %{ + last_confirmed_block_number: 1, + highest_block: 0 + } + + Process.send_after(self(), :poll, @polling_frequency_ms) + {:ok, state} + end + + @doc """ + This handler will first poll the chain for the latest block number, check which blocks are confirmed but have not + been proved yet, then run a proof for them and upload it to S3. + """ + @impl true + def handle_info( + :poll, + state = %{ + last_confirmed_block_number: last_confirmed_block_number + } + ) do + Process.send_after(self(), :poll, @polling_frequency_ms) + current_block_height = 0 + + Logger.info("Current block height: #{current_block_height}") + + result = Verifier.add(1, 5) + Logger.info("Got result from Rust: #{result}") + + {:noreply, + %{ + state + | last_confirmed_block_number: last_confirmed_block_number + }} + end +end diff --git a/monitor/mix.exs b/monitor/mix.exs new file mode 100644 index 00000000..df8faf3e --- /dev/null +++ b/monitor/mix.exs @@ -0,0 +1,31 @@ +defmodule Monitor.MixProject do + use Mix.Project + + def project do + [ + app: :monitor, + version: "0.1.0", + elixir: "~> 1.15", + start_permanent: Mix.env() == :prod, + deps: deps() + ] + end + + # Run "mix help compile.app" to learn about applications. + def application do + [ + extra_applications: [:logger], + mod: {Monitor.Application, []} + ] + end + + # Run "mix help deps" to learn about dependencies. + defp deps do + [ + {:rustler, "~> 0.29.0"}, + {:absinthe, "~> 1.7"} + # {:dep_from_hexpm, "~> 0.3.0"}, + # {:dep_from_git, git: "https://github.com/elixir-lang/my_dep.git", tag: "0.1.0"} + ] + end +end diff --git a/monitor/mix.lock b/monitor/mix.lock new file mode 100644 index 00000000..34de0434 --- /dev/null +++ b/monitor/mix.lock @@ -0,0 +1,8 @@ +%{ + "absinthe": {:hex, :absinthe, "1.7.5", "a15054f05738e766f7cc7fd352887dfd5e61cec371fb4741cca37c3359ff74ac", [:mix], [{:dataloader, "~> 1.0.0 or ~> 2.0", [hex: :dataloader, repo: "hexpm", optional: true]}, {:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}, {:nimble_parsec, "~> 1.2.2 or ~> 1.3.0", [hex: :nimble_parsec, repo: "hexpm", optional: false]}, {:opentelemetry_process_propagator, "~> 0.2.1", [hex: :opentelemetry_process_propagator, repo: "hexpm", optional: true]}, {:telemetry, "~> 1.0 or ~> 0.4", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "22a9a38adca26294ad0ee91226168f5d215b401efd770b8a1b8fd9c9b21ec316"}, + "jason": {:hex, :jason, "1.4.1", "af1504e35f629ddcdd6addb3513c3853991f694921b1b9368b0bd32beb9f1b63", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "fbb01ecdfd565b56261302f7e1fcc27c4fb8f32d56eab74db621fc154604a7a1"}, + "nimble_parsec": {:hex, :nimble_parsec, "1.3.1", "2c54013ecf170e249e9291ed0a62e5832f70a476c61da16f6aac6dca0189f2af", [:mix], [], "hexpm", "2682e3c0b2eb58d90c6375fc0cc30bc7be06f365bf72608804fb9cffa5e1b167"}, + "rustler": {:hex, :rustler, "0.29.1", "880f20ae3027bd7945def6cea767f5257bc926f33ff50c0d5d5a5315883c084d", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:toml, "~> 0.6", [hex: :toml, repo: "hexpm", optional: false]}], "hexpm", "109497d701861bfcd26eb8f5801fe327a8eef304f56a5b63ef61151ff44ac9b6"}, + "telemetry": {:hex, :telemetry, "1.2.1", "68fdfe8d8f05a8428483a97d7aab2f268aaff24b49e0f599faa091f1d4e7f61c", [:rebar3], [], "hexpm", "dad9ce9d8effc621708f99eac538ef1cbe05d6a874dd741de2e689c47feafed5"}, + "toml": {:hex, :toml, "0.7.0", "fbcd773caa937d0c7a02c301a1feea25612720ac3fa1ccb8bfd9d30d822911de", [:mix], [], "hexpm", "0690246a2478c1defd100b0c9b89b4ea280a22be9a7b313a8a058a2408a2fa70"}, +} diff --git a/monitor/native/verifier/.cargo/config.toml b/monitor/native/verifier/.cargo/config.toml new file mode 100644 index 00000000..20f03f3d --- /dev/null +++ b/monitor/native/verifier/.cargo/config.toml @@ -0,0 +1,5 @@ +[target.'cfg(target_os = "macos")'] +rustflags = [ + "-C", "link-arg=-undefined", + "-C", "link-arg=dynamic_lookup", +] diff --git a/monitor/native/verifier/.gitignore b/monitor/native/verifier/.gitignore new file mode 100644 index 00000000..ea8c4bf7 --- /dev/null +++ b/monitor/native/verifier/.gitignore @@ -0,0 +1 @@ +/target diff --git a/monitor/native/verifier/Cargo.lock b/monitor/native/verifier/Cargo.lock new file mode 100644 index 00000000..a01ee294 --- /dev/null +++ b/monitor/native/verifier/Cargo.lock @@ -0,0 +1,149 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "aho-corasick" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0" +dependencies = [ + "memchr", +] + +[[package]] +name = "heck" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "memchr" +version = "2.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167" + +[[package]] +name = "proc-macro2" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "134c189feb4956b20f6f547d2cf727d4c0fe06722b20a0eec87ed445a97f92da" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "regex" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d119d7c7ca818f8a53c300863d4f87566aac09943aef5b355bb83969dae75d87" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "465c6fc0621e4abc4187a2bda0937bfd4f722c2730b29562e19689ea796c9a4b" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56d84fdd47036b038fc80dd333d10b6aab10d5d31f4a366e20014def75328d33" + +[[package]] +name = "rustler" +version = "0.29.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0884cb623b9f43d3e2c51f9071c5e96a5acf3e6e6007866812884ff0cb983f1e" +dependencies = [ + "lazy_static", + "rustler_codegen", + "rustler_sys", +] + +[[package]] +name = "rustler_codegen" +version = "0.29.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50e277af754f2560cf4c4ebedb68c1a735292fb354505c6133e47ec406e699cf" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "rustler_sys" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a7c0740e5322b64e2b952d8f0edce5f90fcf6f6fe74cca3f6e78eb3de5ea858" +dependencies = [ + "regex", + "unreachable", +] + +[[package]] +name = "syn" +version = "2.0.38" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e96b79aaa137db8f61e26363a0c9b47d8b4ec75da28b7d1d614c2303e232408b" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "unicode-ident" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" + +[[package]] +name = "unreachable" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "382810877fe448991dfc7f0dd6e3ae5d58088fd0ea5e35189655f84e6814fa56" +dependencies = [ + "void", +] + +[[package]] +name = "verifier" +version = "0.1.0" +dependencies = [ + "rustler", +] + +[[package]] +name = "void" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" diff --git a/monitor/native/verifier/Cargo.toml b/monitor/native/verifier/Cargo.toml new file mode 100644 index 00000000..a334747e --- /dev/null +++ b/monitor/native/verifier/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "verifier" +version = "0.1.0" +authors = [] +edition = "2021" + +[lib] +name = "verifier" +path = "src/lib.rs" +crate-type = ["cdylib"] + +[dependencies] +rustler = "0.29.1" diff --git a/monitor/native/verifier/README.md b/monitor/native/verifier/README.md new file mode 100644 index 00000000..ec5c1035 --- /dev/null +++ b/monitor/native/verifier/README.md @@ -0,0 +1,20 @@ +# NIF for Elixir.Verifier + +## To build the NIF module: + +- Your NIF will now build along with your project. + +## To load the NIF: + +```elixir +defmodule Verifier do + use Rustler, otp_app: :monitor, crate: "verifier" + + # When your NIF is loaded, it will override this function. + def add(_a, _b), do: :erlang.nif_error(:nif_not_loaded) +end +``` + +## Examples + +[This](https://github.com/rusterlium/NifIo) is a complete example of a NIF written in Rust. diff --git a/monitor/native/verifier/src/lib.rs b/monitor/native/verifier/src/lib.rs new file mode 100644 index 00000000..5146a7ba --- /dev/null +++ b/monitor/native/verifier/src/lib.rs @@ -0,0 +1,6 @@ +#[rustler::nif] +fn add(a: i64, b: i64) -> i64 { + a + b +} + +rustler::init!("Elixir.Verifier", [add]); diff --git a/monitor/test/monitor_test.exs b/monitor/test/monitor_test.exs new file mode 100644 index 00000000..8581d720 --- /dev/null +++ b/monitor/test/monitor_test.exs @@ -0,0 +1,8 @@ +defmodule MonitorTest do + use ExUnit.Case + doctest Monitor + + test "greets the world" do + assert Monitor.hello() == :world + end +end diff --git a/monitor/test/test_helper.exs b/monitor/test/test_helper.exs new file mode 100644 index 00000000..869559e7 --- /dev/null +++ b/monitor/test/test_helper.exs @@ -0,0 +1 @@ +ExUnit.start()