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

New
WestKeys
Currently suffering from paralysis by [HTTP client] analysis. This is rather unusual in Elixirland as there tends to be consensus on the ...
New
Patoshizzle
After calling mix ecto.create I get this error: 17:00:32.162 [error] GenServer #PID&lt;0.412.0&gt; terminating ** (Postgrex.Error) FATAL...
New
jay1
Why is it that the mnesia database isn’t the most preferred database for use in Elixir/Phoenix?
New
freewebwithme
Using vs code and installed ElixirLS: support and debugger. And I got an error popped up on start up says Failed to run ‘elixir’ comma...
New
vrod
I am using the Starship cross-shell prompt – it seems pretty nice, but I get some errors: [WARN] - (starship::utils): Executing command ...
New
RisingFromAshes
I’ve read in another post that it may be possible with a router helper - but I couldn’t find an appropriate one, and tbh, I’m still just ...
New
komlanvi
Hi everyone, I was playing with phoenix liveView but I run into an issue. I have a form and want to validate each input text when the te...
New
Brian
What is the proper way to load a module from a file in to IEX? In the python world, doing something like this pretty standard: from ....
New
dotdotdotPaul
Okay, I’m having a heck of a time trying to figure out how to best handle the validation of belongs_to associations in Ecto. I’m sure I’...
New

Other popular topics Top

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
sorentwo
Hello! tl;dr Announcing Oban, an Ecto based job processing library with a focus on reliability and historical observability. After spen...
985 43657 311
New
chrismccord
As promised, the first release candidate of Phoenix 1.3.0 is out! This release focuses on code generators with improved project structure...
New
johnnyicon
Hi all, I’ve just started learning Elixir and Phoenix Framework, so please pardon my n00bness at this stage. I’m trying to use Postgres...
New
Lily
In templates/appointment/index.html.eex: &lt;%= for appointment &lt;- @appointments do %&gt; &lt;tr&gt; &lt;td&gt;&lt;%= appoi...
New
dblack
I’ve got an issue with an app and I’ve no idea of how to troubleshoot it. I’m hoping someone here might have seen something similar. I p...
New
nsuchy
Hi. I’ve noticed that Windows Powershell has it’s own IEX command and you cannot access Elixir’s IEX due to the conflict. This isn’t a cr...
New
AstonJ
We’ve put together this wiki for Phoenix LiveView - please feel free to add any info you feel is worth including. What is Phoenix LiveV...
New
hariharasudhan94
Lets say I have map like this fetching from my database %{"_id" =&gt; #BSON.ObjectId&lt;58eb1a7a9ad169198c3dXXXX&gt;, "email" =&gt; ...
New
dogweather
I wrote this comment on r/haskell, and it’s not popular there. :wink: But I think I’m on to something… Haskell reminds me of Java, and e...
New

We're in Beta

About us Mission Statement