aboutsummaryrefslogtreecommitdiff
path: root/shard/lib/data
diff options
context:
space:
mode:
Diffstat (limited to 'shard/lib/data')
-rw-r--r--shard/lib/data/signrev.ex74
1 files changed, 74 insertions, 0 deletions
diff --git a/shard/lib/data/signrev.ex b/shard/lib/data/signrev.ex
new file mode 100644
index 0000000..6360b53
--- /dev/null
+++ b/shard/lib/data/signrev.ex
@@ -0,0 +1,74 @@
+defmodule SData.SignRev do
+ @moduledoc"""
+ Implement a simple signed object with a revision number.
+ """
+
+
+ defstruct [:term, :rev, :signed]
+
+ @doc"""
+ New SignRev with an unsigned initial state (use this if initial state is deterministic/not signed).
+ """
+ def new(init_term) do
+ %__MODULE__{term: init_term, rev: 0, signed: nil}
+ end
+
+ @doc"""
+ New SignRev with a signed initial state.
+ """
+ def new(init_term, pk) do
+ bin = SData.term_bin {0, init_term}
+ case Shard.Keys.sign(pk, bin) do
+ {:ok, signed} ->
+ {:ok, %__MODULE__{term: init_term, rev: 0, signed: signed}}
+ err -> err
+ end
+ end
+
+ @doc"""
+ Get the current value of the SignRev.
+ """
+ def get(sr) do
+ sr.term
+ end
+
+ @doc"""
+ Update the SignRev with a new value and sign it with this pk
+ """
+ def set(sr, new_term, pk) do
+ rev = sr.rev + 1
+ bin = SData.term_bin {rev, new_term}
+ case Shard.Keys.sign(pk, bin) do
+ {:ok, signed} ->
+ {:ok, %__MODULE__{term: new_term, rev: rev, signed: signed}}
+ err -> err
+ end
+ end
+
+ @doc"""
+ Get the signed binary for the SignRev. Just send the output of this
+ to a peer for him to update.
+ """
+ def signed(sr) do
+ sr.signed
+ end
+
+ @doc"""
+ Check that a signed binary is correct and merge it into the SignRev.
+
+ Returns {true, new_sr} if an update happenned, {false, sr} otherwise.
+ """
+ def merge(sr, signed, pk) do
+ case Shard.Keys.open(pk, signed) do
+ {:ok, bin} ->
+ {rev, new_term} = SData.term_unbin bin
+ if rev > sr.rev do
+ {true, %__MODULE__{term: new_term, rev: rev, signed: signed}}
+ else
+ {false, sr}
+ end
+ _ ->
+ {false, sr}
+ end
+ end
+end