roehst

roehst

Verifying properties of a financial contract in Elixir

Hi, I am interested in verifying properties of Elixir code. In particular, I write code for financial institutions and I am exploring if formal verification can be useful for me.

A loan contract starts in a unsigned state, waiting for some party to propose an amount.

When an amount is proposed, the contract enters a state when it waits for signatures from lender and lendee.

Whenever an amount is proposed, both signatures are reset, so that a lendee never has to pay more than he agreed to, because every time the amount is changed, new signatures are needed.

The contract is done when all debt has been paid (and not more).

Is there an easy-to-use solution for verifying this property in the Elixir/Erlang ecossystem?

The answer might rely on property-based testing, as long as it is exhaustive up to a given measure, as in bounded model checking.

My code is:

defmodule Loan do

  def start() do
    spawn(__MODULE__, :main_loop, [:unsigned])
  end

  def main_loop(:done) do
    receive do
      :show ->
        IO.puts("Contract is finished")
        apply(__MODULE__, :main_loop, [:done])
    end
  end

  def main_loop(:unsigned) do
    receive do
      {:propose, amount} ->
        apply(__MODULE__, :main_loop, [:proposal, amount, [lendee: false, lender: false]])
    end
  end

  @spec main_loop(:proposal, any, [{:lendee, any} | {:lender, any}, ...]) :: any
  def main_loop(:proposal, amount, lendee: true, lender: true) do
    IO.puts("Contract is now signed, contract value is #{amount}")
    apply(__MODULE__, :main_loop, [:signed, amount])
  end

  def main_loop(:proposal, amount, lendee: lendee, lender: lender) do
    receive do
      :sign_lendee ->
        apply(__MODULE__, :main_loop, [:proposal, amount, [lendee: true, lender: lender]])

      :sign_lender ->
        apply(__MODULE__, :main_loop, [:proposal, amount, [lendee: lendee, lender: true]])

      {:propose, amount} ->
        apply(__MODULE__, :main_loop, [:proposal, amount, lendee: false, lender: false])

      :show ->
        case {lendee, lender} do
          {false, false} ->
            IO.puts("No one has signed, contract value is #{amount}")

          {false, true} ->
            IO.puts("Lender has signed, contract value is #{amount}")

          {true, false} ->
            IO.puts("Lendee has signed, contract value is #{amount}")

          {true, true} ->
            IO.puts("Both lender and lendee have signed, contract value is #{amount}")
        end

        apply(__MODULE__, :main_loop, [:proposal, amount, [lendee: lendee, lender: lender]])
    end
  end

  def main_loop(:signed, balance) when balance > 0 do
    receive do
      :show ->
        IO.puts(balance)
        apply(__MODULE__, :main_loop, [:signed, balance])

      {:pay, amount} when amount <= balance ->
        IO.puts("Paying #{amount} to lender")
        apply(__MODULE__, :main_loop, [:signed, balance - amount])
    end
  end

  def main_loop(:signed, 0) do
    IO.puts("Contract is finished")
    main_loop(:done)
  end
end

Most Liked

ausimian

ausimian

Agreed, the most practical way to test your code would be to build a stateful property test via PropEr. I don’t know of any verification tool for Elixir that can statically verify properties of algorithms in the same way that, for example, Frama-C does for C.

On the topic of stateful property tests, I would encourage you to consider using a higher-level tool to help capture exactly what you wish to model. A language like TLA+ can help you model the rules of your state machine and its model checker will help you find errors in your model, or your understanding of the model, or both. This can often lead to insights into the specific invariants you wish to exercise in your property test. Finally, if you really need to (and you probably don’t) you could use its proof-assistant to prove these invariants hold. But for code, stateful property-testing is realistically as good as it gets right now.

Finally, the advice to separate mechanism (e.g. your receive loop) from your state-transition logic is good, and GenServer and GenStateMachine will do that for you.

Where Next?

Popular in Questions Top

sergio
In Ruby, I can go: User.find_by(email: "foobar@email.com").update(email: "hello@email.com") How can I do something similar in Elixir? ...
New
tduccuong
Hi, is there any work on GUI with Elixir, that is similar to Electron/Javascript? My idea is to bundle Phoenix and BEAM into a single se...
New
Werner
Hi, I’m using Ubuntu 18.04 and after updating to OTP-24.0 yesterday i have this warning when I run “mix local.hex”: 14:57:30.512 [warn] ...
New
quazar
How to set Jason to encode all fields in ecto schema, I don’t care about security and implementing only is taking long list of attributes...
New
fireproofsocks
I’m working on defining a simple Ecto schema for a table (in PostGres), but I don’t see where I can define a column as NOT NULL. Conside...
New
script
If I have a string “1000 cfu/ml” . I want to remove the characters and / and space . So the string is like this "1000" What is the ...
New
ashish173
I am using Ecto timestamps with postgres, I can see the timestamps() use the :naive_dateime but for my use case I wanted to store the ti...
New
shahryarjb
Hello, I have map which I want to convert it to string like this: the map: %{last_name: "tavakkoli", name: "shahryar"} the string I ne...
New
Exadra37
Sometimes I want to check if the input into a function is not a blank string. My first approach: defmodule Example do def do_stuff(s...
New
beno
I will often find my self writing things similar to: case some_value do nil -&gt; something() "" -&gt; something() _ -&gt; someth...
New

Other popular topics Top

chrismccord
Phoenix 1.4.0 released Phoenix 1.4 is out! This release ships with exciting new features, most notably with HTTP2 support, improved deve...
688 30048 115
New
peerreynders
Manning 2016 Halloween weekend sale via Deal of the Day Friday, October 28 - Half off all MEAPs - code WM102816LT Saturday, October 29 ...
326 29600 154
New
sergio
In Ruby, I can go: User.find_by(email: "foobar@email.com").update(email: "hello@email.com") How can I do something similar in Elixir? ...
New
Harrisonl
We have an ECS cluster with 4 services, where each task joins a single cluster, via discovery ECS discovery service. Currently when I de...
New
aadeshere1
I have a another noob question about loop. Since elixir is immutable, while loop is not directly possible. total = 10 while total != 0 ...
New
rms.mrcs
Hi, I need to transform a list of numbers into a map where the keys are the indexes and the values are the original values of the list....
New
alice
Hey, Just curious what are the main benefits of Elixir compared to Clojure? When is Elixir more useful than Clojure and vice versa? Th...
New
romenigld
I am trying to run a deploy with docker and I successfully runned with this command: docker build -t romenigld/blog-prod . but when I t...
New
siddhant3030
Hi, I have to write a raw query for one of my project. But till now I have used ecto queries and don’t have much experience writing raw ...
New
lanycrost
Hi everyone! I need implement if…else if…else condition from my elixir code, and anymore of this control flow structures not work proper...
New

We're in Beta

About us Mission Statement