Cleaned up git
authorAli Younis <ayounis@uci.edu>
Wed, 21 Dec 2016 23:48:41 +0000 (15:48 -0800)
committerAli Younis <ayounis@uci.edu>
Wed, 21 Dec 2016 23:48:41 +0000 (15:48 -0800)
99 files changed:
non_block_chain/doc/iotcloud.tex [new file with mode: 0644]
non_block_chain/doc/iotcloud_formal/iotcloud.tex [new file with mode: 0644]
non_block_chain/doc/iotcloud_formal/makefile [new file with mode: 0644]
non_block_chain/doc/iotcloud_informal/iotcloud.tex [new file with mode: 0644]
non_block_chain/doc/iotcloud_informal/makefile [new file with mode: 0644]
non_block_chain/doc/makefile [new file with mode: 0644]
version1/doc/iotcloud.tex [new file with mode: 0644]
version1/doc/makefile [new file with mode: 0644]
version1/src/java/.dir-locals.el [new file with mode: 0644]
version1/src/java/iotcloud/CloudComm.java [new file with mode: 0644]
version1/src/java/iotcloud/Entry.java [new file with mode: 0644]
version1/src/java/iotcloud/IoTString.java [new file with mode: 0644]
version1/src/java/iotcloud/KeyValue.java [new file with mode: 0644]
version1/src/java/iotcloud/LastMessage.java [new file with mode: 0644]
version1/src/java/iotcloud/Liveness.java [new file with mode: 0644]
version1/src/java/iotcloud/Makefile [new file with mode: 0644]
version1/src/java/iotcloud/Pair.java [new file with mode: 0644]
version1/src/java/iotcloud/RejectedMessage.java [new file with mode: 0644]
version1/src/java/iotcloud/Slot.java [new file with mode: 0644]
version1/src/java/iotcloud/SlotBuffer.java [new file with mode: 0644]
version1/src/java/iotcloud/SlotIndexer.java [new file with mode: 0644]
version1/src/java/iotcloud/Table.java [new file with mode: 0644]
version1/src/java/iotcloud/TableStatus.java [new file with mode: 0644]
version1/src/java/iotcloud/Test.java [new file with mode: 0644]
version1/src/java/iotcloud/issues.txt [new file with mode: 0644]
version1/src/js/iotjs/.babelrc [new file with mode: 0644]
version1/src/js/iotjs/.bowerrc [new file with mode: 0644]
version1/src/js/iotjs/.editorconfig [new file with mode: 0644]
version1/src/js/iotjs/.jshintrc [new file with mode: 0644]
version1/src/js/iotjs/README.md [new file with mode: 0644]
version1/src/js/iotjs/bower.json [new file with mode: 0644]
version1/src/js/iotjs/examples/index.html [new file with mode: 0644]
version1/src/js/iotjs/gulpfile.js [new file with mode: 0644]
version1/src/js/iotjs/orig/compat.txt [new file with mode: 0644]
version1/src/js/iotjs/orig/entry.js [new file with mode: 0644]
version1/src/js/iotjs/orig/keyvalue.js [new file with mode: 0644]
version1/src/js/iotjs/orig/lastmessage.js [new file with mode: 0644]
version1/src/js/iotjs/orig/rejectedmessage.js [new file with mode: 0644]
version1/src/js/iotjs/orig/slot.js [new file with mode: 0644]
version1/src/js/iotjs/orig/slotbuffer.js [new file with mode: 0644]
version1/src/js/iotjs/orig/slotindexer.js [new file with mode: 0644]
version1/src/js/iotjs/orig/tablestatus.js [new file with mode: 0644]
version1/src/js/iotjs/package.json [new file with mode: 0644]
version1/src/js/iotjs/src/entry.js [new file with mode: 0644]
version1/src/js/iotjs/src/iotstring.js [new file with mode: 0644]
version1/src/js/iotjs/src/keyvalue.js [new file with mode: 0644]
version1/src/js/iotjs/src/lastmessage.js [new file with mode: 0644]
version1/src/js/iotjs/src/liveness.js [new file with mode: 0644]
version1/src/js/iotjs/src/main.js [new file with mode: 0644]
version1/src/js/iotjs/src/pair.js [new file with mode: 0644]
version1/src/js/iotjs/src/rejectedmessage.js [new file with mode: 0644]
version1/src/js/iotjs/src/slot.js [new file with mode: 0644]
version1/src/js/iotjs/src/slotbuffer.js [new file with mode: 0644]
version1/src/js/iotjs/src/slotindexer.js [new file with mode: 0644]
version1/src/js/iotjs/src/tablestatus.js [new file with mode: 0644]
version1/src/js/iotjs/test/test.js [new file with mode: 0644]
version1/src/script/C.cfg [new file with mode: 0644]
version1/src/script/java.cfg [new file with mode: 0644]
version1/src/script/makefile [new file with mode: 0644]
version1/src/server/.dir-locals.el [new file with mode: 0644]
version1/src/server/Makefile [new file with mode: 0644]
version1/src/server/README.txt [new file with mode: 0644]
version1/src/server/iotcloud.cpp [new file with mode: 0644]
version1/src/server/iotquery.cpp [new file with mode: 0644]
version1/src/server/iotquery.h [new file with mode: 0644]
version2/doc/iotcloud.tex [new file with mode: 0644]
version2/doc/makefile [new file with mode: 0644]
version2/src/java/.dir-locals.el [new file with mode: 0644]
version2/src/java/iotcloud/Abort.java [new file with mode: 0644]
version2/src/java/iotcloud/CloudComm.java [new file with mode: 0644]
version2/src/java/iotcloud/Commit.java [new file with mode: 0644]
version2/src/java/iotcloud/Entry.java [new file with mode: 0644]
version2/src/java/iotcloud/Guard.java [new file with mode: 0644]
version2/src/java/iotcloud/IoTString.java [new file with mode: 0644]
version2/src/java/iotcloud/KeyValue.java [new file with mode: 0644]
version2/src/java/iotcloud/LastMessage.java [new file with mode: 0644]
version2/src/java/iotcloud/Liveness.java [new file with mode: 0644]
version2/src/java/iotcloud/Makefile [new file with mode: 0644]
version2/src/java/iotcloud/NewKey.java [new file with mode: 0644]
version2/src/java/iotcloud/Pair.java [new file with mode: 0644]
version2/src/java/iotcloud/PendingTransaction.java [new file with mode: 0644]
version2/src/java/iotcloud/RejectedMessage.java [new file with mode: 0644]
version2/src/java/iotcloud/Slot.java [new file with mode: 0644]
version2/src/java/iotcloud/SlotBuffer.java [new file with mode: 0644]
version2/src/java/iotcloud/SlotIndexer.java [new file with mode: 0644]
version2/src/java/iotcloud/Table.java [new file with mode: 0644]
version2/src/java/iotcloud/TableStatus.java [new file with mode: 0644]
version2/src/java/iotcloud/Test.java [new file with mode: 0644]
version2/src/java/iotcloud/Transaction.java [new file with mode: 0644]
version2/src/java/iotcloud/issues.txt [new file with mode: 0644]
version2/src/script/C.cfg [new file with mode: 0644]
version2/src/script/java.cfg [new file with mode: 0644]
version2/src/script/makefile [new file with mode: 0644]
version2/src/server/.dir-locals.el [new file with mode: 0644]
version2/src/server/Makefile [new file with mode: 0644]
version2/src/server/README.txt [new file with mode: 0644]
version2/src/server/iotcloud.cpp [new file with mode: 0644]
version2/src/server/iotquery.cpp [new file with mode: 0644]
version2/src/server/iotquery.h [new file with mode: 0644]

diff --git a/non_block_chain/doc/iotcloud.tex b/non_block_chain/doc/iotcloud.tex
new file mode 100644 (file)
index 0000000..9d10557
--- /dev/null
@@ -0,0 +1,1239 @@
+\documentclass[11pt]{article}\r
+\newcommand{\tuple}[1]{\ensuremath \langle #1 \rangle}\r
+\usepackage{color}\r
+\usepackage{amsthm}\r
+\usepackage{amsmath}\r
+\usepackage{graphicx}\r
+\usepackage{mathrsfs}\r
+\usepackage{algpseudocode}% http://ctan.org/pkg/algorithmicx\r
+\usepackage[all]{xy}\r
+\newtheorem{theorem}{Theorem}\r
+\newtheorem{prop}{Proposition}\r
+\newtheorem{lem}{Lemma}\r
+\newtheorem{defn}{Definition}\r
+\newcommand{\note}[1]{{\color{red} \bf [[#1]]}}\r
+\newcommand{\push}[1][1]{\hskip\dimexpr #1\algorithmicindent\relax}\r
+\begin{document}\r
+\section{Approach}\r
+\r
+\subsection{Keys}\r
+\r
+Each device has: user id + password\r
+\r
+Server login is:\r
+hash1(user id), hash1(password)\r
+\r
+Symmetric Crypto keys is:\r
+hash2(user id | password)\r
+\r
+Server has finite length queue of entries + max\_entry\_identifier +\r
+server login key\r
+\r
+\subsection{Entry layout}\r
+Each entry has:\r
+\begin{enumerate}\r
+\item Sequence identifier\r
+\item Random IV (if needed by crypto algorithm)\r
+\item Encrypted payload\r
+\end{enumerate}\r
+\r
+Payload has:\r
+\begin{enumerate}\r
+\item Sequence identifier\r
+\item Machine id (most probably something like a 64-bit random number \r
+that is self-generated by client)\r
+\item HMAC of previous slot\r
+\item Data entries\r
+\item HMAC of current slot\r
+\end{enumerate}\r
+\r
+A data entry can be one of these:\r
+\begin{enumerate}\r
+\item All or part of a Key-value entry\r
+\item Slot sequence entry: Machine id + last message identifier \r
+\newline {The purpose of this is to keep the record of the last slot \r
+from a certain client if a client's update has to expunge that other \r
+client's last entry from the queue. This is kept in the slot until \r
+the entry owner inserts a newer update into the queue.}\r
+\item Queue state entry: Includes queue size \newline {The purpose \r
+of this is for the client to tell if the server lies about the number \r
+of slots in the queue, e.g. if there are 2 queue state entry in the queue, \r
+e.g. 50 and 70, the client knows that when it sees 50, it should expect \r
+at most 50 slots in the queue and after it sees 70, it should expect \r
+50 slots before that queue state entry slot 50 and at most 70 slots. \r
+The queue state entry slot 70 is counted as slot number 51 in the queue.}\r
+\item Collision resolution entry: message identifier + machine id of a\r
+collision winner\r
+\newline {The purpose of this is to keep keep track of the winner of \r
+all the collisions until all clients have seen the particular entry.}\r
+\end{enumerate}\r
+\r
+\subsection{Live status}\r
+\r
+Live status of entries:\r
+\begin{enumerate}\r
+\item Key-Value Entry is dead if either (a) there is a newer key-value pair or (b) it is incomplete.\r
+       \r
+\item Slot sequence number (of either a message version data\r
+or user-level data) is dead if there is a newer slot from the same machine.\r
+\r
+\item Queue state entry is dead if there is a newer queue state entry.\r
+{In the case of queue state entries 50 and 70, this means that queue state \r
+entry 50 is dead and 70 is live. However, not until the number of slots reaches \r
+70 that queue state entry 50 will be expunged from the queue.}\r
+\r
+\item Collision resolution entry is dead if this entry has been seen\r
+by all clients after a collision happens.\r
+\end{enumerate}\r
+\r
+When data is at the end of the queue ready to expunge, if:\r
+\begin{enumerate}\r
+\item The key-value entry is not dead, it must be reinserted at the\r
+beginning of the queue.\r
+\r
+\item If the slot sequence number is not dead, then a message sequence\r
+entry must be inserted.\r
+\r
+\item If the queue state entry is not dead, it must be reinserted at the\r
+beginning of the queue.\r
+\end{enumerate}\r
+\r
+\r
+\paragraph{Reads:}\r
+Client sends a sequence number.  Server replies with either: all data\r
+entries or all newer data entries.\r
+\r
+\paragraph{Writes:}\r
+Client sends slot, server verifies that sequence number is valid,\r
+checks entry hash, and replies with an accept message if all checks\r
+pass.  On success, client updates its sequence number.  On failure,\r
+server sends updates slots to client and client validates those slots.\r
+\r
+\paragraph{Local state on each client:}\r
+A list of machines and the corresponding latest sequence numbers.\r
+\r
+\paragraph{Validation procedure on client:}\r
+\begin{enumerate}\r
+\item Decrypt each new slot in order.\r
+\item For each slot:\r
+    (a) check its HMAC, and\r
+    (b) check that the previous entry HMAC field matches the previous\r
+    entry.\r
+\item Check that the last-message entry for our machine matches the stored HMAC of our last message sent.\r
+\item For all other machines, check that the latest sequence number is\r
+at least as large (never goes backwards).\r
+\item That the queue has a current queue state entry.\r
+\item That the number of entries received is consistent with the size\r
+specified in the queue state entry.\r
+\end{enumerate}\r
+\r
+Key-value entries can span multiple slots.  They aren't valid until\r
+they are complete.\r
+\r
+\subsection{Resizing Queue}\r
+Client can make a request to resize the queue. This is done as a write that combines:\r
+  (a) a slot with the message, and (b) a request to the server. The queue can only be expanded, never contracted; attempting to decrease the size of the queue will cause future clients to throw an error.\r
+\r
+\subsection{Server Algorithm}\r
+$s \in SN$ is a sequence number\\\r
+$sv \in SV$ is a slot's value\\\r
+$slot_s = \tuple{s, sv} \in SL \subseteq SN \times SV$ \\ \\\r
+\textbf{State} \\\r
+\textit{SL = set of live slots on server} \\\r
+\textit{max = maximum number of slots (input only for resize message)} \\\r
+\textit{n = number of slots} \\ \\\r
+\textbf{Helper Function} \\\r
+$MaxSlot(SL_s)= \tuple{s, sv} \mid \tuple{s, sv}\r
+\in SL_s \wedge \forall \tuple{s_s, sv_s} \in SL_s, s \geq s_s$ \\\r
+$MinSlot(SL_s)= \tuple{s, sv} \mid \tuple{s, sv} \r
+\in SL_s \wedge \forall \tuple{s_s, sv_s} \in SL_s, s \leq s_s$ \\\r
+$SeqN(slot_s = \tuple{s, sv})=s$ \\\r
+$SlotVal(slot_s = \tuple{s, sv})=sv$ \\\r
+\r
+\begin{algorithmic}[1]\r
+\Function{GetSlot}{$s_g$}\r
+\State \Return{$\{\tuple{s, sv} \in SL \mid s \geq s_g\}$}\r
+\EndFunction\r
+\end{algorithmic}\r
+\r
+\begin{algorithmic}[1]\r
+\Function{PutSlot}{$s_p,sv_p,max'$}\r
+\If{$(max' \neq \emptyset)$}  \Comment{Resize}\r
+\State $max \gets max'$\r
+\EndIf\r
+\State $\tuple{s_n,sv_n} \gets MaxSlot(SL)$\Comment{Last sv}\r
+%\State $s_n \gets SeqN(\tuple{s_n,sv_n})$\r
+\If{$(s_p = s_n + 1)$}\r
+       \If{$n = max$}\r
+       \State $\tuple{s_m,sv_m} \gets MinSlot(SL)$\Comment{First sv}\r
+               \State $SL \gets SL - \{\tuple{s_m,sv_m}\}$\r
+       \Else \Comment{$n < max$}\r
+               \State $n \gets n + 1$\r
+       \EndIf\r
+    \State $SL \gets SL \cup \{\tuple{s_p,sv_p}\}$\r
+       \State \Return{$(true,\emptyset)$}\r
+\Else\r
+       \State \Return{$(false,\{\tuple{s,sv}\in SL \mid \r
+    s \geq s_p\})$}\r
+\EndIf\r
+\EndFunction\r
+\end{algorithmic}\r
+\r
+\subsection{Client Algorithm}\r
+\subsubsection{Reading Slots}\r
+\textbf{Data Entry} \\\r
+$k$ is key of entry \\\r
+$v$ is value of entry \\\r
+$kv$ is a key-value entry $\tuple{k,v}$, $kv \in DE$ \\\r
+$ss$ is a slot sequence entry $\tuple{id,s_{last}}$, \r
+id + last s of a machine, $ss \in DE$ \\\r
+$qs$ is a queue state entry (contains $max$ size of queue), $qs \in DE$ \\\r
+$cr$ is a collision resolution entry $\tuple{s_{col},id_{col}}$, \r
+s + id of a machine that wins a collision, $cr \in DE$ \\\r
+$de$ is a data entry that can be a $kv$, $ss$, $qs$, or $cr$ \\\r
+$DE$ is a set of all data entries, possibly of different types, in a single message \\\r
+$s \in SN$ is a sequence number \\\r
+$id$ is a machine ID\\\r
+$hmac_p$ is the HMAC value of the previous slot \\\r
+$hmac_c$ is the HMAC value of the current slot \\\r
+$hmac_{p_g}$ is the HMAC value of the previous slot in procedure $\Call{ProcessSL}{}$ \\\r
+$hmac_{c_g}$ is the HMAC value of the current slot in procedure $\Call{ProcessSL}{}$ \\\r
+$Dat_s = \tuple{s,id,hmac_p,DE,hmac_c}$ \\\r
+$slot_s = \tuple{s, E(Dat_s)} = \r
+\tuple{s, E(\tuple{s,id,hmac_p,DE,hmac_c})}$ \\ \\\r
+\textbf{States} \\\r
+\textit{$d$ = delta between the last $s$ recorded and the first $s$ received} \\\r
+\textit{$id_{self}$ = machine Id of this client} \\\r
+\textit{$max_g$ = maximum number of slots (initially $max_g > 0$)} \\\r
+\textit{$sl_{last}$ = info of last slot in queue = \r
+       $\tuple{s_{last},sv_{last},id_{last}}$ (initially $\emptyset$)} \\\r
+\textit{DT = set of $\tuple{k,v}$ on client} \\\r
+\textit{MS = associative array of $\tuple{id, s_{last}}$ of all clients on client \r
+(initially empty)} \\\r
+\textit{$LV$ = live set of $kv$ entries on client, contains \r
+       $\tuple{kv,s}$ entries} \\\r
+\textit{$SS_{live}$ = live set of $ss$ entries on client} \\\r
+\textit{$CR_{live}$ = live set of $cr$ entries on client} \\\r
+\textit{$MS_g$ = set MS to save all $\tuple{id, s_{last}}$ pairs while\r
+traversing DT after a request to server (initially empty)} \\\r
+\textit{SK = Secret Key} \\\r
+\textit{$SM$ = associative array of $\tuple{s, id}$ of all slots in previous reads\r
+(initially empty)} \\ \\\r
+\textbf{Helper Functions} \\\r
+$MaxSlot(SL_s)= \tuple{s, sv}$ \textit{such that} $\tuple{s, sv}\r
+       \in SL_s \wedge \forall \tuple{s_s, sv_s} \in SL_s, s \geq s_s$ \\\r
+$MinSlot(SL_s)= \tuple{s, sv}$ \textit{such that} $\tuple{s, sv} \r
+       \in SL_s \wedge \forall \tuple{s_s, sv_s} \in SL_s, s \leq s_s$ \\\r
+$Slot(SL_s,s_s)= \tuple{s, sv}$ \textit{such that} $\tuple{s, sv} \r
+       \in SL_s \wedge \forall \tuple{s_s, sv_s} \in SL_s, s = s_s$ \\\r
+$SeqN(\tuple{s, sv})=s$ \\\r
+$SlotVal(\tuple{s, sv})=sv$ \\\r
+$CreateLastSL(s,sv,id)=\tuple{s,sv,id}=sl_{last}$ \\\r
+$Decrypt(SK_s,sv_s)=Dat_s=\tuple{s,id,hmac_p,DE,hmac_c}$ \\\r
+$GetSeqN(Dat_s = \tuple{s,id,hmac_p,DE,hmac_c})=s$ \\\r
+$GetMacId(Dat_s = \tuple{s,id,hmac_p,DE,hmac_c})=id$ \\\r
+$GetPrevHmac(Dat_s = \tuple{s,id,hmac_p,DE,hmac_c})=hmac_p$ \\\r
+$GetCurrHmac(Dat_s = \tuple{s,id,hmac_p,DE,hmac_c})=hmac_c$ \\\r
+$GetDatEnt(Dat_s = \tuple{s,id,hmac_p,DE,hmac_c})=DE$ \\\r
+$GetLiveSS(SS_{live},ss_s)= ss$ \textit{such that} $ss \in SS_{live} \r
+       \wedge \forall ss_s \in SS_{live}, ss = ss_s$ \\\r
+$GetLiveCR(CR_{live},cr_s)= cr$ \textit{such that} $cr \in CR_{live} \r
+       \wedge \forall cr_s \in CR_{live}, cr = cr_s$ \\\r
+$GetLivEntLastS(LV_s,kv_s)= s$ \textit{such that} $\tuple{kv, s} \in LV_s \r
+       \wedge \forall \tuple{kv_s, s_s} \in LV_s, kv_s = kv$ \\\r
+$GetKV($key-value data entry$)=\tuple{k_s,v_s} = kv_s$ \\\r
+$GetSS($slot-sequence data entry$)=\tuple{id_s,s_{s_{last}}} = ss_s$ \\\r
+$GetCR($de$)=\tuple{s_s,id_s} = cr_s$ \\\r
+$Hmac(Dat_s,SK) = hmac_c$ \textit{value computed from $s$, $id$,\r
+$hmac_p$, and $DE$ taken from $Dat_s$} \\\r
+$IsKv(de) = true$ \textit{if $de$ is a $kv$, false otherwise} \\\r
+$IsSs(de) = true$ \textit{if $de$ is a $ss$, false otherwise} \\\r
+$IsQs(de) = true$ \textit{if $de$ is a $qs$, false otherwise} \\\r
+$IsCr(de) = true$ \textit{if $de$ is a $cr$, false otherwise} \\\r
+$GetKey(kv)=k$\Comment{$kv = \tuple{k, v}$} \\\r
+$GetVal(kv)=v$ \\\r
+$GetId(ss)=id$\Comment{$ss = \tuple{id, s_{last}}$} \\\r
+$GetSLast(ss)=s_{last}$ \\\r
+$GetS(cr)=s$\Comment{$cr = \tuple{s, id}$} \\\r
+$GetId(cr)=id$ \\\r
+$GetLastS(sl_{last})=s$\Comment{$sl_{last} = \tuple{s,sv,id}$} \\\r
+$GetSV(sl_{last})=sv$ \\\r
+$GetID(sl_{last})=id$ \\\r
+$GetKeyVal(DT_s,k_s)= \tuple{k, v}$ \textit{such that} $\tuple{k, v} \r
+       \in DT_s \wedge \forall \tuple{k_s, v_s} \in DT_s, k = k_s$ \\\r
+$MaxLastSeqN(MS_s)= s_{last}$ \textit{such that} $\tuple{id, s_{last}} \in MS_s \r
+       \wedge \forall \tuple{id_s, s_{s_{last}}} \in MS_s, s_{last} \geq s_{s_{last}}$ \\\r
+$MinLastSeqN(MS_s)= s_{last}$ \textit{such that} $\tuple{id, s_{last}} \in MS_s \r
+       \wedge \forall \tuple{id_s, s_{s_{last}}} \in MS_s, s_{last} \leq s_{s_{last}}$ \\\r
+$MinCRSeqN(CR_s)= s$ \textit{such that} $\tuple{s, id} \in CR_s \r
+       \wedge \forall \tuple{s_s, id_s} \in CR_s, s \leq s_s$ \\\r
+$MaxSMSeqN(SM_s)= s$ \textit{such that} $\tuple{s, id} \in SM_s \r
+       \wedge \forall \tuple{s_s, id_s} \in SM_s, s \geq s_s$ \\\r
+\r
+\begin{algorithmic}[1]\r
+\Procedure{Error}{$msg$}\r
+\State $Print(msg)$\r
+\State $Halt()$\r
+\EndProcedure\r
+\end{algorithmic}\r
+\r
+\begin{algorithmic}[1]\r
+\Function{GetQueSta}{$DE_s$}\r
+\State $qs_{de} \gets qs$ \textit{such that} $qs \in DE_s, \r
+       de_s \in D \land IsQs(de_s)$\r
+\If{$qs_{de} \neq \emptyset$}\r
+       \State $qs_{ret} \gets qs_{de})$\r
+\Else\r
+       \State $qs_{ret} \gets \emptyset$\r
+\EndIf\r
+\State \Return{$qs_{ret}$}\r
+\EndFunction\r
+\end{algorithmic}\r
+\r
+\begin{algorithmic}[1]\r
+\Function{GetSlotSeq}{$DE_s$}\r
+\State $DE_{ss} \gets \{de | de \in DE_s \land IsSs(de)\}$\r
+\State \Return{$DE_{ss}$}\r
+\EndFunction\r
+\end{algorithmic}\r
+\r
+\begin{algorithmic}[1]\r
+\Function{GetColRes}{$DE_s$}\r
+\State $DE_{cr} \gets \{de | de \in DE_s \land IsCr(de)\}$\r
+\State \Return{$DE_{cr}$}\r
+\EndFunction\r
+\end{algorithmic}\r
+\r
+\begin{algorithmic}[1]\r
+\Function{UpdateLastSeqN}{$id_s,s_s,MS_s$}\r
+\State $s_t \gets MS_s[id_s]$\r
+\If{$s_t = \emptyset$}\r
+       \State $MS_s[id_s] = s_s$  \Comment{First occurrence}\r
+\Else\r
+       \If{$id_s = id_{self}$}\r
+               \If{$s_t \neq s_s$}\Comment{Check for mismatch on $s$}\r
+                       \State \Call{Error}{'Mismatch on $s$ for $id_{self}$'}\r
+               \EndIf\r
+       \Else\r
+               \If{$s_t > s_s$}\Comment{Check for rollback on $s$}\r
+                       \State \Call{Error}{'Rollback on $s$ for $id_s$'}\r
+               \EndIf\r
+       \EndIf\r
+       \State $MS_S[id_s] \gets max(s_t, s_s)$\r
+\EndIf\r
+\State \Return{$MS_s$}\r
+\EndFunction\r
+\end{algorithmic}\r
+\r
+\begin{algorithmic}[1]\r
+\Function{UpdateKVLivEnt}{$LV_s,kv_s,s_s$}\r
+\State $s_t \gets GetLivEntLastS(LV_s,kv_s)$\r
+\If{$s_t = \emptyset$}\r
+       \State $LV_s \gets LV_s \cup \{\tuple{kv_s,s_s}\}$\Comment{First occurrence}\r
+\Else\r
+       \If{$s_s > s_t$}\Comment{Update entry with a later s}\r
+               \State $LV_s \gets (LV_s - \{\tuple{kv_s,s_t}\}) \cup \r
+                       \{\tuple{kv_s,s_s}\}$\r
+       \EndIf\r
+\EndIf\r
+\State \Return{$LV_s$}\r
+\EndFunction\r
+\end{algorithmic}\r
+\r
+\begin{algorithmic}[1]\r
+\Function{AddSSLivEnt}{$SS_{s_{live}},de_s$}\r
+\State $ss_s \gets GetSS(de_s)$\r
+\State $ss_t \gets GetLiveSS(SS_{s_{live}},ss_s)$\r
+\If{$ss_t = \emptyset$}\r
+       \State $SS_{s_{live}} \gets SS_{s_{live}} \cup \{ss_s\}$\Comment{First occurrence}\r
+\EndIf\r
+\State \Return{$SS_{s_{live}}$}\r
+\EndFunction\r
+\end{algorithmic}\r
+\r
+\begin{algorithmic}[1]\r
+\Function{AddCRLivEnt}{$CR_{s_{live}},cr_s$}\r
+\State $cr_t \gets GetLiveCR(CR_{s_{live}},cr_s)$\r
+\If{$cr_t = \emptyset$}\r
+       \State $CR_{s_{live}} \gets CR_{s_{live}} \cup \{cr_s\}$\Comment{First occurrence}\r
+\EndIf\r
+\State \Return{$CR_{s_{live}}$}\r
+\EndFunction\r
+\end{algorithmic}\r
+\r
+\begin{algorithmic}[1]\r
+\Function{UpdateSSLivEnt}{$SS_{s_{live}},MS_s$}\r
+\State $s_{s_{min}} \gets MinLastSeqN(MS_s)$\r
+\ForAll{$ss_s \in SS_{s_{live}}$}\r
+       \State $s_{s_{last}} \gets GetSLast(ss_s)$\r
+       \If{$s_{s_{min}} > s_{s_{last}}$}\Comment{Remove if dead}\r
+               \State $SS_{s_{live}} \gets SS_{s_{live}} - \{ss_s\}$           \r
+       \EndIf\r
+\EndFor\r
+\State \Return{$SS_{s_{live}}$}\r
+\EndFunction\r
+\end{algorithmic}\r
+\r
+\begin{algorithmic}[1]\r
+\Function{UpdateCRLivEnt}{$CR_{s_{live}},MS_s$}\r
+\State $s_{s_{min}} \gets MinLastSeqN(MS_s)$\r
+\ForAll{$cr_s \in CR_{s_{live}}$}\r
+       \State $s_s \gets GetS(cr_s)$\r
+       \If{$s_{s_{min}} > s_s$}\Comment{Remove if dead}\r
+               \State $CR_{s_{live}} \gets CR_{s_{live}} - \{cr_s\}$   \r
+       \EndIf\r
+\EndFor\r
+\State \Return{$CR_{s_{live}}$}\r
+\EndFunction\r
+\end{algorithmic}\r
+\r
+\begin{algorithmic}[1]\r
+\Function{UpdateSM}{$SM_s,CR_s$}\Comment{Remove if dead}\r
+\State $s_{cr_{min}} \gets MinCRSeqN(CR_s)$\r
+       \State $SM_s \gets SM_s - \{\tuple{s_s,id_s} \mid \tuple{s_s,id_s}\r
+               \in SM_s \wedge s_s < s_{cr_{min}}\}$\r
+\State \Return{$CR_{s_{live}}$}\r
+\EndFunction\r
+\end{algorithmic}\r
+\r
+\begin{algorithmic}[1]\r
+\Procedure{CheckLastSeqN}{$MS_s,MS_t,d$}\r
+\For {$\tuple{id, s_t}$ in $MS_t$}\Comment{Check $MS_t$ based on the newer $MS_s$}\r
+       \State $s_s \gets MS_s[id]$\r
+       \If{$d \land s_s = \emptyset$}\r
+       \State \Call{Error}{'Missing $s$ for machine $id$'}\r
+       \ElsIf{$id = id_{self}$ and $s_s \neq s_t$}\r
+               \State \Call{Error}{'Invalid last $s$ for this machine'}\r
+       \ElsIf{$id \neq id_{self}$ and $s_{s_{last}} < s_{t_{last}}$}\r
+       \State \Call{Error}{'Invalid last $s$ for machine $id$'}\r
+    \Else\r
+               \State $MS_t[id] \gets s_s$\r
+       \EndIf\r
+\EndFor\r
+\EndProcedure\r
+\end{algorithmic}\r
+\r
+\begin{algorithmic}[1]\r
+\Procedure{CheckCollision}{$MS_s,SM_s,cr_s$}\r
+\If{$cr_s \neq \emptyset$}\r
+       \State $s_s \gets GetS(cr_s)$\r
+       \State $id_s \gets GetId(cr_s)$\r
+       \State $s_{s_{last}} \gets GetLastSeqN(MS_s,id_s)$\r
+       \If{$s_{s_{last}} < s_s$}\r
+               \State $id_t \gets SM_s[s_s]$\r
+               \If{$id_s \neq id_t$}\r
+                       \State \Call{Error}{'Invalid $id$ for this slot update'}\r
+               \EndIf\r
+       \EndIf\r
+\EndIf\r
+\EndProcedure\r
+\end{algorithmic}\r
+\r
+\begin{algorithmic}[1]\r
+\Function{ValidSlotsRange}{$s_{s_{min}}$}\r
+\State $s_{s_{last}} \gets MaxSMSeqN(SM)$\r
+\If{$s_{s_{min}} \leq s_{s_{last}}$}\r
+       \State \Call{Error}{'Server sent old slots'}\r
+\EndIf\r
+\State \Return{$s_{s_{min}} > s_{s_{last}} + 1$}\r
+\EndFunction\r
+\end{algorithmic}\r
+\r
+\begin{algorithmic}[1]\r
+\Procedure{CheckNumSlots}{$|SL_s|,sz_s$}\r
+\If{$|SL_s| \neq sz_s$}\r
+       \State \Call{Error}{'Actual number of slots does not match expected'}\r
+\EndIf\r
+\EndProcedure\r
+\end{algorithmic}\r
+\r
+\begin{algorithmic}[1]\r
+\Function{StoreLastSlot}{$MS_s,sl_l,s_s,sv_s,id_s$}\r
+\State $s_{min} \gets MinLastSeqN(MS_s)$\r
+\If{$s_{min} \neq \emptyset \land s_{min} = s_s$}\Comment{$MS$ initially empty}\r
+       \State $sl_l \gets CreateLastSL(s_s,sv_s,id_s)$\r
+\EndIf\r
+\State \Return{$sl_l$}\r
+\EndFunction\r
+\end{algorithmic}\r
+\r
+\begin{algorithmic}[1]\r
+\Function{ValidHmacChain}{$Dat_s,s_s,hmac_{p_s},sl_l$}\r
+       \State $hmac_{p_{stored}} \gets GetPrevHmac(Dat_s)$\r
+       \If {$ \neg(s_s = 0 \land hmac_{p_s} = 0)$}\r
+               \State $s_l \gets GetLastS(sl_l)$\r
+               \If {$(s_s > s_l + 1) \land (hmac_{p_{stored}} \neq hmac_{p_s})$}\r
+                       \State \Call{Error}{'Invalid previous HMAC value'}\r
+               \EndIf\r
+       \EndIf\r
+       \If{$Hmac(Dat_s,SK) \neq GetCurrHmac(Dat_s)$ }\r
+               \State \Call{Error}{'Invalid current HMAC value'}\r
+       \EndIf\r
+       \State $hmac_{p_s} \gets Hmac(Dat_s,SK)$\Comment{Update $hmac_{p_s}$ for next check}\r
+\State \Return{$hmac_{p_s}$}\r
+\EndFunction\r
+\end{algorithmic}\r
+\r
+\begin{algorithmic}[1]\r
+\Function{UpdateDT}{$DT_s,DE_s,LV_s,s_s$}\r
+\State $DE_{s_{kv}} \gets \{de_s | de_s \in DE_s \land IsKv(de_s)\}$\r
+\ForAll{$de_s \in DE_{s_{kv}}$}\r
+       \State $kv_s \gets GetKV(de_s)$\r
+       \State $LV_s \gets \Call{UpdateKVLivEnt}{LV_s,kv_s,s_s}$\r
+       \State $k_s \gets GetKey(kv_s)$\r
+       \State $\tuple{k_s,v_t} \gets GetKeyVal(DT_s,k_s)$\r
+       \If{$\tuple{k_s,v_t} = \emptyset$}\r
+               \State $DT_s \gets DT_s \cup \{\tuple{k_s,v_s}\}$\r
+       \Else\r
+               \State $DT_s \gets (DT_s - \{\tuple{k_s,v_t}\}) \cup \r
+                       \{\tuple{k_s,v_s}\}$\r
+       \EndIf\r
+\EndFor\r
+\State \Return{$DT_s$}\r
+\EndFunction\r
+\end{algorithmic}\r
+\r
+\begin{algorithmic}[1]\r
+\Function{InitExpSize}{$s_{min}$}\r
+\If{$s_{min} < max_g$}\Comment{Check whether $SL$ is full on server}\r
+       \State $sz_s \gets s_{min}$\r
+\Else\r
+       \State $sz_s \gets max_g$\r
+\EndIf\r
+\State \Return{$sz_s$}\r
+\EndFunction\r
+\end{algorithmic}\r
+\r
+\begin{algorithmic}[1]\r
+\Function{UpdateExpSize}{$sz_s$}\r
+\State $sz_s \gets sz_s + 1$\r
+\If{$sz_s > max_g$}\Comment{Expected size $\leq max_g$}\r
+       \State $sz_s \gets max_g$\r
+\EndIf\r
+\State \Return{$sz_s$}\r
+\EndFunction\r
+\end{algorithmic}\r
+\r
+\begin{algorithmic}[1]\r
+\Function{UpdateQS}{$Dat_s,max_s$}\r
+\State $DE_s \gets GetDatEnt(Dat_s)$\r
+\State $qs_s \gets \Call{GetQueSta}{DE_s}$\Comment{Handle qs}\r
+\If{$qs_s \neq \emptyset \land qs_s > max_s$}\r
+       \State $max_s \gets qs_s$\r
+\EndIf\r
+\State \Return{$max_s$}\r
+\EndFunction\r
+\end{algorithmic}\r
+\r
+\begin{algorithmic}[1]\r
+\Procedure{UpdateCR}{$DE_s$}\r
+\State $DE_{s_{cr}} \gets \Call{GetColRes}{DE_s}$\Comment{Handle cr}\r
+\If{$DE_{s_{cr}} \neq \emptyset$}\r
+       \ForAll{$de_{s_{cr}} \in DE_{s_{cr}}$}\r
+               \State $cr_s \gets GetCR(de_{s_{cr}})$\r
+               \State $\Call{CheckCollision}{MS,SM,cr_s}$\r
+               \State $CR_{live} \gets \Call{AddCRLivEnt}{CR_{live},cr_s}$\r
+       \EndFor\r
+\EndIf\r
+\EndProcedure\r
+\end{algorithmic}\r
+\r
+\begin{algorithmic}[1]\r
+\Function{UpdateSS}{$DE_s,MS_s$}\r
+\State $DE_{s_{ss}} \gets \Call{GetSlotSeq}{DE_s}$\Comment{Handle ss}\r
+\If{$DE_{s_{ss}} \neq \emptyset$}\r
+       \ForAll{$de_{s_{ss}} \in DE_{s_{ss}}$}\r
+               \State $\tuple{id_d,s_{d_{last}}} \gets GetSS(de_{s_{ss}})$\r
+               \State $MS_s \gets \Call{UpdateLastSeqN}{id_d,s_{d_{last}},MS_s}$\r
+               \State $SS_{live} \gets \Call{AddSSLivEnt}{SS_{live},de_{s_{ss}}}$\r
+       \EndFor\r
+\EndIf\r
+\State \Return{$MS_s$}\r
+\EndFunction\r
+\end{algorithmic}\r
+\r
+\begin{algorithmic}[1]\r
+\Procedure{ProcessSL}{$SL_g$}\r
+\State $MS_g \gets \emptyset$\r
+\State $\tuple{s_{g_{min}},sv_{g_{min}}} \gets MinSlot(SL_g)$\r
+\State $\tuple{s_{g_{max}},sv_{g_{max}}} \gets MaxSlot(SL_g)$\r
+\State $d \gets \Call{ValidSlotsRange}{s_{g_{min}}}$\r
+\State $sz \gets \Call{InitExpSize}{s_{g_{min}}}$\r
+\For{$s_g \gets s_{g_{min}}$ \textbf{to} $s_{g_{max}}$}\Comment{Process slots \r
+       in $SL_g$ in order}\r
+       \State $\tuple{s_g,sv_g} \gets Slot(SL_g,s_g)$\r
+       \State $Dat_g \gets Decrypt(SK,sv_g)$\r
+       \State $id_g \gets GetMacId(Dat_g)$\r
+       \State $SM \gets SM \cup \{\tuple{s_g,id_g}\}$\r
+       \State $s_{g_{in}} \gets GetSeqN(Dat_g)$\r
+    \If{$s_g \neq s_{g_{in}}$}\r
+               \State \Call{Error}{'Invalid sequence number'}\r
+       \EndIf\r
+       \State $hmac_{p_g} \gets \Call{ValidHmacChain}{Dat_g,s_g,hmac_{p_g},sl_{last}}$\r
+       \State $sz \gets \Call{UpdateExpSize}{sz}$\r
+       \State $max_g \gets \Call{UpdateQS}{Dat_g,max_g}$\Comment{Handle qs}\r
+       \State $MS_g \gets \Call{UpdateLastSeqN}{id_g,s_g,MS_g}$\Comment{Handle last s}\r
+       \State $MS_g \gets \Call{UpdateSS}{DE_g,MS_g}$\Comment{Handle ss}\r
+       %\State $DE_{g_{ss}} \gets \Call{GetSlotSeq}{DE_g}$\Comment{Handle ss}\r
+       %\If{$DE_{g_{ss}} \neq \emptyset$}\r
+       %       \ForAll{$de_{g_{ss}} \in DE_{g_{ss}}$}\r
+       %               \State $\tuple{id_d,s_{d_{last}}} \gets GetSS(de_{g_{ss}})$\r
+       %               \State $MS_g \gets \Call{UpdateLastSeqN}{id_d,s_{d_{last}},MS_g}$\r
+       %               \State $SS_{live} \gets \Call{AddSSLivEnt}{SS_{live},de_{g_{ss}}}$\r
+       %       \EndFor\r
+       %\EndIf\r
+       \State $\Call{UpdateCR}{DE_g}$\Comment{Handle cr}\r
+       %\State $DE_{g_{cr}} \gets \Call{GetColRes}{DE_g}$\Comment{Handle cr}\r
+       %\If{$DE_{g_{cr}} \neq \emptyset$}\r
+       %       \ForAll{$de_{g_{cr}} \in DE_{g_{cr}}$}\r
+       %               \State $cr_g \gets GetCR(de_{g_{cr}})$\r
+       %               \State $\Call{CheckCollision}{MS,SM,cr_g}$\r
+       %               \State $CR_{live} \gets \Call{AddCRLivEnt}{CR_{live},cr_g}$\r
+       %       \EndFor\r
+       %\EndIf\r
+       \State $sl_{last} \gets \Call{StoreLastSlot}{MS,sl_{last},s_g,sv_g,id_g}$\r
+       \State $DT \gets \Call{UpdateDT}{DT,DE_g,LV,s_g}$\r
+\EndFor\r
+\State $\Call{CheckLastSeqN}{MS_g,MS,d}$\r
+\State $\Call{CheckNumSlots}{|SL_g|,sz}$\r
+\State $\Call{UpdateSSLivEnt}{SS_{live},MS}$\r
+\State $\Call{UpdateCRLivEnt}{CR_{live},MS}$\r
+\State $\Call{UpdateSM}{SM,CR_{live}}$\r
+\EndProcedure\r
+\end{algorithmic}\r
+\r
+\begin{algorithmic}[1]\r
+\Procedure{GetKVPairs}{}\r
+\State $s_g \gets GetLastSeqN(MS,id_{self}) + 1$\r
+\State $SL_c \gets \Call{GetSlot}{s_g}$\r
+\State $\Call{ProcessSL}{SL_c}$\Comment{Process slots and update DT}\r
+\EndProcedure\r
+\end{algorithmic}\r
+\r
+\begin{algorithmic}[1]\r
+\Function{Get}{$k_g$}  \Comment{Interface function to get a value}\r
+\State $\tuple{k_s,v_s} \gets \tuple{k,v}$ \textit{such that} $\tuple{k,v} \r
+       \in DT \land k = k_g$\r
+\State \Return{$v_s$}\r
+\EndFunction\r
+\end{algorithmic}\r
+\r
+\subsubsection{Writing Slots}\r
+\textbf{States} \\\r
+\textit{$cp$ = data entry $DE$ maximum size/capacity} \\\r
+\textit{$ck_p$ = counter of $kv \in KV$ for putting pairs (initially 0)} \\\r
+\textit{$ck_g$ = counter of $kv \in KV$ for getting pairs (initially 0)} \\\r
+\textit{$cs_p$ = counter of $ss \in SS$ for putting pairs (initially 0)} \\\r
+\textit{$cs_g$ = counter of $ss \in SS$ for getting pairs (initially 0)} \\\r
+\textit{$cc_p$ = counter of $cr \in CR$ for putting pairs (initially 0)} \\\r
+\textit{$cc_g$ = counter of $cr \in CR$ for getting pairs (initially 0)} \\\r
+\textit{$hmac_{c_p}$ = the HMAC value of the current slot in procedure \r
+$\Call{PutDataEntries}{}$} \\\r
+\textit{$hmac_{p_p}$ = the HMAC value of the previous slot \r
+($hmac_{p_p} = \emptyset$ for the first slot) in procedure \r
+$\Call{PutDataEntries}{}$} \\\r
+\textit{$id_{self}$ = machine Id of this client} \\\r
+\textit{$sl_{last}$ = info of last slot in queue = \r
+       $\tuple{s_{last},sv_{last},id_{last}}$ (initially $\emptyset$)} \\\r
+\textit{$sz$ = expected size of received slots from server} \\\r
+\textit{$th_p$ = threshold number of dead slots for a resize to happen} \\\r
+\textit{$m'_p$ = offset added to $max$ for resize} \\\r
+\textit{$reinsert_{qs}$ = boolean to decide $qs$($max_g$) reinsertion} \\\r
+\textit{$KV$ = set of $\tuple{ck, \tuple{k,v}}$ of kv entries on client} \\\r
+\textit{$SS$ = set of $\tuple{cs, \tuple{id,s_{last}}}$ of ss entries on client} \\\r
+\textit{$CR$ = set of $\tuple{cc, \tuple{s_{col},id_{col}}}$ of cr entries on client} \\\r
+\textit{$SL_p$ = set of returned slots on client} \\\r
+\textit{SK = Secret Key} \\ \\\r
+\textbf{Helper Functions} \\\r
+$CreateDat(s,id,hmac_p,DE,hmac_c)=Dat_s=\tuple{s,id,hmac_p,DE,hmac_c}$ \\\r
+$CreateSS(id_s,s_{s_{last}})=\tuple{id_s,s_{s_{last}}} = ss_s$ \\\r
+$CreateQS(max'_s)=qs_s$ \\\r
+$CreateCR(s_s,id_s)=\tuple{s_s,id_s} = cr_s$ \\\r
+$Encrypt(Dat_s,SK_s)=sv_s$ \\\r
+$GetColSeqN(SL_s,s_s)= \tuple{s, sv}$ \textit{such that} $\tuple{s, sv}\r
+\in SL_s \wedge \forall \tuple{s_s, sv_s} \in SL_s, s = s_s$ \\\r
+$GetKVPair(KV_s,k_s)= \tuple{ck,\tuple{k, v}}$ \textit{such that} \r
+$\tuple{ck,\tuple{k, v}} \in KV_s \wedge\r
+\forall \tuple{ck_s,\tuple{k_s, v_s}} \in KV_s, k = k_s$ \\\r
+\r
+\begin{algorithmic}[1]\r
+\Function{Put}{$KV_s,\tuple{k_s,v_s}$}  \Comment{Interface function to update a key-value pair}\r
+\State $\tuple{ck_s,\tuple{k_s,v_t}} \gets GetKVPair(KV_s,k_s)$\r
+\If{$\tuple{ck_s,\tuple{k_s,v_t}} = \emptyset$}\r
+       \State $KV_s \gets KV_s \cup \{\tuple{ck_p, \tuple{k_s,v_s}}\}$\r
+       \State $ck_p \gets ck_p + 1$\r
+\Else\r
+       \State $KV_s \gets (KV_s - \{\tuple{ck_s, \tuple{k_s,v_t}}\}) \cup \r
+       \{\tuple{ck_s, \tuple{k_s,v_s}}\}$\r
+\EndIf\r
+\State \Return{$KV_s$}\r
+\EndFunction\r
+\end{algorithmic}\r
+\r
+\begin{algorithmic}[1]\r
+\Function{PutSSPair}{$SS_s,\tuple{id_s,s_{s_{last}}}$}\Comment{Insert a set of $ss$ entries}\r
+\State $SS_s \gets SS_s \cup \{\tuple{cs_p, \tuple{id_s,s_{s_{last}}}}\}$\r
+\State $cs_p \gets cs_p + 1$\r
+\State \Return{$SS_s$}\r
+\EndFunction\r
+\end{algorithmic}\r
+\r
+\begin{algorithmic}[1]\r
+\Function{PutCRPair}{$CR_s,\tuple{s_s,id_s}$}\Comment{Insert a set of $cr$ entries}\r
+\State $CR_s \gets CR_s \cup \{\tuple{cc_p, \tuple{s_s,id_s}}\}$\r
+\State $cc_p \gets cc_p + 1$\r
+\State \Return{$CR_s$}\r
+\EndFunction\r
+\end{algorithmic}\r
+\r
+\begin{algorithmic}[1]\r
+\Function{CheckResize}{$MS_s,th_s,max_t,m'_s$}\r
+\State $s_{last_{min}} \gets MinLastSeqN(MS_s)$\r
+\State $s_{last_{max}} \gets MaxLastSeqN(MS_s)$\r
+\State $n_{live} \gets s_{last_{max}} - s_{last_{min}} + 1$\Comment{Number of live slots}\r
+\State $n_{dead} \gets max_t - n_{live}$\r
+\If{$n_{dead} \leq th_s$}\r
+       \State $max'_s \gets max_t + m'_s$\r
+\Else\r
+       \State $max'_s \gets \emptyset$\r
+\EndIf\r
+\State \Return{$max'_s$}\r
+\EndFunction\r
+\end{algorithmic}\r
+\r
+\begin{algorithmic}[1]\r
+\Function{CheckSLFull}{$MS_s,max_t$}\Comment{Check if $ss$ is needed}\r
+\State $s_{last_{min}} \gets MinLastSeqN(MS_s)$\r
+\State $s_{last_{max}} \gets MaxLastSeqN(MS_s)$\r
+\State $n_{live} \gets s_{last_{max}} - s_{last_{min}}$\Comment{Number of live slots}\r
+\State $n_{dead} \gets max_t - n_{live}$\r
+\State \Return {$n_{dead} = 0$}\r
+\EndFunction\r
+\end{algorithmic}\r
+\r
+\begin{algorithmic}[1]\r
+\Function{HandleCollision}{$SL_s,s_s$}\r
+\If{$SL_s = \emptyset$}\r
+       \State \Call{Error}{'No slots received from server'}\r
+\EndIf\r
+\State $\tuple{s_{col},sv_{col}} \gets GetColSeqN(SL_s,s_s)$\r
+\State $Dat_{col} \gets Decrypt(SK,sv_{col})$\r
+\State $id_{col} \gets GetMacId(Dat_{col})$\r
+\State $cr_s \gets CreateCR(s_{col},id_{col})$\r
+\State $\Call{ProcessSL}{SL_s}$\r
+\State \Return{$cr_s$}\r
+\EndFunction\r
+\end{algorithmic}\r
+\r
+\begin{algorithmic}[1]\r
+\Procedure{CheckLastSlot}{$sl_{s_{last}}$}\r
+\State $s_s \gets GetLastS(sl_{s_{last}})$\r
+\State $sv_s \gets GetSV(sl_{s_{last}})$\r
+\State $Dat_s \gets Decrypt(SK,sv_s)$\r
+\State $DE_s \gets GetDatEnt(Dat_s)$\r
+\ForAll{$de_s \in DE_s$}\r
+       \State $live \gets \Call{CheckLiveness}{s_s,de_s}$\r
+       \If{$live$}\r
+               \If{$type(de_s) = ``kv"$}\r
+                       \State $\tuple{k_s,v_s} \gets GetKV(de_s)$\r
+                       \State $KV \gets \Call{PutKVPair}{KV,\tuple{k_s,v_s}}$\r
+               \ElsIf{$type(de_s) = ``ss"$}\r
+                       \State $\tuple{id_s,s_{s_{last}}} \gets GetSS(de_s)$\r
+                       \State $SS \gets \Call{PutSSPair}{SS,\tuple{id_s,s_{s_{last}}}}$\r
+               \ElsIf{$type(de_s) = ``cr"$}\r
+                       \State $\tuple{s_s,id_s} \gets GetCR(de_s)$\r
+                       \State $CR \gets \Call{PutCRPair}{CR,\tuple{s_s,id_s}}$\r
+               \ElsIf{$type(de_s) = ``qs"$}\r
+                       \State $reinsert_{qs} \gets true$\r
+               \EndIf\r
+       \EndIf\r
+\EndFor\r
+\EndProcedure\r
+\end{algorithmic}\r
+\r
+\begin{algorithmic}[1]\r
+\Function{CheckLiveness}{$s_s,de_s$}\r
+\State $live \gets true$\r
+\If{$de_s = kv$}\r
+       \State $s_l \gets GetLivEntLastS(LV,de_s)$\r
+       \If{$s_l = \emptyset \lor s_s < s_l$}\r
+               \State $live \gets false$\r
+       \EndIf\r
+\ElsIf{$de_s = ss$}\r
+       \State $ss_s \gets GetSS(de_s)$\r
+       \State $ss_l \gets GetLiveSS(SS_{live},ss_s)$\r
+       \If{$ss_l = \emptyset$}\r
+               \State $live \gets false$\r
+       \EndIf\r
+\ElsIf{$de_s = cr$}\r
+       \State $cr_s \gets GetCR(de_s)$\r
+       \State $cr_l \gets GetLiveCR(CR_{live},cr_s)$\r
+       \If{$cr_l = \emptyset$}\r
+               \State $live \gets false$\r
+       \EndIf\r
+\ElsIf{$de_s = qs$}\r
+       \State $qs_s \gets GetQS(de_s)$\r
+       \If{$qs_s \neq max_g$}\r
+               \State $live \gets false$\r
+       \EndIf\r
+\Else\r
+       \State \Call{Error}{'Unrecognized $de$ type'}\r
+\EndIf\r
+\State \Return{$live$}\r
+\EndFunction\r
+\end{algorithmic}\r
+\r
+\begin{algorithmic}[1]\r
+\Function{CreateSlotSeq}{$sl_s$}\r
+\State $id_s \gets GetID(sl_s)$\r
+\State $s_{s_{last}} \gets GetLastS(sl_s)$\r
+\State $ss_s \gets CreateSS(id_s,s_{s_{last}})$\r
+\State \Return{$\tuple{ss_s}$}\r
+\EndFunction\r
+\end{algorithmic}\r
+\r
+\begin{algorithmic}[1]\r
+\Function{AddQueSta}{$DE_s,max'_s,cp_s$}\Comment{Insert a $qs$}\r
+\State $DE_{ret} \gets \emptyset$\r
+\State $qs_s \gets max'_s$\r
+\State $DE_{ret} \gets DE_s \cup \{qs_s\}$\r
+\State $cp_s \gets cp_s - 1$\r
+\State \Return{$\tuple{DE_{ret},cp_s}$}\r
+\EndFunction\r
+\end{algorithmic}\r
+\r
+\begin{algorithmic}[1]\r
+\Function{GetKVPairs}{$DE_s,KV_s,cp_s$}\r
+\State $DE_{ret} \gets \emptyset$\r
+\If{$|KV_s| \leq cp_s$}\Comment{$KV$ set can span multiple slots}\r
+       \State $DE_{ret} \gets DE_s \cup\r
+       \{\tuple{k_s,v_s} \mid \tuple{ck_s,\tuple{k_s,v_s}} \in KV_s\}$\r
+\Else\r
+       \State $DE_{ret} \gets DE_s \cup\r
+       \{\tuple{k_s,v_s} \mid \tuple{ck_s,\tuple{k_s,v_s}} \in KV_s,\r
+               ck_g \leq ck_s < ck_g + cp_s\}$\r
+\EndIf\r
+\State \Return{$\tuple{DE_{ret}}$}\r
+\EndFunction\r
+\end{algorithmic}\r
+\r
+\begin{algorithmic}[1]\r
+\Function{GetSSPairs}{$DE_s,SS_s,cp_s$}\r
+\State $DE_{ret} \gets \emptyset$\r
+\If{$|SS_s| \leq cp_s$}\Comment{$SS$ set can span multiple slots}\r
+       \State $DE_{ret} \gets DE_s \cup\r
+       \{\tuple{id_s,s_{s_{last}}} \mid \tuple{cs_s,\tuple{id_s,s_{s_{last}}}} \in SS_s\}$\r
+       \State $cp_s \gets cp_s - |SS_s|$\r
+\Else\r
+       \State $DE_{ret} \gets DE_s \cup\r
+       \{\tuple{id_s,s_{s_{last}}} \mid \tuple{cs_s,\tuple{id_s,s_{s_{last}}}} \in SS_s,\r
+               cs_g \leq cs_s < cs_g + cp_s\}$\r
+       \State $cp_s \gets 0$\r
+\EndIf\r
+\State \Return{$\tuple{DE_{ret},cp_s}$}\r
+\EndFunction\r
+\end{algorithmic}\r
+\r
+\begin{algorithmic}[1]\r
+\Function{GetCRPairs}{$DE_s,CR_s,cp_s$}\r
+\State $DE_{ret} \gets \emptyset$\r
+\If{$|CR_s| \leq cp_s$}\Comment{$CR$ set can span multiple slots}\r
+       \State $DE_{ret} \gets DE_s \cup\r
+       \{\tuple{s_s,id_s} \mid \tuple{cc_s,\tuple{s_s,id_s}} \in CR_s\}$\r
+       \State $cp_s \gets cp_s - |CR_s|$\r
+\Else\r
+       \State $DE_{ret} \gets DE_s \cup\r
+       \{\tuple{s_s,id_s} \mid \tuple{cc_s,\tuple{s_s,id_s}} \in CR_s,\r
+               cc_g \leq cc_s < cc_g + cp_s\}$\r
+       \State $cp_s \gets 0$\r
+\EndIf\r
+\State \Return{$\tuple{DE_{ret},cp_s}$}\r
+\EndFunction\r
+\end{algorithmic}\r
+\r
+\begin{algorithmic}[1]\r
+\Procedure{PutDataEntries}{$th_p,m'_p$}\r
+\State $success_p \gets false$\r
+\State $CR_p \gets \emptyset$\r
+\While{$\neg success_p$}\r
+       \State $DE_p \gets \emptyset$\r
+       \State $s_p \gets MaxLastSeqN(MS)$\r
+       \State $cp_p \gets cp$\r
+       \State $max'_p \gets \Call{CheckResize}{MS,th_p,max_g,m'_p}$\r
+       \If{$max'_p \neq \emptyset$}\Comment{Add a qs entry}\r
+               \State $\tuple{DE_p,cp_p} \gets \Call{AddQueSta}{DE_p,max'_p,cp_p}$\r
+               \State $reinsert_{qs} \gets false$\r
+       \Else\Comment{Check if there is $qs$ reinsertion}\r
+               \If{$reinsert_{qs}$}\r
+                       \State $\tuple{DE_p,cp_p} \gets \Call{AddQueSta}{DE_p,max_g,cp_p}$\r
+                       \State $reinsert_{qs} \gets false$\r
+               \EndIf\r
+       \EndIf\r
+       \If{$SS \neq \emptyset$}\Comment{Add $ss$ entries}\r
+               \State $\tuple{DE_p,cp_p} \gets \Call{GetSSPairs}{DE_p,SS,cp_p}$\r
+       \EndIf\r
+       \If{$CR \neq \emptyset$}\Comment{Add $cr$ entries}\r
+               \State $\tuple{DE_p,cp_p} \gets \Call{GetCRPairs}{DE_p,CR,cp_p}$\r
+       \EndIf\r
+       \State $\tuple{DE_p,cp_p} \gets \Call{GetKVPairs}{DE_p,KV,cp_p}$\Comment{Add $kv$ entries}\r
+       \State $hmac_{c_p} \gets Hmac(DE_p,SK)$\r
+       \State $Dat_p \gets CreateDat(s_p,id_{self},hmac_{p_p},DE_p,hmac_{c_p})$\r
+       \State $hmac_{p_p} \gets hmac_{c_p}$\r
+       \State $sv_p \gets Encrypt(Dat_p,SK)$\r
+       \State $\tuple{success_p,SL_p} \gets \Call{PutSlot}{s_p,sv_p,max'_p}$\r
+       \If{$\neg success_p$}\r
+               \State $cr_p \gets \Call{HandleCollision}{SL_p,s_p}$\r
+               \State $\tuple{s_{p_{col}},id_{p_{col}}} \gets GetCR(cr_p)$\r
+               \State $CR \gets \Call{PutCRPair}{CR,\tuple{s_{p_{col}},id_{p_{col}}}}$\r
+       \EndIf\r
+\EndWhile\r
+\State $MS \gets \Call{UpdateLastSeqN}{id_{self},s_p,MS}$\r
+\If{$|DE_p| = cp$}\Comment{Update set counters}\r
+       \State $ck_g \gets ck_g + cp_p$\Comment{Middle of set}\r
+       \State $cs_g \gets cs_g + |SS|$\r
+       \State $cc_g \gets cc_g + |CR|$\r
+\Else\Comment{End of set}\r
+       \State $ck_g \gets 0$\r
+       \State $cs_g \gets 0$\r
+       \State $cc_g \gets 0$\r
+\EndIf\r
+\State $need_p \gets \Call{CheckSLFull}{MS,max_g}$\r
+\If{$need_p$}\Comment{SL on server is full}\r
+       \State $\Call{CheckLastSlot}{sl_{last}}$\Comment{Salvage entries from expunged slot}\r
+       \State $ss_p \gets \Call{CreateSlotSeq}{sl_{last}}$\r
+       \State $\tuple{id_p,s_{p_{last}}} \gets GetSS(ss_p)$\r
+       \State $SS \gets \Call{PutSSPair}{SS,\tuple{id_p,s_{p_{last}}}}$\Comment{Add ss}\r
+\EndIf\r
+\EndProcedure\r
+\end{algorithmic}\r
+\r
+%\note{Lots of problems with PutDataEntries: (1) What happens if lose network connectivity after adding the key value pair, but before reinserting the last slot?  You probably need to create space first and then insert your data entry...  (2) What if reinsertlastslot kicks something else important out?  What if the server rejects our update because it is out of date?  At the very least, any putdataentries function w/o a loop is wrong!}\r
+\r
+%\note{General comments...  Work on structuring things to improve readability...  This include names of functions/variables, how things are partitioned into functions, adding useful comments,...}\r
+  \r
+%\note{Also Missing liveness state definition in algorithm...}\r
+\r
+\r
+\subsection{Formal Guarantees}\r
+\subsubsection{Definitions}\r
+\r
+\begin{defn}[Message]\r
+A message $\mathsf{t}$, is the tuple \r
+\begin{center}\r
+$\mathsf{t = \tuple{s, E(Dat_s)}}$ \\\r
+$\mathsf{Dat_t = \tuple{s,id,hmac_p, DE,hmac_c}}$\r
+\end{center}\r
+containing $\mathsf{s}$ as sequence number and $\mathsf{Dat_t}$ as its \r
+encrypted contents. $\mathsf{Dat_t}$ consists of $\mathsf{s}$, \r
+$\mathsf{id}$ as machine ID of the sender, $\mathsf{hmac_p}$ as HMAC \r
+from a previous message, $\mathsf{DE}$ as set of data entries, and \r
+$\mathsf{hmac_c}$ as HMAC from message $\mathsf{t}$ respectively.\r
+\end{defn}\r
+\r
+\begin{defn}[Equality]\r
+Two messages $\mathsf{t}$ and $\mathsf{u}$ are equal if their $\mathsf{s}$, \r
+and $\mathsf{Dat_t}$ are exactly the same.\r
+\end{defn}\r
+\r
+\begin{defn}[Parent]\r
+A parent of a message $\mathsf{t}$ is the message $\mathsf{p_t}$, \r
+unique by the correctness of HMACs in $\mathsf{Dat_t}$, such that \r
+$\mathsf{hmac_p(t) = hmac_c(p_t)}$.\r
+\end{defn}\r
+\r
+\begin{defn}[Chain]\r
+A chain of messages with length $\mathsf{n \ge 1}$ is a message sequence \r
+$\mathsf{R = (r_s, r_{s+1}, ..., r_{s+n-1})}$ such that for every sequence \r
+number $\mathsf{s < k \le s+n-1}$, $\mathsf{r_k}$ has sequence number \r
+$\mathsf{k}$ and is the parent of $\mathsf{r_{k-1}}$.\r
+\end{defn}\r
+\r
+\begin{defn}[Partial sequence]\r
+A partial sequence $\mathsf{P}$ is a sequence of messages, no two \r
+with the same sequence number, that can be divided into disjoint chains.\r
+\end{defn}\r
+\r
+\begin{defn}[Total sequence]\r
+A total sequence $\mathsf{T =}$ $\mathsf{(t_1, t_2, ..., t_n)}$ with \r
+length $\mathsf{n}$ is a chain of messages that starts at $\mathsf{s = 1}$.\r
+\end{defn}\r
+\r
+\begin{defn}[Path]\r
+The path of a message $\mathsf{t}$ is the chain that starts at $\mathsf{s = 1}$ \r
+and whose last message is $\mathsf{t}$. The uniqueness of a path follows \r
+from the uniqueness of a parent.\r
+\end{defn}\r
+\r
+\begin{defn}[Consistency]\r
+A partial sequence $\mathsf{P}$ is consistent with a total sequence \r
+$\mathsf{T}$ of length $\mathsf{n}$ if for every message $\mathsf{p \in P}$ \r
+with $\mathsf{s_p \leq n}$, $\mathsf{t_{s_p} = p}$. This implies that \r
+$\mathsf{\{p \in P | s_p \le n\}}$ is a partial sequence of $\mathsf{T}$.\r
+\end{defn}\r
+\r
+\begin{defn}[Transitive closure]\r
+Transitive closure set at sequence number $\mathsf{s_n}$ is a set \r
+$\mathsf{\mathscr{S}}$ of clients comprising a connected component of an \r
+undirected graph, where two clients are connected by an edge if they both \r
+received the same message $\mathsf{t}$ with sequence number $\mathsf{s_t > s_n}$.\r
+\end{defn}\r
+\r
+\subsubsection{Lemmas and Proofs}\r
+\r
+\begin{prop}\r
+\label{prop:parentmessage}\r
+Every client $\mathsf{J}$ who sends a message $\mathsf{t}$ \r
+has parent $\mathsf{p_t}$ as its latest stored message, and \r
+$\mathsf{s_t = s_{p_t} + 1}$. \r
+\end{prop}\r
+\begin{proof} True by definition, because $J$ sets \r
+$\mathsf{hmac_p(t) = hmac_c(p_t)}$ and \r
+$\mathsf{s_t = }$ $\mathsf{s_{p_t + 1}}$ when a message \r
+is sent. \r
+\end{proof}\r
+\r
+\begin{prop} \r
+\label{prop:rejectedmessage}\r
+If a rejected message entry is added to the set $\mathsf{CR}$ \r
+at sequence number $\mathsf{s}$, the message will remain in $\mathsf{CR}$ \r
+until every client has seen it. \r
+\end{prop}\r
+\begin{proof} Every $\mathsf{CR}$ entry $\mathsf{cr}$ remains in the queue until it \r
+reaches the tail, and is refreshed by the next sender $\mathsf{J}$ at that time if \r
+$\mathsf{min(MS) > s_{cr}}$; that is, until every client has sent a message with \r
+sequence number greater than $\mathsf{s_{cr}}$. Because every client who sends a \r
+message with sequence number $\mathsf{s}$ has the state of the set $\mathsf{SL}$ at \r
+$\mathsf{s - 1}$, this client will have seen the message at $\mathsf{s_{cr}}$. \r
+\end{proof}\r
+\r
+\begin{figure}[h]\r
+  \centering\r
+      \xymatrix{ & & L \\\r
+\dots \ar[r] & q \ar[dr]_{J} \ar[r]^{K} & l_1 \ar[r] & l_2 \ar[r] & \dots \ar[r] & m \ar[r] & \dots \ar[r] & l_n = u \\\r
+& & r_1 \ar[r] & r_2 \ar[r] & \dots \ar[r] & r_m = t \\\r
+& & R\r
+\save "2,3"."2,8"*+\frm{^\}}\r
+\save "3,3"."3,6"*+\frm{_\}}\r
+\restore\r
+\restore\r
+}\r
+\caption{By \textbf{Lemma \ref{lem:twomessages}}, receiving both $t$ and $u$ here is impossible.}\r
+\end{figure}\r
+\r
+\begin{lem}\r
+\label{lem:twomessages}\r
+Two messages are received without errors by a client $\mathsf{C}$; \r
+call them $\mathsf{t}$ and $\mathsf{u}$ such that $\mathsf{s_t \le s_u}$. \r
+Then $\mathsf{t}$ is in the path of $\mathsf{u}$. \r
+\end{lem}\r
+\begin{proof}\r
+Assume that there are some pairs of messages $\mathsf{(t,u)}$ that violate this lemma. \r
+Take a specific $\mathsf{(t,u)}$ such that $\mathsf{s_u}$ is minimized, and \r
+$\mathsf{s_t}$ is maximized for this choice of $\mathsf{s_u}$. We will show that $\mathsf{C}$\r
+cannot receive both $\mathsf{t}$ and $\mathsf{u}$ without throwing an error.\r
+\r
+Clearly $\mathsf{C}$ will throw an error if $\mathsf{s_t = s_u}$. So \r
+$\mathsf{s_t < s_u}$. Additionally, if $\mathsf{C}$ receives $\mathsf{u}$ before \r
+$\mathsf{t}$, this will cause it to throw an error, so $\mathsf{t}$ is received \r
+before $\mathsf{u}$. We will prove that an error occurs upon receipt of $\mathsf{u}$.\r
+\r
+Let $\mathsf{r_1}$ be the earliest member of the path of $\mathsf{t}$ that is \r
+not in the path of $\mathsf{u}$, and $\mathsf{q}$ be its parent. Message \r
+$\mathsf{q}$, the last common ancestor of $\mathsf{t}$ and $\mathsf{u}$, must exist, \r
+since all clients and the server were initialized with the same state. Let \r
+$\mathsf{l_1}$ be the successor of $\mathsf{q}$ that is in the path of $\mathsf{u}$; \r
+we know $\mathsf{l_1 \neq r_1}$. Let $\mathsf{R = (r_1, r_2, \dots, r_{|R|} = t)}$ be \r
+the distinct portion of the path of $\mathsf{t}$, and similarly let $\mathsf{L}$ \r
+be the distinct portion of the path of $\mathsf{l_{|L|} = u}$.\r
+\r
+Let $\mathsf{J}$ be the client who sent $\mathsf{r_1}$; that is, such that \r
+$\mathsf{{id_{self}}_J = GetMacID(r_1)}$, and $\mathsf{K}$ be the client who \r
+sent $\mathsf{l_1}$. Because no client can send two messages with the same sequence number, and \r
+$\mathsf{s_{r_1} = s_{l_1} = s_q + 1}$, $\mathsf{J \neq K}$.\r
+\r
+We also know the following facts: \r
+\r
+\begin{prop} \r
+\label{prop:bothmessages}\r
+No client sends both a message in $\mathsf{(r_2,...,t)}$ and a message in $\mathsf{(l_2,...,u)}$. \r
+\end{prop}\r
+\r
+\begin{proof}\r
+To send a message $\mathsf{p}$ that is the parent of some other \r
+message, one must have received the parent of $\mathsf{p}$. Since \r
+$\mathsf{u}$ is the message with smallest sequence number received by any \r
+client that violates Lemma \ref{lem:twomessages}, no client receives both a message \r
+in $\mathsf{r}$ and a message in $\mathsf{l}$. \r
+\end{proof}\r
+\r
+\begin{prop} \r
+\label{prop:seqnumb}\r
+$\mathsf{C}$ does not receive any message with a\r
+sequence number strictly between $\mathsf{s_t}$ and $\mathsf{s_u}$. \r
+\end{prop}\r
+\r
+\begin{proof} If there were such a message with sequence number smaller than \r
+$\mathsf{s_u}$, it would contradict the assumption that $\mathsf{u}$ is the \r
+message with the least sequence number that violates Lemma \ref{lem:twomessages}. \r
+\end{proof}\r
+\r
+There are two cases:\r
+\begin{itemize}\r
+\item Case 1: $\mathsf{J}$ did not send a message in $\mathsf{L}$. Then, where $\mathsf{s_{t_J}}$ \r
+is the greatest sequence number of the messages that client $\mathsf{J}$ sent in \r
+the path of message $\mathsf{t}$, $\mathsf{s_{t_J} > s_{q_J} = s_{u_J}}$.\r
+\begin{itemize}\r
+\item Case 1.1: $\mathsf{C}$ never updates its slot sequence list $\mathsf{SS}$ \r
+between receiving $\mathsf{t}$ and receiving $\mathsf{u}$; this can only happen if \r
+$\mathsf{s_t = s_u - 1}$. Since $\mathsf{t}$ is not the parent of $\mathsf{u}$, \r
+$\mathsf{hmac_p(u) \neq hmac_c(t)}$, causing $\mathsf{C}$ to throw an error.\r
+\item Case 1.2: Case 1.1 does not occur; therefore, $\mathsf{C}$ must update \r
+its slot sequence list $\mathsf{SS}$ at some point between receiving $\mathsf{t}$ \r
+and $\mathsf{u}$. \r
+The latest sequence number of $\mathsf{J}$ decreases during this time, which \r
+means it must decrease when some message is received, which means $\mathsf{C}$ \r
+throws an error in the $\mathsf{CheckLastSeqN()}$ subroutine.\r
+\end{itemize}\r
+\r
+\item Case 2: $\mathsf{J}$ sent at least one message in $\mathsf{L}$. Call the \r
+first one $\mathsf{m}$. We know that $\mathsf{s_m > s_{r_1}}$, since \r
+$\mathsf{J \neq K}$ and $\mathsf{m \neq l_1}$. Message $\mathsf{r_1}$ must be sent \r
+either before or after $\mathsf{m}$.\r
+\begin{itemize}\r
+\item Case 2.1: Client $\mathsf{J}$ sends $\mathsf{m}$, and then $\mathsf{r_1}$. \r
+Before sending $\mathsf{m}$, the greatest sequence number of a message that \r
+$\mathsf{J}$ has received, $\mathsf{{s_{last}}_J}$, must be equal to \r
+$\mathsf{s_m - 1 \ge s_{r_1}}$. Since $\mathsf{{s_{last}}_J}$ never decreases, \r
+client $\mathsf{J}$ cannot then send a message with sequence number \r
+$\mathsf{s_{r_1}}$, a contradiction.\r
+\item Case 2.2: Client $\mathsf{J}$ sends $\mathsf{r_1}$, and then $\mathsf{m}$. \r
+Let $\mathsf{X = (r_1 = x_1, \dots , x_n)}$ be the list of messages $\mathsf{J}$ sends \r
+starting before $\mathsf{r_1}$ and ending before $m$; clearly these all have sequence \r
+number $\mathsf{s_p = s_q + 1}$.\r
+\begin{itemize}\r
+\item Case 2.2.1: Some message in $\mathsf{X}$ was accepted. Before sending $\mathsf{m}$, \r
+$\mathsf{J}$'s value in $\mathsf{MS_J}$ for its own latest sequence number would \r
+be strictly greater than $\mathsf{s_{q_J}}$. If there is a sequence of messages with \r
+contiguous sequence numbers that $\mathsf{J}$ receives between $\mathsf{r_1}$ and \r
+$\mathsf{m}$, $\mathsf{J}$ throws an error for a similar reason as Case 1.1. Otherwise, \r
+when preparing to send $\mathsf{m}$, $\mathsf{J}$ would have received an update of its \r
+own latest sequence number as at most $\mathsf{s_{q_J}}$. $J$ throws an error before \r
+sending $\mathsf{p}$, because its own latest sequence number decreases.\r
+\item Case 2.2.2: All messages in $\mathsf{X}$ were rejected, making $\mathsf{m}$ \r
+the first message of $\mathsf{J}$ that is accepted after $\mathsf{r_1}$.\r
+\r
+We will show that $\mathsf{C}$ sees $\mathsf{r_1}$. Assume not. Then $\mathsf{(r_2, ..., u)}$ \r
+must have at least $\mathsf{{max_g}_C} \geq 2$ messages for $\mathsf{r_1}$ to fall off the \r
+end of the queue. Consider the sender of $\mathsf{r_3}$ and call it $\mathsf{H}$. \r
+$\mathsf{H \neq J}$ by Proposition \ref{prop:bothmessages} and the existence of $\mathsf{m}$. \r
+Since $\mathsf{H \neq J}$, then by Proposition \ref{prop:bothmessages} it could not also \r
+have sent a message in $\mathsf{(l_2,..., u)}$. Therefore, $\mathsf{s_{u_H} < s_q + 2 = s_{t_H}}$, \r
+so upon receipt of $\mathsf{u}$, $\mathsf{C}$ will throw an error by the decrease in a \r
+last sequence number similar to Case 1, a contradiction.\r
+\r
+Now that we know that $\mathsf{C}$ sees $\mathsf{r_1}$, note that C receives $\mathsf{u}$ \r
+immediately after $\mathsf{t}$ by Proposition \ref{prop:seqnumb}. Therefore, \r
+$\mathsf{C}$ could not have seen a message after $\mathsf{t}$ with sequence number less \r
+than $\mathsf{s_m}$. In the $\mathsf{PutDataEntries()}$ subroutine, $\mathsf{J}$ adds every \r
+$\mathsf{cr}$ entry that contains sequence number $\mathsf{s}$ and machine ID \r
+$\mathsf{id}$ of the messsages that win in the collisions before $\mathsf{m}$ into \r
+$\mathsf{CR}$; $\mathsf{CR}$ keeps the collection of live $\mathsf{cr}$ entries, namely\r
+those which not all clients have seen. Hence, for every $\mathsf{i}$, $\mathsf{1 \leq i < |X|}$, \r
+the collision winner that has collided with $\mathsf{x_i}$ will be recorded appropriately. Since all the $\mathsf{cr}$ entries that record the results of the collisions before $\mathsf{p}$ will also be seen when $\mathsf{u}$ \r
+is received, and $\mathsf{C}$ sees $\mathsf{r_1}$, ${l_1}$ will be recorded in a $\mathsf{cr}$ entry as the winner in the \r
+collision against ${r_1}$.\r
+\r
+When $\mathsf{C}$ receives $\mathsf{u}$, if $\mathsf{C}$ \r
+has seen the $\mathsf{cr}$ entry that records the collision at index $\mathsf{s_q + 1}$, it will throw \r
+an error from the mismatch of $\mathsf{\tuple{s_q+1, id_J}}$ with \r
+$\mathsf{\tuple{s_q+1, id_K}}$ in the corresponding $\mathsf{cr}$ entry.\r
+\r
+\end{itemize}\r
+\end{itemize}\r
+\r
+\end{itemize}\r
+\end{proof}\r
+\r
+\begin{lem} \r
+\label{lem:pathmessages}\r
+If there are two messages $\mathsf{t}$ and $\mathsf{u}$, with \r
+$\mathsf{s_t \leq s_u}$, such that $\mathsf{t}$ is in the path of $\mathsf{u}$, \r
+then for any message $\mathsf{p}$ with $\mathsf{s_p \leq s_t}$, iff $\mathsf{p}$ is in \r
+the path of $\mathsf{t}$, it is in the path of $\mathsf{u}$. \r
+\end{lem}\r
+\r
+\begin{proof}\r
+If $\mathsf{s_t = s_u}$ or $\mathsf{s_p = s_t}$, then we are done, because the two \r
+relevant messages are the same. If they are different messages, then:\r
+\begin{itemize}\r
+\item Reverse direction: The definition of $\mathsf{t}$ being in the path of \r
+$\mathsf{u}$ is the existence of a message sequence $\mathsf{(\dots, t, \dots, u)}$ \r
+such that each message except $\mathsf{u}$ is the parent of the succeeding message. \r
+The path of $\mathsf{u}$ must contain some message with sequence number $\mathsf{s_p}$; \r
+because $\mathsf{p}$ is in the path of $\mathsf{u}$, this message is $\mathsf{p}$ \r
+itself. The path of $\mathsf{t}$ is then the prefix of this path ending at $\mathsf{t}$, \r
+which clearly contains $\mathsf{p}$.\r
+\r
+\item Forward direction: The path of $\mathsf{t}$ is a substring of the path of \r
+$\mathsf{u}$, so if the path of $\mathsf{t}$ contains $\mathsf{p}$, so does the path \r
+of $\mathsf{u}$.\r
+\end{itemize}\r
+\end{proof}\r
+\r
+\begin{theorem}\r
+Suppose that there is a transitive closure set $\mathsf{\mathscr{S}}$ of clients, \r
+at sequence number $\mathsf{s_n}$. Then there is some total sequence $\mathsf{T}$ of \r
+length $\mathsf{n}$ such that every client $\mathsf{C}$ in $\mathsf{\mathscr{S}}$ \r
+sees a partial sequence $\mathsf{P_C}$ consistent with $\mathsf{T}$. \r
+\end{theorem}\r
+\r
+\begin{proof}\r
+\r
+The definition of consistency of $\mathsf{P_C}$ with $\mathsf{T}$ is that every message \r
+$\mathsf{p \in P_C}$ with sequence number $\mathsf{s_p \le s_n}$ is equal to the message \r
+in that slot in $\mathsf{T}$. Let $\mathsf{C_1}$ be some client in the transitive closure \r
+set, with partial sequence $\mathsf{P_{C_1}}$, and let $\mathsf{u}$ be some message with \r
+$\mathsf{s_u > s_n}$ that $\mathsf{C_1}$ shares with another client. Then let $\mathsf{T}$ \r
+be the portion of the path of $\mathsf{u}$ ending at sequence number $\mathsf{s_n}$ and \r
+$\mathsf{t}$ be the message at that sequence number. Clearly, by Lemma \ref{lem:twomessages}, \r
+$\mathsf{P_{C_1}}$ is consistent with $\mathsf{T}$. We will show that, for every other client \r
+$\mathsf{D}$ with partial sequence $\mathsf{P_D}$, $\mathsf{P_D}$ has some message whose path \r
+includes $\mathsf{t}$. Because $\mathsf{D}$ is in the transitive closure, there is a sequence \r
+of clients $\mathsf{\mathscr{C} = (C_1, C_2, ..., D)}$ from $\mathsf{C_1}$ to $\mathsf{D}$, \r
+where each shares an edge with the next.\r
+We prove by induction that $\mathsf{P_D}$ has a message whose path includes $\mathsf{t}$.\r
+\begin{itemize}\r
+\item Base case: $\mathsf{P_{C_1}}$ includes $\mathsf{u}$, whose path includes $\mathsf{t}$.\r
+\r
+\item Inductive step: Each client in $\mathsf{\mathscr{C}}$ has a partial sequence with a message \r
+that includes $\mathsf{t}$ if the previous client does. Suppose $\mathsf{P_{C_k}}$ has \r
+a message $\mathsf{w}$ with a path that includes $\mathsf{t}$, and shares message $\mathsf{x}$ \r
+with $\mathsf{P_{C_{k+1}}}$ such that $\mathsf{s_x > s_n}$. By Lemma \ref{lem:twomessages}, \r
+$\mathsf{w}$ or $\mathsf{x}$, whichever has the least sequence number, is in the path of the other, \r
+and therefore by Lemma \ref{lem:pathmessages}, $\mathsf{t}$ is in the path of $\mathsf{x}$.\r
+\r
+\item Let $\mathsf{z}$ be the message of $\mathsf{D}$ whose path includes $\mathsf{t}$. \r
+By Lemma \ref{lem:twomessages}, every message in $\mathsf{P_D}$ with sequence number smaller \r
+than $\mathsf{s_w}$ is in the path of $\mathsf{z}$. Since $\mathsf{t}$ is in the path of \r
+$\mathsf{z}$, every message in $\mathsf{P_D}$ with smaller sequence number than \r
+$\mathsf{s_t = s_n}$ is in $\mathsf{T}$. \r
+Therefore, $\mathsf{P_D}$ is consistent with $\mathsf{T}$.\r
+\r
+\end{itemize}\r
+\end{proof}\r
+\r
+\subsection{Future Work}\r
+\paragraph{Support Messages}\r
+  A message is dead once receiving machine sends an entry with a newer\r
+  sequence identifier\r
+\r
+\paragraph{Persistent data structures}\r
+       Root object w/ fields\r
+       Other objects can be reachable from root\r
+       Each object has its own entries\r
+       Dead objects correspond to dead \r
+\r
+\paragraph{Multiple App Sharing}\r
+\r
+Idea is to separate subspace of entries...  Shared with other cloud...\r
+\end{document}\r
diff --git a/non_block_chain/doc/iotcloud_formal/iotcloud.tex b/non_block_chain/doc/iotcloud_formal/iotcloud.tex
new file mode 100644 (file)
index 0000000..8f15592
--- /dev/null
@@ -0,0 +1,1312 @@
+\documentclass[11pt]{article}\r
+\newcommand{\tuple}[1]{\ensuremath \langle #1 \rangle}\r
+\usepackage{color}\r
+\usepackage{amsthm}\r
+\usepackage{amsmath}\r
+\usepackage{graphicx}\r
+\usepackage{mathrsfs}\r
+\usepackage{amssymb}\r
+\usepackage{algpseudocode}% http://ctan.org/pkg/algorithmicx\r
+\usepackage[all]{xy}\r
+\usepackage{varwidth}\r
+\r
+\newtheorem{theorem}{Theorem}\r
+\newtheorem{prop}{Proposition}\r
+\newtheorem{lem}{Lemma}\r
+\newtheorem{defn}{Definition}\r
+\newcommand{\note}[1]{{\color{red} \bf [[#1]]}}\r
+\newcommand{\push}[1][1]{\hskip\dimexpr #1\algorithmicindent\relax}\r
+\newcommand*\xor{\mathbin{\oplus}}\r
+\begin{document}\r
+\r
+\r
+\setlength\parindent{0pt} % Removes all indentation from paragraphs - comment this line for an assignment with lots of text\r
+\r
+\r
+\section{\textbf{Introduction}}\r
+\r
+\r
+\r
+\r
+\r
+\section{\textbf{Server}}\r
+The server maintains a collection of slots such that each slot contains some data.\r
+The operations on the slot are as follows:\r
+\begin{itemize}\r
+    \item Put slot\r
+    \item Get slot\r
+    \item Delete Slot\r
+\end{itemize}\r
+\r
+\subsection{\textbf{Server Notation Conventions}}\r
+$s \in SN$ is a server sequence number\\\r
+$sv \in SV$ is a slot's value\\\r
+$slot_s = \tuple{s, sv} \in SL \subseteq SN \times SV$\r
+\r
+\subsection{\textbf{Server State}}\r
+\textit{n = current server sequence number}\\\r
+\textit{SL = set of live slots on the server}\\\r
+\r
+\textbf{Initial Server State}\\\r
+$SL = \emptyset$\\\r
+$n = 0$\r
+\r
+\subsection{\textbf{Put Slot}}\r
+Put slot is an operation that inserts data into a new slot at the server.\\\r
+\r
+%Put Function\r
+\noindent\fbox{%\r
+\begin{varwidth}{\dimexpr\linewidth-2\fboxsep-2\fboxrule\relax}\r
+\textbf{Put Function:}\r
+\begin{algorithmic}[1]\r
+\Function{PutSlotServer}{$sv_p$}\r
+    \State $s_p \gets n$\r
+    \State $n \gets n + 1$\r
+    \State $SL \gets SL \cup \{\tuple{s_p,sv_p}\}$\r
+\EndFunction\r
+\end{algorithmic}\r
+\end{varwidth}% \r
+}\r
+\r
+\subsection{\textbf{Get Slot}}\r
+Get slot is an operation that returns all server slots that are greater than some server sequence number.\\\r
+\r
+% Get Function\r
+\noindent\fbox{%\r
+\begin{varwidth}{\dimexpr\linewidth-2\fboxsep-2\fboxrule\relax}\r
+\textbf{Get Function:}\r
+\begin{algorithmic}[1]\r
+\Function{GetSlotServer}{$s_g$}\r
+    \State \Return{$\{\tuple{s, sv} \in SL \mid s \geq s_g\}$}\r
+\EndFunction\r
+\end{algorithmic}\r
+\end{varwidth}% \r
+}\r
+\r
+\subsection{\textbf{Delete Slot}}\r
+Delete slot is an operation that deletes all live slots that have server sequence numbers that are equal to or less than some server sequence number.\\\r
+\r
+%Delete Function\r
+\noindent\fbox{%\r
+\begin{varwidth}{\dimexpr\linewidth-2\fboxsep-2\fboxrule\relax}\r
+\textbf{Delete Function:}\r
+\begin{algorithmic}[1]\r
+\Function{DeleteSlotServer}{$s_d$}\r
+    \State $SD \gets \{\tuple{s, sv} \in SL \mid s \leq s_g\}$\r
+    \State $SL \gets SL - SD$\r
+\EndFunction\r
+\end{algorithmic}\r
+\end{varwidth}% \r
+}\r
+\r
+\r
+\r
+\r
+\section{\textbf{Client}}\r
+The data structure acts as a key store where key-value pairs can be read and set.\r
+The data structure exposes the following functions:\r
+\begin{itemize}\r
+    \item Put Transaction\r
+    \item Get key-value pair\r
+    \item Create new key\r
+\end{itemize}\r
+\r
+\r
+\subsubsection{\textbf{Types of Payloads}}\r
+The different types of record payloads are:\r
+\begin{itemize}\r
+    \item Transactions\r
+        \begin{itemize}\r
+            \item Used to make updates to key value pairs.\r
+        \end{itemize}\r
+    \item Commit notifications\r
+        \begin{itemize}\r
+            \item Contains the commit of a single transaction, the whole transaction.\r
+            \item There is 1 commit per transaction.\r
+            \item Generated by the arbitrator for the set of key-value gets and sets in the transaction.\r
+        \end{itemize}\r
+    \item Abort notifications\r
+        \begin{itemize}\r
+            \item Causes a transaction to be aborted, key-values not used in updates.\r
+        \end{itemize}\r
+    \item Data structure re-size notifications\r
+        \begin{itemize}\r
+            \item Contains new size of data structure (number of record allowed in the data structure or something like that).\r
+        \end{itemize}\r
+    \item Server sequence number confirmations.\r
+        \begin{itemize}\r
+            \item Created by any device if that device finds a record with a server sequence number that does not have a server sequence number conformation yet.\r
+        \end{itemize}\r
+    \item Delete notifications\r
+        \begin{itemize}\r
+            \item Generated when a device deletes a record.\r
+            \item records the record that was last deleted\r
+        \end{itemize}\r
+    \item New Key notification\r
+        \begin{itemize}\r
+            \item Generated when a device generates a new (never used) key-value pair.\r
+        \end{itemize}\r
+\end{itemize}\r
+\r
+\subsection{\textbf{Client Notation Conventions}}\r
+\r
+$K$ is the set of all keys.\\\r
+$MID$ is the set of the machine IDs of the devices that are in the system.\r
+$K_{mid}$ is a set of all keys that have device mid as the arbitrator\\\r
+$ssn_s$ is the server sequence number of a record $s$\\\r
+$mid_s \in MID$ is the machine ID for the device that created $record_s$.\\\r
+$hmac_s$ is the HMAC of $record_s$\\\r
+$c_{mid}$ is the latest read clock for a device with machine ID $mid$\\\r
+$vc_s = \{c_{mid} | mid \in MID\}$\\\r
+$rid_s = \tuple{mid_s, c_{mid_s}}$\r
+$k$ is a key entry\\\r
+$v$ is a value entry\\\r
+$kv_n$ is a key-value entry $\tuple{k_n,v_n} , k \in K$\\\r
+\r
+$tid_s = \tuple{mid_s,c_{mid_s}}$\\\r
+$guard_s = \tuple{\{kv_1, kv_2, ... ,kv_n | \exists mid \in MID, \forall n, kv_n[k] \in K_{mid}\},$ boolean condition using $ \{kv_1, kv_2, ... ,kv_n\}} $\\\r
+$transaction_s = \tuple{mid_s,vc_{s_t} ,\{kv_1, kv_2,...kv_n | \exists mid \in MID, mid = guard_s[mid], \forall n, kv_n[k] \in K_{mid}\},guard_s}$\\\r
+$commit_s = \tuple{tid_s,vc_s}$\\\r
+$abort_s = \tuple{tid_s,mid_s,vc_s}$\\\r
+$sequence_s = \tuple{rid_s, ssn_s}$\\\r
+$delete_s = \tuple{ssn_d}$\\\r
+$resize_s = \tuple{x | x \in \mathbb{N}}$\\\r
+$newkey_s = \tuple{k_s, vc_s, ssn_s$ or $NULL, mid_s}$\\\r
+\r
+$payload_s = \{x_1, x_2,..., x_k | \forall k, x_k \in \{$transaction, commit, abort, resize, newkey, sequence, delete$\}\}$\\\r
+$rd_s = \tuple{mid_s, vc_s, hmac_s, payload_s}$ \\\r
+$record_s = \tuple{ssn_s,rd_s}$\\\r
+\r
+\subsection{\textbf{Client State}}\r
+\textit{s = largest server sequence number pulled from the server by a device} \\\r
+\textit{R = set of records pulled from the server so far with their server sequence numbers} \\\r
+\r
+\subsection{Helper Functions}\r
+The following helper functions are needed:\\\r
+\r
+% Error\r
+\noindent\fbox{%\r
+\begin{varwidth}{\dimexpr\linewidth-2\fboxsep-2\fboxrule\relax}\r
+\textbf{ Error:}\r
+\begin{algorithmic}[1]\r
+\Function{Error}{$msg$}\r
+    \State $Print(msg)$\r
+    \State $Halt()$\r
+\EndFunction\r
+\end{algorithmic}\r
+\end{varwidth}% \r
+}\r
+\r
+%Get Payload Items from Record with SSN\r
+\noindent\fbox{%\r
+\begin{varwidth}{\dimexpr\linewidth-2\fboxsep-2\fboxrule\relax}\r
+\textbf{Get Payload Items from Record with SSN}:\r
+\begin{algorithmic}[1]\r
+\Function{GetPayloadItemsWithSSN}{$record_s$}\r
+    \State $PISSN \gets \emptyset$ \Comment{Set of Payload Items with ssn}\r
+    \State $\tuple{ssn_s, rd_s} \gets record_s$\r
+    \State $\tuple{mid_s, vc_s, hmac_s, payload_s} \gets rd_s$\\\r
+    \r
+    \ForAll{$payloadItems$ in $payload_s$}\r
+        \State $PISSN \gets PISSN \cup \{\tuple{payloadItem, ssn_s}\}$\r
+    \EndFor\\\r
+    \r
+    \State \Return {$PISSN$}\r
+\EndFunction\r
+\end{algorithmic}\r
+\end{varwidth}% \r
+}\r
+\r
+%Get rid of record\r
+\noindent\fbox{%\r
+\begin{varwidth}{\dimexpr\linewidth-2\fboxsep-2\fboxrule\relax}\r
+\textbf{Get rid of record:}\r
+\begin{algorithmic}[1]\r
+\Function{GetRid}{$record_s$}\r
+    \State $\tuple{ssn_s, \tuple{mid_s, \{c_{mid_1}, c_{mid_2}, ... , c_{mid_k}\}, hmac_s, payload_s}} \gets record_s$\r
+    \State \Return {$\tuple{mid_s, c_{mid_s}}$}\r
+\EndFunction\r
+\end{algorithmic}\r
+\end{varwidth}% \r
+}\r
+\r
+%Get tid of transaction\r
+\noindent\fbox{%\r
+\begin{varwidth}{\dimexpr\linewidth-2\fboxsep-2\fboxrule\relax}\r
+\textbf{Get tid of transaction:}\r
+\begin{algorithmic}[1]\r
+\Function{GetTid}{$transaction_s$}\r
+    \State $\tuple{ssn_s,\{c_{mid_1}, c_{mid_2}, ... , c_{mid_k}\}, \{kv_1, kv_2,...kv_n\}, guard_s} \gets record_s$\r
+    \State \Return {$\tuple{mid_s, c_{mid_s}}$}\r
+\EndFunction\r
+\end{algorithmic}\r
+\end{varwidth}% \r
+}\r
+\r
+%Key Value Live\r
+%\noindent\fbox{%\r
+%\begin{varwidth}{\dimexpr\linewidth-2\fboxsep-2\fboxrule\relax}\r
+\textbf{Key Value Live:}\r
+\begin{algorithmic}[1]\r
+\Function{KeyValueLive}{$keyName_s, transaction_s$}\r
+    \State $API \gets \emptyset$   \Comment{Set of all Payload Items}\r
+    \State $AT \gets \emptyset$    \Comment{Set of all Payload Items that are transactions}\r
+    \State $AC \gets \emptyset$    \Comment{Set of all Payload Items that are commits}\r
+    \State $AA \gets \emptyset$    \Comment{Set of all Payload Items that are aborts}\r
+    \State $commitTrans = NULL$\r
+    \State $tid \gets $ \Call{GetTid}{$transaction_s$}\\\r
+\r
+    \ForAll{$record$ in $R$}\r
+        \State $API \gets API \cup$ \Call{GetPayloadItemsWithSSN}{record}\r
+    \EndFor\\\r
+    \r
+    \ForAll{$\tuple{ssn, payload}$ in $API$}\r
+        \If{$payload$ is a $transaction$}\r
+            \State $AT \gets AT \cup \{payload\}$\r
+        \ElsIf{$payload$ is a $commit$}\r
+            \State $AC \gets AC \cup \{payload\}$\r
+        \ElsIf{$payload$ is a $abort$}\r
+            \State $AA \gets AA \cup \{payload\}$\r
+        \EndIf\r
+    \EndFor\\\r
+    \r
+    \ForAll{$\tuple{tid',mid',vc'}$ in $AA$} \Comment{Has an abort}\r
+        \If{$tid' = tid$}\r
+            \State \Return{False}\r
+        \EndIf\r
+    \EndFor\\\r
+\r
+    \ForAll{$\tuple{tid',vc'}$ in $AC$} \Comment{Has a commit}\r
+        \If{$tid' = tid$}\r
+            \State $commitTrans \gets \tuple{tid',vc'}$\r
+            \State Break\r
+        \EndIf\r
+    \EndFor\\\r
+    \r
+    \If{$commitTrans = NULL$}   \r
+        \State \Return{True} \Comment{If transaction not yet committed then alive}\r
+    \EndIf\\\r
+    \r
+    \State $\tuple{tid_c, vc_c} \gets commitTrans$\r
+    \ForAll{$trans$ in $AT$}\r
+        \State $\{mid_t,vc_t ,\{\tuple{k_1, v_1}, \tuple{k_2, v_2},..., \tuple{k_k, v_k}\},guard_t\} \gets trans$\r
+        \If{$(trans \neq transaction_s) \land (keyName_s = k_n)$}\r
+            \ForAll{$\tuple{tid_c',vc_c'}$ in $AC$}\r
+                \If{$(tid_c = $ \Call{GetTid}{$trans$} $) \land (vc_c' > vc_c)$}\r
+                    \State \Return{False}\r
+                \EndIf\r
+            \EndFor\r
+        \EndIf\r
+    \EndFor\\\r
+    \r
+    \State \Return{True}\r
+    \r
+\EndFunction\r
+\end{algorithmic}\r
+%\end{varwidth}% \r
+%}\r
+\r
+%Sequence Live\r
+\noindent\fbox{%\r
+\begin{varwidth}{\dimexpr\linewidth-2\fboxsep-2\fboxrule\relax}\r
+\textbf{Sequence Live}:\r
+\begin{algorithmic}[1]\r
+\Function{SequenceLive}{$sequence_s, ssn_{s1}$}\r
+    \State $API \gets \emptyset$   \Comment{Set of all Payload Items}\r
+    \State $AS \gets \emptyset$    \Comment{Set of all Payload Items that are sequences}\r
+    \State $StillHasRecord \gets False$\r
+    \State $\tuple{rid_s, ssn_{s2}} \gets sequence_s$\\\r
+    \r
+    \ForAll{$record$ in $R$}\r
+        \State $API \gets API \cup$ \Call{GetPayloadItemsWithSSN}{record}\r
+        \If{$rid_s = $\Call{GetRid}{$record$}}\r
+            \State $StillHasRecord \gets True$\r
+        \EndIf\r
+    \EndFor\\\r
+    \r
+    \If{$\lnot StillHasRecord$}  \Comment{The Record does not exists anymore}\r
+        \State \Return{False}\r
+    \EndIf\\\r
+    \r
+    \ForAll{$\tuple{ssn, payload}$ in $API$}\r
+        \If{$payload$ is a $sequence$}\r
+            \State $AS \gets AS \cup \{\tuple{ssn, payload}\}$   \Comment{Extract all sequence payloads}\r
+        \EndIf\r
+    \EndFor\\\r
+    \r
+    \ForAll{$\tuple{ssn_1', \tuple{rid', ssn_2'}}$ in $AS$}\r
+        \If{$(rid'=rid_s) \land (ssn_1' > ssn_{s_1})$}\r
+            \State \Return{False}\r
+        \EndIf\r
+    \EndFor \\\r
+    \State \Return{True}\r
+\EndFunction\r
+\end{algorithmic}\r
+\end{varwidth}% \r
+}\r
+\r
+% Delete Live\r
+\noindent\fbox{%\r
+\begin{varwidth}{\dimexpr\linewidth-2\fboxsep-2\fboxrule\relax}\r
+\textbf{Delete Live}:\r
+\begin{algorithmic}[1]\r
+\Function{DeleteLive}{$delete_s, ssn_s$}\r
+    \State $API \gets \emptyset$   \Comment{Set of all Payload Items}\r
+    \State $AD \gets \emptyset$    \Comment{Set of all Payload Items that are deletes}\r
+    \State $\tuple{ssn_d} \gets delete_s$\\\r
+    \r
+    \ForAll{record in R}\r
+        \State $API \gets API \cup$ \Call{GetPayloadItemsWithSSN}{record}\r
+    \EndFor\\\r
+    \r
+    \ForAll{$\tuple{ssn, payload}$ in $API$}\r
+        \If{$payload$ is a $delete$}\r
+            \State $AD \gets AD \cup \{\tuple{ssn, payload}\}$   \Comment{Extract all delete payloads}\r
+        \EndIf\r
+    \EndFor\\\r
+    \r
+    \ForAll{delete in AD}\r
+        \State $\tuple{{ssn_s}', \tuple{{ssn_d}'}} \gets delete$\r
+        \If{${ssn_d}' > ssn_d$}    \Comment{More recently deleted record}\r
+            \State \Return{False}\r
+        \ElsIf{$({ssn_d}'= ssn_d) \land ({ssn_s}' > ssn_s)$} \Comment{More recent delete of same record}\r
+            \State \Return{False}\r
+        \EndIf\r
+    \EndFor \\\r
+    \State \Return{True}\r
+\EndFunction\r
+\end{algorithmic}\r
+\end{varwidth}% \r
+}\r
+\r
+%Abort Live\r
+\noindent\fbox{%\r
+\begin{varwidth}{\dimexpr\linewidth-2\fboxsep-2\fboxrule\relax}\r
+\textbf{Abort Live}:\r
+\begin{algorithmic}[1]\r
+\Function{AbortLive}{$abort_s$}\r
+    \State $API \gets \emptyset$   \Comment{Set of all Payload Items}\r
+    \State $tid \gets NULL$\r
+    \State $\tuple{tid_s,mid_s,vc_s} \gets abort_s$\\\r
+\r
+    \ForAll{$record$ in $R$}\r
+        \State $API \gets API \cup$ \Call{GetPayloadItemsWithSSN}{record}\r
+    \EndFor\\\r
+    \r
+    \ForAll{$\tuple{ssn, payload}$ in $API$} \Comment{Transaction still in data structure}\r
+        \If{$payload$ is a $transaction$}\r
+            \State $tid \gets $\Call{GetTid}{$payload$}\r
+            \If{$tid = tid_s$}\r
+                \State Return{True}\r
+            \EndIf\r
+        \EndIf\r
+    \EndFor\\\r
+    \r
+    \r
+    \r
+    \ForAll{record in R}\r
+        \State $\tuple{ssn_s',\tuple{mid_s', vc_s', hmac_s', payload_s'}} \gets record$\r
+        \If{$(mid_s'=mid_s) \land (vc_s' > vc_s)$}\r
+            \State \Return{False}\r
+        \EndIf\r
+    \EndFor\\\r
+    \State \Return{True}\r
+\EndFunction\r
+\end{algorithmic}\r
+\end{varwidth}% \r
+}\r
+\r
+%Resize Live\r
+\noindent\fbox{%\r
+\begin{varwidth}{\dimexpr\linewidth-2\fboxsep-2\fboxrule\relax}\r
+\textbf{Resize Live}:\r
+\begin{algorithmic}[1]\r
+\Function{ResizeLive}{$resize_s, ssn_s$}\r
+    \State $API \gets \emptyset$   \Comment{Set of all Payload Items}\r
+    \State $AR \gets \emptyset$    \Comment{Set of all Payload Items that are resize}\r
+    \State $\tuple{size} \gets resize_s$\\\r
+    \r
+    \ForAll{record in R}\r
+        \State $API \gets API \cup$ \Call{GetPayloadItemsWithSSN}{record}\r
+    \EndFor\\\r
+    \r
+    \ForAll{$\tuple{ssn, payload}$ in $API$}\r
+        \If{$payload$ is a $resize$}\r
+            \State $AR \gets AR \cup \{\tuple{ssn, payload}\}$   \Comment{Extract all resize payloads}\r
+        \EndIf\r
+    \EndFor\\\r
+    \r
+    \ForAll{$\tuple{ssn', \tuple{size'}}$ in $AR$}\r
+        \If{$size' > size$}\r
+            \State \Return{False}\r
+        \ElsIf{$(size'=size) \land (ssn' > ssn_s)$}\r
+            \State \Return{False}\r
+        \EndIf\r
+    \EndFor \\\r
+    \State \Return{True}\r
+\EndFunction\r
+\end{algorithmic}\r
+\end{varwidth}% \r
+}\r
+\r
+%New Key Live\r
+\noindent\fbox{%\r
+\begin{varwidth}{\dimexpr\linewidth-2\fboxsep-2\fboxrule\relax}\r
+\textbf{New Key Live:}\r
+\begin{algorithmic}[1]\r
+\Function{NewKeyLive}{$newkey_s, ssn_r$}\r
+    \State $API \gets \emptyset$   \Comment{Set of all Payload Items}\r
+    \State $ANK \gets \emptyset$    \Comment{Set of all Payload Items that are new keys}\r
+    \State $\tuple{k_s, vc_s, ssn_s, mid_s}\gets newkey_s$\\\r
+    \r
+    \If{$ssn_s = NULL$}                    \Comment{Make sure ssn is the correct one}\r
+        \State $ssn_s \gets ssn_r$\r
+    \EndIf\\\r
+    \r
+    \ForAll{record in R}\r
+        \State $API \gets API \cup$ \Call{GetPayloadItemsWithSSN}{record}\r
+    \EndFor\\\r
+    \r
+    \ForAll{$\tuple{ssn', payload'}$ in $API$}\r
+        \If{$payload'$ is a $newkey$}\r
+            \State $ANK \gets ANK \cup \{\tuple{ssn', payload'}\}$   \Comment{Extract all new key payloads}\r
+        \EndIf\r
+    \EndFor\\\r
+    \r
+    \ForAll{$\tuple{ssn', \tuple{k_s', vc_s', ssn_s', mid_s'}}$ in $ANK$}\r
+        \If{$vc_s' < vc_s$}\r
+            \State \Return{False}\r
+        \ElsIf{$\lnot (vc_s' < vc_s) \land (ssn_s' < ssn_s)$}\r
+            \State \Return{False}\r
+        \EndIf\r
+    \EndFor \\\r
+    \State \Return{True}\r
+\EndFunction\r
+\end{algorithmic}\r
+\end{varwidth}% \r
+}\r
+\r
+%Transaction Live\r
+\noindent\fbox{%\r
+\begin{varwidth}{\dimexpr\linewidth-2\fboxsep-2\fboxrule\relax}\r
+\textbf{Transaction Live:}\r
+\begin{algorithmic}[1]\r
+\Function{TransactionLive}{$transaction_s$}\r
+    \State $AA \gets \emptyset$    \Comment{Set of all Payload Items that are aborts}\r
+    \State $AC \gets \emptyset$    \Comment{Set of all Payload Items that are commits}\r
+    \State $API \gets \emptyset$   \Comment{Set of all Payload Items}\r
+    \State $tid \gets $ \Call{GetTid}{$transaction_s$}\r
+    \State $foundCommit \gets False$\\\r
+    \r
+    \ForAll{$record$ in $R$}\r
+        \State $API \gets API \cup$ \Call{GetPayloadItemsWithSSN}{record}\r
+    \EndFor\\\r
+    \r
+    \ForAll{$\tuple{ssn, payload}$ in $API$}\r
+        \If{$payload$ is a $abort$}\r
+            \State $AA \gets AA \cup \{payload\}$\r
+        \ElsIf{$payload$ is a $commit$}\r
+            \State $AC \gets AC \cup \{payload\}$\r
+        \EndIf\r
+    \EndFor\\\r
+    \r
+    \ForAll{$\tuple{tid',mid',vc'}$ in $AA$} \Comment{There is an abort}\r
+        \If{$tid' = tid$}\r
+            \State \Return{False}\r
+        \EndIf\r
+    \EndFor\\\r
+    \r
+    \ForAll{$\tuple{tid',vc'}$ in $AC$} \Comment{There is no commit}\r
+        \If{$tid' = tid$}\r
+            \State $foundCommit \gets True$\r
+            \State Break\r
+        \EndIf\r
+    \EndFor\\\r
+    \r
+    \If{$\lnot foundCommit$}\r
+        \State \Return{True}\r
+    \EndIf\\\r
+    \r
+    \State $\tuple{mid',vc' ,kvSet',guard'} \gets transaction_s$ \Comment{All Keys are dead}\r
+    \ForAll{$\tuple{k',v'}$ in $kvSet'$}\r
+        \If{\Call{KeyValueLive}{$k', transaction_s$}}\r
+            \State \Return{True}\r
+        \EndIf\r
+    \EndFor\r
+\r
+    \State \Return{False}\r
+\r
+\EndFunction\r
+\end{algorithmic}\r
+\end{varwidth}% \r
+}\r
+\r
+%Commit Live\r
+\noindent\fbox{%\r
+\begin{varwidth}{\dimexpr\linewidth-2\fboxsep-2\fboxrule\relax}\r
+\textbf{Commit Live:}\r
+\begin{algorithmic}[1]\r
+\Function{CommitLive}{$commit_s, ssn_s$}\r
+    \State $API \gets \emptyset$   \Comment{Set of all Payload Items}\r
+    \State $AT \gets \emptyset$    \Comment{Set of all Payload Items that are transaction}\r
+    \State $tid' \gets NULL$ \r
+    \State $\tuple{tid, vc} \gets commit_s$ \\ \r
+\r
+    \ForAll{$record$ in $R$}\r
+        \State $API \gets API \cup$ \Call{GetPayloadItemsWithSSN}{record}\r
+    \EndFor\\\r
+    \r
+    \ForAll{$\tuple{ssn, payload}$ in $API$}\r
+        \If{$payload$ is a $transaction$}\r
+            \State $tid' \gets$ \Call{GetTid}{$payload$}\r
+            \If{$tid' = tid$}\r
+                \State \Return{True}\r
+            \EndIf\r
+        \EndIf\r
+    \EndFor\\\r
+\r
+    \State \Return{False}\r
+\EndFunction\r
+\end{algorithmic}\r
+\end{varwidth}% \r
+}\r
+\r
+%Is Live\r
+\noindent\fbox{%\r
+\begin{varwidth}{\dimexpr\linewidth-2\fboxsep-2\fboxrule\relax}\r
+\textbf{Is Live:}:\r
+\begin{algorithmic}[1]\r
+\Function{IsLive}{$item_s, ssn_S$}\r
+    \If{$item_s$ is a $tansaction$}\r
+        \State \Return{\Call{TransactionLive}{$item_s$}}\r
+    \r
+    \ElsIf{$item_s$ is a $commit$}\r
+        \State \Return{\Call{CommitLive}{$item_s, ssn_s$}}\r
+    \r
+    \ElsIf{$item_s$ is a $abort$}\r
+        \State \Return{\Call{AbortLive}{$item_s$}}\r
+            \r
+    \ElsIf{$item_s$ is a $delete$}\r
+        \State \Return{\Call{DeleteLive}{$item_s, ssn_s$}}\r
+        \r
+    \ElsIf{$item_s$ is a $commit$}\r
+        \State \Return{\Call{ResizeLive}{$item_s, ssn_s$}}\r
+        \r
+    \ElsIf{$item_s$ is a $sequence$}\r
+        \State \Return{\Call{SequenceLive}{$item_s, ssn_s$}}\r
+        \r
+    \ElsIf{$item_s$ is a $newkey$}\r
+        \State \Return{\Call{NewKeyLive}{$item_s, ssn_s$}}\r
+        \r
+    \ElsIf{$item_s$ is a $keyvalue$}\r
+        \State \Return{\Call{KeyValueLive}{$item_s, ssn_s$}}\r
+    \EndIf\\\r
+    \r
+    \State \Return{False}  \Comment{Will never get here}\r
+\EndFunction\r
+\end{algorithmic}\r
+\end{varwidth}% \r
+}\r
+\r
+%Record has live payload data\r
+\noindent\fbox{%\r
+\begin{varwidth}{\dimexpr\linewidth-2\fboxsep-2\fboxrule\relax}\r
+\textbf{Record has live payload data:}:\r
+\begin{algorithmic}[1]\r
+\Function{HasLivePayload}{$record_s, ssn_s$}\r
+    \State $\tuple{mid_s, vc_s, hmac_s, payload_s} \gets record_s$\r
+    \ForAll{$item$ in $payload_s$}\r
+        \If{\Call{IsLive}{$item, ssn_s$}}\r
+            \State \Return{True}\r
+        \EndIf\r
+    \EndFor\r
+    \State \Return{False}\r
+\EndFunction\r
+\end{algorithmic}\r
+\end{varwidth}% \r
+}\r
+\r
+% Get Data Structure Size\r
+\noindent\fbox{%\r
+\begin{varwidth}{\dimexpr\linewidth-2\fboxsep-2\fboxrule\relax}\r
+\textbf{Get Data Structure Size:}\r
+\begin{algorithmic}[1]\r
+\Function{GetDataStrucSize}{ }\r
+    \State $API \gets \emptyset$   \Comment{Set of all Payload Items}\r
+    \State $AR \gets \emptyset$    \Comment{Set of all Payload Items that are resize}\r
+\r
+    \ForAll{record in R}\r
+        \State $API \gets API \cup$ \Call{GetPayloadItemsWithSSN}{record}\r
+    \EndFor\\\r
+    \r
+    \ForAll{$\tuple{ssn, payload}$ in $API$}\r
+        \If{($payload$ is a $resize) \land$ \Call{IsLive}{$payload, ssn$}}\r
+            \State $\tuple{size'} \gets payload$\r
+            \State \Return{$size'$}\r
+        \EndIf\r
+    \EndFor\\\r
+    \r
+    \State \Return{$0$}  \Comment{Get Here only if data structure has no entries}\r
+\EndFunction\r
+\end{algorithmic}\r
+\end{varwidth}% \r
+}\r
+\r
+%Rescue New Key\r
+\noindent\fbox{%\r
+\begin{varwidth}{\dimexpr\linewidth-2\fboxsep-2\fboxrule\relax}\r
+\textbf{Rescue New Key:}\r
+\begin{algorithmic}[1]\r
+\Function{RescueNewKey}{$newKeyPayload, ssn$}\r
+    \State $\tuple{k', vc', ssn', mid'} \gets newKeyPayload$\r
+    \State \Return{$\tuple{k', vc', ssn, mid'}$}\r
+\EndFunction\r
+\end{algorithmic}\r
+\end{varwidth}% \r
+}\r
+\r
+%Rescue Transaction\r
+\noindent\fbox{%\r
+\begin{varwidth}{\dimexpr\linewidth-2\fboxsep-2\fboxrule\relax}\r
+\textbf{Rescue New Key:}\r
+\begin{algorithmic}[1]\r
+\Function{RescueTransaction}{$transPayload, ssn$}\r
+    \State $KVRescue \gets \emptyset$\r
+    \State $\tuple{mid',vc', KVSet,guard_s} \gets transPayload$\\\r
+    \r
+    \ForAll{$\tuple{k,v}$ in $KVSet$}\r
+        \If{\Call{KeyValueLive}{$k, transPayload$}}\r
+            \State $KVRescue \gets KVRescue \cup \{\tuple{k,v}\}$\r
+        \EndIf\r
+    \EndFor\\\r
+    \r
+    \State \Return{$\tuple{mid',vc', KVRescue,guard_s}$}\r
+\EndFunction\r
+\end{algorithmic}\r
+\end{varwidth}% \r
+}\r
+\r
+\r
+%Rescue Payload Items\r
+\noindent\fbox{%\r
+\begin{varwidth}{\dimexpr\linewidth-2\fboxsep-2\fboxrule\relax}\r
+\textbf{Rescue Payload Items}:\r
+\begin{algorithmic}[1]\r
+\Function{RescuePayloadItems}{$payload_s$}\r
+    \State $PIList =$ empty list of $\tuple{ssn, payload}$\r
+    \State $SpaceRemaining = MaxPayloadSize - $ \Call{GetSize}{$payload_s$}\r
+    \r
+    \If{$SpaceRemaining = 0$}\r
+        \Return{$payload_s$}\r
+    \EndIf\\\r
+    \r
+    \ForAll{record in R}\r
+        \State $PIList \gets PIList \cup$ \Call{GetPayloadItemsWithSSN}{$record$}\r
+    \EndFor\\\r
+    \r
+    \State Sort $PIList$ by $ssn$ from lowest to highest\\\r
+    \r
+    \ForAll{$\tuple{ssn', payload'}$ in $PIList$}\r
+        \If{\Call{IsLive}{$payload', ssn'$} $\land$ \Call{getRandomBoolean}{ } }\\\r
+            \r
+            \If{$payload'$ is a $newkey$}\r
+                \State $payload' \gets $ \Call{RescueNewKey}{$payload'$}\r
+            \ElsIf{$payload'$ is a $transaction$}\r
+                \State $payload' \gets $ \Call{RescueTransaction}{$payload'$}\r
+            \EndIf\\\r
+        \r
+            \If{\Call{GetSize}{$payload'$} $ > SpaceRemaining$} \Comment{No more space for resuces in payload}\r
+                \State \Return{$payload_s$}\r
+            \EndIf\r
+            \r
+            \State $SpaceRemaining \gets SpaceRemaining -$ \Call{GetSize}{$payload'$}\r
+            \State $payload_s \gets payload_s \cup \{payload'\}$\r
+        \EndIf\r
+    \EndFor\\\r
+    \State \Return{$payload_s$}\r
+\EndFunction\r
+\end{algorithmic}\r
+\end{varwidth}% \r
+}\r
+\r
+%Pad Payload\r
+\noindent\fbox{%\r
+\begin{varwidth}{\dimexpr\linewidth-2\fboxsep-2\fboxrule\relax}\r
+\textbf{Pad Payload}:\r
+\begin{algorithmic}[1]\r
+\Function{PadPayload}{$payload_s$}    \State $SpaceRemaining =  MaxPayloadSize - $ \Call{GetSize}{$payload_s$}\r
+    \r
+    \If{$SpaceRemaining = 0$}\r
+        \State \Return{$payload_s$}\r
+    \EndIf\\\r
+    \State \Return{$payload_s \gets payload_s \cup$ \Call{GenerateFiller}{$SpaceRemaining$}}\r
+\EndFunction\r
+\end{algorithmic}\r
+\end{varwidth}% \r
+}\r
+\r
+%Delete Records\r
+\noindent\fbox{%\r
+\begin{varwidth}{\dimexpr\linewidth-2\fboxsep-2\fboxrule\relax}\r
+\textbf{Delete Records (Deletes n records)}:\r
+\begin{algorithmic}[1]\r
+\Function{Delete}{$num\_of\_records$}\r
+    \State $RS \gets$ List of all Records sorted by ssn and has form $\tuple{ssn_s, record_s}$\r
+    \State $n \gets 0$\\\r
+        \r
+    \ForAll{$\tuple{ssn_s, record_s}$ in $RS$}\r
+        \If{\Call{HasLivePayload}{$record_s, ssn_s$}}\r
+            \State \Return{False}\r
+        \Else\r
+            \State \Call{DeleteSlotServer}{$ssn_s$}\r
+            \State $n \gets n + 1$\r
+        \EndIf\\\r
+        \r
+        \If{$n = num\_of\_records$}\r
+            \State \textbf{break}\r
+        \EndIf\r
+    \EndFor\\\r
+    \r
+    \State \Return{True}\r
+    \r
+\EndFunction\r
+\end{algorithmic}\r
+\end{varwidth}% \r
+}\r
+\r
+%Create Resize Data Structure Payload Item\r
+\noindent\fbox{%\r
+\begin{varwidth}{\dimexpr\linewidth-2\fboxsep-2\fboxrule\relax}\r
+\textbf{Create Resize Data Structure Payload Item:}\r
+\begin{algorithmic}[1]\r
+\Function{MakeResizePayload}{ }\r
+    \State $rp \gets$ Empty $resize$ payload\r
+    \State $cs \gets$ \Call{GetDataStrucSize}{ }\r
+    \State $rp \gets \tuple{cs * 2}$\r
+    \State \Return{$\{rp\}$}\r
+\EndFunction\r
+\end{algorithmic}\r
+\end{varwidth}% \r
+}\r
+\r
+%Get Arbitrator\r
+\noindent\fbox{%\r
+\begin{varwidth}{\dimexpr\linewidth-2\fboxsep-2\fboxrule\relax}\r
+\textbf{Get Arbitrator:}\r
+\begin{algorithmic}[1]\r
+\Function{GetArbitrator}{$key$}\r
+    \State $API \gets \emptyset$   \Comment{Set of all Payload Items}\\\r
+\r
+    \ForAll{record in R}\r
+        \State $API \gets API \cup$ \Call{GetPayloadItemsWithSSN}{record}\r
+    \EndFor\\\r
+    \r
+    \ForAll{$\tuple{ssn, payload}$ in $API$}\r
+        \If{($payload$ is a $newkey) \land$ \Call{IsLive}{$payload, ssn$}}\r
+            \State $\tuple{k', vc', ssn', mid'} \gets payload$\r
+            \r
+            \If{$k' = key$}\r
+                \State \Return{$mid'$}\r
+            \EndIf\r
+        \EndIf\r
+    \EndFor\\\r
+    \State \Call{Error}{No arbitrator for key: $key$}\r
+\EndFunction\r
+\end{algorithmic}\r
+\r
+\begin{algorithmic}[1]\r
+\Function{GetArbitrator}{$guard$}\r
+    \State $API \gets \emptyset$   \Comment{Set of all Payload Items}\r
+    \State $\tuple{kvSet, condition} \gets guard$\\\r
+    \r
+    \ForAll{record in R}\r
+        \State $API \gets API \cup$ \Call{GetPayloadItemsWithSSN}{record}\r
+    \EndFor\\\r
+    \r
+    \ForAll{$\tuple{key, value}$ in $kvSet$}\r
+        \ForAll{$\tuple{ssn, payload}$ in $API$}\r
+            \If{($payload$ is a $newkey) \land$ \Call{IsLive}{$payload, ssn$}}\r
+                \State $\tuple{k', vc', ssn', mid'} \gets payload$\r
+                \If{$k' = key$}\r
+                    \State \Return{$mid'$}\r
+                \EndIf\r
+            \EndIf\r
+        \EndFor\r
+    \EndFor\\\r
+    \State \Call{Error}{No arbitrator for key: $key$}\r
+\EndFunction\r
+\end{algorithmic}\r
+\r
+\end{varwidth}% \r
+}\r
+\r
+%Insert Payload\r
+\noindent\fbox{%\r
+\begin{varwidth}{\dimexpr\linewidth-2\fboxsep-2\fboxrule\relax}\r
+\textbf{Insert Payload:}\r
+\begin{algorithmic}[1]\r
+\Function{InsertPayload}{$payload_s$}\r
+    \r
+    \State $numOfRecords \gets |R|+1$\r
+    \State $targetSize \gets $ \Call{GetDataStrucSize}{ }\r
+    \State $numToDelete \gets numOfRecords - targetSize$\r
+    \State $rp \gets NULL$\r
+    \State $hmac \gets NULL$\r
+    \State $vc \gets NULL$\r
+    \State $record \gets NULL$\\\r
+\r
+    \If{\Call{GetSize}{$payload_s$} $> MaxPayloadSize$}\r
+        \State \Call{Error}{Payload too large}\r
+    \EndIf\\\r
+    \r
+    \If{$numToDelete > 0$}\r
+        \If{$\lnot$\Call{Delete}{$numToDelete$}}\r
+            \State $rp \gets$\Call{MakeResizePayload}{ }\r
+            \If{\Call{GetSize}{$payload_s \cup rp$} $> MaxPayloadSize$}\r
+                \State \Call{InsertPayload}{$rp$}\r
+            \Else\r
+                \State $payload_s \gets payload_s \cup rp$\r
+            \EndIf\r
+        \EndIf\r
+    \EndIf\\\r
+    \r
+    \State $payload_s \gets$ \Call{RescuePayloadItems}{$payload_s$}\r
+    \State $payload_s \gets$ \Call{PadPayload}{$payload_s$}\r
+    \State $vc \gets $ \Call{GenerateVectorClock}{ }\r
+    \State \Call{IncrementVectorClock}{ }\r
+    \State $hmac \gets$ \Call{GenerateHmac}{$mid, vc, payload_s$}\r
+    \State $record \gets \tuple{mid,vc,hmac,payload}$\r
+    \State $record \gets $\Call{Encrypt}{$record$}\r
+    \State \Call{PutSlotServer}{$record$}\r
+\EndFunction\r
+\end{algorithmic}\r
+\end{varwidth}% \r
+}\r
+\r
+%Check Data Structure for Malicious Activity\r
+%\noindent\fbox{%\r
+%\begin{varwidth}{\dimexpr\linewidth-2\fboxsep-2\fboxrule\relax}\r
+\textbf{Check Data Structure for Malicious Activity:}\r
+\begin{algorithmic}[1]\r
+\Function{CheckDataStructForValidity}{ }\r
+    \State $API \gets \emptyset$   \Comment{Set of all Payload Items}\r
+    \State $ASeq \gets \emptyset$   \Comment{Set of all Payload Items that are sequences}\r
+    \State $MID \gets \emptyset$   \Comment{Set of all machine IDs}\r
+    \State $midClocks \gets \emptyset$ \Comment{Set of all clocks for the same machine IDs}\r
+    \State $oldestDeletedSsn \gets NULL$\r
+    \State $didFindSsn \gets False$\r
+    \State $didFindClock \gets False$\r
+    \State $hmac \gets NULL$\\\r
+    \r
+    \State Sort $R$ by $ssn$ from smallest $ssn$ to largest $ssn$\\\r
+    \r
+    \ForAll{record in R}\r
+        \State $\tuple{ssn',\tuple{mid', vc', hmac', payload'}} \gets record$\r
+        \State $API \gets API \cup$ \Call{GetPayloadItemsWithSSN}{record}\r
+        \State $MID \gets MID \cup \{mid'\}$\r
+    \EndFor\\\r
+\r
+    \ForAll{$record$ in $R$} \Comment{Check HMACs are all valid}\r
+        \State $\tuple{ssn',\tuple{mid', vc', hmac', payload'}} \gets record$\r
+        \State $hmac \gets $ \Call{GenerateHmac}{$mid', vc', payload'$}\r
+        \If{$hmac \neq hmac'$}\r
+            \State \Call{Error}{HMAC mismatch}\r
+        \EndIf\r
+    \EndFor\\\r
+    \r
+    \ForAll{$record_1$ in $R$} \Comment{Check no SSN duplicates}\r
+        \State $\tuple{ssn_1,rData_1} \gets record_1$\r
+        \ForAll{$record_2$ in $R$}\r
+            \If{$record_2 \neq record_1$}\r
+               \State $\tuple{ssn_2,rData_2} \gets record_2$\r
+               \If{$ssn_2 = ssn_1$}\r
+                    \State \Call{Error}{Duplicate SSN for different records}\r
+               \EndIf\r
+            \EndIf\r
+        \EndFor\r
+    \EndFor\\\r
+    \r
+    \r
+    \ForAll{$record_1$ in $R[0:-1]$} \Comment{Check for missing SSN}\r
+        \State $\tuple{ssn_1,rData_1} \gets record_1$\r
+        \State $didFindSsn \gets False$\r
+        \ForAll{$record_2$ in $R[1:]$}\r
+            \State $\tuple{ssn_2,rData_2} \gets record_2$\r
+            \If{$ssn_2 = (ssn_1 + 1)$}\r
+                \    State $didFindSsn \gets True$\r
+                \State Break\r
+            \EndIf\r
+        \EndFor\r
+        \r
+        \If{$\lnot didFindSsn$}\r
+            \State \Call{Error}{Missing SSN in SSN sequence.}\r
+        \EndIf\r
+    \EndFor\\\r
+    \r
+     \ForAll{$\tuple{ssn, payload}$ in $API$}\r
+        \If{($payload$ is a $delete) \land$ \Call{IsLive}{$payload, ssn$}}\r
+            \State $\tuple{ssn'} \gets payload$\r
+            \State $oldestDeleteSsn \gets ssn'$\r
+        \ElsIf{($payload$ is a $sequence) \land$ \Call{IsLive}{$payload, ssn$}}\r
+            \State $ASeq \gets ASeq \cup \{payload\}$\r
+        \EndIf\r
+    \EndFor\\\r
+    \r
+    \r
+    \ForAll{$record$ in $R$} \Comment{Check SSN's are all valid}\r
+        \State $\tuple{ssn, rData} \gets record$\r
+        \ForAll{$\tuple{rid', ssn'}$ in $ASeq$}\r
+            \If{$(rid' =$ \Call{GetRid}{$record$}$) \land ssn' \neq ssn$}\r
+                \State \Call{Error}{SSN mismatch}\r
+            \EndIf\r
+        \EndFor\r
+    \EndFor\\\r
+    \r
+    \r
+    \State $\tuple{ssn, payload} \gets R[0]$ \Comment{Get first record in the sorted R}\r
+    \If{$ssn > (oldestDeleteSsn + 1) $}\r
+        \State \Call{Error}{Missing records}\r
+   \EndIf\\\r
+    \r
+    \r
+    \ForAll{$mid$ in $MID$}\r
+        \State $midClocks \gets \emptyset$\r
+        \r
+        \ForAll{record in R}\r
+            \State $\tuple{ssn',\tuple{mid', vc', hmac', payload'}} \gets record$\r
+            \If{$mid' = mid$}\r
+                \State $\tuple{c_{mid_1}, c_{mid_2},...,c_{mid_k}} \gets vc'$\r
+                \State $midClocks \gets midClocks \cup \{c_{mid_n}|mid_n=mid\}$\r
+            \EndIf\r
+        \EndFor\\\r
+        \r
+        \State Sort $midClocks$ from smallest clock to largest clock\\\r
+        \r
+        \ForAll{$c_1$ in $midClocks[0:-1]$} \Comment{Check for missing SSN}\r
+            \State $didFindSsn \gets False$\r
+            \ForAll{$c_2$ in $midClocks[1:]$}\r
+                \If{$c_2 = (c_1 + 1)$}\r
+                    \State $didFindC\r
+ock\gets True$\r
+                    \State Break\r
+                \EndIf\r
+            \EndFor\r
+        \EndFor\r
+        \r
+        \If{$\lnot didFindClock$}\r
+            \State \Call{Error}{Missing clock in clock sequence for: $mid$.}\r
+        \EndIf\r
+    \EndFor\\\r
+    \r
+    \State \Comment{If got here then data structure is valid}\r
+\EndFunction\r
+\end{algorithmic}\r
+%\end{varwidth}% \r
+%}\r
+\r
+%Get Latest Data Structure From Server\r
+\noindent\fbox{%\r
+\begin{varwidth}{\dimexpr\linewidth-2\fboxsep-2\fboxrule\relax}\r
+\textbf{Get  Latest Data Structure From Server}:\r
+\begin{algorithmic}[1]\r
+\Function{GetLatestDataStruct}{}\r
+    \State $largestSsn \gets $ Largest $ssn$ of all $ssn$ in $R$\r
+    \State $R \gets R \cup $ \Call{GetSlotServer}{$largestSsn + 1$}\r
+    \State \Call{CheckDataStructForValidity}{ }\r
+\EndFunction\r
+\end{algorithmic}\r
+\end{varwidth}% \r
+}\r
+\r
+%Update Key Value Set\r
+\noindent\fbox{%\r
+\begin{varwidth}{\dimexpr\linewidth-2\fboxsep-2\fboxrule\relax}\r
+\textbf{Update Key Value Set:}\r
+\begin{algorithmic}[1]\r
+\Function{UpdateKVSet}{$currentKV, kvSet$}\r
+    \State $newKVSet \gets kvSet$\r
+    \State $foundKey \gets False$\\\r
+    \r
+    \ForAll{$\tuple{k,v}$ in $currentKV$}\r
+        \State $foundKey \gets False$\\\r
+        \r
+        \ForAll{$\tuple{k',v'}$ in $kvSet$}\r
+            \If{$k = k'$}\r
+                \State $foundKey \gets True$\r
+                \State Break\r
+            \EndIf\r
+        \EndFor\\\r
+        \r
+        \If{$\lnot foundKey$}\r
+            \State $newKVSet \gets newKVSet \cup \{\tuple{k,v}\}$\r
+        \EndIf\r
+    \EndFor\r
+    \r
+    \State \Return{$newKVSet$}\r
+\EndFunction\r
+\end{algorithmic}\r
+\end{varwidth}% \r
+}\r
+\r
+\subsection{\textbf{Create new key}}\r
+This operation creates a key and assigns an arbitrator to arbitrate on that new key.  In the case where more than one clients concurrently try to create the same new key, the client that inserted the newkey payload with the lowest ssn will be the client to generate the key, all other clients generation attempts would be invalid.\r
+\r
+\noindent\fbox{%\r
+\begin{varwidth}{\dimexpr\linewidth-2\fboxsep-2\fboxrule\relax}\r
+\textbf{Create new key:}\r
+\begin{algorithmic}[1]\r
+\Function{CreateNewKey}{$keyName, mid$}\r
+    \State $vc \gets $ \Call{GenerateVectorClock}{ }\r
+    \State $newKeyPayload \gets \tuple{keyName, vc, NULL, mid}$\r
+    \State $API \gets \emptyset$   \Comment{Set of all Payload Items}\\\r
+\r
+    \State \Call{GetLatestDataStruct}{ } \Comment{Update local version of data struct}\\\r
+\r
+    \ForAll{record in R}\r
+        \State $API \gets API \cup$ \Call{GetPayloadItemsWithSSN}{record}\r
+    \EndFor\\\r
+    \r
+    \ForAll{$\tuple{ssn, payload}$ in $API$}\r
+        \If{($payload$ is a $newkey) \land$ \Call{IsLive}{$payload, ssn$}}\r
+            \State $\tuple{k', vc', ssn', mid'} \gets payload$\r
+            \r
+            \If{$k' = key$}\r
+                \State \Return{False}\r
+            \EndIf\r
+        \EndIf\r
+    \EndFor\\\r
+    \r
+    \State \Call{InsertPayload}{$newKeyPayload$}\r
+    \State \Return{True}\r
+\EndFunction\r
+\end{algorithmic}\r
+\end{varwidth}% \r
+}\r
+\r
+\subsection{\textbf{Put Transaction}}\r
+This operation puts a transaction into the data structure if this transaction fits inside a payload.\r
+If by adding this transaction the data structure size exceeds the proposed max data structure size then deletes take place.  If no deletes can take place (too much live data) then the data structure is resized.\\\r
+\r
+%\r
+\noindent\fbox{%\r
+\begin{varwidth}{\dimexpr\linewidth-2\fboxsep-2\fboxrule\relax}\r
+\textbf{Put Transaction:}\r
+\begin{algorithmic}[1]\r
+\Function{PutTransaction}{$kVUpdates, guard$}\r
+    \State $mid \gets NULL$\r
+    \State $vc \gets $ \Call{GenerateVectorClock}{ }\r
+    \State $transPayload \gets NULL$\\\r
+\r
+    \State \Call{GetLatestDataStruct}{ } \Comment{Update local version of data struct}\\\r
+\r
+    \ForAll{$kv$ in $kVUpdates$}\r
+        \State $\tuple{k', v'} \gets kv$\r
+        \r
+        \If{$mid = NULL$}\r
+            \State $mid \gets$ \Call{GetArbitrator}{$k'$}\r
+        \ElsIf{$mid \neq $ \Call{GetArbitrator}{$k'$}}\r
+            \State \Call{Error}{Multiple Arbitrators}\r
+        \EndIf\r
+    \EndFor\\\r
+    \r
+    \If{\Call{GetArbitrator}{$guard$} $\neq mid$}\r
+        \State \Call{Error}{Multiple Arbitrators}\r
+    \EndIf\\\r
+    \r
+    \State $transPayload \gets \tuple{mid, vc, kVUpdates, guard}$\r
+    \State \Call{InsertPayload}{$transPayload$}\r
+\EndFunction\r
+\end{algorithmic}\r
+\end{varwidth}% \r
+}\r
+\r
+\subsection{\textbf{Get key-value pair}}\r
+This operation gets the latest key value pair from the data structure.  This is done by starting at the last known committed key value pairs then extrapolating into the future of uncommitted transactions till the transaction with the largest ssn is reached.  Everytime a new transaction is evaluated, it is evaluated against the current best guess of key value pairs based on the transactions up to the transaction being evaluated (by ssn).  This allows each client to "guess" what the latest value for a specified key will be even when the arbitrator has not stepped in yet to arbitrate.\r
+\r
+%\noindent\fbox{%\r
+%\begin{varwidth}{\dimexpr\linewidth-2\fboxsep-2\fboxrule\relax}\r
+\textbf{Get  Latest Data Structure From Server}:\r
+\begin{algorithmic}[1]\r
+\Function{GetValueForKey}{$keyName$}\r
+    \State $API \gets \emptyset$   \Comment{Set of all Payload Items}\r
+    \State $AT \gets \emptyset$    \Comment{Set of all Payload Items that are transactions}\r
+    \State $AC \gets \emptyset$    \Comment{Set of all Payload Items that are commits}\r
+    \State $AA \gets \emptyset$    \Comment{Set of all Payload Items that are aborts}\r
+    \State $kSet \gets \emptyset$ \Comment{Set of all key names in the system}\r
+    \State $tid \gets NULL$\r
+    \State $currentKV \gets \emptyset$\\\r
+    \r
+    \State \Call{GetLatestDataStruct}{ } \Comment{Update local version of data struct}\\\r
+    \r
+    \ForAll{$record$ in $R$}\r
+        \State $API \gets API \cup$ \Call{GetPayloadItemsWithSSN}{record}\r
+    \EndFor\\\r
+    \r
+    \ForAll{$\tuple{ssn, payload}$ in $API$}\r
+        \If{$payload$ is a $transaction$}\r
+            \State $AT \gets AT \cup \{\tuple{ssn,payload}\}$\r
+        \ElsIf{$payload$ is a $commit$}\r
+            \State $AC \gets AC \cup \{payload\}$\r
+        \ElsIf{$payload$ is a $abort$}\r
+            \State $AA \gets AA \cup \{payload\}$\r
+        \EndIf\r
+    \EndFor\\\r
+    \r
+    \State Sort $AT$ by ssn from oldest to newest\\\r
+    \r
+    \ForAll{$trans$ in $AT$} \Comment{Get the latest committed keys}\r
+        \State $\tuple{mid,vc ,kvSet,guard} \gets trans$\\\r
+    \r
+        \ForAll{$\tuple{k,v}$ in $kvSet$} \Comment{Get all key names in the system}\r
+            \State $kSet \gets kSet \cup \{k\}$\r
+        \EndFor\\\r
+\r
+        \If{$\lnot $\Call{TransactionLive}{$trans$}} \Comment{Only keep live transactions}\r
+            \State $AT \gets AT - \{trans\}$\r
+            \State Continue\r
+        \EndIf\\\r
+    \r
+        \State $tid \gets $ \Call{GetTid}{$trans$}\r
+        \ForAll{$com$ in $AC$}\r
+            \State $\tuple{tid', vc'} \gets com$\r
+            \If{$tid' = tid$}\r
+                \ForAll{$\tuple{k,v}$ in $kvSet$}\r
+                    \If{\Call{KeyValueLive}{$k,trans$}}\r
+                        \State $currentKV \gets currentKV \cup \{\tuple{k,v}\}$\r
+                    \EndIf\r
+                \EndFor\\\r
+                \r
+                \State $AT \gets AT - \{trans\}$ \Comment{No need for committed transactions}\r
+                \State Break\r
+            \EndIf\r
+        \EndFor\r
+    \EndFor\\\r
+    \r
+    \ForAll{$trans$ in $AT$} \Comment{Uncommitted ones only in order from lowest ssn to highest ssn}\r
+        \State $\tuple{mid,vc ,kvSet,guard} \gets trans$\r
+        \If{\Call{EvaluateGuard}{$guard, currentKV$}} \Comment{Check if will abort}\r
+            \State $currentKV \gets $\Call{UpdateKVSet}{$currentKV, kvSet$}\r
+        \EndIf\r
+    \EndFor\\\r
+    \r
+    \r
+    \ForAll{$\tuple{k,v}$ in $currentKV$} \Comment{Return the latest guessed value}\r
+        \If{$k = keyName$}\r
+            \State \Return{$v$}\r
+        \EndIf\r
+    \EndFor\\\r
+    \r
+    \State \Return{$NULL$} \Comment{Key was not present}\r
+    \r
+\EndFunction\r
+\end{algorithmic}\r
+%\end{varwidth}% \r
+%}\r
+\r
+\subsection{\textbf{Arbitrate On Transaction}}\r
+\r
+%\noindent\fbox{%\r
+%\begin{varwidth}{\dimexpr\linewidth-2\fboxsep-2\fboxrule\relax}\r
+\textbf{Get  Latest Data Structure From Server}:\r
+\begin{algorithmic}[1]\r
+\Function{Arbitrate }{ }\r
+    \State $API \gets \emptyset$   \Comment{Set of all Payload Items}\r
+    \State $AT \gets \emptyset$    \Comment{Set of all Payload Items that are transactions}\r
+    \State $AC \gets \emptyset$    \Comment{Set of all Payload Items that are commits}\r
+    \State $AA \gets \emptyset$    \Comment{Set of all Payload Items that are aborts}\r
+    \State $kSet \gets \emptyset$ \Comment{Set of all key names in the system}\r
+    \State $tid \gets NULL$\r
+    \State $currentKV \gets \emptyset$\r
+    \State $newPayload \gets NULL$\r
+    \State $midClient \gets mid$ of this client\\\r
+    \r
+    \State \Call{GetLatestDataStruct}{ } \Comment{Update local version of data struct}\\\r
+    \r
+    \ForAll{$record$ in $R$}\r
+        \State $API \gets API \cup$ \Call{GetPayloadItemsWithSSN}{record}\r
+    \EndFor\\\r
+    \r
+    \ForAll{$\tuple{ssn, payload}$ in $API$}\r
+        \If{$payload$ is a $transaction$}\r
+            \State $AT \gets AT \cup \{\tuple{ssn,payload}\}$\r
+        \ElsIf{$payload$ is a $commit$}\r
+            \State $AC \gets AC \cup \{payload\}$\r
+        \ElsIf{$payload$ is a $abort$}\r
+            \State $AA \gets AA \cup \{payload\}$\r
+        \EndIf\r
+    \EndFor\\\r
+    \r
+    \State Sort $AT$ by ssn from oldest to newest\\\r
+    \r
+    \ForAll{$trans$ in $AT$} \Comment{Get the latest committed keys}\r
+        \State $\tuple{mid,vc ,kvSet,guard} \gets trans$\\\r
+    \r
+        \ForAll{$\tuple{k,v}$ in $kvSet$} \Comment{Get all key names in the system}\r
+            \State $kSet \gets kSet \cup \{k\}$\r
+        \EndFor\\\r
+\r
+        \If{$\lnot $\Call{TransactionLive}{$trans$}} \Comment{Only keep live transactions}\r
+            \State $AT \gets AT - \{trans\}$\r
+            \State Continue\r
+        \EndIf\\\r
+    \r
+        \State $tid \gets $ \Call{GetTid}{$trans$}\r
+        \ForAll{$com$ in $AC$}\r
+            \State $\tuple{tid', vc'} \gets com$\r
+            \If{$tid' = tid$}\r
+                \ForAll{$\tuple{k,v}$ in $kvSet$}\r
+                    \If{\Call{KeyValueLive}{$k,trans$}}\r
+                        \State $currentKV \gets currentKV \cup \{\tuple{k,v}\}$\r
+                    \EndIf\r
+                \EndFor\\\r
+                \r
+                \State $AT \gets AT - \{trans\}$ \Comment{No need for committed transactions}\r
+                \State Break\r
+            \EndIf\r
+        \EndFor\r
+    \EndFor\\\r
+    \r
+    \ForAll{$trans$ in $AT$} \Comment{Uncommitted ones only in order from lowest ssn to highest ssn}\r
+        \State $\tuple{mid,vc ,kvSet,guard} \gets trans$\r
+        \r
+        \If{\Call{GetArbitrator}{$guard$} $\neq midClient$}\r
+            \State Continue\r
+        \EndIf\r
+        \r
+        \If{\Call{EvaluateGuard}{$guard, currentKV$}} \Comment{Check if will abort}\r
+            \State $currentKV \gets $\Call{UpdateKVSet}{$currentKV, kvSet$}\r
+            \State $newPayload \gets \tuple{$\Call{GetTid}{$trans$}$, $\Call{GenerateVectorClock}{ } $}$ \Comment{Make new commit payload}\r
+        \Else\r
+            \State $newPayload \gets \tuple{$\Call{GetTid}{$trans$}$, mid, $\Call{GenerateVectorClock}{ } $}$ \Comment{Make new abort payload}\r
+        \EndIf\\\r
+        \r
+        \State \Call{InsertPayload}{$newPayload$}\r
+    \EndFor\\\r
+    \r
+\EndFunction\r
+\end{algorithmic}\r
+%\end{varwidth}% \r
+%}\r
+\r
+\r
+\r
+\section{\textbf{System Guarantees}}\r
+\begin{itemize}\r
+    \item Server cannot view data inside records\r
+    \item Server cannot forge or modify or create any records\r
+    \item Server cannot withhold any records\r
+    \item Server cannot reorder records that could not have been ordered differently due to network latency\r
+    \item Server cannot delete records unless told to do so.\r
+    \item There will always be an obvious key-value pair that is the latest key value pair.\r
+    \item The data structure is bounded in size such that $m$ is the minimum size of the data structure,  $n$ is the number of devices in the system and $s$ is the current size of the data structure: $m \leq s \leq (m+n-1)$\r
+    \item Data structure can only grow when there are too may key-value pairs (and aborts) than what fit in the current data structure size within reason.\r
+    \item No currently valid data can be lost by the system and go undetected.\r
+    \item Devices can operate offline and re-sync with the system and get a consistent view of the system\r
+    \item If the server tries to hold a device on an older version of the data structure, that device can eventually rejoin the main data structure without problems.\r
+    \item Devices that have a transaction aborted will be able to be notified about the abort indefinitely (no time frame when notification must be accepted).\r
+    \item Server cannot hold a device on an old version of the data structure and then move them to a newer version of the data structure without being detected (The server sequence numbers would reveal conflicts or gaps or both).\r
+\r
+\end{itemize}\r
+\r
+\r
+\end{document}\r
diff --git a/non_block_chain/doc/iotcloud_formal/makefile b/non_block_chain/doc/iotcloud_formal/makefile
new file mode 100644 (file)
index 0000000..cff4a15
--- /dev/null
@@ -0,0 +1,8 @@
+LATEX := pdflatex -halt-on-error
+
+default:
+       $(LATEX) iotcloud.tex
+
+clean:
+       rm -f *.dvi *.log *.aux *.blg *.bbl *~
+       rm -f iotcloud.ps iotcloud.pdf 
diff --git a/non_block_chain/doc/iotcloud_informal/iotcloud.tex b/non_block_chain/doc/iotcloud_informal/iotcloud.tex
new file mode 100644 (file)
index 0000000..01b6449
--- /dev/null
@@ -0,0 +1,437 @@
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Short Sectioned Assignment
+% LaTeX Template
+% Version 1.0 (5/5/12)
+%
+% This template has been downloaded from:
+% http://www.LaTeXTemplates.com
+%
+% Original author:
+% Frits Wenneker (http://www.howtotex.com)
+%
+% License:
+% CC BY-NC-SA 3.0 (http://creativecommons.org/licenses/by-nc-sa/3.0/)
+%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%----------------------------------------------------------------------------------------
+%   PACKAGES AND OTHER DOCUMENT CONFIGURATIONS
+%----------------------------------------------------------------------------------------
+
+\documentclass[paper=letter, fontsize=11pt]{scrartcl} % A4 paper and 11pt font size
+
+\usepackage[T1]{fontenc} % Use 8-bit encoding that has 256 glyphs
+\usepackage{fourier} % Use the Adobe Utopia font for the document - comment this line to return to the LaTeX default
+\usepackage[english]{babel} % English language/hyphenation
+\usepackage{amsmath,amsfonts,amsthm} % Math packages
+\usepackage{graphicx}
+\usepackage{lipsum} % Used for inserting dummy 'Lorem ipsum' text into the template
+\usepackage{hyperref}
+\usepackage{amssymb}
+\usepackage{listings}
+\usepackage[]{algorithm2e}
+\usepackage{algpseudocode}
+\usepackage{enumerate}
+\usepackage[table,xcdraw]{xcolor}
+\usepackage{sectsty} % Allows customizing section commands
+\usepackage{float}
+\usepackage{caption}
+\usepackage{gensymb} % to used degree symbol 
+\usepackage{siunitx} 
+\usepackage{enumitem}
+
+\usepackage[sc]{mathpazo}
+\allsectionsfont{ \normalfont\scshape} % Make all sections the default font and small caps
+\usepackage{fancyhdr} % Custom headers and footers
+\pagestyle{fancyplain} % Makes all pages in the document conform to the custom headers and footers
+\fancyhead{} % No page header - if you want one, create it in the same way as the footers below
+\fancyfoot[L]{} % Empty left footer
+\fancyfoot[C]{} % Empty center footer
+\fancyfoot[R]{\thepage} % Page numbering for right footer
+\renewcommand{\headrulewidth}{0pt} % Remove header underlines
+\renewcommand{\footrulewidth}{0pt} % Remove footer underlines
+\setlength{\headheight}{13.6pt} % Customize the height of the header
+
+\numberwithin{equation}{section} % Number equations within sections (i.e. 1.1, 1.2, 2.1, 2.2 instead of 1, 2, 3, 4)
+\numberwithin{figure}{section} % Number figures within sections (i.e. 1.1, 1.2, 2.1, 2.2 instead of 1, 2, 3, 4)
+\numberwithin{table}{section} % Number tables within sections (i.e. 1.1, 1.2, 2.1, 2.2 instead of 1, 2, 3, 4)
+
+\setlength\parindent{0pt} % Removes all indentation from paragraphs - comment this line for an assignment with lots of text
+
+%----------------------------------------------------------------------------------------
+%   TITLE SECTION
+%----------------------------------------------------------------------------------------
+\newcommand{\horrule}[1]{\rule{\linewidth}{#1}} % Create horizontal rule command with 1 argument of height
+
+\title{ 
+\normalfont \normalsize 
+\textsc{University of California Irvine} \\  % Your university, school and/or department name(s)
+\textsc{Prgramming Language Research Group} \\ [25pt]
+\horrule{0.5pt} \\[0.4cm] % Thin top horizontal rule
+\huge IoTCloud Version 2.0\\ % The assignment title
+\horrule{2pt} \\[0.5cm] % Thick bottom horizontal rule
+}
+
+\author{Authors} % Your name
+
+
+\date{\normalsize\today} % Today's date or a custom date
+
+\begin{document}
+
+\maketitle % Print the title
+
+
+
+
+%---------------------------------------------------------------------------------------
+% Custom Stuff
+%---------------------------------------------------------------------------------------
+\newcommand{\tab}[1]{\hspace{.2\textwidth}\rlap{#1}}
+
+
+
+
+\section{\textbf{Introduction}}
+
+\section{\textbf{Device Approach}}
+
+\subsection{\textbf{Records}}
+Each record has the following information included in it:
+\begin{itemize}
+    \item Machine ID of the device creating the record
+    \item The vector clock using the largest clock values from each device it knows and its own largest clock value incremented by 1.
+    \item Data payload
+    \item HMAC of the record.
+\end{itemize}
+    
+Records can be identified by the machine ID and the local machine clock, hereby referred to as the record ID.
+
+\subsubsection{\textbf{Types of Payloads}}
+The different types of record payloads are:
+\begin{itemize}
+
+    \item Transactions
+        \begin{itemize}
+            \item Contains:
+            \begin{itemize}
+                \item Transaction ID
+                \item key-value pair gets (reads)
+                \item A guard condition (boolean condition) that can be evaluated on the key-value gets.
+                \item A set of key-value pairs that are to be updated if the guard condition is met.
+                \item Can only get and set key-value pairs that are from 1 arbitrator.  Getting and/or setting key-value pairs from more than 1 arbitrator causes the transaction to be invalid and dead.
+            \end{itemize}
+        \end{itemize}
+    \item Commit notifications
+        \begin{itemize}
+            \item Contains the commit of a single transaction, the whole transaction.
+            \item There is 1 commit per transaction.
+            \item Generated by the arbitrator for the set of key-value gets and sets in the transaction.
+        \end{itemize}
+    \item Abort notifications
+        \begin{itemize}
+            \item Contains a transaction ID of an aborted transaction and the machine ID of the device that created that transaction.
+            \item Causes a transaction to be aborted, key-values not used in updates.
+        \end{itemize}
+    \item Data structure re-size notifications
+        \begin{itemize}
+            \item Contains new size of data structure (number of record allowed in the data structure or something like that).
+        \end{itemize}
+    \item Server sequence number confirmations.
+        \begin{itemize}
+            \item Contains a record ID and the server sequence number for that record that the server reported.
+            \item Created by any device if that device finds a record with a server sequence number that does not have a server sequence number conformation yet.
+        \end{itemize}
+    \item Delete notifications
+        \begin{itemize}
+            \item Contain the server sequence number of the record that was deleted.
+            \item Generated when a device deletes a record.
+        \end{itemize}
+    \item New Key notification
+        \begin{itemize}
+            \item Contains the name of a new key and the machine ID of the machine that is to arbitrate
+            \item Generated when a device generates a new (never used) key-value pair.
+        \end{itemize}
+\end{itemize}
+
+\subsection{\textbf{Pulling the data structure}}
+To pull the latest version of the data structure the following is done:
+\begin{enumerate}
+    \item Make a pull request to the server and get all the records sent back.
+    \item Separate the records by machine ID.
+    \item For each machine ID, order the records based on that machine IDs clock within each of the records.
+    \item Check the data structure for any malicious activity (discussed below)
+\end{enumerate}
+
+\subsection{\textbf{Updates}}
+Updates take place as follows:
+\begin{enumerate}
+    \item A device pulls the latest version of the data structure.  If the device cannot pull the latest version because of network connectivity or some other issues then that device will just work using the local copy of the data structure it has.
+    \item Check the pulled data structure for any malicious activity (as stated in a section below) if not done already.
+    \item Check if any records in the current server need to be deleted (have delete notifications in data structure but the delete never took place), if so then delete them.
+    \item Check that the size of the data structure will not exceed the max size when the new record is inserted.  If it does then prepare to delete records by inserting delete payloads in the new record (discussed below).
+    \item The device makes a record as follows:
+        \begin{enumerate}
+            \item Adds its machine ID.
+            \item Creates a vector clock using the largest clock values from each device it knows and its own largest clock value incremented by 1.
+            \item Fill the record payload section with the transactions and other types of payloads.
+            \item Fill the empty space of the record payload with server sequence number confirmations for records that have yet to have their server sequence numbers confirmed.
+            \item Fill the empty space of the record payload with rescued key-value pairs, transactions, ext (Discussed later).
+            \item Pad the record to be the same size for all records.
+            \item Calculate the HMAC of the record and add that to the record
+            \item Encrypt the record.
+        \end{enumerate}
+    \item Send the record to the server for insertion into the device's queue.
+    \item Issue any server commands such as deletes to the server.
+\end{enumerate}
+
+If there is a connectivity issue then all the records will be held by the local device until connection is resumed then pushed to the server in the order which they occurred.  Also the device can only delete records for which there is a server sequence number.  At some point the device could run out of records to delete (it hasn't connected to the server in a while) in which case the device will not be able to delete any records.
+
+\subsection{\textbf{Deletions}}
+When deciding which records to delete the following is to be done:
+\begin{enumerate}
+    \item Order all the records in order based on their server sequence numbers
+    \item Calculate the difference between the current size of the data structure and the minimum size of the data structure (lets call this $m$). Note: count newly inserted records towards the total size of the data structure if doing deletes while doing updates.
+    \item Delete the oldest m records based on the ordering from step 1. 
+    \begin{itemize}
+        \item If a record to be deleted has live data in it then the whole data structure needs to be re-sized.
+    \end{itemize}
+\end{enumerate}
+
+Note this makes that size of the data structure be bounded:
+If there are $n$ devices and the data structure has a minimum size of $m$.  Then the max size of the data structure is given by $m + n -1$ for the case when all the devices make an update at the same time.   
+
+\subsection{\textbf{Reading a key-value pair}}
+When getting a key-value pair the following is done:
+\begin{enumerate}
+    \item A device pulls the latest version of the data structure.  If the device cannot pull the latest version because of network connectivity or some other issues then that device will just work using the local copy of the data structure it has.
+    \item Check the pulled data structure for any malicious activity (as stated in a section below) if not done already.
+    \item Find the transaction with the largest server sequence number that contains the key-value pair of interest (this is the latest value).
+\end{enumerate}
+
+\subsection{\textbf{Rescuing Transactions, Commits, Aborts, Ext}}
+Data should be proactively rescued from the "oldest" records currently in the data structure.  Unused space in new records should be used to rescue data from old records so that when it comes time to delete the old records, there are no live pieces of data that need to be rescued.  When a piece of data is rescued, it is rescued with its vector clock as well (so that the time of that data can be saved).\\
+
+When rescuing transactions and commits: only keep the key-value pair sets that do not have a newer key-value pair set (no other transaction/commits sets that key-value pair later in the future).  This means that transactions/commits can shrink in size.\\
+
+When rescuing Key Value notifications: save the vector clock and the server sequence number of the notification in the rescued data.
+
+When deciding which data to rescue the following is to be done:
+\begin{enumerate}
+    \item Order all the records in order based on their server sequence numbers
+    \item Create an ordered list of currently live transactions, commits, aborts, ext from the oldest $n$ records from step one where the order is based on the age of the data (how old the record is).
+    \item Randomly select from the list of live transactions, commits, aborts, ext to save.  Save as much as can fit in the current new record.  The random selection could give higher probability to transactions, commits, aborts, ext from records that are to be deleted sooner.
+\end{enumerate}
+
+\subsection{\textbf{Checking the Data Structure}}
+Checking the data structure for consistency is done as follows:
+\begin{enumerate}
+    \item Verify that each record in the data structure has an HMAC that matches the data in the record.
+    \item Verify that the oldest record the server sent has a server sequence number that is equal to or less than the server sequence number in the most recent delete notification (currently live delete notification) + 1.
+    \item Make sure that for each device queue the difference between the vector clock value of the device queues clock is at most 1 between 2 consecutive messages for all records with server sequence numbers above the last deleted records server sequence numbers.
+    \item Verify that no currently live data Structure re-size notification is smaller than the last known data structure size.  Data structure can only grow in size.
+    \item Verify that all the server sequence numbers for the records that are currently present have unique numbers.
+    \item Verify that all the server sequence numbers for the records have a difference of 1 (no gaps) for all records with server sequence numbers above the last deleted records server sequence numbers.
+    \item Verify record server sequence numbers against the stated server sequence numbers in the server sequence number notification payloads (make sure the server is not changing the sequence number on the fly).
+\end{enumerate}
+
+\subsection{\textbf{The Arbitrator}}
+The arbitrator can:
+\begin{enumerate}
+    \item Send Commits
+    \item Send Aborts
+\end{enumerate}
+
+\subsubsection{\textbf{Commits}}
+Commits have the following properties
+\begin{itemize}
+    \item Agree with the ordering of the server sequence numbers most of the time.
+    \item Cannot commit an already aborted transaction.
+    \item Commits state the ordering of key-value pairs.
+    \item Can disagree with the ordering of server sequence numbers if arbitrator decides to do so.
+    \item Should occur frequently as to make sure that the commit order matches the server sequence ordering as closely as possible (prevent large divergence of the 2 orderings)
+\end{itemize}
+    
+\subsubsection{\textbf{Aborts}}
+
+\begin{itemize}
+    \item Aborts are used to show which transactions have been aborted based on the arbitrators decision.
+    \item Aborts are considered live until an abort acknowledgement is presented.
+\end{itemize}
+\subsection{\textbf{Setting Up New Keys (Choosing the Arbitrator)}}
+Setting up new keys is done as follows:
+\begin{enumerate}
+    \item Device wishes to generate new key
+    \item Device inserts a New Key notification into the data structure.
+\end{enumerate}
+In the case where multiple devices are creating the same key, the key with the smallest vector clock is the only valid one.  In the case of a concurrent vector clock, the smallest server sequence number notification is the valid one.
+    
+\subsection{\textbf{Live Status}}
+Live Status of entries:
+\begin{enumerate}
+
+    \item Delete notifications
+        \begin{itemize}
+            \item Live if it deleted the largest known server sequence number to be deleted (most recent delete).
+        \end{itemize}
+    
+    \item Commit notifications
+        \begin{itemize}
+            \item Live until all the key-value pair sets in the transaction commit are dead.
+                \begin{itemize}
+                    \item key-value pairs are dead when a commit for a transaction that sets the same key-value pair occurs with a larger vector clock.
+                \end{itemize}
+        \end{itemize}
+    
+    \item Abort notifications
+        \begin{itemize}
+            \item Live until the device whos machine ID is in the abort notification makes an update to the data structure that contains a vector clock that is more in the future than the vector clock for this abort notification.
+        \end{itemize}
+    
+    \item Data structure re-size notifications
+        \begin{itemize}
+            \item Live if it contains the largest target size of the data structure.
+        \end{itemize}
+    
+    \item Server sequence number confirmations.
+         \begin{itemize}
+            \item Live until the record that this notification is reporting on is deleted.
+        \end{itemize}
+        
+    \item Transactions
+        \begin{itemize}
+            \item Is dead if it is invalid (contains keys-values for multiple arbitrators)
+            \item Live until a commit or abort notification for this transaction is generated.
+        \end{itemize}
+        
+    \item New Key notification
+        \begin{itemize}
+            \item Is dead if there exists a New Key notification that has a server sequence number that is smaller and the same key name.
+        \end{itemize}
+    
+\end{enumerate}
+
+\section{\textbf{Server Approach}}
+
+The servers view of the system is in terms of data slots where each data slot holds a single record, has a monotonically increasing number associated with it (server sequence number) for the record that currently is present in that data slot and can be set or deleted.  A server may have a finite amount of memory which it can partition into slots, reusing memory that newly deleted slots used to occupy.
+
+There are 3 types of requests from a device that the server must respond to:
+\begin{enumerate}
+    \item Pull all current slots.
+    \item Put a new record in a slot.
+    \item Delete a slot.
+\end{enumerate}
+
+\subsection{\textbf{Pull all current slots}}
+In this case the server will simply send back all active slots (slots that have data) in any order along with each slots server sequence number.  It is the job of the devices to order the slots.
+
+\subsection{\textbf{Put a new record in a slot}}
+In this case the server will:
+\begin{enumerate}
+    \item Receive a record data from a device.
+    \item Put this record data in an empty slot.
+    \item Assign the just received record the next number in the server sequence numbers.
+\end{enumerate}
+If more than 1 put request is made at the same time, the server is free to order the requests however it wishes.
+
+\subsection{\textbf{Delete a slot}}
+In this case the server will delete the data in the slot that has the server sequence number that matches the server sequence number in the delete request.  The server could delay the delete if it wishes (if it has plenty of space for new slots).
+
+\section{\textbf{Data Structure Abstraction}}
+This section outlines the data structure abstraction that is provided to the IoT application.  It is similar to a hash table key-value store.
+
+Operations on the key-value store:
+\begin{itemize}
+    \item Put operation
+    \item Get operation
+    \item Check put status
+    \item Create New Key Operation. 
+\end{itemize}
+
+\subsection{\textbf{Put Operation}}
+This operation is described as follows:
+\begin{itemize}
+    \item Has the form:  put(Key-value-list, guard)
+    \item Updates the key-value pairs listed in the key-value list.
+    \item Has a boolean guard that is passed in that is able to read from keys that are associated with the same arbitrator as the keys being updated
+    \item Returns an ID for this put (Transaction ID) or an error code if put is formatted incorrectly.
+    \item Underlying action: Creates a transaction, creates a record and inserts that record in the data structure (doing deletes and other house keeping operations as needed).
+\end{itemize}
+
+\subsection{\textbf{Get Operation}}
+\begin{itemize}
+    \item Has the form:  get(key-name)
+    \item Gets the current value of a key, also returns a machine ID for the arbitrator of that key.
+    \item Underlying action:  Does a pull from the server and resolves the latest value for the specified key (as mentioned above).  Also does house keeping work like key rescue and sequence number notification as needed.
+\end{itemize}
+
+\subsection{\textbf{Check put status}}
+\begin{itemize}
+    \item Has the form of a callback.
+    \item Notifies the application of an aborted transaction.
+    \item Underlying action:  when an abort notification is received then the callback is called.  This is checked whenever this application makes changes to the data structure.
+\end{itemize}
+
+\subsection{\textbf{Create New Key Operation}}
+\begin{itemize}
+    \item Has the form:  createKey(key-name, machine-id)
+    \item Creates a new key with an arbitrator at a specific machine ID
+    \item Underlying action: Creates a new key notification, creates a record and inserts that record in the data structure (doing deletes and other house keeping operations as needed).
+\end{itemize}
+
+
+
+\section{\textbf{System Guarantees}}
+\begin{itemize}
+    \item Server cannot view data inside records
+    \item Server cannot forge or modify or create any records
+    \item Server cannot withhold any records
+    \item Server cannot reorder records that could not have been ordered differently due to network latency
+    \item Server cannot delete records unless told to do so.
+    \item There will always be an obvious key-value pair that is the latest key value pair.
+    \item The data structure is bounded in size such that $m$ is the minimum size of the data structure,  $n$ is the number of devices in the system and $s$ is the current size of the data structure: $m \leq s \leq (m+n-1)$
+    \item Data structure can only grow when there are too may key-value pairs (and aborts) than what fit in the current data structure size within reason.
+    \item No currently valid data can be lost by the system and go undetected.
+    \item Devices can operate offline and re-sync with the system and get a consistent view of the system
+    \item If the server tries to hold a device on an older version of the data structure, that device can eventually rejoin the main data structure without problems.
+    \item Devices that have a transaction aborted will be able to be notified about the abort indefinitely (no time frame when notification must be accepted).
+    \item Server cannot hold a device on an old version of the data structure and then move them to a newer version of the data structure without being detected (The server sequence numbers would reveal conflicts or gaps or both).
+
+\end{itemize}
+    
+\section{\textbf{System Correctness}}
+The measures of correctness for the system are divided by context and the different system operations as follows:
+\begin{itemize}
+    \item Data Integrity and Authentication
+    \item Ordering of Records
+    \item Data Structure Functions
+\end{itemize}
+
+\subsection{\textbf{Data Integrity and Authentication}}
+The correctness of the cryptographic aspects of the data structure can be assumed provided that each record is encrypted with one of the client's key and the HMAC of each record does not indicate the data was tampered with. See section 2.7 for more details on how the data structure is verified.
+
+\subsection{\textbf{Ordering of Records}}
+The ordering of the records within the data structure is said to be correct if the total ordering derived from the records by the server sequence numbers does not conflict with the partial ordering derived from the vector clock.
+
+\subsection{\textbf{Data Structure Functions}}
+\subsubsection{\textbf{Put}}
+\begin{itemize}
+     \item From the client side the put operation is said to be correct if the function returns a valid transaction ID for a successful operation or an error code for an unsuccessful operation.
+     \item From the server side the put operation is correct if the key-value pair changes only when the guard condition evaluates to true. The server should reply with either a transaction ID or and error code depending on the guard condition???
+\end{itemize}
+
+\subsubsection{\textbf{Get}}
+\begin{itemize}
+     \item For the client the get operation is correct if it returns the value and arbitrator machine ID that corresponds with the input key. Or and error message if no key-value pair exists with that key??? In addition, if any housekeeping work is involved, the get operation must only rescue transactions with a live status. See section 2.10 for details on Live Status.
+     \item For the server a get operation is correct if the server returns a correctly ordered and untampered version of the data structure when the initial pull is done.
+\end{itemize}
+
+\subsubsection{\textbf{Create New Key}}
+\begin{itemize}
+     \item The client correctly created a new key if it inserts a properly formatted new key notification into the data structure with a valid arbitrator machine ID.
+     \item The server is said to have correctly added a new key if a new key-value pair with the indicated arbitrator machine ID is inserted into the data structure. Or if it returns an error message for an invalid arbitrator machine ID??? What about collisions???
+\end{itemize}
+
+
+\end{document}
\ No newline at end of file
diff --git a/non_block_chain/doc/iotcloud_informal/makefile b/non_block_chain/doc/iotcloud_informal/makefile
new file mode 100644 (file)
index 0000000..cff4a15
--- /dev/null
@@ -0,0 +1,8 @@
+LATEX := pdflatex -halt-on-error
+
+default:
+       $(LATEX) iotcloud.tex
+
+clean:
+       rm -f *.dvi *.log *.aux *.blg *.bbl *~
+       rm -f iotcloud.ps iotcloud.pdf 
diff --git a/non_block_chain/doc/makefile b/non_block_chain/doc/makefile
new file mode 100644 (file)
index 0000000..cff4a15
--- /dev/null
@@ -0,0 +1,8 @@
+LATEX := pdflatex -halt-on-error
+
+default:
+       $(LATEX) iotcloud.tex
+
+clean:
+       rm -f *.dvi *.log *.aux *.blg *.bbl *~
+       rm -f iotcloud.ps iotcloud.pdf 
diff --git a/version1/doc/iotcloud.tex b/version1/doc/iotcloud.tex
new file mode 100644 (file)
index 0000000..9d10557
--- /dev/null
@@ -0,0 +1,1239 @@
+\documentclass[11pt]{article}\r
+\newcommand{\tuple}[1]{\ensuremath \langle #1 \rangle}\r
+\usepackage{color}\r
+\usepackage{amsthm}\r
+\usepackage{amsmath}\r
+\usepackage{graphicx}\r
+\usepackage{mathrsfs}\r
+\usepackage{algpseudocode}% http://ctan.org/pkg/algorithmicx\r
+\usepackage[all]{xy}\r
+\newtheorem{theorem}{Theorem}\r
+\newtheorem{prop}{Proposition}\r
+\newtheorem{lem}{Lemma}\r
+\newtheorem{defn}{Definition}\r
+\newcommand{\note}[1]{{\color{red} \bf [[#1]]}}\r
+\newcommand{\push}[1][1]{\hskip\dimexpr #1\algorithmicindent\relax}\r
+\begin{document}\r
+\section{Approach}\r
+\r
+\subsection{Keys}\r
+\r
+Each device has: user id + password\r
+\r
+Server login is:\r
+hash1(user id), hash1(password)\r
+\r
+Symmetric Crypto keys is:\r
+hash2(user id | password)\r
+\r
+Server has finite length queue of entries + max\_entry\_identifier +\r
+server login key\r
+\r
+\subsection{Entry layout}\r
+Each entry has:\r
+\begin{enumerate}\r
+\item Sequence identifier\r
+\item Random IV (if needed by crypto algorithm)\r
+\item Encrypted payload\r
+\end{enumerate}\r
+\r
+Payload has:\r
+\begin{enumerate}\r
+\item Sequence identifier\r
+\item Machine id (most probably something like a 64-bit random number \r
+that is self-generated by client)\r
+\item HMAC of previous slot\r
+\item Data entries\r
+\item HMAC of current slot\r
+\end{enumerate}\r
+\r
+A data entry can be one of these:\r
+\begin{enumerate}\r
+\item All or part of a Key-value entry\r
+\item Slot sequence entry: Machine id + last message identifier \r
+\newline {The purpose of this is to keep the record of the last slot \r
+from a certain client if a client's update has to expunge that other \r
+client's last entry from the queue. This is kept in the slot until \r
+the entry owner inserts a newer update into the queue.}\r
+\item Queue state entry: Includes queue size \newline {The purpose \r
+of this is for the client to tell if the server lies about the number \r
+of slots in the queue, e.g. if there are 2 queue state entry in the queue, \r
+e.g. 50 and 70, the client knows that when it sees 50, it should expect \r
+at most 50 slots in the queue and after it sees 70, it should expect \r
+50 slots before that queue state entry slot 50 and at most 70 slots. \r
+The queue state entry slot 70 is counted as slot number 51 in the queue.}\r
+\item Collision resolution entry: message identifier + machine id of a\r
+collision winner\r
+\newline {The purpose of this is to keep keep track of the winner of \r
+all the collisions until all clients have seen the particular entry.}\r
+\end{enumerate}\r
+\r
+\subsection{Live status}\r
+\r
+Live status of entries:\r
+\begin{enumerate}\r
+\item Key-Value Entry is dead if either (a) there is a newer key-value pair or (b) it is incomplete.\r
+       \r
+\item Slot sequence number (of either a message version data\r
+or user-level data) is dead if there is a newer slot from the same machine.\r
+\r
+\item Queue state entry is dead if there is a newer queue state entry.\r
+{In the case of queue state entries 50 and 70, this means that queue state \r
+entry 50 is dead and 70 is live. However, not until the number of slots reaches \r
+70 that queue state entry 50 will be expunged from the queue.}\r
+\r
+\item Collision resolution entry is dead if this entry has been seen\r
+by all clients after a collision happens.\r
+\end{enumerate}\r
+\r
+When data is at the end of the queue ready to expunge, if:\r
+\begin{enumerate}\r
+\item The key-value entry is not dead, it must be reinserted at the\r
+beginning of the queue.\r
+\r
+\item If the slot sequence number is not dead, then a message sequence\r
+entry must be inserted.\r
+\r
+\item If the queue state entry is not dead, it must be reinserted at the\r
+beginning of the queue.\r
+\end{enumerate}\r
+\r
+\r
+\paragraph{Reads:}\r
+Client sends a sequence number.  Server replies with either: all data\r
+entries or all newer data entries.\r
+\r
+\paragraph{Writes:}\r
+Client sends slot, server verifies that sequence number is valid,\r
+checks entry hash, and replies with an accept message if all checks\r
+pass.  On success, client updates its sequence number.  On failure,\r
+server sends updates slots to client and client validates those slots.\r
+\r
+\paragraph{Local state on each client:}\r
+A list of machines and the corresponding latest sequence numbers.\r
+\r
+\paragraph{Validation procedure on client:}\r
+\begin{enumerate}\r
+\item Decrypt each new slot in order.\r
+\item For each slot:\r
+    (a) check its HMAC, and\r
+    (b) check that the previous entry HMAC field matches the previous\r
+    entry.\r
+\item Check that the last-message entry for our machine matches the stored HMAC of our last message sent.\r
+\item For all other machines, check that the latest sequence number is\r
+at least as large (never goes backwards).\r
+\item That the queue has a current queue state entry.\r
+\item That the number of entries received is consistent with the size\r
+specified in the queue state entry.\r
+\end{enumerate}\r
+\r
+Key-value entries can span multiple slots.  They aren't valid until\r
+they are complete.\r
+\r
+\subsection{Resizing Queue}\r
+Client can make a request to resize the queue. This is done as a write that combines:\r
+  (a) a slot with the message, and (b) a request to the server. The queue can only be expanded, never contracted; attempting to decrease the size of the queue will cause future clients to throw an error.\r
+\r
+\subsection{Server Algorithm}\r
+$s \in SN$ is a sequence number\\\r
+$sv \in SV$ is a slot's value\\\r
+$slot_s = \tuple{s, sv} \in SL \subseteq SN \times SV$ \\ \\\r
+\textbf{State} \\\r
+\textit{SL = set of live slots on server} \\\r
+\textit{max = maximum number of slots (input only for resize message)} \\\r
+\textit{n = number of slots} \\ \\\r
+\textbf{Helper Function} \\\r
+$MaxSlot(SL_s)= \tuple{s, sv} \mid \tuple{s, sv}\r
+\in SL_s \wedge \forall \tuple{s_s, sv_s} \in SL_s, s \geq s_s$ \\\r
+$MinSlot(SL_s)= \tuple{s, sv} \mid \tuple{s, sv} \r
+\in SL_s \wedge \forall \tuple{s_s, sv_s} \in SL_s, s \leq s_s$ \\\r
+$SeqN(slot_s = \tuple{s, sv})=s$ \\\r
+$SlotVal(slot_s = \tuple{s, sv})=sv$ \\\r
+\r
+\begin{algorithmic}[1]\r
+\Function{GetSlot}{$s_g$}\r
+\State \Return{$\{\tuple{s, sv} \in SL \mid s \geq s_g\}$}\r
+\EndFunction\r
+\end{algorithmic}\r
+\r
+\begin{algorithmic}[1]\r
+\Function{PutSlot}{$s_p,sv_p,max'$}\r
+\If{$(max' \neq \emptyset)$}  \Comment{Resize}\r
+\State $max \gets max'$\r
+\EndIf\r
+\State $\tuple{s_n,sv_n} \gets MaxSlot(SL)$\Comment{Last sv}\r
+%\State $s_n \gets SeqN(\tuple{s_n,sv_n})$\r
+\If{$(s_p = s_n + 1)$}\r
+       \If{$n = max$}\r
+       \State $\tuple{s_m,sv_m} \gets MinSlot(SL)$\Comment{First sv}\r
+               \State $SL \gets SL - \{\tuple{s_m,sv_m}\}$\r
+       \Else \Comment{$n < max$}\r
+               \State $n \gets n + 1$\r
+       \EndIf\r
+    \State $SL \gets SL \cup \{\tuple{s_p,sv_p}\}$\r
+       \State \Return{$(true,\emptyset)$}\r
+\Else\r
+       \State \Return{$(false,\{\tuple{s,sv}\in SL \mid \r
+    s \geq s_p\})$}\r
+\EndIf\r
+\EndFunction\r
+\end{algorithmic}\r
+\r
+\subsection{Client Algorithm}\r
+\subsubsection{Reading Slots}\r
+\textbf{Data Entry} \\\r
+$k$ is key of entry \\\r
+$v$ is value of entry \\\r
+$kv$ is a key-value entry $\tuple{k,v}$, $kv \in DE$ \\\r
+$ss$ is a slot sequence entry $\tuple{id,s_{last}}$, \r
+id + last s of a machine, $ss \in DE$ \\\r
+$qs$ is a queue state entry (contains $max$ size of queue), $qs \in DE$ \\\r
+$cr$ is a collision resolution entry $\tuple{s_{col},id_{col}}$, \r
+s + id of a machine that wins a collision, $cr \in DE$ \\\r
+$de$ is a data entry that can be a $kv$, $ss$, $qs$, or $cr$ \\\r
+$DE$ is a set of all data entries, possibly of different types, in a single message \\\r
+$s \in SN$ is a sequence number \\\r
+$id$ is a machine ID\\\r
+$hmac_p$ is the HMAC value of the previous slot \\\r
+$hmac_c$ is the HMAC value of the current slot \\\r
+$hmac_{p_g}$ is the HMAC value of the previous slot in procedure $\Call{ProcessSL}{}$ \\\r
+$hmac_{c_g}$ is the HMAC value of the current slot in procedure $\Call{ProcessSL}{}$ \\\r
+$Dat_s = \tuple{s,id,hmac_p,DE,hmac_c}$ \\\r
+$slot_s = \tuple{s, E(Dat_s)} = \r
+\tuple{s, E(\tuple{s,id,hmac_p,DE,hmac_c})}$ \\ \\\r
+\textbf{States} \\\r
+\textit{$d$ = delta between the last $s$ recorded and the first $s$ received} \\\r
+\textit{$id_{self}$ = machine Id of this client} \\\r
+\textit{$max_g$ = maximum number of slots (initially $max_g > 0$)} \\\r
+\textit{$sl_{last}$ = info of last slot in queue = \r
+       $\tuple{s_{last},sv_{last},id_{last}}$ (initially $\emptyset$)} \\\r
+\textit{DT = set of $\tuple{k,v}$ on client} \\\r
+\textit{MS = associative array of $\tuple{id, s_{last}}$ of all clients on client \r
+(initially empty)} \\\r
+\textit{$LV$ = live set of $kv$ entries on client, contains \r
+       $\tuple{kv,s}$ entries} \\\r
+\textit{$SS_{live}$ = live set of $ss$ entries on client} \\\r
+\textit{$CR_{live}$ = live set of $cr$ entries on client} \\\r
+\textit{$MS_g$ = set MS to save all $\tuple{id, s_{last}}$ pairs while\r
+traversing DT after a request to server (initially empty)} \\\r
+\textit{SK = Secret Key} \\\r
+\textit{$SM$ = associative array of $\tuple{s, id}$ of all slots in previous reads\r
+(initially empty)} \\ \\\r
+\textbf{Helper Functions} \\\r
+$MaxSlot(SL_s)= \tuple{s, sv}$ \textit{such that} $\tuple{s, sv}\r
+       \in SL_s \wedge \forall \tuple{s_s, sv_s} \in SL_s, s \geq s_s$ \\\r
+$MinSlot(SL_s)= \tuple{s, sv}$ \textit{such that} $\tuple{s, sv} \r
+       \in SL_s \wedge \forall \tuple{s_s, sv_s} \in SL_s, s \leq s_s$ \\\r
+$Slot(SL_s,s_s)= \tuple{s, sv}$ \textit{such that} $\tuple{s, sv} \r
+       \in SL_s \wedge \forall \tuple{s_s, sv_s} \in SL_s, s = s_s$ \\\r
+$SeqN(\tuple{s, sv})=s$ \\\r
+$SlotVal(\tuple{s, sv})=sv$ \\\r
+$CreateLastSL(s,sv,id)=\tuple{s,sv,id}=sl_{last}$ \\\r
+$Decrypt(SK_s,sv_s)=Dat_s=\tuple{s,id,hmac_p,DE,hmac_c}$ \\\r
+$GetSeqN(Dat_s = \tuple{s,id,hmac_p,DE,hmac_c})=s$ \\\r
+$GetMacId(Dat_s = \tuple{s,id,hmac_p,DE,hmac_c})=id$ \\\r
+$GetPrevHmac(Dat_s = \tuple{s,id,hmac_p,DE,hmac_c})=hmac_p$ \\\r
+$GetCurrHmac(Dat_s = \tuple{s,id,hmac_p,DE,hmac_c})=hmac_c$ \\\r
+$GetDatEnt(Dat_s = \tuple{s,id,hmac_p,DE,hmac_c})=DE$ \\\r
+$GetLiveSS(SS_{live},ss_s)= ss$ \textit{such that} $ss \in SS_{live} \r
+       \wedge \forall ss_s \in SS_{live}, ss = ss_s$ \\\r
+$GetLiveCR(CR_{live},cr_s)= cr$ \textit{such that} $cr \in CR_{live} \r
+       \wedge \forall cr_s \in CR_{live}, cr = cr_s$ \\\r
+$GetLivEntLastS(LV_s,kv_s)= s$ \textit{such that} $\tuple{kv, s} \in LV_s \r
+       \wedge \forall \tuple{kv_s, s_s} \in LV_s, kv_s = kv$ \\\r
+$GetKV($key-value data entry$)=\tuple{k_s,v_s} = kv_s$ \\\r
+$GetSS($slot-sequence data entry$)=\tuple{id_s,s_{s_{last}}} = ss_s$ \\\r
+$GetCR($de$)=\tuple{s_s,id_s} = cr_s$ \\\r
+$Hmac(Dat_s,SK) = hmac_c$ \textit{value computed from $s$, $id$,\r
+$hmac_p$, and $DE$ taken from $Dat_s$} \\\r
+$IsKv(de) = true$ \textit{if $de$ is a $kv$, false otherwise} \\\r
+$IsSs(de) = true$ \textit{if $de$ is a $ss$, false otherwise} \\\r
+$IsQs(de) = true$ \textit{if $de$ is a $qs$, false otherwise} \\\r
+$IsCr(de) = true$ \textit{if $de$ is a $cr$, false otherwise} \\\r
+$GetKey(kv)=k$\Comment{$kv = \tuple{k, v}$} \\\r
+$GetVal(kv)=v$ \\\r
+$GetId(ss)=id$\Comment{$ss = \tuple{id, s_{last}}$} \\\r
+$GetSLast(ss)=s_{last}$ \\\r
+$GetS(cr)=s$\Comment{$cr = \tuple{s, id}$} \\\r
+$GetId(cr)=id$ \\\r
+$GetLastS(sl_{last})=s$\Comment{$sl_{last} = \tuple{s,sv,id}$} \\\r
+$GetSV(sl_{last})=sv$ \\\r
+$GetID(sl_{last})=id$ \\\r
+$GetKeyVal(DT_s,k_s)= \tuple{k, v}$ \textit{such that} $\tuple{k, v} \r
+       \in DT_s \wedge \forall \tuple{k_s, v_s} \in DT_s, k = k_s$ \\\r
+$MaxLastSeqN(MS_s)= s_{last}$ \textit{such that} $\tuple{id, s_{last}} \in MS_s \r
+       \wedge \forall \tuple{id_s, s_{s_{last}}} \in MS_s, s_{last} \geq s_{s_{last}}$ \\\r
+$MinLastSeqN(MS_s)= s_{last}$ \textit{such that} $\tuple{id, s_{last}} \in MS_s \r
+       \wedge \forall \tuple{id_s, s_{s_{last}}} \in MS_s, s_{last} \leq s_{s_{last}}$ \\\r
+$MinCRSeqN(CR_s)= s$ \textit{such that} $\tuple{s, id} \in CR_s \r
+       \wedge \forall \tuple{s_s, id_s} \in CR_s, s \leq s_s$ \\\r
+$MaxSMSeqN(SM_s)= s$ \textit{such that} $\tuple{s, id} \in SM_s \r
+       \wedge \forall \tuple{s_s, id_s} \in SM_s, s \geq s_s$ \\\r
+\r
+\begin{algorithmic}[1]\r
+\Procedure{Error}{$msg$}\r
+\State $Print(msg)$\r
+\State $Halt()$\r
+\EndProcedure\r
+\end{algorithmic}\r
+\r
+\begin{algorithmic}[1]\r
+\Function{GetQueSta}{$DE_s$}\r
+\State $qs_{de} \gets qs$ \textit{such that} $qs \in DE_s, \r
+       de_s \in D \land IsQs(de_s)$\r
+\If{$qs_{de} \neq \emptyset$}\r
+       \State $qs_{ret} \gets qs_{de})$\r
+\Else\r
+       \State $qs_{ret} \gets \emptyset$\r
+\EndIf\r
+\State \Return{$qs_{ret}$}\r
+\EndFunction\r
+\end{algorithmic}\r
+\r
+\begin{algorithmic}[1]\r
+\Function{GetSlotSeq}{$DE_s$}\r
+\State $DE_{ss} \gets \{de | de \in DE_s \land IsSs(de)\}$\r
+\State \Return{$DE_{ss}$}\r
+\EndFunction\r
+\end{algorithmic}\r
+\r
+\begin{algorithmic}[1]\r
+\Function{GetColRes}{$DE_s$}\r
+\State $DE_{cr} \gets \{de | de \in DE_s \land IsCr(de)\}$\r
+\State \Return{$DE_{cr}$}\r
+\EndFunction\r
+\end{algorithmic}\r
+\r
+\begin{algorithmic}[1]\r
+\Function{UpdateLastSeqN}{$id_s,s_s,MS_s$}\r
+\State $s_t \gets MS_s[id_s]$\r
+\If{$s_t = \emptyset$}\r
+       \State $MS_s[id_s] = s_s$  \Comment{First occurrence}\r
+\Else\r
+       \If{$id_s = id_{self}$}\r
+               \If{$s_t \neq s_s$}\Comment{Check for mismatch on $s$}\r
+                       \State \Call{Error}{'Mismatch on $s$ for $id_{self}$'}\r
+               \EndIf\r
+       \Else\r
+               \If{$s_t > s_s$}\Comment{Check for rollback on $s$}\r
+                       \State \Call{Error}{'Rollback on $s$ for $id_s$'}\r
+               \EndIf\r
+       \EndIf\r
+       \State $MS_S[id_s] \gets max(s_t, s_s)$\r
+\EndIf\r
+\State \Return{$MS_s$}\r
+\EndFunction\r
+\end{algorithmic}\r
+\r
+\begin{algorithmic}[1]\r
+\Function{UpdateKVLivEnt}{$LV_s,kv_s,s_s$}\r
+\State $s_t \gets GetLivEntLastS(LV_s,kv_s)$\r
+\If{$s_t = \emptyset$}\r
+       \State $LV_s \gets LV_s \cup \{\tuple{kv_s,s_s}\}$\Comment{First occurrence}\r
+\Else\r
+       \If{$s_s > s_t$}\Comment{Update entry with a later s}\r
+               \State $LV_s \gets (LV_s - \{\tuple{kv_s,s_t}\}) \cup \r
+                       \{\tuple{kv_s,s_s}\}$\r
+       \EndIf\r
+\EndIf\r
+\State \Return{$LV_s$}\r
+\EndFunction\r
+\end{algorithmic}\r
+\r
+\begin{algorithmic}[1]\r
+\Function{AddSSLivEnt}{$SS_{s_{live}},de_s$}\r
+\State $ss_s \gets GetSS(de_s)$\r
+\State $ss_t \gets GetLiveSS(SS_{s_{live}},ss_s)$\r
+\If{$ss_t = \emptyset$}\r
+       \State $SS_{s_{live}} \gets SS_{s_{live}} \cup \{ss_s\}$\Comment{First occurrence}\r
+\EndIf\r
+\State \Return{$SS_{s_{live}}$}\r
+\EndFunction\r
+\end{algorithmic}\r
+\r
+\begin{algorithmic}[1]\r
+\Function{AddCRLivEnt}{$CR_{s_{live}},cr_s$}\r
+\State $cr_t \gets GetLiveCR(CR_{s_{live}},cr_s)$\r
+\If{$cr_t = \emptyset$}\r
+       \State $CR_{s_{live}} \gets CR_{s_{live}} \cup \{cr_s\}$\Comment{First occurrence}\r
+\EndIf\r
+\State \Return{$CR_{s_{live}}$}\r
+\EndFunction\r
+\end{algorithmic}\r
+\r
+\begin{algorithmic}[1]\r
+\Function{UpdateSSLivEnt}{$SS_{s_{live}},MS_s$}\r
+\State $s_{s_{min}} \gets MinLastSeqN(MS_s)$\r
+\ForAll{$ss_s \in SS_{s_{live}}$}\r
+       \State $s_{s_{last}} \gets GetSLast(ss_s)$\r
+       \If{$s_{s_{min}} > s_{s_{last}}$}\Comment{Remove if dead}\r
+               \State $SS_{s_{live}} \gets SS_{s_{live}} - \{ss_s\}$           \r
+       \EndIf\r
+\EndFor\r
+\State \Return{$SS_{s_{live}}$}\r
+\EndFunction\r
+\end{algorithmic}\r
+\r
+\begin{algorithmic}[1]\r
+\Function{UpdateCRLivEnt}{$CR_{s_{live}},MS_s$}\r
+\State $s_{s_{min}} \gets MinLastSeqN(MS_s)$\r
+\ForAll{$cr_s \in CR_{s_{live}}$}\r
+       \State $s_s \gets GetS(cr_s)$\r
+       \If{$s_{s_{min}} > s_s$}\Comment{Remove if dead}\r
+               \State $CR_{s_{live}} \gets CR_{s_{live}} - \{cr_s\}$   \r
+       \EndIf\r
+\EndFor\r
+\State \Return{$CR_{s_{live}}$}\r
+\EndFunction\r
+\end{algorithmic}\r
+\r
+\begin{algorithmic}[1]\r
+\Function{UpdateSM}{$SM_s,CR_s$}\Comment{Remove if dead}\r
+\State $s_{cr_{min}} \gets MinCRSeqN(CR_s)$\r
+       \State $SM_s \gets SM_s - \{\tuple{s_s,id_s} \mid \tuple{s_s,id_s}\r
+               \in SM_s \wedge s_s < s_{cr_{min}}\}$\r
+\State \Return{$CR_{s_{live}}$}\r
+\EndFunction\r
+\end{algorithmic}\r
+\r
+\begin{algorithmic}[1]\r
+\Procedure{CheckLastSeqN}{$MS_s,MS_t,d$}\r
+\For {$\tuple{id, s_t}$ in $MS_t$}\Comment{Check $MS_t$ based on the newer $MS_s$}\r
+       \State $s_s \gets MS_s[id]$\r
+       \If{$d \land s_s = \emptyset$}\r
+       \State \Call{Error}{'Missing $s$ for machine $id$'}\r
+       \ElsIf{$id = id_{self}$ and $s_s \neq s_t$}\r
+               \State \Call{Error}{'Invalid last $s$ for this machine'}\r
+       \ElsIf{$id \neq id_{self}$ and $s_{s_{last}} < s_{t_{last}}$}\r
+       \State \Call{Error}{'Invalid last $s$ for machine $id$'}\r
+    \Else\r
+               \State $MS_t[id] \gets s_s$\r
+       \EndIf\r
+\EndFor\r
+\EndProcedure\r
+\end{algorithmic}\r
+\r
+\begin{algorithmic}[1]\r
+\Procedure{CheckCollision}{$MS_s,SM_s,cr_s$}\r
+\If{$cr_s \neq \emptyset$}\r
+       \State $s_s \gets GetS(cr_s)$\r
+       \State $id_s \gets GetId(cr_s)$\r
+       \State $s_{s_{last}} \gets GetLastSeqN(MS_s,id_s)$\r
+       \If{$s_{s_{last}} < s_s$}\r
+               \State $id_t \gets SM_s[s_s]$\r
+               \If{$id_s \neq id_t$}\r
+                       \State \Call{Error}{'Invalid $id$ for this slot update'}\r
+               \EndIf\r
+       \EndIf\r
+\EndIf\r
+\EndProcedure\r
+\end{algorithmic}\r
+\r
+\begin{algorithmic}[1]\r
+\Function{ValidSlotsRange}{$s_{s_{min}}$}\r
+\State $s_{s_{last}} \gets MaxSMSeqN(SM)$\r
+\If{$s_{s_{min}} \leq s_{s_{last}}$}\r
+       \State \Call{Error}{'Server sent old slots'}\r
+\EndIf\r
+\State \Return{$s_{s_{min}} > s_{s_{last}} + 1$}\r
+\EndFunction\r
+\end{algorithmic}\r
+\r
+\begin{algorithmic}[1]\r
+\Procedure{CheckNumSlots}{$|SL_s|,sz_s$}\r
+\If{$|SL_s| \neq sz_s$}\r
+       \State \Call{Error}{'Actual number of slots does not match expected'}\r
+\EndIf\r
+\EndProcedure\r
+\end{algorithmic}\r
+\r
+\begin{algorithmic}[1]\r
+\Function{StoreLastSlot}{$MS_s,sl_l,s_s,sv_s,id_s$}\r
+\State $s_{min} \gets MinLastSeqN(MS_s)$\r
+\If{$s_{min} \neq \emptyset \land s_{min} = s_s$}\Comment{$MS$ initially empty}\r
+       \State $sl_l \gets CreateLastSL(s_s,sv_s,id_s)$\r
+\EndIf\r
+\State \Return{$sl_l$}\r
+\EndFunction\r
+\end{algorithmic}\r
+\r
+\begin{algorithmic}[1]\r
+\Function{ValidHmacChain}{$Dat_s,s_s,hmac_{p_s},sl_l$}\r
+       \State $hmac_{p_{stored}} \gets GetPrevHmac(Dat_s)$\r
+       \If {$ \neg(s_s = 0 \land hmac_{p_s} = 0)$}\r
+               \State $s_l \gets GetLastS(sl_l)$\r
+               \If {$(s_s > s_l + 1) \land (hmac_{p_{stored}} \neq hmac_{p_s})$}\r
+                       \State \Call{Error}{'Invalid previous HMAC value'}\r
+               \EndIf\r
+       \EndIf\r
+       \If{$Hmac(Dat_s,SK) \neq GetCurrHmac(Dat_s)$ }\r
+               \State \Call{Error}{'Invalid current HMAC value'}\r
+       \EndIf\r
+       \State $hmac_{p_s} \gets Hmac(Dat_s,SK)$\Comment{Update $hmac_{p_s}$ for next check}\r
+\State \Return{$hmac_{p_s}$}\r
+\EndFunction\r
+\end{algorithmic}\r
+\r
+\begin{algorithmic}[1]\r
+\Function{UpdateDT}{$DT_s,DE_s,LV_s,s_s$}\r
+\State $DE_{s_{kv}} \gets \{de_s | de_s \in DE_s \land IsKv(de_s)\}$\r
+\ForAll{$de_s \in DE_{s_{kv}}$}\r
+       \State $kv_s \gets GetKV(de_s)$\r
+       \State $LV_s \gets \Call{UpdateKVLivEnt}{LV_s,kv_s,s_s}$\r
+       \State $k_s \gets GetKey(kv_s)$\r
+       \State $\tuple{k_s,v_t} \gets GetKeyVal(DT_s,k_s)$\r
+       \If{$\tuple{k_s,v_t} = \emptyset$}\r
+               \State $DT_s \gets DT_s \cup \{\tuple{k_s,v_s}\}$\r
+       \Else\r
+               \State $DT_s \gets (DT_s - \{\tuple{k_s,v_t}\}) \cup \r
+                       \{\tuple{k_s,v_s}\}$\r
+       \EndIf\r
+\EndFor\r
+\State \Return{$DT_s$}\r
+\EndFunction\r
+\end{algorithmic}\r
+\r
+\begin{algorithmic}[1]\r
+\Function{InitExpSize}{$s_{min}$}\r
+\If{$s_{min} < max_g$}\Comment{Check whether $SL$ is full on server}\r
+       \State $sz_s \gets s_{min}$\r
+\Else\r
+       \State $sz_s \gets max_g$\r
+\EndIf\r
+\State \Return{$sz_s$}\r
+\EndFunction\r
+\end{algorithmic}\r
+\r
+\begin{algorithmic}[1]\r
+\Function{UpdateExpSize}{$sz_s$}\r
+\State $sz_s \gets sz_s + 1$\r
+\If{$sz_s > max_g$}\Comment{Expected size $\leq max_g$}\r
+       \State $sz_s \gets max_g$\r
+\EndIf\r
+\State \Return{$sz_s$}\r
+\EndFunction\r
+\end{algorithmic}\r
+\r
+\begin{algorithmic}[1]\r
+\Function{UpdateQS}{$Dat_s,max_s$}\r
+\State $DE_s \gets GetDatEnt(Dat_s)$\r
+\State $qs_s \gets \Call{GetQueSta}{DE_s}$\Comment{Handle qs}\r
+\If{$qs_s \neq \emptyset \land qs_s > max_s$}\r
+       \State $max_s \gets qs_s$\r
+\EndIf\r
+\State \Return{$max_s$}\r
+\EndFunction\r
+\end{algorithmic}\r
+\r
+\begin{algorithmic}[1]\r
+\Procedure{UpdateCR}{$DE_s$}\r
+\State $DE_{s_{cr}} \gets \Call{GetColRes}{DE_s}$\Comment{Handle cr}\r
+\If{$DE_{s_{cr}} \neq \emptyset$}\r
+       \ForAll{$de_{s_{cr}} \in DE_{s_{cr}}$}\r
+               \State $cr_s \gets GetCR(de_{s_{cr}})$\r
+               \State $\Call{CheckCollision}{MS,SM,cr_s}$\r
+               \State $CR_{live} \gets \Call{AddCRLivEnt}{CR_{live},cr_s}$\r
+       \EndFor\r
+\EndIf\r
+\EndProcedure\r
+\end{algorithmic}\r
+\r
+\begin{algorithmic}[1]\r
+\Function{UpdateSS}{$DE_s,MS_s$}\r
+\State $DE_{s_{ss}} \gets \Call{GetSlotSeq}{DE_s}$\Comment{Handle ss}\r
+\If{$DE_{s_{ss}} \neq \emptyset$}\r
+       \ForAll{$de_{s_{ss}} \in DE_{s_{ss}}$}\r
+               \State $\tuple{id_d,s_{d_{last}}} \gets GetSS(de_{s_{ss}})$\r
+               \State $MS_s \gets \Call{UpdateLastSeqN}{id_d,s_{d_{last}},MS_s}$\r
+               \State $SS_{live} \gets \Call{AddSSLivEnt}{SS_{live},de_{s_{ss}}}$\r
+       \EndFor\r
+\EndIf\r
+\State \Return{$MS_s$}\r
+\EndFunction\r
+\end{algorithmic}\r
+\r
+\begin{algorithmic}[1]\r
+\Procedure{ProcessSL}{$SL_g$}\r
+\State $MS_g \gets \emptyset$\r
+\State $\tuple{s_{g_{min}},sv_{g_{min}}} \gets MinSlot(SL_g)$\r
+\State $\tuple{s_{g_{max}},sv_{g_{max}}} \gets MaxSlot(SL_g)$\r
+\State $d \gets \Call{ValidSlotsRange}{s_{g_{min}}}$\r
+\State $sz \gets \Call{InitExpSize}{s_{g_{min}}}$\r
+\For{$s_g \gets s_{g_{min}}$ \textbf{to} $s_{g_{max}}$}\Comment{Process slots \r
+       in $SL_g$ in order}\r
+       \State $\tuple{s_g,sv_g} \gets Slot(SL_g,s_g)$\r
+       \State $Dat_g \gets Decrypt(SK,sv_g)$\r
+       \State $id_g \gets GetMacId(Dat_g)$\r
+       \State $SM \gets SM \cup \{\tuple{s_g,id_g}\}$\r
+       \State $s_{g_{in}} \gets GetSeqN(Dat_g)$\r
+    \If{$s_g \neq s_{g_{in}}$}\r
+               \State \Call{Error}{'Invalid sequence number'}\r
+       \EndIf\r
+       \State $hmac_{p_g} \gets \Call{ValidHmacChain}{Dat_g,s_g,hmac_{p_g},sl_{last}}$\r
+       \State $sz \gets \Call{UpdateExpSize}{sz}$\r
+       \State $max_g \gets \Call{UpdateQS}{Dat_g,max_g}$\Comment{Handle qs}\r
+       \State $MS_g \gets \Call{UpdateLastSeqN}{id_g,s_g,MS_g}$\Comment{Handle last s}\r
+       \State $MS_g \gets \Call{UpdateSS}{DE_g,MS_g}$\Comment{Handle ss}\r
+       %\State $DE_{g_{ss}} \gets \Call{GetSlotSeq}{DE_g}$\Comment{Handle ss}\r
+       %\If{$DE_{g_{ss}} \neq \emptyset$}\r
+       %       \ForAll{$de_{g_{ss}} \in DE_{g_{ss}}$}\r
+       %               \State $\tuple{id_d,s_{d_{last}}} \gets GetSS(de_{g_{ss}})$\r
+       %               \State $MS_g \gets \Call{UpdateLastSeqN}{id_d,s_{d_{last}},MS_g}$\r
+       %               \State $SS_{live} \gets \Call{AddSSLivEnt}{SS_{live},de_{g_{ss}}}$\r
+       %       \EndFor\r
+       %\EndIf\r
+       \State $\Call{UpdateCR}{DE_g}$\Comment{Handle cr}\r
+       %\State $DE_{g_{cr}} \gets \Call{GetColRes}{DE_g}$\Comment{Handle cr}\r
+       %\If{$DE_{g_{cr}} \neq \emptyset$}\r
+       %       \ForAll{$de_{g_{cr}} \in DE_{g_{cr}}$}\r
+       %               \State $cr_g \gets GetCR(de_{g_{cr}})$\r
+       %               \State $\Call{CheckCollision}{MS,SM,cr_g}$\r
+       %               \State $CR_{live} \gets \Call{AddCRLivEnt}{CR_{live},cr_g}$\r
+       %       \EndFor\r
+       %\EndIf\r
+       \State $sl_{last} \gets \Call{StoreLastSlot}{MS,sl_{last},s_g,sv_g,id_g}$\r
+       \State $DT \gets \Call{UpdateDT}{DT,DE_g,LV,s_g}$\r
+\EndFor\r
+\State $\Call{CheckLastSeqN}{MS_g,MS,d}$\r
+\State $\Call{CheckNumSlots}{|SL_g|,sz}$\r
+\State $\Call{UpdateSSLivEnt}{SS_{live},MS}$\r
+\State $\Call{UpdateCRLivEnt}{CR_{live},MS}$\r
+\State $\Call{UpdateSM}{SM,CR_{live}}$\r
+\EndProcedure\r
+\end{algorithmic}\r
+\r
+\begin{algorithmic}[1]\r
+\Procedure{GetKVPairs}{}\r
+\State $s_g \gets GetLastSeqN(MS,id_{self}) + 1$\r
+\State $SL_c \gets \Call{GetSlot}{s_g}$\r
+\State $\Call{ProcessSL}{SL_c}$\Comment{Process slots and update DT}\r
+\EndProcedure\r
+\end{algorithmic}\r
+\r
+\begin{algorithmic}[1]\r
+\Function{Get}{$k_g$}  \Comment{Interface function to get a value}\r
+\State $\tuple{k_s,v_s} \gets \tuple{k,v}$ \textit{such that} $\tuple{k,v} \r
+       \in DT \land k = k_g$\r
+\State \Return{$v_s$}\r
+\EndFunction\r
+\end{algorithmic}\r
+\r
+\subsubsection{Writing Slots}\r
+\textbf{States} \\\r
+\textit{$cp$ = data entry $DE$ maximum size/capacity} \\\r
+\textit{$ck_p$ = counter of $kv \in KV$ for putting pairs (initially 0)} \\\r
+\textit{$ck_g$ = counter of $kv \in KV$ for getting pairs (initially 0)} \\\r
+\textit{$cs_p$ = counter of $ss \in SS$ for putting pairs (initially 0)} \\\r
+\textit{$cs_g$ = counter of $ss \in SS$ for getting pairs (initially 0)} \\\r
+\textit{$cc_p$ = counter of $cr \in CR$ for putting pairs (initially 0)} \\\r
+\textit{$cc_g$ = counter of $cr \in CR$ for getting pairs (initially 0)} \\\r
+\textit{$hmac_{c_p}$ = the HMAC value of the current slot in procedure \r
+$\Call{PutDataEntries}{}$} \\\r
+\textit{$hmac_{p_p}$ = the HMAC value of the previous slot \r
+($hmac_{p_p} = \emptyset$ for the first slot) in procedure \r
+$\Call{PutDataEntries}{}$} \\\r
+\textit{$id_{self}$ = machine Id of this client} \\\r
+\textit{$sl_{last}$ = info of last slot in queue = \r
+       $\tuple{s_{last},sv_{last},id_{last}}$ (initially $\emptyset$)} \\\r
+\textit{$sz$ = expected size of received slots from server} \\\r
+\textit{$th_p$ = threshold number of dead slots for a resize to happen} \\\r
+\textit{$m'_p$ = offset added to $max$ for resize} \\\r
+\textit{$reinsert_{qs}$ = boolean to decide $qs$($max_g$) reinsertion} \\\r
+\textit{$KV$ = set of $\tuple{ck, \tuple{k,v}}$ of kv entries on client} \\\r
+\textit{$SS$ = set of $\tuple{cs, \tuple{id,s_{last}}}$ of ss entries on client} \\\r
+\textit{$CR$ = set of $\tuple{cc, \tuple{s_{col},id_{col}}}$ of cr entries on client} \\\r
+\textit{$SL_p$ = set of returned slots on client} \\\r
+\textit{SK = Secret Key} \\ \\\r
+\textbf{Helper Functions} \\\r
+$CreateDat(s,id,hmac_p,DE,hmac_c)=Dat_s=\tuple{s,id,hmac_p,DE,hmac_c}$ \\\r
+$CreateSS(id_s,s_{s_{last}})=\tuple{id_s,s_{s_{last}}} = ss_s$ \\\r
+$CreateQS(max'_s)=qs_s$ \\\r
+$CreateCR(s_s,id_s)=\tuple{s_s,id_s} = cr_s$ \\\r
+$Encrypt(Dat_s,SK_s)=sv_s$ \\\r
+$GetColSeqN(SL_s,s_s)= \tuple{s, sv}$ \textit{such that} $\tuple{s, sv}\r
+\in SL_s \wedge \forall \tuple{s_s, sv_s} \in SL_s, s = s_s$ \\\r
+$GetKVPair(KV_s,k_s)= \tuple{ck,\tuple{k, v}}$ \textit{such that} \r
+$\tuple{ck,\tuple{k, v}} \in KV_s \wedge\r
+\forall \tuple{ck_s,\tuple{k_s, v_s}} \in KV_s, k = k_s$ \\\r
+\r
+\begin{algorithmic}[1]\r
+\Function{Put}{$KV_s,\tuple{k_s,v_s}$}  \Comment{Interface function to update a key-value pair}\r
+\State $\tuple{ck_s,\tuple{k_s,v_t}} \gets GetKVPair(KV_s,k_s)$\r
+\If{$\tuple{ck_s,\tuple{k_s,v_t}} = \emptyset$}\r
+       \State $KV_s \gets KV_s \cup \{\tuple{ck_p, \tuple{k_s,v_s}}\}$\r
+       \State $ck_p \gets ck_p + 1$\r
+\Else\r
+       \State $KV_s \gets (KV_s - \{\tuple{ck_s, \tuple{k_s,v_t}}\}) \cup \r
+       \{\tuple{ck_s, \tuple{k_s,v_s}}\}$\r
+\EndIf\r
+\State \Return{$KV_s$}\r
+\EndFunction\r
+\end{algorithmic}\r
+\r
+\begin{algorithmic}[1]\r
+\Function{PutSSPair}{$SS_s,\tuple{id_s,s_{s_{last}}}$}\Comment{Insert a set of $ss$ entries}\r
+\State $SS_s \gets SS_s \cup \{\tuple{cs_p, \tuple{id_s,s_{s_{last}}}}\}$\r
+\State $cs_p \gets cs_p + 1$\r
+\State \Return{$SS_s$}\r
+\EndFunction\r
+\end{algorithmic}\r
+\r
+\begin{algorithmic}[1]\r
+\Function{PutCRPair}{$CR_s,\tuple{s_s,id_s}$}\Comment{Insert a set of $cr$ entries}\r
+\State $CR_s \gets CR_s \cup \{\tuple{cc_p, \tuple{s_s,id_s}}\}$\r
+\State $cc_p \gets cc_p + 1$\r
+\State \Return{$CR_s$}\r
+\EndFunction\r
+\end{algorithmic}\r
+\r
+\begin{algorithmic}[1]\r
+\Function{CheckResize}{$MS_s,th_s,max_t,m'_s$}\r
+\State $s_{last_{min}} \gets MinLastSeqN(MS_s)$\r
+\State $s_{last_{max}} \gets MaxLastSeqN(MS_s)$\r
+\State $n_{live} \gets s_{last_{max}} - s_{last_{min}} + 1$\Comment{Number of live slots}\r
+\State $n_{dead} \gets max_t - n_{live}$\r
+\If{$n_{dead} \leq th_s$}\r
+       \State $max'_s \gets max_t + m'_s$\r
+\Else\r
+       \State $max'_s \gets \emptyset$\r
+\EndIf\r
+\State \Return{$max'_s$}\r
+\EndFunction\r
+\end{algorithmic}\r
+\r
+\begin{algorithmic}[1]\r
+\Function{CheckSLFull}{$MS_s,max_t$}\Comment{Check if $ss$ is needed}\r
+\State $s_{last_{min}} \gets MinLastSeqN(MS_s)$\r
+\State $s_{last_{max}} \gets MaxLastSeqN(MS_s)$\r
+\State $n_{live} \gets s_{last_{max}} - s_{last_{min}}$\Comment{Number of live slots}\r
+\State $n_{dead} \gets max_t - n_{live}$\r
+\State \Return {$n_{dead} = 0$}\r
+\EndFunction\r
+\end{algorithmic}\r
+\r
+\begin{algorithmic}[1]\r
+\Function{HandleCollision}{$SL_s,s_s$}\r
+\If{$SL_s = \emptyset$}\r
+       \State \Call{Error}{'No slots received from server'}\r
+\EndIf\r
+\State $\tuple{s_{col},sv_{col}} \gets GetColSeqN(SL_s,s_s)$\r
+\State $Dat_{col} \gets Decrypt(SK,sv_{col})$\r
+\State $id_{col} \gets GetMacId(Dat_{col})$\r
+\State $cr_s \gets CreateCR(s_{col},id_{col})$\r
+\State $\Call{ProcessSL}{SL_s}$\r
+\State \Return{$cr_s$}\r
+\EndFunction\r
+\end{algorithmic}\r
+\r
+\begin{algorithmic}[1]\r
+\Procedure{CheckLastSlot}{$sl_{s_{last}}$}\r
+\State $s_s \gets GetLastS(sl_{s_{last}})$\r
+\State $sv_s \gets GetSV(sl_{s_{last}})$\r
+\State $Dat_s \gets Decrypt(SK,sv_s)$\r
+\State $DE_s \gets GetDatEnt(Dat_s)$\r
+\ForAll{$de_s \in DE_s$}\r
+       \State $live \gets \Call{CheckLiveness}{s_s,de_s}$\r
+       \If{$live$}\r
+               \If{$type(de_s) = ``kv"$}\r
+                       \State $\tuple{k_s,v_s} \gets GetKV(de_s)$\r
+                       \State $KV \gets \Call{PutKVPair}{KV,\tuple{k_s,v_s}}$\r
+               \ElsIf{$type(de_s) = ``ss"$}\r
+                       \State $\tuple{id_s,s_{s_{last}}} \gets GetSS(de_s)$\r
+                       \State $SS \gets \Call{PutSSPair}{SS,\tuple{id_s,s_{s_{last}}}}$\r
+               \ElsIf{$type(de_s) = ``cr"$}\r
+                       \State $\tuple{s_s,id_s} \gets GetCR(de_s)$\r
+                       \State $CR \gets \Call{PutCRPair}{CR,\tuple{s_s,id_s}}$\r
+               \ElsIf{$type(de_s) = ``qs"$}\r
+                       \State $reinsert_{qs} \gets true$\r
+               \EndIf\r
+       \EndIf\r
+\EndFor\r
+\EndProcedure\r
+\end{algorithmic}\r
+\r
+\begin{algorithmic}[1]\r
+\Function{CheckLiveness}{$s_s,de_s$}\r
+\State $live \gets true$\r
+\If{$de_s = kv$}\r
+       \State $s_l \gets GetLivEntLastS(LV,de_s)$\r
+       \If{$s_l = \emptyset \lor s_s < s_l$}\r
+               \State $live \gets false$\r
+       \EndIf\r
+\ElsIf{$de_s = ss$}\r
+       \State $ss_s \gets GetSS(de_s)$\r
+       \State $ss_l \gets GetLiveSS(SS_{live},ss_s)$\r
+       \If{$ss_l = \emptyset$}\r
+               \State $live \gets false$\r
+       \EndIf\r
+\ElsIf{$de_s = cr$}\r
+       \State $cr_s \gets GetCR(de_s)$\r
+       \State $cr_l \gets GetLiveCR(CR_{live},cr_s)$\r
+       \If{$cr_l = \emptyset$}\r
+               \State $live \gets false$\r
+       \EndIf\r
+\ElsIf{$de_s = qs$}\r
+       \State $qs_s \gets GetQS(de_s)$\r
+       \If{$qs_s \neq max_g$}\r
+               \State $live \gets false$\r
+       \EndIf\r
+\Else\r
+       \State \Call{Error}{'Unrecognized $de$ type'}\r
+\EndIf\r
+\State \Return{$live$}\r
+\EndFunction\r
+\end{algorithmic}\r
+\r
+\begin{algorithmic}[1]\r
+\Function{CreateSlotSeq}{$sl_s$}\r
+\State $id_s \gets GetID(sl_s)$\r
+\State $s_{s_{last}} \gets GetLastS(sl_s)$\r
+\State $ss_s \gets CreateSS(id_s,s_{s_{last}})$\r
+\State \Return{$\tuple{ss_s}$}\r
+\EndFunction\r
+\end{algorithmic}\r
+\r
+\begin{algorithmic}[1]\r
+\Function{AddQueSta}{$DE_s,max'_s,cp_s$}\Comment{Insert a $qs$}\r
+\State $DE_{ret} \gets \emptyset$\r
+\State $qs_s \gets max'_s$\r
+\State $DE_{ret} \gets DE_s \cup \{qs_s\}$\r
+\State $cp_s \gets cp_s - 1$\r
+\State \Return{$\tuple{DE_{ret},cp_s}$}\r
+\EndFunction\r
+\end{algorithmic}\r
+\r
+\begin{algorithmic}[1]\r
+\Function{GetKVPairs}{$DE_s,KV_s,cp_s$}\r
+\State $DE_{ret} \gets \emptyset$\r
+\If{$|KV_s| \leq cp_s$}\Comment{$KV$ set can span multiple slots}\r
+       \State $DE_{ret} \gets DE_s \cup\r
+       \{\tuple{k_s,v_s} \mid \tuple{ck_s,\tuple{k_s,v_s}} \in KV_s\}$\r
+\Else\r
+       \State $DE_{ret} \gets DE_s \cup\r
+       \{\tuple{k_s,v_s} \mid \tuple{ck_s,\tuple{k_s,v_s}} \in KV_s,\r
+               ck_g \leq ck_s < ck_g + cp_s\}$\r
+\EndIf\r
+\State \Return{$\tuple{DE_{ret}}$}\r
+\EndFunction\r
+\end{algorithmic}\r
+\r
+\begin{algorithmic}[1]\r
+\Function{GetSSPairs}{$DE_s,SS_s,cp_s$}\r
+\State $DE_{ret} \gets \emptyset$\r
+\If{$|SS_s| \leq cp_s$}\Comment{$SS$ set can span multiple slots}\r
+       \State $DE_{ret} \gets DE_s \cup\r
+       \{\tuple{id_s,s_{s_{last}}} \mid \tuple{cs_s,\tuple{id_s,s_{s_{last}}}} \in SS_s\}$\r
+       \State $cp_s \gets cp_s - |SS_s|$\r
+\Else\r
+       \State $DE_{ret} \gets DE_s \cup\r
+       \{\tuple{id_s,s_{s_{last}}} \mid \tuple{cs_s,\tuple{id_s,s_{s_{last}}}} \in SS_s,\r
+               cs_g \leq cs_s < cs_g + cp_s\}$\r
+       \State $cp_s \gets 0$\r
+\EndIf\r
+\State \Return{$\tuple{DE_{ret},cp_s}$}\r
+\EndFunction\r
+\end{algorithmic}\r
+\r
+\begin{algorithmic}[1]\r
+\Function{GetCRPairs}{$DE_s,CR_s,cp_s$}\r
+\State $DE_{ret} \gets \emptyset$\r
+\If{$|CR_s| \leq cp_s$}\Comment{$CR$ set can span multiple slots}\r
+       \State $DE_{ret} \gets DE_s \cup\r
+       \{\tuple{s_s,id_s} \mid \tuple{cc_s,\tuple{s_s,id_s}} \in CR_s\}$\r
+       \State $cp_s \gets cp_s - |CR_s|$\r
+\Else\r
+       \State $DE_{ret} \gets DE_s \cup\r
+       \{\tuple{s_s,id_s} \mid \tuple{cc_s,\tuple{s_s,id_s}} \in CR_s,\r
+               cc_g \leq cc_s < cc_g + cp_s\}$\r
+       \State $cp_s \gets 0$\r
+\EndIf\r
+\State \Return{$\tuple{DE_{ret},cp_s}$}\r
+\EndFunction\r
+\end{algorithmic}\r
+\r
+\begin{algorithmic}[1]\r
+\Procedure{PutDataEntries}{$th_p,m'_p$}\r
+\State $success_p \gets false$\r
+\State $CR_p \gets \emptyset$\r
+\While{$\neg success_p$}\r
+       \State $DE_p \gets \emptyset$\r
+       \State $s_p \gets MaxLastSeqN(MS)$\r
+       \State $cp_p \gets cp$\r
+       \State $max'_p \gets \Call{CheckResize}{MS,th_p,max_g,m'_p}$\r
+       \If{$max'_p \neq \emptyset$}\Comment{Add a qs entry}\r
+               \State $\tuple{DE_p,cp_p} \gets \Call{AddQueSta}{DE_p,max'_p,cp_p}$\r
+               \State $reinsert_{qs} \gets false$\r
+       \Else\Comment{Check if there is $qs$ reinsertion}\r
+               \If{$reinsert_{qs}$}\r
+                       \State $\tuple{DE_p,cp_p} \gets \Call{AddQueSta}{DE_p,max_g,cp_p}$\r
+                       \State $reinsert_{qs} \gets false$\r
+               \EndIf\r
+       \EndIf\r
+       \If{$SS \neq \emptyset$}\Comment{Add $ss$ entries}\r
+               \State $\tuple{DE_p,cp_p} \gets \Call{GetSSPairs}{DE_p,SS,cp_p}$\r
+       \EndIf\r
+       \If{$CR \neq \emptyset$}\Comment{Add $cr$ entries}\r
+               \State $\tuple{DE_p,cp_p} \gets \Call{GetCRPairs}{DE_p,CR,cp_p}$\r
+       \EndIf\r
+       \State $\tuple{DE_p,cp_p} \gets \Call{GetKVPairs}{DE_p,KV,cp_p}$\Comment{Add $kv$ entries}\r
+       \State $hmac_{c_p} \gets Hmac(DE_p,SK)$\r
+       \State $Dat_p \gets CreateDat(s_p,id_{self},hmac_{p_p},DE_p,hmac_{c_p})$\r
+       \State $hmac_{p_p} \gets hmac_{c_p}$\r
+       \State $sv_p \gets Encrypt(Dat_p,SK)$\r
+       \State $\tuple{success_p,SL_p} \gets \Call{PutSlot}{s_p,sv_p,max'_p}$\r
+       \If{$\neg success_p$}\r
+               \State $cr_p \gets \Call{HandleCollision}{SL_p,s_p}$\r
+               \State $\tuple{s_{p_{col}},id_{p_{col}}} \gets GetCR(cr_p)$\r
+               \State $CR \gets \Call{PutCRPair}{CR,\tuple{s_{p_{col}},id_{p_{col}}}}$\r
+       \EndIf\r
+\EndWhile\r
+\State $MS \gets \Call{UpdateLastSeqN}{id_{self},s_p,MS}$\r
+\If{$|DE_p| = cp$}\Comment{Update set counters}\r
+       \State $ck_g \gets ck_g + cp_p$\Comment{Middle of set}\r
+       \State $cs_g \gets cs_g + |SS|$\r
+       \State $cc_g \gets cc_g + |CR|$\r
+\Else\Comment{End of set}\r
+       \State $ck_g \gets 0$\r
+       \State $cs_g \gets 0$\r
+       \State $cc_g \gets 0$\r
+\EndIf\r
+\State $need_p \gets \Call{CheckSLFull}{MS,max_g}$\r
+\If{$need_p$}\Comment{SL on server is full}\r
+       \State $\Call{CheckLastSlot}{sl_{last}}$\Comment{Salvage entries from expunged slot}\r
+       \State $ss_p \gets \Call{CreateSlotSeq}{sl_{last}}$\r
+       \State $\tuple{id_p,s_{p_{last}}} \gets GetSS(ss_p)$\r
+       \State $SS \gets \Call{PutSSPair}{SS,\tuple{id_p,s_{p_{last}}}}$\Comment{Add ss}\r
+\EndIf\r
+\EndProcedure\r
+\end{algorithmic}\r
+\r
+%\note{Lots of problems with PutDataEntries: (1) What happens if lose network connectivity after adding the key value pair, but before reinserting the last slot?  You probably need to create space first and then insert your data entry...  (2) What if reinsertlastslot kicks something else important out?  What if the server rejects our update because it is out of date?  At the very least, any putdataentries function w/o a loop is wrong!}\r
+\r
+%\note{General comments...  Work on structuring things to improve readability...  This include names of functions/variables, how things are partitioned into functions, adding useful comments,...}\r
+  \r
+%\note{Also Missing liveness state definition in algorithm...}\r
+\r
+\r
+\subsection{Formal Guarantees}\r
+\subsubsection{Definitions}\r
+\r
+\begin{defn}[Message]\r
+A message $\mathsf{t}$, is the tuple \r
+\begin{center}\r
+$\mathsf{t = \tuple{s, E(Dat_s)}}$ \\\r
+$\mathsf{Dat_t = \tuple{s,id,hmac_p, DE,hmac_c}}$\r
+\end{center}\r
+containing $\mathsf{s}$ as sequence number and $\mathsf{Dat_t}$ as its \r
+encrypted contents. $\mathsf{Dat_t}$ consists of $\mathsf{s}$, \r
+$\mathsf{id}$ as machine ID of the sender, $\mathsf{hmac_p}$ as HMAC \r
+from a previous message, $\mathsf{DE}$ as set of data entries, and \r
+$\mathsf{hmac_c}$ as HMAC from message $\mathsf{t}$ respectively.\r
+\end{defn}\r
+\r
+\begin{defn}[Equality]\r
+Two messages $\mathsf{t}$ and $\mathsf{u}$ are equal if their $\mathsf{s}$, \r
+and $\mathsf{Dat_t}$ are exactly the same.\r
+\end{defn}\r
+\r
+\begin{defn}[Parent]\r
+A parent of a message $\mathsf{t}$ is the message $\mathsf{p_t}$, \r
+unique by the correctness of HMACs in $\mathsf{Dat_t}$, such that \r
+$\mathsf{hmac_p(t) = hmac_c(p_t)}$.\r
+\end{defn}\r
+\r
+\begin{defn}[Chain]\r
+A chain of messages with length $\mathsf{n \ge 1}$ is a message sequence \r
+$\mathsf{R = (r_s, r_{s+1}, ..., r_{s+n-1})}$ such that for every sequence \r
+number $\mathsf{s < k \le s+n-1}$, $\mathsf{r_k}$ has sequence number \r
+$\mathsf{k}$ and is the parent of $\mathsf{r_{k-1}}$.\r
+\end{defn}\r
+\r
+\begin{defn}[Partial sequence]\r
+A partial sequence $\mathsf{P}$ is a sequence of messages, no two \r
+with the same sequence number, that can be divided into disjoint chains.\r
+\end{defn}\r
+\r
+\begin{defn}[Total sequence]\r
+A total sequence $\mathsf{T =}$ $\mathsf{(t_1, t_2, ..., t_n)}$ with \r
+length $\mathsf{n}$ is a chain of messages that starts at $\mathsf{s = 1}$.\r
+\end{defn}\r
+\r
+\begin{defn}[Path]\r
+The path of a message $\mathsf{t}$ is the chain that starts at $\mathsf{s = 1}$ \r
+and whose last message is $\mathsf{t}$. The uniqueness of a path follows \r
+from the uniqueness of a parent.\r
+\end{defn}\r
+\r
+\begin{defn}[Consistency]\r
+A partial sequence $\mathsf{P}$ is consistent with a total sequence \r
+$\mathsf{T}$ of length $\mathsf{n}$ if for every message $\mathsf{p \in P}$ \r
+with $\mathsf{s_p \leq n}$, $\mathsf{t_{s_p} = p}$. This implies that \r
+$\mathsf{\{p \in P | s_p \le n\}}$ is a partial sequence of $\mathsf{T}$.\r
+\end{defn}\r
+\r
+\begin{defn}[Transitive closure]\r
+Transitive closure set at sequence number $\mathsf{s_n}$ is a set \r
+$\mathsf{\mathscr{S}}$ of clients comprising a connected component of an \r
+undirected graph, where two clients are connected by an edge if they both \r
+received the same message $\mathsf{t}$ with sequence number $\mathsf{s_t > s_n}$.\r
+\end{defn}\r
+\r
+\subsubsection{Lemmas and Proofs}\r
+\r
+\begin{prop}\r
+\label{prop:parentmessage}\r
+Every client $\mathsf{J}$ who sends a message $\mathsf{t}$ \r
+has parent $\mathsf{p_t}$ as its latest stored message, and \r
+$\mathsf{s_t = s_{p_t} + 1}$. \r
+\end{prop}\r
+\begin{proof} True by definition, because $J$ sets \r
+$\mathsf{hmac_p(t) = hmac_c(p_t)}$ and \r
+$\mathsf{s_t = }$ $\mathsf{s_{p_t + 1}}$ when a message \r
+is sent. \r
+\end{proof}\r
+\r
+\begin{prop} \r
+\label{prop:rejectedmessage}\r
+If a rejected message entry is added to the set $\mathsf{CR}$ \r
+at sequence number $\mathsf{s}$, the message will remain in $\mathsf{CR}$ \r
+until every client has seen it. \r
+\end{prop}\r
+\begin{proof} Every $\mathsf{CR}$ entry $\mathsf{cr}$ remains in the queue until it \r
+reaches the tail, and is refreshed by the next sender $\mathsf{J}$ at that time if \r
+$\mathsf{min(MS) > s_{cr}}$; that is, until every client has sent a message with \r
+sequence number greater than $\mathsf{s_{cr}}$. Because every client who sends a \r
+message with sequence number $\mathsf{s}$ has the state of the set $\mathsf{SL}$ at \r
+$\mathsf{s - 1}$, this client will have seen the message at $\mathsf{s_{cr}}$. \r
+\end{proof}\r
+\r
+\begin{figure}[h]\r
+  \centering\r
+      \xymatrix{ & & L \\\r
+\dots \ar[r] & q \ar[dr]_{J} \ar[r]^{K} & l_1 \ar[r] & l_2 \ar[r] & \dots \ar[r] & m \ar[r] & \dots \ar[r] & l_n = u \\\r
+& & r_1 \ar[r] & r_2 \ar[r] & \dots \ar[r] & r_m = t \\\r
+& & R\r
+\save "2,3"."2,8"*+\frm{^\}}\r
+\save "3,3"."3,6"*+\frm{_\}}\r
+\restore\r
+\restore\r
+}\r
+\caption{By \textbf{Lemma \ref{lem:twomessages}}, receiving both $t$ and $u$ here is impossible.}\r
+\end{figure}\r
+\r
+\begin{lem}\r
+\label{lem:twomessages}\r
+Two messages are received without errors by a client $\mathsf{C}$; \r
+call them $\mathsf{t}$ and $\mathsf{u}$ such that $\mathsf{s_t \le s_u}$. \r
+Then $\mathsf{t}$ is in the path of $\mathsf{u}$. \r
+\end{lem}\r
+\begin{proof}\r
+Assume that there are some pairs of messages $\mathsf{(t,u)}$ that violate this lemma. \r
+Take a specific $\mathsf{(t,u)}$ such that $\mathsf{s_u}$ is minimized, and \r
+$\mathsf{s_t}$ is maximized for this choice of $\mathsf{s_u}$. We will show that $\mathsf{C}$\r
+cannot receive both $\mathsf{t}$ and $\mathsf{u}$ without throwing an error.\r
+\r
+Clearly $\mathsf{C}$ will throw an error if $\mathsf{s_t = s_u}$. So \r
+$\mathsf{s_t < s_u}$. Additionally, if $\mathsf{C}$ receives $\mathsf{u}$ before \r
+$\mathsf{t}$, this will cause it to throw an error, so $\mathsf{t}$ is received \r
+before $\mathsf{u}$. We will prove that an error occurs upon receipt of $\mathsf{u}$.\r
+\r
+Let $\mathsf{r_1}$ be the earliest member of the path of $\mathsf{t}$ that is \r
+not in the path of $\mathsf{u}$, and $\mathsf{q}$ be its parent. Message \r
+$\mathsf{q}$, the last common ancestor of $\mathsf{t}$ and $\mathsf{u}$, must exist, \r
+since all clients and the server were initialized with the same state. Let \r
+$\mathsf{l_1}$ be the successor of $\mathsf{q}$ that is in the path of $\mathsf{u}$; \r
+we know $\mathsf{l_1 \neq r_1}$. Let $\mathsf{R = (r_1, r_2, \dots, r_{|R|} = t)}$ be \r
+the distinct portion of the path of $\mathsf{t}$, and similarly let $\mathsf{L}$ \r
+be the distinct portion of the path of $\mathsf{l_{|L|} = u}$.\r
+\r
+Let $\mathsf{J}$ be the client who sent $\mathsf{r_1}$; that is, such that \r
+$\mathsf{{id_{self}}_J = GetMacID(r_1)}$, and $\mathsf{K}$ be the client who \r
+sent $\mathsf{l_1}$. Because no client can send two messages with the same sequence number, and \r
+$\mathsf{s_{r_1} = s_{l_1} = s_q + 1}$, $\mathsf{J \neq K}$.\r
+\r
+We also know the following facts: \r
+\r
+\begin{prop} \r
+\label{prop:bothmessages}\r
+No client sends both a message in $\mathsf{(r_2,...,t)}$ and a message in $\mathsf{(l_2,...,u)}$. \r
+\end{prop}\r
+\r
+\begin{proof}\r
+To send a message $\mathsf{p}$ that is the parent of some other \r
+message, one must have received the parent of $\mathsf{p}$. Since \r
+$\mathsf{u}$ is the message with smallest sequence number received by any \r
+client that violates Lemma \ref{lem:twomessages}, no client receives both a message \r
+in $\mathsf{r}$ and a message in $\mathsf{l}$. \r
+\end{proof}\r
+\r
+\begin{prop} \r
+\label{prop:seqnumb}\r
+$\mathsf{C}$ does not receive any message with a\r
+sequence number strictly between $\mathsf{s_t}$ and $\mathsf{s_u}$. \r
+\end{prop}\r
+\r
+\begin{proof} If there were such a message with sequence number smaller than \r
+$\mathsf{s_u}$, it would contradict the assumption that $\mathsf{u}$ is the \r
+message with the least sequence number that violates Lemma \ref{lem:twomessages}. \r
+\end{proof}\r
+\r
+There are two cases:\r
+\begin{itemize}\r
+\item Case 1: $\mathsf{J}$ did not send a message in $\mathsf{L}$. Then, where $\mathsf{s_{t_J}}$ \r
+is the greatest sequence number of the messages that client $\mathsf{J}$ sent in \r
+the path of message $\mathsf{t}$, $\mathsf{s_{t_J} > s_{q_J} = s_{u_J}}$.\r
+\begin{itemize}\r
+\item Case 1.1: $\mathsf{C}$ never updates its slot sequence list $\mathsf{SS}$ \r
+between receiving $\mathsf{t}$ and receiving $\mathsf{u}$; this can only happen if \r
+$\mathsf{s_t = s_u - 1}$. Since $\mathsf{t}$ is not the parent of $\mathsf{u}$, \r
+$\mathsf{hmac_p(u) \neq hmac_c(t)}$, causing $\mathsf{C}$ to throw an error.\r
+\item Case 1.2: Case 1.1 does not occur; therefore, $\mathsf{C}$ must update \r
+its slot sequence list $\mathsf{SS}$ at some point between receiving $\mathsf{t}$ \r
+and $\mathsf{u}$. \r
+The latest sequence number of $\mathsf{J}$ decreases during this time, which \r
+means it must decrease when some message is received, which means $\mathsf{C}$ \r
+throws an error in the $\mathsf{CheckLastSeqN()}$ subroutine.\r
+\end{itemize}\r
+\r
+\item Case 2: $\mathsf{J}$ sent at least one message in $\mathsf{L}$. Call the \r
+first one $\mathsf{m}$. We know that $\mathsf{s_m > s_{r_1}}$, since \r
+$\mathsf{J \neq K}$ and $\mathsf{m \neq l_1}$. Message $\mathsf{r_1}$ must be sent \r
+either before or after $\mathsf{m}$.\r
+\begin{itemize}\r
+\item Case 2.1: Client $\mathsf{J}$ sends $\mathsf{m}$, and then $\mathsf{r_1}$. \r
+Before sending $\mathsf{m}$, the greatest sequence number of a message that \r
+$\mathsf{J}$ has received, $\mathsf{{s_{last}}_J}$, must be equal to \r
+$\mathsf{s_m - 1 \ge s_{r_1}}$. Since $\mathsf{{s_{last}}_J}$ never decreases, \r
+client $\mathsf{J}$ cannot then send a message with sequence number \r
+$\mathsf{s_{r_1}}$, a contradiction.\r
+\item Case 2.2: Client $\mathsf{J}$ sends $\mathsf{r_1}$, and then $\mathsf{m}$. \r
+Let $\mathsf{X = (r_1 = x_1, \dots , x_n)}$ be the list of messages $\mathsf{J}$ sends \r
+starting before $\mathsf{r_1}$ and ending before $m$; clearly these all have sequence \r
+number $\mathsf{s_p = s_q + 1}$.\r
+\begin{itemize}\r
+\item Case 2.2.1: Some message in $\mathsf{X}$ was accepted. Before sending $\mathsf{m}$, \r
+$\mathsf{J}$'s value in $\mathsf{MS_J}$ for its own latest sequence number would \r
+be strictly greater than $\mathsf{s_{q_J}}$. If there is a sequence of messages with \r
+contiguous sequence numbers that $\mathsf{J}$ receives between $\mathsf{r_1}$ and \r
+$\mathsf{m}$, $\mathsf{J}$ throws an error for a similar reason as Case 1.1. Otherwise, \r
+when preparing to send $\mathsf{m}$, $\mathsf{J}$ would have received an update of its \r
+own latest sequence number as at most $\mathsf{s_{q_J}}$. $J$ throws an error before \r
+sending $\mathsf{p}$, because its own latest sequence number decreases.\r
+\item Case 2.2.2: All messages in $\mathsf{X}$ were rejected, making $\mathsf{m}$ \r
+the first message of $\mathsf{J}$ that is accepted after $\mathsf{r_1}$.\r
+\r
+We will show that $\mathsf{C}$ sees $\mathsf{r_1}$. Assume not. Then $\mathsf{(r_2, ..., u)}$ \r
+must have at least $\mathsf{{max_g}_C} \geq 2$ messages for $\mathsf{r_1}$ to fall off the \r
+end of the queue. Consider the sender of $\mathsf{r_3}$ and call it $\mathsf{H}$. \r
+$\mathsf{H \neq J}$ by Proposition \ref{prop:bothmessages} and the existence of $\mathsf{m}$. \r
+Since $\mathsf{H \neq J}$, then by Proposition \ref{prop:bothmessages} it could not also \r
+have sent a message in $\mathsf{(l_2,..., u)}$. Therefore, $\mathsf{s_{u_H} < s_q + 2 = s_{t_H}}$, \r
+so upon receipt of $\mathsf{u}$, $\mathsf{C}$ will throw an error by the decrease in a \r
+last sequence number similar to Case 1, a contradiction.\r
+\r
+Now that we know that $\mathsf{C}$ sees $\mathsf{r_1}$, note that C receives $\mathsf{u}$ \r
+immediately after $\mathsf{t}$ by Proposition \ref{prop:seqnumb}. Therefore, \r
+$\mathsf{C}$ could not have seen a message after $\mathsf{t}$ with sequence number less \r
+than $\mathsf{s_m}$. In the $\mathsf{PutDataEntries()}$ subroutine, $\mathsf{J}$ adds every \r
+$\mathsf{cr}$ entry that contains sequence number $\mathsf{s}$ and machine ID \r
+$\mathsf{id}$ of the messsages that win in the collisions before $\mathsf{m}$ into \r
+$\mathsf{CR}$; $\mathsf{CR}$ keeps the collection of live $\mathsf{cr}$ entries, namely\r
+those which not all clients have seen. Hence, for every $\mathsf{i}$, $\mathsf{1 \leq i < |X|}$, \r
+the collision winner that has collided with $\mathsf{x_i}$ will be recorded appropriately. Since all the $\mathsf{cr}$ entries that record the results of the collisions before $\mathsf{p}$ will also be seen when $\mathsf{u}$ \r
+is received, and $\mathsf{C}$ sees $\mathsf{r_1}$, ${l_1}$ will be recorded in a $\mathsf{cr}$ entry as the winner in the \r
+collision against ${r_1}$.\r
+\r
+When $\mathsf{C}$ receives $\mathsf{u}$, if $\mathsf{C}$ \r
+has seen the $\mathsf{cr}$ entry that records the collision at index $\mathsf{s_q + 1}$, it will throw \r
+an error from the mismatch of $\mathsf{\tuple{s_q+1, id_J}}$ with \r
+$\mathsf{\tuple{s_q+1, id_K}}$ in the corresponding $\mathsf{cr}$ entry.\r
+\r
+\end{itemize}\r
+\end{itemize}\r
+\r
+\end{itemize}\r
+\end{proof}\r
+\r
+\begin{lem} \r
+\label{lem:pathmessages}\r
+If there are two messages $\mathsf{t}$ and $\mathsf{u}$, with \r
+$\mathsf{s_t \leq s_u}$, such that $\mathsf{t}$ is in the path of $\mathsf{u}$, \r
+then for any message $\mathsf{p}$ with $\mathsf{s_p \leq s_t}$, iff $\mathsf{p}$ is in \r
+the path of $\mathsf{t}$, it is in the path of $\mathsf{u}$. \r
+\end{lem}\r
+\r
+\begin{proof}\r
+If $\mathsf{s_t = s_u}$ or $\mathsf{s_p = s_t}$, then we are done, because the two \r
+relevant messages are the same. If they are different messages, then:\r
+\begin{itemize}\r
+\item Reverse direction: The definition of $\mathsf{t}$ being in the path of \r
+$\mathsf{u}$ is the existence of a message sequence $\mathsf{(\dots, t, \dots, u)}$ \r
+such that each message except $\mathsf{u}$ is the parent of the succeeding message. \r
+The path of $\mathsf{u}$ must contain some message with sequence number $\mathsf{s_p}$; \r
+because $\mathsf{p}$ is in the path of $\mathsf{u}$, this message is $\mathsf{p}$ \r
+itself. The path of $\mathsf{t}$ is then the prefix of this path ending at $\mathsf{t}$, \r
+which clearly contains $\mathsf{p}$.\r
+\r
+\item Forward direction: The path of $\mathsf{t}$ is a substring of the path of \r
+$\mathsf{u}$, so if the path of $\mathsf{t}$ contains $\mathsf{p}$, so does the path \r
+of $\mathsf{u}$.\r
+\end{itemize}\r
+\end{proof}\r
+\r
+\begin{theorem}\r
+Suppose that there is a transitive closure set $\mathsf{\mathscr{S}}$ of clients, \r
+at sequence number $\mathsf{s_n}$. Then there is some total sequence $\mathsf{T}$ of \r
+length $\mathsf{n}$ such that every client $\mathsf{C}$ in $\mathsf{\mathscr{S}}$ \r
+sees a partial sequence $\mathsf{P_C}$ consistent with $\mathsf{T}$. \r
+\end{theorem}\r
+\r
+\begin{proof}\r
+\r
+The definition of consistency of $\mathsf{P_C}$ with $\mathsf{T}$ is that every message \r
+$\mathsf{p \in P_C}$ with sequence number $\mathsf{s_p \le s_n}$ is equal to the message \r
+in that slot in $\mathsf{T}$. Let $\mathsf{C_1}$ be some client in the transitive closure \r
+set, with partial sequence $\mathsf{P_{C_1}}$, and let $\mathsf{u}$ be some message with \r
+$\mathsf{s_u > s_n}$ that $\mathsf{C_1}$ shares with another client. Then let $\mathsf{T}$ \r
+be the portion of the path of $\mathsf{u}$ ending at sequence number $\mathsf{s_n}$ and \r
+$\mathsf{t}$ be the message at that sequence number. Clearly, by Lemma \ref{lem:twomessages}, \r
+$\mathsf{P_{C_1}}$ is consistent with $\mathsf{T}$. We will show that, for every other client \r
+$\mathsf{D}$ with partial sequence $\mathsf{P_D}$, $\mathsf{P_D}$ has some message whose path \r
+includes $\mathsf{t}$. Because $\mathsf{D}$ is in the transitive closure, there is a sequence \r
+of clients $\mathsf{\mathscr{C} = (C_1, C_2, ..., D)}$ from $\mathsf{C_1}$ to $\mathsf{D}$, \r
+where each shares an edge with the next.\r
+We prove by induction that $\mathsf{P_D}$ has a message whose path includes $\mathsf{t}$.\r
+\begin{itemize}\r
+\item Base case: $\mathsf{P_{C_1}}$ includes $\mathsf{u}$, whose path includes $\mathsf{t}$.\r
+\r
+\item Inductive step: Each client in $\mathsf{\mathscr{C}}$ has a partial sequence with a message \r
+that includes $\mathsf{t}$ if the previous client does. Suppose $\mathsf{P_{C_k}}$ has \r
+a message $\mathsf{w}$ with a path that includes $\mathsf{t}$, and shares message $\mathsf{x}$ \r
+with $\mathsf{P_{C_{k+1}}}$ such that $\mathsf{s_x > s_n}$. By Lemma \ref{lem:twomessages}, \r
+$\mathsf{w}$ or $\mathsf{x}$, whichever has the least sequence number, is in the path of the other, \r
+and therefore by Lemma \ref{lem:pathmessages}, $\mathsf{t}$ is in the path of $\mathsf{x}$.\r
+\r
+\item Let $\mathsf{z}$ be the message of $\mathsf{D}$ whose path includes $\mathsf{t}$. \r
+By Lemma \ref{lem:twomessages}, every message in $\mathsf{P_D}$ with sequence number smaller \r
+than $\mathsf{s_w}$ is in the path of $\mathsf{z}$. Since $\mathsf{t}$ is in the path of \r
+$\mathsf{z}$, every message in $\mathsf{P_D}$ with smaller sequence number than \r
+$\mathsf{s_t = s_n}$ is in $\mathsf{T}$. \r
+Therefore, $\mathsf{P_D}$ is consistent with $\mathsf{T}$.\r
+\r
+\end{itemize}\r
+\end{proof}\r
+\r
+\subsection{Future Work}\r
+\paragraph{Support Messages}\r
+  A message is dead once receiving machine sends an entry with a newer\r
+  sequence identifier\r
+\r
+\paragraph{Persistent data structures}\r
+       Root object w/ fields\r
+       Other objects can be reachable from root\r
+       Each object has its own entries\r
+       Dead objects correspond to dead \r
+\r
+\paragraph{Multiple App Sharing}\r
+\r
+Idea is to separate subspace of entries...  Shared with other cloud...\r
+\end{document}\r
diff --git a/version1/doc/makefile b/version1/doc/makefile
new file mode 100644 (file)
index 0000000..cff4a15
--- /dev/null
@@ -0,0 +1,8 @@
+LATEX := pdflatex -halt-on-error
+
+default:
+       $(LATEX) iotcloud.tex
+
+clean:
+       rm -f *.dvi *.log *.aux *.blg *.bbl *~
+       rm -f iotcloud.ps iotcloud.pdf 
diff --git a/version1/src/java/.dir-locals.el b/version1/src/java/.dir-locals.el
new file mode 100644 (file)
index 0000000..e166a2e
--- /dev/null
@@ -0,0 +1,2 @@
+((nil . ((indent-tabs-mode . t))))
+
diff --git a/version1/src/java/iotcloud/CloudComm.java b/version1/src/java/iotcloud/CloudComm.java
new file mode 100644 (file)
index 0000000..ac906b1
--- /dev/null
@@ -0,0 +1,232 @@
+package iotcloud;
+import java.io.*;
+import java.net.*;
+import java.util.Arrays;
+import javax.crypto.*;
+import javax.crypto.spec.*;
+import java.security.SecureRandom;
+
+/**
+ * This class provides a communication API to the webserver.  It also
+ * validates the HMACs on the slots and handles encryption.
+ * @author Brian Demsky <bdemsky@uci.edu>
+ * @version 1.0
+ */
+
+
+class CloudComm {
+       String baseurl;
+       Cipher encryptCipher;
+       Cipher decryptCipher;
+       Mac mac;
+       String password;
+       SecureRandom random;
+       static final int SALT_SIZE = 8;
+       byte salt[];
+       Table table;
+       
+       /**
+        * Empty Constructor needed for child class.
+        */
+
+       CloudComm() {
+       }
+
+       /**
+        * Constructor for actual use. Takes in the url and password.
+        */
+
+       CloudComm(Table _table, String _baseurl, String _password) {
+               this.table=_table;
+               this.baseurl=_baseurl;
+               this.password = _password;
+               this.random = new SecureRandom();
+       }
+
+       /**
+        * Generates Key from password.
+        */
+
+       private SecretKeySpec initKey() {
+               try {
+                       PBEKeySpec keyspec = new PBEKeySpec(password.toCharArray(), salt, 65536, 128);
+                       SecretKey tmpkey = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256").generateSecret(keyspec);
+                       return new SecretKeySpec(tmpkey.getEncoded(), "AES");
+               } catch (Exception e) {
+                       e.printStackTrace();
+                       throw new Error("Failed generating key.");
+               }
+       }
+
+       /**
+        * Inits the HMAC generator.
+        */
+
+       private void initCrypt() {
+               try {
+                       SecretKeySpec key=initKey();
+                       password = null; // drop password
+                       mac = Mac.getInstance("HmacSHA256");
+                       mac.init(key);
+                       encryptCipher =Cipher.getInstance("AES/ECB/PKCS5Padding");
+                       encryptCipher.init(Cipher.ENCRYPT_MODE, key);
+                       decryptCipher =Cipher.getInstance("AES/ECB/PKCS5Padding");
+                       decryptCipher.init(Cipher.DECRYPT_MODE, key);
+               } catch (Exception e) {
+                       e.printStackTrace();
+                       throw new Error("Failed To Initialize Ciphers");
+               }
+       }
+
+       /*
+        * Builds the URL for the given request.
+        */
+
+       private URL buildRequest(boolean isput, long sequencenumber, long maxentries) throws IOException {
+               String reqstring=isput?"req=putslot":"req=getslot";
+               String urlstr=baseurl+"?"+reqstring+"&seq="+sequencenumber;
+               if (maxentries != 0)
+                       urlstr += "&max="+maxentries;
+               return new URL(urlstr);
+       }
+       
+       public void setSalt() {
+               try {
+                       salt = new byte[SALT_SIZE];
+                       random.nextBytes(salt);
+                       URL url=new URL(baseurl+"?req=setsalt");
+                       URLConnection con=url.openConnection();
+                       HttpURLConnection http = (HttpURLConnection) con;
+                       http.setRequestMethod("POST");
+                       http.setFixedLengthStreamingMode(salt.length);
+                       http.setDoOutput(true);
+                       http.connect();
+                       OutputStream os=http.getOutputStream();
+                       os.write(salt);
+                       int responsecode=http.getResponseCode();
+                       if (responsecode != HttpURLConnection.HTTP_OK)
+                               throw new Error("Invalid response");
+               } catch (Exception e) {
+                       e.printStackTrace();
+                       throw new Error("Failed setting salt");
+               }
+               initCrypt();
+       }
+
+       private void getSalt() throws Exception {
+               URL url=new URL(baseurl+"?req=getsalt");
+               URLConnection con=url.openConnection();
+               HttpURLConnection http = (HttpURLConnection) con;
+               http.setRequestMethod("POST");
+               http.connect();
+               
+               InputStream is=http.getInputStream();
+               DataInputStream dis=new DataInputStream(is);
+               int salt_length=dis.readInt();
+               byte [] tmp=new byte[salt_length];
+               dis.readFully(tmp);
+               salt=tmp;
+       }
+       
+       /*
+        * API for putting a slot into the queue.  Returns null on success.
+        * On failure, the server will send slots with newer sequence
+        * numbers.
+        */
+
+       Slot[] putSlot(Slot slot, int max) {
+               try {
+                       if (salt == null) {
+                               getSalt();
+                               initCrypt();
+                       }
+                       
+                       long sequencenumber=slot.getSequenceNumber();
+                       byte[] bytes=slot.encode(mac);
+                       bytes = encryptCipher.doFinal(bytes);
+
+                       URL url=buildRequest(true, sequencenumber, max);
+                       URLConnection con=url.openConnection();
+                       HttpURLConnection http = (HttpURLConnection) con;
+
+                       http.setRequestMethod("POST");
+                       http.setFixedLengthStreamingMode(bytes.length);
+                       http.setDoOutput(true);
+                       http.connect();
+
+                       OutputStream os=http.getOutputStream();
+                       os.write(bytes);
+
+                       InputStream is=http.getInputStream();
+                       DataInputStream dis=new DataInputStream(is);
+                       byte[] resptype=new byte[7];
+                       dis.readFully(resptype);
+                       if (Arrays.equals(resptype, "getslot".getBytes()))
+                               return processSlots(dis);
+                       else if (Arrays.equals(resptype, "putslot".getBytes()))
+                               return null;
+                       else
+                               throw new Error("Bad response to putslot");
+               } catch (Exception e) {
+                       e.printStackTrace();
+                       throw new Error("putSlot failed");
+               }
+       }
+
+       /**
+        * Request the server to send all slots with the given
+        * sequencenumber or newer.
+        */
+
+       Slot[] getSlots(long sequencenumber) {
+               try {
+                       if (salt == null) {
+                               getSalt();
+                               initCrypt();
+                       }
+                       
+                       URL url=buildRequest(false, sequencenumber, 0);
+                       URLConnection con=url.openConnection();
+                       HttpURLConnection http = (HttpURLConnection) con;
+                       http.setRequestMethod("POST");
+                       http.connect();
+                       InputStream is=http.getInputStream();
+
+                       DataInputStream dis=new DataInputStream(is);
+                       
+                       byte[] resptype=new byte[7];
+                       dis.readFully(resptype);
+                       if (!Arrays.equals(resptype, "getslot".getBytes()))
+                               throw new Error("Bad Response: "+new String(resptype));
+                       else
+                               return processSlots(dis);
+               } catch (Exception e) {
+                       e.printStackTrace();
+                       throw new Error("getSlots failed");
+               }
+       }
+
+       /**
+        * Method that actually handles building Slot objects from the
+        * server response.  Shared by both putSlot and getSlots.
+        */
+
+       private Slot[] processSlots(DataInputStream dis) throws Exception {
+               int numberofslots=dis.readInt();
+               int[] sizesofslots=new int[numberofslots];
+               Slot[] slots=new Slot[numberofslots];
+               for(int i=0; i<numberofslots; i++)
+                       sizesofslots[i]=dis.readInt();
+
+               for(int i=0; i<numberofslots; i++) {
+                       byte[] data=new byte[sizesofslots[i]];
+                       dis.readFully(data);
+
+                       data = decryptCipher.doFinal(data);
+
+                       slots[i]=Slot.decode(table, data, mac);
+               }
+               dis.close();
+               return slots;
+       }
+}
diff --git a/version1/src/java/iotcloud/Entry.java b/version1/src/java/iotcloud/Entry.java
new file mode 100644 (file)
index 0000000..70f90ee
--- /dev/null
@@ -0,0 +1,94 @@
+package iotcloud;
+import java.nio.ByteBuffer;
+
+/**
+ * Generic class that wraps all the different types of information
+ * that can be stored in a Slot.
+ * @author Brian Demsky <bdemsky@uci.edu>
+ * @version 1.0
+ */
+
+abstract class Entry implements Liveness {
+       static final byte TypeKeyValue = 1;
+       static final byte TypeLastMessage = 2;
+       static final byte TypeRejectedMessage = 3;
+       static final byte TypeTableStatus = 4;
+
+       /* Records whether the information is still live or has been
+                superceded by a newer update.  */
+
+       private boolean islive = true;
+       private Slot parentslot;
+
+       Entry(Slot _parentslot) {
+               parentslot = _parentslot;
+       }
+
+       /**
+        * Static method for decoding byte array into Entry objects.  First
+        * byte tells the type of entry.
+        */
+
+       static Entry decode(Slot slot, ByteBuffer bb) {
+               byte type=bb.get();
+               switch(type) {
+               case TypeKeyValue:
+                       return KeyValue.decode(slot, bb);
+
+               case TypeLastMessage:
+                       return LastMessage.decode(slot, bb);
+
+               case TypeRejectedMessage:
+                       return RejectedMessage.decode(slot, bb);
+
+               case TypeTableStatus:
+                       return TableStatus.decode(slot, bb);
+
+               default:
+                       throw new Error("Unrecognized Entry Type: "+type);
+               }
+       }
+
+       /**
+        * Returns true if the Entry object is still live.
+        */
+
+       boolean isLive() {
+               return islive;
+       }
+
+       /**
+        * Flags the entry object as dead.  Also decrements the live count
+        * of the parent slot.
+        */
+
+       void setDead() {
+               islive = false;
+               parentslot.decrementLiveCount();
+       }
+
+       /**
+        * Serializes the Entry object into the byte buffer.
+        */
+
+       abstract void encode(ByteBuffer bb);
+
+       /**
+        * Returns the size in bytes the entry object will take in the byte
+        * array.
+        */
+
+       abstract int getSize();
+
+       /**
+        * Returns a byte encoding the type of the entry object.
+        */
+
+       abstract byte getType();
+
+       /**
+        * Returns a copy of the Entry that can be added to a different slot.
+        */
+       abstract Entry getCopy(Slot s);
+
+}
diff --git a/version1/src/java/iotcloud/IoTString.java b/version1/src/java/iotcloud/IoTString.java
new file mode 100644 (file)
index 0000000..19ebee3
--- /dev/null
@@ -0,0 +1,105 @@
+package iotcloud;
+
+import java.util.Arrays;
+
+/**
+ * IoTString is wraps the underlying byte string.  We don't use the
+ * standard String class as we have bytes and not chars.
+ * @author Brian Demsky <bdemsky@uci.edu>
+ * @version 1.0
+ */
+
+
+final public class IoTString {
+       byte[] array;
+       int hashcode;
+
+       private IoTString() {
+       }
+
+       /**
+        * Builds an IoTString object around the byte array.  This
+        * constructor makes a copy, so the caller is free to modify the byte array.
+        */
+
+       public IoTString(byte[] _array) {
+               array=(byte[]) _array.clone();
+               hashcode=Arrays.hashCode(array);
+       }
+
+       /**
+        * Converts the String object to a byte representation and stores it
+        * into the IoTString object.
+        */
+
+       public IoTString(String str) {
+               array=str.getBytes();
+               hashcode=Arrays.hashCode(array);
+       }
+
+       /**
+        * Internal methods to build an IoTString using the byte[] passed
+        * in.  Caller is responsible for ensuring the byte[] is never
+        * modified.
+        */
+
+       static IoTString shallow(byte[] _array) {
+               IoTString i=new IoTString();
+               i.array = _array;
+               i.hashcode = Arrays.hashCode(_array);
+               return i;
+       }
+
+       /**
+        * Internal method to grab a reference to our byte array.  Caller
+        * must not modify it.
+        */
+
+       byte[] internalBytes() {
+               return array;
+       }
+
+       /**
+        * Returns the hashCode as computed by Arrays.hashcode(byte[]).
+        */
+
+       public int hashCode() {
+               return hashcode;
+       }
+
+       /**
+        * Returns a String representation of the IoTString.
+        */
+
+       public String toString() {
+               return new String(array);
+       }
+
+       /**
+        * Returns a copy of the underlying byte string.
+        */
+
+       public byte[] getBytes() {
+               return (byte[]) array.clone();
+       }
+
+       /**
+        * Returns true if two byte strings have the same content.
+        */
+
+       public boolean equals(Object o) {
+               if (o instanceof IoTString) {
+                       IoTString i=(IoTString)o;
+                       return Arrays.equals(array, i.array);
+               }
+               return false;
+       }
+
+       /**
+        * Returns the length in bytes of the IoTString.
+        */
+
+       public int length() {
+               return array.length;
+       }
+}
diff --git a/version1/src/java/iotcloud/KeyValue.java b/version1/src/java/iotcloud/KeyValue.java
new file mode 100644 (file)
index 0000000..bed66a2
--- /dev/null
@@ -0,0 +1,61 @@
+package iotcloud;
+import java.nio.ByteBuffer;
+
+/**
+ * KeyValue entry for Slot.
+ * @author Brian Demsky <bdemsky@uci.edu>
+ * @version 1.0
+ */
+
+class KeyValue extends Entry {
+       private IoTString key;
+       private IoTString value;
+
+       KeyValue(Slot slot, IoTString _key, IoTString _value) {
+               super(slot);
+               key=_key;
+               value=_value;
+       }
+
+       IoTString getKey() {
+               return key;
+       }
+
+       IoTString getValue() {
+               return value;
+       }
+
+       static Entry decode(Slot slot, ByteBuffer bb) {
+               int keylength=bb.getInt();
+               int valuelength=bb.getInt();
+               byte[] key=new byte[keylength];
+               byte[] value=new byte[valuelength];
+               bb.get(key);
+               bb.get(value);
+               return new KeyValue(slot, IoTString.shallow(key), IoTString.shallow(value));
+       }
+
+       void encode(ByteBuffer bb) {
+               bb.put(Entry.TypeKeyValue);
+               bb.putInt(key.length());
+               bb.putInt(value.length());
+               bb.put(key.internalBytes());
+               bb.put(value.internalBytes());
+       }
+
+       int getSize() {
+               return 2*Integer.BYTES+key.length()+value.length()+Byte.BYTES;
+       }
+
+       byte getType() {
+               return Entry.TypeKeyValue;
+       }
+
+       public String toString() {
+               return value.toString();
+       }
+
+       Entry getCopy(Slot s) {
+               return new KeyValue(s, key, value);
+       }
+}
diff --git a/version1/src/java/iotcloud/LastMessage.java b/version1/src/java/iotcloud/LastMessage.java
new file mode 100644 (file)
index 0000000..c87c2e9
--- /dev/null
@@ -0,0 +1,55 @@
+package iotcloud;
+
+import java.nio.ByteBuffer;
+
+/**
+ * This Entry records the last message sent by a given machine.
+ * @author Brian Demsky <bdemsky@uci.edu>
+ * @version 1.0
+ */
+
+
+class LastMessage extends Entry {
+       private long machineid;
+       private long seqnum;
+
+       LastMessage(Slot slot, long _machineid, long _seqnum) {
+               super(slot);
+               machineid=_machineid;
+               seqnum=_seqnum;
+       }
+
+       long getMachineID() {
+               return machineid;
+       }
+
+       long getSequenceNumber() {
+               return seqnum;
+       }
+
+       static Entry decode(Slot slot, ByteBuffer bb) {
+               long machineid=bb.getLong();
+               long seqnum=bb.getLong();
+               return new LastMessage(slot, machineid, seqnum);
+       }
+
+       void encode(ByteBuffer bb) {
+               bb.put(Entry.TypeLastMessage);
+               bb.putLong(machineid);
+               bb.putLong(seqnum);
+       }
+
+       int getSize() {
+               return 2*Long.BYTES+Byte.BYTES;
+       }
+
+       byte getType() {
+               return Entry.TypeLastMessage;
+       }
+
+       Entry getCopy(Slot s) {
+               return new LastMessage(s, machineid, seqnum);
+       }
+}
+
+
diff --git a/version1/src/java/iotcloud/Liveness.java b/version1/src/java/iotcloud/Liveness.java
new file mode 100644 (file)
index 0000000..2c840e4
--- /dev/null
@@ -0,0 +1,11 @@
+package iotcloud;
+
+/**
+ * Interface common to both classes that record information about the
+ * last message sent by a machine.  (Either a Slot or a LastMessage.
+ * @author Brian Demsky <bdemsky@uci.edu>
+ * @version 1.0
+ */
+
+interface Liveness {
+}
diff --git a/version1/src/java/iotcloud/Makefile b/version1/src/java/iotcloud/Makefile
new file mode 100644 (file)
index 0000000..2d45b63
--- /dev/null
@@ -0,0 +1,17 @@
+all: server
+
+JAVAC = javac
+JAVADOC = javadoc
+BIN_DIR = bin
+DOCS_DIR = docs
+
+server:
+       $(JAVAC) -d $(BIN_DIR) *.java
+
+doc: server
+       $(JAVADOC) -private -d $(DOCS_DIR) *.java
+
+clean:
+       rm -r bin/*
+       rm -r docs/*
+       rm *~
diff --git a/version1/src/java/iotcloud/Pair.java b/version1/src/java/iotcloud/Pair.java
new file mode 100644 (file)
index 0000000..73ed6bd
--- /dev/null
@@ -0,0 +1,23 @@
+package iotcloud;
+
+class Pair<A,B> {
+       private A a;
+       private B b;
+
+       Pair(A a, B b) {
+               this.a=a;
+               this.b=b;
+       }
+
+       A getFirst() {
+               return a;
+       }
+
+       B getSecond() {
+               return b;
+       }
+
+       public String toString() {
+               return "<"+a+","+b+">";
+       }
+}
diff --git a/version1/src/java/iotcloud/RejectedMessage.java b/version1/src/java/iotcloud/RejectedMessage.java
new file mode 100644 (file)
index 0000000..9c84f18
--- /dev/null
@@ -0,0 +1,88 @@
+package iotcloud;
+import java.nio.ByteBuffer;
+import java.util.HashSet;
+
+/**
+ * Entry for tracking messages that the server rejected.  We have to
+ * make sure that all clients know that this message was rejected to
+ * prevent the server from reusing these messages in an attack.
+ * @author Brian Demsky
+ * @version 1.0
+ */
+
+
+class RejectedMessage extends Entry {
+       /* Machine identifier */
+       private long machineid;
+       /* Oldest sequence number in range */
+       private long oldseqnum;
+       /* Newest sequence number in range */
+       private long newseqnum;
+       /* Is the machine identifier of the relevant slots equal to (or not
+        * equal to) the specified machine identifier. */
+       private boolean equalto;
+       /* Set of machines that have not received notification. */
+       private HashSet<Long> watchset;
+
+       RejectedMessage(Slot slot, long _machineid, long _oldseqnum, long _newseqnum, boolean _equalto) {
+               super(slot);
+               machineid=_machineid;
+               oldseqnum=_oldseqnum;
+               newseqnum=_newseqnum;
+               equalto=_equalto;
+       }
+
+       long getOldSeqNum() {
+               return oldseqnum;
+       }
+
+       long getNewSeqNum() {
+               return newseqnum;
+       }
+
+       boolean getEqual() {
+               return equalto;
+       }
+
+       long getMachineID() {
+               return machineid;
+       }
+
+       static Entry decode(Slot slot, ByteBuffer bb) {
+               long machineid=bb.getLong();
+               long oldseqnum=bb.getLong();
+               long newseqnum=bb.getLong();
+               byte equalto=bb.get();
+               return new RejectedMessage(slot, machineid, oldseqnum, newseqnum, equalto==1);
+       }
+
+       void setWatchSet(HashSet<Long> _watchset) {
+               watchset=_watchset;
+       }
+
+       void removeWatcher(long machineid) {
+               if (watchset.remove(machineid))
+                       if (watchset.isEmpty())
+                               setDead();
+       }
+
+       void encode(ByteBuffer bb) {
+               bb.put(Entry.TypeRejectedMessage);
+               bb.putLong(machineid);
+               bb.putLong(oldseqnum);
+               bb.putLong(newseqnum);
+               bb.put(equalto?(byte)1:(byte)0);
+       }
+
+       int getSize() {
+               return 3*Long.BYTES + 2*Byte.BYTES;
+       }
+
+       byte getType() {
+               return Entry.TypeRejectedMessage;
+       }
+       
+       Entry getCopy(Slot s) {
+               return new RejectedMessage(s, machineid, oldseqnum, newseqnum, equalto);
+       }
+}
diff --git a/version1/src/java/iotcloud/Slot.java b/version1/src/java/iotcloud/Slot.java
new file mode 100644 (file)
index 0000000..5828fd3
--- /dev/null
@@ -0,0 +1,214 @@
+package iotcloud;
+import java.util.Vector;
+import java.nio.ByteBuffer;
+import javax.crypto.Mac;
+import java.util.Arrays;
+
+/**
+ * Data structuring for holding Slot information.
+ * @author Brian Demsky
+ * @version 1.0
+ */
+
+class Slot implements Liveness {
+       /** Sets the slot size. */
+       static final int SLOT_SIZE=2048;
+       /** Sets the size for the HMAC. */
+       static final int HMAC_SIZE=32;
+
+       /** Sequence number of the slot. */
+       private long seqnum;
+       /** HMAC of previous slot. */
+       private byte[] prevhmac;
+       /** HMAC of this slot. */
+       private byte[] hmac;
+       /** Machine that sent this slot. */
+       private long machineid;
+       /** Vector of entries in this slot. */
+       private Vector<Entry> entries;
+       /** Pieces of information that are live. */
+       private int livecount;
+       /** Flag that indicates whether this slot is still live for
+        * recording the machine that sent it. */
+       private boolean seqnumlive;
+       /** Number of bytes of free space. */
+       private int freespace;
+       /** Reference to Table */
+       private Table table;
+
+       Slot(Table _table, long _seqnum, long _machineid, byte[] _prevhmac, byte[] _hmac) {
+               seqnum=_seqnum;
+               machineid=_machineid;
+               prevhmac=_prevhmac;
+               hmac=_hmac;
+               entries=new Vector<Entry>();
+               livecount=1;
+               seqnumlive=true;
+               freespace = SLOT_SIZE - getBaseSize();
+               table=_table;
+       }
+
+       Slot(Table _table, long _seqnum, long _machineid, byte[] _prevhmac) {
+               this(_table, _seqnum, _machineid, _prevhmac, null);
+       }
+
+       Slot(Table _table, long _seqnum, long _machineid) {
+               this(_table, _seqnum, _machineid, new byte[HMAC_SIZE], null);
+       }
+
+       byte[] getHMAC() {
+               return hmac;
+       }
+
+       byte[] getPrevHMAC() {
+               return prevhmac;
+       }
+
+       void addEntry(Entry e) {
+               e=e.getCopy(this);
+               entries.add(e);
+               livecount++;
+               freespace -= e.getSize();
+       }
+
+       private void addShallowEntry(Entry e) {
+               entries.add(e);
+               livecount++;
+               freespace -= e.getSize();
+       }
+
+       /**
+        * Returns true if the slot has free space to hold the entry without
+        * using its reserved space. */
+
+       boolean hasSpace(Entry e) {
+               int newfreespace = freespace - e.getSize();
+               return newfreespace >= 0;
+       }
+
+       Vector<Entry> getEntries() {
+               return entries;
+       }
+
+       static Slot decode(Table table, byte[] array, Mac mac) {
+               mac.update(array, HMAC_SIZE, array.length-HMAC_SIZE);
+               byte[] realmac=mac.doFinal();
+
+               ByteBuffer bb=ByteBuffer.wrap(array);
+               byte[] hmac=new byte[HMAC_SIZE];
+               byte[] prevhmac=new byte[HMAC_SIZE];
+               bb.get(hmac);
+               bb.get(prevhmac);
+               if (!Arrays.equals(realmac, hmac))
+                       throw new Error("Server Error: Invalid HMAC!  Potential Attack!");
+
+               long seqnum=bb.getLong();
+               long machineid=bb.getLong();
+               int numentries=bb.getInt();
+               Slot slot=new Slot(table, seqnum, machineid, prevhmac, hmac);
+
+               for(int i=0; i<numentries; i++) {
+                       slot.addShallowEntry(Entry.decode(slot, bb));
+               }
+
+               return slot;
+       }
+
+       byte[] encode(Mac mac) {
+               byte[] array=new byte[SLOT_SIZE];
+               ByteBuffer bb=ByteBuffer.wrap(array);
+               /* Leave space for the slot HMAC.  */
+               bb.position(HMAC_SIZE);
+               bb.put(prevhmac);
+               bb.putLong(seqnum);
+               bb.putLong(machineid);
+               bb.putInt(entries.size());
+               for(Entry entry:entries) {
+                       entry.encode(bb);
+               }
+               /* Compute our HMAC */
+               mac.update(array, HMAC_SIZE, array.length-HMAC_SIZE);
+               byte[] realmac=mac.doFinal();
+               hmac = realmac;
+               bb.position(0);
+               bb.put(realmac);
+               return array;
+       }
+
+       /**
+        * Returns the empty size of a Slot. Includes 2 HMACs, the machine
+        * identifier, the sequence number, and the number of entries.
+        */
+       int getBaseSize() {
+               return 2*HMAC_SIZE+2*Long.BYTES+Integer.BYTES;
+       }
+
+       /**
+        * Returns the live set of entries for this Slot.  Generates a fake
+        * LastMessage entry to represent the information stored by the slot
+        * itself.
+        */
+
+       Vector<Entry> getLiveEntries(boolean resize) {
+               Vector<Entry> liveEntries=new Vector<Entry>();
+               for(Entry entry: entries) {
+                       if (entry.isLive()) {
+                               if (!resize || entry.getType() != Entry.TypeTableStatus)
+                                       liveEntries.add(entry);
+                       }
+               }
+                       
+               if (seqnumlive && !resize)
+                       liveEntries.add(new LastMessage(this, machineid, seqnum));
+
+               return liveEntries;
+       }
+
+       /**
+        * Returns the sequence number of the slot.
+        */
+
+       long getSequenceNumber() {
+               return seqnum;
+       }
+
+       /**
+        * Returns the machine that sent this slot.
+        */
+
+       long getMachineID() {
+               return machineid;
+       }
+
+       /**
+        * Records that a newer slot records the fact that this slot was
+        * sent by the relevant machine.
+        */
+
+       void setDead() {
+               seqnumlive=false;
+               decrementLiveCount();
+       }
+
+       /**
+        * Update the count of live entries.
+        */
+
+       void decrementLiveCount() {
+               livecount--;
+               if (livecount==0)
+                       table.decrementLiveCount();
+       }
+
+       /**
+        * Returns whether the slot stores any live information.
+        */
+
+       boolean isLive() {
+               return livecount > 0;
+       }
+
+       public String toString() {
+               return "<"+getSequenceNumber()+">";
+       }
+}
diff --git a/version1/src/java/iotcloud/SlotBuffer.java b/version1/src/java/iotcloud/SlotBuffer.java
new file mode 100644 (file)
index 0000000..14bc926
--- /dev/null
@@ -0,0 +1,99 @@
+package iotcloud;
+
+/**
+ * Circular buffer that holds the live set of slots.
+ * @author Brian Demsky
+ * @version 1.0
+ */
+
+class SlotBuffer {
+       static final int DEFAULT_SIZE = 128;
+
+       private Slot[] array;
+       private int head;
+       private int tail;
+       private long oldestseqn;
+
+       SlotBuffer() {
+               array=new Slot[DEFAULT_SIZE+1];
+               head=tail=0;
+               oldestseqn=0;
+       }
+
+       int size() {
+               if (head >= tail)
+                       return head - tail;
+               return (array.length + head) - tail;
+       }
+
+       int capacity() {
+               return array.length - 1;
+       }
+
+       void resize(int newsize) {
+               if (newsize == (array.length-1))
+                       return;
+               Slot[] newarray = new Slot[newsize+1];
+               int currsize = size();
+               int index = tail;
+               for(int i=0; i < currsize; i++) {
+                       newarray[i] = array[index];
+                       if ((++index) == array.length)
+                               index = 0;
+               }
+               array = newarray;
+               tail = 0;
+               head = currsize;
+       }
+
+       private void incrementHead() {
+               head++;
+               if (head >= array.length)
+                       head=0;
+       }
+
+       private void incrementTail() {
+               tail++;
+               if (tail >= array.length)
+                       tail=0;
+       }
+
+       void putSlot(Slot s) {
+               array[head]=s;
+               incrementHead();
+
+               if (oldestseqn==0)
+                       oldestseqn = s.getSequenceNumber();
+
+               if (head==tail) {
+                       incrementTail();
+                       oldestseqn++;
+               }
+       }
+
+       Slot getSlot(long seqnum) {
+               int diff=(int) (seqnum-oldestseqn);
+               int index=diff + tail;
+               if (index >= array.length) {
+                       if (head >= tail)
+                               return null;
+                       index-= array.length;
+               }
+
+               if (index >= array.length)
+                       return null;
+
+               if (head >= tail && index >= head)
+                       return null;
+
+               return array[index];
+       }
+
+       long getOldestSeqNum() {
+               return oldestseqn;
+       }
+
+       long getNewestSeqNum() {
+               return oldestseqn + size() - 1;
+       }
+}
diff --git a/version1/src/java/iotcloud/SlotIndexer.java b/version1/src/java/iotcloud/SlotIndexer.java
new file mode 100644 (file)
index 0000000..cecdf2d
--- /dev/null
@@ -0,0 +1,31 @@
+package iotcloud;
+
+/**
+ * Slot indexer allows slots in both the slot buffer and the new
+ * server response to looked up in a consistent fashion.
+ * @author Brian Demsky
+ * @version 1.0
+ */
+
+class SlotIndexer {
+       private Slot[] updates;
+       private SlotBuffer buffer;
+       private long firstslotseqnum;
+
+       SlotIndexer(Slot[] _updates, SlotBuffer _buffer) {
+               buffer = _buffer;
+               updates = _updates;
+               firstslotseqnum = updates[0].getSequenceNumber();
+       }
+
+       Slot getSlot(long seqnum) {
+               if (seqnum >= firstslotseqnum) {
+                       int offset = (int) (seqnum - firstslotseqnum);
+                       if (offset >= updates.length)
+                               throw new Error("Invalid Slot Sequence Number Reference");
+                       else
+                               return updates[offset];
+               } else
+                       return buffer.getSlot(seqnum);
+       }
+}
diff --git a/version1/src/java/iotcloud/Table.java b/version1/src/java/iotcloud/Table.java
new file mode 100644 (file)
index 0000000..1d6259a
--- /dev/null
@@ -0,0 +1,476 @@
+package iotcloud;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Iterator;
+import java.util.HashSet;
+import java.util.Arrays;
+import java.util.Vector;
+import java.util.Random;
+
+/**
+ * IoTTable data structure.  Provides client inferface.
+ * @author Brian Demsky
+ * @version 1.0
+ */
+
+final public class Table {
+       private int numslots;   //number of slots stored in buffer
+
+       //table of key-value pairs
+       private HashMap<IoTString, KeyValue> table=new HashMap<IoTString, KeyValue>();
+
+       // machine id -> (sequence number, Slot or LastMessage); records last message by each client
+       private HashMap<Long, Pair<Long, Liveness> > lastmessagetable=new HashMap<Long, Pair<Long, Liveness> >();
+       // machine id -> ...
+       private HashMap<Long, HashSet<RejectedMessage> > watchlist = new HashMap<Long, HashSet<RejectedMessage> >();
+       private Vector<Long> rejectedmessagelist=new Vector<Long>();
+       private SlotBuffer buffer;
+       private CloudComm cloud;
+       private long sequencenumber; //Largest sequence number a client has received
+       private long localmachineid;
+       private TableStatus lastTableStatus;
+       static final int FREE_SLOTS = 10; //number of slots that should be kept free
+       static final int SKIP_THRESHOLD = 10;
+       private long liveslotcount=0;
+       private int chance;
+       static final double RESIZE_MULTIPLE = 1.2;
+       static final double RESIZE_THRESHOLD = 0.75;
+       static final int REJECTED_THRESHOLD = 5;
+       private int resizethreshold;
+       private long lastliveslotseqn;  //smallest sequence number with a live entry
+       private Random random=new Random();
+       
+       public Table(String baseurl, String password, long _localmachineid) {
+               localmachineid=_localmachineid;
+               buffer = new SlotBuffer();
+               numslots = buffer.capacity();
+               setResizeThreshold();
+               sequencenumber = 0;
+               cloud=new CloudComm(this, baseurl, password);
+               lastliveslotseqn = 1;
+       }
+
+       public Table(CloudComm _cloud, long _localmachineid) {
+               localmachineid=_localmachineid;
+               buffer = new SlotBuffer();
+               numslots = buffer.capacity();
+               setResizeThreshold();
+               sequencenumber = 0;
+               cloud=_cloud;
+       }
+
+       public void rebuild() {
+               Slot[] newslots=cloud.getSlots(sequencenumber+1);
+               validateandupdate(newslots, true);
+       }
+
+       public void update() {
+               Slot[] newslots=cloud.getSlots(sequencenumber+1);
+
+               validateandupdate(newslots, false);
+       }
+
+       public IoTString get(IoTString key) {
+               KeyValue kv=table.get(key);
+               if (kv != null)
+                       return kv.getValue();
+               else
+                       return null;
+       }
+
+       public void initTable() {
+               cloud.setSalt();//Set the salt
+               Slot s=new Slot(this, 1, localmachineid);
+               TableStatus status=new TableStatus(s, numslots);
+               s.addEntry(status);
+               Slot[] array=cloud.putSlot(s, numslots);
+               if (array == null) {
+                       array = new Slot[] {s};
+                       /* update data structure */
+                       validateandupdate(array, true);
+               } else {
+                       throw new Error("Error on initialization");
+               }
+       }
+
+       public String toString() {
+               return table.toString();
+       }
+       
+       public IoTString put(IoTString key, IoTString value) {
+               while(true) {
+                       KeyValue oldvalue=table.get(key);
+                       if (tryput(key, value, false)) {
+                               if (oldvalue==null)
+                                       return null;
+                               else
+                                       return oldvalue.getValue();
+                       }
+               }
+       }
+
+       void decrementLiveCount() {
+               liveslotcount--;
+       }
+       
+       
+       private void setResizeThreshold() {
+               int resize_lower=(int) (RESIZE_THRESHOLD * numslots);
+               resizethreshold=resize_lower-1+random.nextInt(numslots-resize_lower);
+       }
+       
+       private boolean tryput(IoTString key, IoTString value, boolean resize) {
+               Slot s=new Slot(this, sequencenumber+1, localmachineid, buffer.getSlot(sequencenumber).getHMAC());
+               int newsize = 0;
+               if (liveslotcount > resizethreshold) { 
+                       resize=true; //Resize is forced
+               }
+               
+               if (resize) {
+                       newsize = (int) (numslots * RESIZE_MULTIPLE);
+                       TableStatus status=new TableStatus(s, newsize);
+                       s.addEntry(status);
+               }
+
+               if (! rejectedmessagelist.isEmpty()) {
+                       /* TODO: We should avoid generating a rejected message entry if
+                        * there is already a sufficient entry in the queue (e.g.,
+                        * equalsto value of true and same sequence number).  */
+
+                       long old_seqn=rejectedmessagelist.firstElement();
+                       if (rejectedmessagelist.size() > REJECTED_THRESHOLD) {
+                               long new_seqn=rejectedmessagelist.lastElement();
+                               RejectedMessage rm=new RejectedMessage(s, localmachineid, old_seqn, new_seqn, false);
+                               s.addEntry(rm);
+                       } else {
+                               long prev_seqn = -1;
+                               int i=0;
+                               /* Go through list of missing messages */
+                               for(; i<rejectedmessagelist.size(); i++) {
+                                       long curr_seqn = rejectedmessagelist.get(i);
+                                       Slot s_msg = buffer.getSlot(curr_seqn);
+                                       if (s_msg != null)
+                                               break;
+                                       prev_seqn=curr_seqn;
+                               }
+                               /* Generate rejected message entry for missing messages */
+                               if (prev_seqn != -1) {
+                                       RejectedMessage rm=new RejectedMessage(s, localmachineid, old_seqn, prev_seqn, false);
+                                       s.addEntry(rm);
+                               }
+                               /* Generate rejected message entries for present messages */
+                               for(; i<rejectedmessagelist.size(); i++) {
+                                       long curr_seqn=rejectedmessagelist.get(i);
+                                       Slot s_msg=buffer.getSlot(curr_seqn);
+                                       long machineid=s_msg.getMachineID();
+                                       RejectedMessage rm=new RejectedMessage(s, machineid, curr_seqn, curr_seqn, true);
+                                       s.addEntry(rm);
+                               }
+                       }
+               }
+               
+               long newestseqnum = buffer.getNewestSeqNum();
+               long oldestseqnum = buffer.getOldestSeqNum();
+               if (lastliveslotseqn < oldestseqnum)
+                       lastliveslotseqn = oldestseqnum;
+
+               long seqn = lastliveslotseqn;
+               boolean seenliveslot = false;
+               long firstiffull = newestseqnum + 1 - numslots; //smallest seq number in the buffer if it is full
+               long threshold = firstiffull + FREE_SLOTS;      //we want the buffer to be clear of live entries up to this point
+               
+               for(; seqn < threshold; seqn++) {
+                       Slot prevslot=buffer.getSlot(seqn);
+                       //Push slot number forward
+                       if (! seenliveslot)
+                               lastliveslotseqn = seqn;
+
+                       if (! prevslot.isLive())
+                               continue;
+                       seenliveslot = true;
+                       Vector<Entry> liveentries = prevslot.getLiveEntries(resize);
+                       for(Entry liveentry:liveentries) {
+                               if (s.hasSpace(liveentry)) {
+                                       s.addEntry(liveentry);
+                               } else if (seqn==firstiffull) {   //if there's no space but the entry is about to fall off the queue
+                                       if (!resize) {
+                                               System.out.print("B"); //?
+                                               return tryput(key, value, true);
+                                       }
+                               }
+                       }
+               }
+
+               KeyValue kv=new KeyValue(s, key, value);
+               boolean insertedkv=false;
+               if (s.hasSpace(kv)) {
+                       s.addEntry(kv);
+                       insertedkv=true;
+               }
+
+               /* now go through live entries from least to greatest sequence number until
+                * either all live slots added, or the slot doesn't have enough room
+                * for SKIP_THRESHOLD consecutive entries*/
+               int skipcount=0;
+               search:
+               for(; seqn <= newestseqnum; seqn++) {
+                       Slot prevslot=buffer.getSlot(seqn);
+                       //Push slot number forward
+                       if (!seenliveslot)
+                               lastliveslotseqn = seqn;
+                       
+                       if (!prevslot.isLive())
+                               continue;
+                       seenliveslot = true;
+                       Vector<Entry> liveentries = prevslot.getLiveEntries(resize);
+                       for(Entry liveentry:liveentries) {
+                               if (s.hasSpace(liveentry))
+                                       s.addEntry(liveentry);
+                               else {
+                                       skipcount++;
+                                       if (skipcount > SKIP_THRESHOLD)
+                                               break search;
+                               }
+                       }
+               }
+
+               int max=0;
+               if (resize)
+                       max = newsize;
+               Slot[] array=cloud.putSlot(s, max);
+               if (array == null) {
+                       array = new Slot[] {s};
+                       rejectedmessagelist.clear();
+               }       else {
+                       if (array.length == 0)
+                               throw new Error("Server Error: Did not send any slots");
+                       rejectedmessagelist.add(s.getSequenceNumber());
+                       insertedkv=false;
+               }
+               
+               /* update data structure */
+               validateandupdate(array, true);
+
+               return insertedkv;
+       }
+
+       private void validateandupdate(Slot[] newslots, boolean acceptupdatestolocal) {
+               /* The cloud communication layer has checked slot HMACs already
+                        before decoding */
+               if (newslots.length==0) return;
+
+               long firstseqnum=newslots[0].getSequenceNumber();
+               if (firstseqnum <= sequencenumber)
+                       throw new Error("Server Error: Sent older slots!");
+
+               SlotIndexer indexer = new SlotIndexer(newslots, buffer);
+               checkHMACChain(indexer, newslots);
+
+               HashSet<Long> machineSet=new HashSet<Long>(lastmessagetable.keySet());  //
+
+               initExpectedSize(firstseqnum);
+               for(Slot slot: newslots) {
+                       processSlot(indexer, slot, acceptupdatestolocal, machineSet);
+                       updateExpectedSize();
+               }
+
+               /* If there is a gap, check to see if the server sent us everything. */
+               if (firstseqnum != (sequencenumber+1)) {
+                       checkNumSlots(newslots.length);
+                       if (!machineSet.isEmpty())
+                               throw new Error("Missing record for machines: "+machineSet);
+               }
+
+               commitNewMaxSize();
+
+               /* Commit new to slots. */
+               for(Slot slot:newslots) {
+                       buffer.putSlot(slot);
+                       liveslotcount++;
+               }
+               sequencenumber = newslots[newslots.length - 1].getSequenceNumber();
+       }
+
+       private int expectedsize, currmaxsize;
+
+       private void checkNumSlots(int numslots) {
+               if (numslots != expectedsize)
+                       throw new Error("Server Error: Server did not send all slots.  Expected: "+expectedsize+" Received:"+numslots);
+       }
+
+       private void initExpectedSize(long firstsequencenumber) {
+               long prevslots = firstsequencenumber;
+               expectedsize = (prevslots < ((long) numslots))? (int) prevslots : numslots;
+               currmaxsize = numslots;
+       }
+
+       private void updateExpectedSize() {
+               expectedsize++;
+               if (expectedsize > currmaxsize)
+                       expectedsize = currmaxsize;
+       }
+
+       private void updateCurrMaxSize(int newmaxsize) {
+               currmaxsize=newmaxsize;
+       }
+
+       private void commitNewMaxSize() {
+               if (numslots != currmaxsize)
+                       buffer.resize(currmaxsize);
+
+               numslots=currmaxsize;
+               setResizeThreshold();
+       }
+
+       private void processEntry(KeyValue entry, SlotIndexer indexer) {
+               IoTString key=entry.getKey();
+               KeyValue oldvalue=table.get(key);
+               if (oldvalue != null) {
+                       oldvalue.setDead();
+               }
+               table.put(key, entry);
+       }
+
+       private void processEntry(LastMessage entry, SlotIndexer indexer, HashSet<Long> machineSet) {
+               updateLastMessage(entry.getMachineID(), entry.getSequenceNumber(), entry, false, machineSet);
+       }
+
+       private void processEntry(RejectedMessage entry, SlotIndexer indexer) {
+               long oldseqnum=entry.getOldSeqNum();
+               long newseqnum=entry.getNewSeqNum();
+               boolean isequal=entry.getEqual();
+               long machineid=entry.getMachineID();
+               for(long seqnum=oldseqnum; seqnum <= newseqnum; seqnum++) {
+                       Slot slot=indexer.getSlot(seqnum);
+                       if (slot != null) {
+                               long slotmachineid=slot.getMachineID();
+                               if (isequal != (slotmachineid==machineid)) {
+                                       throw new Error("Server Error: Trying to insert rejected message for slot "+seqnum);
+                               }
+                       }
+               }
+
+               HashSet<Long> watchset=new HashSet<Long>();
+               for(Map.Entry<Long, Pair<Long,Liveness> > lastmsg_entry : lastmessagetable.entrySet()) {
+                       long entry_mid=lastmsg_entry.getKey();
+                       /* We've seen it, don't need to continue to watch.  Our next
+                        * message will implicitly acknowledge it. */
+                       if (entry_mid == localmachineid)
+                               continue;
+                       Pair<Long, Liveness> v=lastmsg_entry.getValue();
+                       long entry_seqn=v.getFirst();
+                       if (entry_seqn < newseqnum) {
+                               addWatchList(entry_mid, entry);
+                               watchset.add(entry_mid);
+                       }
+               }
+               if (watchset.isEmpty())
+                       entry.setDead();
+               else
+                       entry.setWatchSet(watchset);
+       }
+
+       private void addWatchList(long machineid, RejectedMessage entry) {
+               HashSet<RejectedMessage> entries=watchlist.get(machineid);
+               if (entries == null)
+                       watchlist.put(machineid, entries=new HashSet<RejectedMessage>());
+               entries.add(entry);
+       }
+
+       private void processEntry(TableStatus entry, SlotIndexer indexer) {
+               int newnumslots=entry.getMaxSlots();
+               updateCurrMaxSize(newnumslots);
+               if (lastTableStatus != null)
+                       lastTableStatus.setDead();
+               lastTableStatus = entry;
+       }
+
+       private void updateLastMessage(long machineid, long seqnum, Liveness liveness, boolean acceptupdatestolocal, HashSet<Long> machineSet) {
+               machineSet.remove(machineid);
+
+               HashSet<RejectedMessage> watchset=watchlist.get(machineid);
+               if (watchset != null) {
+                       for(Iterator<RejectedMessage> rmit=watchset.iterator(); rmit.hasNext(); ) {
+                               RejectedMessage rm=rmit.next();
+                               if (rm.getNewSeqNum() <= seqnum) {
+                                       /* Remove it from our watchlist */
+                                       rmit.remove();
+                                       /* Decrement machines that need to see this notification */
+                                       rm.removeWatcher(machineid);
+                               }
+                       }
+               }
+               
+               if (machineid == localmachineid) {
+                       /* Our own messages are immediately dead. */
+                       if (liveness instanceof LastMessage) {
+                               ((LastMessage)liveness).setDead();
+                       } else if (liveness instanceof Slot) {
+                               ((Slot)liveness).setDead();
+                       } else {
+                               throw new Error("Unrecognized type");
+                       }
+               }
+               
+               
+               Pair<Long, Liveness> lastmsgentry = lastmessagetable.put(machineid, new Pair<Long, Liveness>(seqnum, liveness));
+               if (lastmsgentry == null)
+                       return;
+
+               long lastmsgseqnum = lastmsgentry.getFirst();
+               Liveness lastentry = lastmsgentry.getSecond();
+               if (machineid != localmachineid) {
+                       if (lastentry instanceof LastMessage) {
+                               ((LastMessage)lastentry).setDead();
+                       } else if (lastentry instanceof Slot) {
+                               ((Slot)lastentry).setDead();
+                       } else {
+                               throw new Error("Unrecognized type");
+                       }
+               }
+               
+               if (machineid == localmachineid) {
+                       if (lastmsgseqnum != seqnum && !acceptupdatestolocal)
+                               throw new Error("Server Error: Mismatch on local machine sequence number");
+               } else {
+                       if (lastmsgseqnum > seqnum)
+                               throw new Error("Server Error: Rollback on remote machine sequence number");
+               }
+       }
+
+       private void processSlot(SlotIndexer indexer, Slot slot, boolean acceptupdatestolocal, HashSet<Long> machineSet) {
+               updateLastMessage(slot.getMachineID(), slot.getSequenceNumber(), slot, acceptupdatestolocal, machineSet);
+               for(Entry entry : slot.getEntries()) {
+                       switch(entry.getType()) {
+                       case Entry.TypeKeyValue:
+                               processEntry((KeyValue)entry, indexer);
+                               break;
+
+                       case Entry.TypeLastMessage:
+                               processEntry((LastMessage)entry, indexer, machineSet);
+                               break;
+
+                       case Entry.TypeRejectedMessage:
+                               processEntry((RejectedMessage)entry, indexer);
+                               break;
+
+                       case Entry.TypeTableStatus:
+                               processEntry((TableStatus)entry, indexer);
+                               break;
+
+                       default:
+                               throw new Error("Unrecognized type: "+entry.getType());
+                       }
+               }
+       }
+
+       private void checkHMACChain(SlotIndexer indexer, Slot[] newslots) {
+               for(int i=0; i < newslots.length; i++) {
+                       Slot currslot=newslots[i];
+                       Slot prevslot=indexer.getSlot(currslot.getSequenceNumber()-1);
+                       if (prevslot != null &&
+                                       !Arrays.equals(prevslot.getHMAC(), currslot.getPrevHMAC()))
+                               throw new Error("Server Error: Invalid HMAC Chain"+currslot+" "+prevslot);
+               }
+       }
+}
diff --git a/version1/src/java/iotcloud/TableStatus.java b/version1/src/java/iotcloud/TableStatus.java
new file mode 100644 (file)
index 0000000..62f3a6d
--- /dev/null
@@ -0,0 +1,45 @@
+package iotcloud;
+import java.nio.ByteBuffer;
+
+/**
+ * TableStatus entries record the current size of the data structure
+ * in slots.  Used to remember the size and to perform resizes.
+ * @author Brian Demsky
+ * @version 1.0
+ */
+
+
+class TableStatus extends Entry {
+       private int maxslots;
+
+       TableStatus(Slot slot, int _maxslots) {
+               super(slot);
+               maxslots=_maxslots;
+       }
+
+       int getMaxSlots() {
+               return maxslots;
+       }
+
+       static Entry decode(Slot slot, ByteBuffer bb) {
+               int maxslots=bb.getInt();
+               return new TableStatus(slot, maxslots);
+       }
+
+       void encode(ByteBuffer bb) {
+               bb.put(Entry.TypeTableStatus);
+               bb.putInt(maxslots);
+       }
+
+       int getSize() {
+               return Integer.BYTES+Byte.BYTES;
+       }
+
+       byte getType() {
+               return Entry.TypeTableStatus;
+       }
+
+       Entry getCopy(Slot s) {
+               return new TableStatus(s, maxslots);
+       }
+}
diff --git a/version1/src/java/iotcloud/Test.java b/version1/src/java/iotcloud/Test.java
new file mode 100644 (file)
index 0000000..ad976ac
--- /dev/null
@@ -0,0 +1,95 @@
+package iotcloud;
+
+/**
+ * Test cases.
+ * @author Brian Demsky
+ * @version 1.0
+ */
+
+public class Test {
+       public static void main(String[] args) {
+               if(args[0].equals("2"))
+                       test2();
+               else if(args[0].equals("3"))
+                       test3();
+               else if(args[0].equals("4"))
+                       test4();
+               else if(args[0].equals("5"))
+                       test5();
+
+       }
+
+       
+       
+       static Thread buildThread(String prefix, Table t) {
+               return new Thread() {
+                       public void run() {
+                               for(int i=0; i<10000; i++) {
+                                       String a=prefix+i;
+                                       IoTString ia=new IoTString(a);
+                                       t.put(ia, ia);
+                                       System.out.println(ia+"->"+t.get(ia));
+                               }
+                       }
+               };
+       }
+       
+       static void test5() {
+               Table t1=new Table("http://127.0.0.1/test.iotcloud/", "reallysecret", 321);
+               t1.rebuild();
+               System.out.println(t1);
+       }
+       
+       static void test4() {
+               Table t1=new Table("http://127.0.0.1/test.iotcloud/", "reallysecret", 321);
+               Table t2=new Table("http://127.0.0.1/test.iotcloud/", "reallysecret", 351);
+               t1.rebuild();
+               t2.rebuild();
+               Thread thr1=buildThread("p1", t1);
+               Thread thr2=buildThread("p2", t2);
+               thr1.start();
+               thr2.start();
+               try {
+                       thr1.join();
+                       thr2.join();
+               } catch (Exception e) {
+                       e.printStackTrace();
+               }
+       }
+
+       static void test3() {
+               Table t1=new Table("http://127.0.0.1/test.iotcloud/", "reallysecret", 321);
+               Table t2=new Table("http://127.0.0.1/test.iotcloud/", "reallysecret", 351);
+               t1.rebuild();
+               t2.rebuild();
+               for(int i=0; i<600; i++) {
+                       String a="STR"+i;
+                       String b="ABR"+i;
+                       IoTString ia=new IoTString(a);
+                       IoTString ib=new IoTString(b);
+                       t1.put(ia, ia);
+                       t2.put(ib, ib);
+                       t1.update();
+                       System.out.println(ib+"->"+t1.get(ib));
+                       System.out.println(ia+"->"+t2.get(ia));
+               }
+       }
+
+       static void test2() {
+               Table t1=new Table("http://127.0.0.1/test.iotcloud/", "reallysecret", 321);
+               t1.initTable();
+               Table t2=new Table("http://127.0.0.1/test.iotcloud/", "reallysecret", 351);
+               t2.update();
+               for(int i=0; i<600; i++) {
+                       String a="STR"+i;
+                       String b="ABR"+i;
+                       IoTString ia=new IoTString(a);
+                       IoTString ib=new IoTString(b);
+                       t1.put(ia, ia);
+                       t2.put(ib, ib);
+                       t1.update();
+                       System.out.println(ib+"->"+t1.get(ib));
+                       System.out.println(ia+"->"+t2.get(ia));
+               }
+       }
+}
diff --git a/version1/src/java/iotcloud/issues.txt b/version1/src/java/iotcloud/issues.txt
new file mode 100644 (file)
index 0000000..816b6b1
--- /dev/null
@@ -0,0 +1 @@
+1) add better resizing support...gets stuck when it is full now...
diff --git a/version1/src/js/iotjs/.babelrc b/version1/src/js/iotjs/.babelrc
new file mode 100644 (file)
index 0000000..9d8d516
--- /dev/null
@@ -0,0 +1 @@
+{ "presets": ["es2015"] }
diff --git a/version1/src/js/iotjs/.bowerrc b/version1/src/js/iotjs/.bowerrc
new file mode 100644 (file)
index 0000000..baa91a3
--- /dev/null
@@ -0,0 +1,3 @@
+{
+  "directory": "bower_components"
+}
\ No newline at end of file
diff --git a/version1/src/js/iotjs/.editorconfig b/version1/src/js/iotjs/.editorconfig
new file mode 100644 (file)
index 0000000..e717f5e
--- /dev/null
@@ -0,0 +1,13 @@
+# http://editorconfig.org
+root = true
+
+[*]
+indent_style = space
+indent_size = 2
+end_of_line = lf
+charset = utf-8
+trim_trailing_whitespace = true
+insert_final_newline = true
+
+[*.md]
+trim_trailing_whitespace = false
diff --git a/version1/src/js/iotjs/.jshintrc b/version1/src/js/iotjs/.jshintrc
new file mode 100644 (file)
index 0000000..63937d2
--- /dev/null
@@ -0,0 +1,18 @@
+{
+    "node": true,
+    "esnext": true,
+    "bitwise": true,
+    "curly": true,
+    "eqeqeq": true,
+    "immed": true,
+    "indent": 2,
+    "latedef": true,
+    "newcap": true,
+    "noarg": true,
+    "regexp": true,
+    "undef": true,
+    "unused": true,
+    "trailing": true,
+    "smarttabs": true,
+    "white": true
+}
diff --git a/version1/src/js/iotjs/README.md b/version1/src/js/iotjs/README.md
new file mode 100644 (file)
index 0000000..a384bd9
--- /dev/null
@@ -0,0 +1,21 @@
+iotjs
+==================================================
+
+What does your library do?
+
+Getting Started
+--------------------------------------
+
+- Install dependencies: `npm install`
+- Run `npm test` to build your library
+- Final src file in build directory.
+
+Usage
+--------------------------------------
+
+How can I use it?
+
+Future Development
+--------------------------------------
+
+What would you like to do but don't have the time for?
diff --git a/version1/src/js/iotjs/bower.json b/version1/src/js/iotjs/bower.json
new file mode 100644 (file)
index 0000000..cb33217
--- /dev/null
@@ -0,0 +1,6 @@
+{
+  "name": "iotjs",
+  "version": "0.0.0",
+  "dependencies": {}
+}
+
diff --git a/version1/src/js/iotjs/examples/index.html b/version1/src/js/iotjs/examples/index.html
new file mode 100644 (file)
index 0000000..8613e8e
--- /dev/null
@@ -0,0 +1,11 @@
+<!DOCTYPE html>
+<html>
+<head>
+  <meta charset="utf-8">
+  <title>iotjs Example</title>
+</head>
+<body>
+
+<script src="../build/iotjs.js"></script>
+</body>
+</html>
\ No newline at end of file
diff --git a/version1/src/js/iotjs/gulpfile.js b/version1/src/js/iotjs/gulpfile.js
new file mode 100644 (file)
index 0000000..ed79d92
--- /dev/null
@@ -0,0 +1,49 @@
+var gulp = require('gulp');
+var gulpif = require('gulp-if');
+var clean = require('gulp-clean');
+var order = require('gulp-order');
+var rename = require('gulp-rename');
+var concat = require('gulp-concat');
+var jshint = require('gulp-jshint');
+var uglify = require('gulp-uglify');
+var stylish = require('jshint-stylish');
+var livereload = require('gulp-livereload');
+var sourcemaps = require('gulp-sourcemaps');
+var flags = require('minimist')(process.argv.slice(2));
+
+// Gulp command line arguments
+var production = flags.production || false;
+var debug = flags.debug || !production;
+var watch = flags.watch;
+
+gulp.task('build',  ['clean'], function() {
+  // Single entry point to browserify
+  gulp.src(['src/*.js', 'vendor/*.js'])
+      .pipe(order([ // The order of concatenation
+        'src/main.js'
+      ], {base: '.'}))
+      .pipe(gulpif(debug, sourcemaps.init()))
+      .pipe(gulpif(production, uglify()))
+      .pipe(concat('iotjs.js'))
+      .pipe(gulpif(debug, sourcemaps.write()))
+      .pipe(gulp.dest('./build/'))
+      .pipe(gulpif(watch, livereload()));
+});
+
+gulp.task('lint', function() {
+  return gulp.src('src/*.js')
+    .pipe(jshint())
+    .pipe(jshint.reporter(stylish))
+});
+
+gulp.task('clean', function() {
+   return gulp.src(['./build'], {read: false})
+          .pipe(clean({force: true}));
+});
+
+gulp.task('watch', function() {
+  livereload.listen();
+  gulp.watch('src/*', ['lint', 'build']);
+});
+
+gulp.task('default', ['clean', 'lint', 'build']);
diff --git a/version1/src/js/iotjs/orig/compat.txt b/version1/src/js/iotjs/orig/compat.txt
new file mode 100644 (file)
index 0000000..4006664
--- /dev/null
@@ -0,0 +1,4 @@
+1.Byte[] -> Uint8Array
+2.Static decode method in slot.js takes the table, uint8array and the secret key as the argument
+3.Vector<Entries> = array of entries []
+4.A Byte in a 'number' in javascript
diff --git a/version1/src/js/iotjs/orig/entry.js b/version1/src/js/iotjs/orig/entry.js
new file mode 100644 (file)
index 0000000..8421d5a
--- /dev/null
@@ -0,0 +1,53 @@
+class Entry{
+    constructor(slot) {
+        if (slot && slot instanceof Slot) {
+            
+            this.TypeKeyValue = 1;
+            this.TypeLastmessage = 2;
+            this.TypeRejectedMessage = 3;
+            this.TypeTableStatus = 4;
+            this.liveStatus = true;
+            this.parentslot = slot;
+            
+        }
+    }
+    static decode(slot, bytebuffer) {
+        if (slot instanceof Slot && bytebuffer instanceof ByteBuffer) {
+            var type = bytebuffer.readByte();
+            switch (type) {
+                case this.TypeKeyValue:
+                    return KeyValue.decode(slot, bytebuffer);
+                case this.TypeLastmessage:
+                    return LastMessage.decode(slot, bytebuffer);
+                case this.TypeRejectedMessage:
+                    return RejectedMessage.decode(slot, bytebuffer);
+                case this.TypeTableStatus:
+                    return TableStatus.decode(slot, bytebuffer);
+                default:
+                    throw new Error("Unrecognized Entry Type: " + type);
+            }
+        }
+    }
+    isLive(){
+       return this.liveStatus;
+    }
+    setDead() {
+               this.liveStatus = false;
+               parentslot.decrementLiveCount();
+       }
+
+       encode(bytebuffer){
+
+       }
+       getSize(){
+
+       }
+       getType(){
+
+       }
+       getCopy(slot){
+               if(slot && slot instanceof Slot){
+                       
+               }
+       }
+}
\ No newline at end of file
diff --git a/version1/src/js/iotjs/orig/keyvalue.js b/version1/src/js/iotjs/orig/keyvalue.js
new file mode 100644 (file)
index 0000000..375b29d
--- /dev/null
@@ -0,0 +1,65 @@
+class KeyValue extends Entry{
+       constructor(slot,_key,_value){
+               if(!(slot instanceof Slot && _key instanceof IoTString && _value instanceof IoTString)){
+                       throw new Error('Argument error ');
+               }
+               super(slot);
+               this.key = _key;
+               this.value = _value;
+       }
+       getKey(){
+               return this.key;
+       }
+       getValue(){
+               return this.value;
+       }
+       decode(slot,bb){
+               if(!(slot instanceof Slot && bb instanceof ByteBuffer)){
+                       throw new Error('Argument error');
+               }
+               var keylength = bb.getByte();
+               var valuelength = bb.getByte();
+               var key = new Uint8Array(keylength);
+               var value = new Uint8Array(valuelength);
+               var keystring = '';
+               for(var i =0 ;i<keylength ; i++){
+                       keystring += bb.readByte();
+               }
+               var valuestring= '';
+               for(var j =0 ;j<keylength ; j++){
+                       valuestring += bb.readByte();
+               }
+               for(var k = 0; k< keystring.length; k++){
+                       key[k] = keystring.charCodeAt(k);
+               }
+               for(var l = 0; l< valuestring.length; l++){
+                       value[l] = valuestring.charCodeAt(l);
+               }
+               return new KeyValue(slot,IoTString.shallow(key),IoTString.shallow(value));
+       }
+
+       encode(bb){
+               if(!(bb instanceof ByteBuffer)){
+                       throw new Error('argument error');
+               }
+               bb.writeByte(Entry.TypeKeyValue);
+               bb.writeByte(this.key.length());
+               bb.writeByte(this.value.length());
+               bb.concat(this.key.internalBytes());
+               bb.concat(this.value.internalBytes());
+       }
+       getSize(){
+               return 2*4+this.jey.length()+this.value.length()+1;
+       }
+
+       getType(){
+               return Entry.TypeKeyValue;
+       }
+
+       toString(){
+               return this.value.toString();
+       }
+       getCopy(s){
+               return new KeyValue(s,this.key,this.value);
+       }
+}
diff --git a/version1/src/js/iotjs/orig/lastmessage.js b/version1/src/js/iotjs/orig/lastmessage.js
new file mode 100644 (file)
index 0000000..496862f
--- /dev/null
@@ -0,0 +1,39 @@
+class LastMessage extends Entry{
+       constructor(slot,_machineid,_seqnum){
+               super(slot);
+               this.machineid = _machineid;
+               this.seqnum = _seqnum;
+       }
+       getMachineID(){
+               return this.machineid;
+       }
+       getSequenceNumber() {
+               return this.seqnum;
+       }
+       decode(slot,bb){
+               //slot and bb are instancesof Slot and ByteBuffer
+               if(!(slot instanceof Slot && bb instanceof ByteBuffer)){
+                       throw new Error('Problem with the Arguments');
+               }
+               var machineid = bb.readInt64();
+               var seqnum = bb.readInt64();
+               return new LastMessage(slot,machineid,seqnum);
+       }
+       encode(bb){
+               bb.writeByte(Entry.TypeLastMessage);
+               bb.writeInt64(this.machineid);
+               bb.writeInt64(this.seqnum);
+       }
+       getSize(){
+               return 2*(1+1);
+       }
+       getType(){
+               return Entry.TypeLastMessage;
+       }
+       getCopy(s){
+               if(!(s instanceof Slot)){
+                       throw new Error('Argument must be a slot object');
+               }
+               return new LastMessage(s,this.machineid,this.seqnum);
+       }
+}
\ No newline at end of file
diff --git a/version1/src/js/iotjs/orig/rejectedmessage.js b/version1/src/js/iotjs/orig/rejectedmessage.js
new file mode 100644 (file)
index 0000000..f9f775a
--- /dev/null
@@ -0,0 +1,59 @@
+class RejectedMessage extends Entry {
+    constructor(slot, _machineid, _oldseqnum, _newseqnum, _equalto) {
+        super(slot);
+        this.machineid = _machineid;
+        this.oldseqnum = _oldseqnum;
+        this.newseqnum = _newseqnum;
+        this.equalto = _equalto;
+        this.watchset = new Set();
+    }
+    getOldSeqNum() {
+        return this.oldseqnum;
+    }
+    getNewSeqNum() {
+        return this.newseqnum;
+    }
+    getEqual() {
+        return this.equalto;
+    }
+    getMachineID() {
+        return this.machineid;
+    }
+    static decode(slot, bb) {
+        this.machineid = bb.readByte();
+        this.oldseqnum = bb.readInt64();
+        this.newseqnum = bb.readInt64();
+        this.equalto = bb.readbyte();
+        return new RejectedMessage(this.slot, this.machineid, this.oldseqnum, this.newseqnum, this.equalto === 1)
+    }
+    setWatchSet(_watchset) {
+        this.watchset = _watchset;
+    }
+    removeWatcher(_machineid) {
+        if (this.watchset.remove(_machineid)) {
+            if (this.watchset.isEmpty()) {
+                this.setDead();
+            }
+        }
+    }
+    encode(bb) {
+        bb.writeByte(Entry.TypeRejectedMessage);
+        bb.writeInt64(this.machineid);
+        bb.writeInt64(this.oldseqnum);
+        bb.writeInt64(this.newseqnum);
+        if (this.equalto === true) {
+            bb.writebyte(1);
+        } else {
+            bb.writebyte(0);
+        }
+    }
+    getSize() {
+        return 3 * 8 + 2 * 1;
+    }
+    getType(){
+       return Entry.TypeRejectedMessage;
+    }
+    getCopy(s){
+       return new RejectedMessage(s,this.machineid,this.oldseqnum,this.newseqnum,this.equalto);
+    }
+}
diff --git a/version1/src/js/iotjs/orig/slot.js b/version1/src/js/iotjs/orig/slot.js
new file mode 100644 (file)
index 0000000..6af5a18
--- /dev/null
@@ -0,0 +1,171 @@
+class Slot {
+    constructor(table, seqnum, machineid, prevhmac, hmac) {
+        this.SLOT_SIZE = 2048;
+        this.RESERVED_SPACE = 64;
+        this.HMAC_SIZE = 32;
+        if(typeof seqnum === "number"){
+               this.seqnum = seqnum;
+        }else{
+               throw new Error("seqnum should be a number");
+        }
+        if(typeof machineid === "number"){
+               this.machineid = machineid;
+        }else{
+               throw new Error("machine should be a number");
+        }
+        this.livecount = 1;
+        this.seqnumlive = true;
+        if(prevhmac && prevhmac instanceof Uint8Array){
+               this.prevhmac = prevhmac;
+        }else{
+               throw new Error("prevhmac input not valid");
+        }
+           if(hmac && hmac instanceof Uint8Array){
+               this.hmac = hmac
+           }else{
+               throw new Error("Hmac input not valid");
+           }
+       this.entries = [];
+       this.freespace = this.SLOT_SIZE - getBaseSize();   //???????
+       this.table = table;
+       }
+       getHMAC() {
+       return this.hmac;
+       }
+       getPrevHmac() {
+       return this.prevhmac;
+       }
+       addEntry(entry) {
+           if (entry && entry instanceof Entry) {
+               var obj;
+               this.entries.push(_.extend(obj, entry));
+               this.livecount++;
+               this.freespace -= entry.getSize();
+           }
+       }
+       addShallowEntry(entry){
+               if(entry && entry instanceof Entry){
+                       this.entries.push(entry);
+                       this.livecount++;
+               this.freespace -= entry.getSize();
+               }
+       }
+       hasSpace(entry){
+               var newfreespace = this.freespace - entry.getSize();
+               return newfreespace > this.RESERVED_SPACE;
+       }
+       getEntries(){
+               return this.entries;
+       }
+       static decode(table, array, key){
+               var cond1 = (array && array instanceof Uint8Array);
+               if(cond1){
+                       var mac = crypto.HmacMD5(array.slice(this.HMAC_SIZE).join([separator='']),key);
+                       
+                       var realmac = new Uint8Array(mac.length);
+                       for(var i=0; i< mac.length ; i++){
+                               realmac[i] = mac.charCodeAt(i);
+                       }
+                       
+                       var bb = new ByteBuffer().wrap(array.join([separator=''])).flip();
+                       var hmac= new Uint8Array(this.HMAC_SIZE);
+                       var prevhmac = new Uint8Array(this.HMAC_SIZE);
+                       for(var i = 0; i<this.HMAC_SIZE; i++){
+                               hmac[i] = bb.readByte();
+                       }
+                       for(var j = 0; j<this.HMAC_SIZE; j++){
+                               prevhmac[j] = bb.readByte();
+                       }
+                       //shallow compare
+                       for(var k =0; k<this.HMAC_SIZE; k++){
+                               if(!(hmac[k] === realmac[k])){
+                                       throw new Error("Server Error: Invalid HMAC!  Potential Attack!");
+                               }
+                       }
+                       var _seqnum = bb.readLong();
+                       var _machineid = bb.readLong();
+                       var numentries = bb.readInt8();
+
+                       var _slot = new Slot(table,_seqnum,_machineid,prevhmac,hmac);
+
+                       for(var l= 0 ;l<numentries;l++){
+                               _slot.addShallowEntry(Entry.decode(_slot,bb));
+                       }
+                       return _slot;
+               }
+       }
+       encode(key){
+               var array = new Uint8Array(this.SLOT_SIZE);
+               var bb = new ByteBuffer().wrap(array.join([separator='']))
+               //leave space for slot HMAC
+               bb.skip(this.HMAC_SIZE);
+               bb.writeIString(this.prevhmac.join([separator='']));
+               bb.writeInt64(this.seqnum);
+               bb.writeInt64(this.machineid);
+               bb.writeByte(this.entries.length);
+               this.entries.forEach((entry) => entry.encode(bb));
+
+               var mac = crypto.HmacMD5(array.slice(this.HMAC_SIZE).join([separator='']),key);
+               var realmac = new Uint8Array(mac.length);
+               for(var i=0; i< mac.length ; i++){
+                       realmac[i] = mac.charCodeAt(i);
+               }
+               this.hmac = realmac;
+               bb.reset();
+               bb.wrap(realmac.join([separator='']));
+               return new Uint8Array(bb.toArrayBuffer());
+       }
+       /**
+        * Returns the empty size of a Slot. Includes 2 HMACs, the machine
+        * identifier, the sequence number, and the number of entries.
+        */
+       getBaseSize(){
+               return 2*this.HMAC_SIZE+2*8+2*4; //Problematic area
+       }
+
+       getLiveEntries(resize){
+               var liveEntries = [];
+               this.entries.forEach(function(entry){
+                       if(entry.isLive === true){
+                               if(!resize || entry.getType() !== entry.TypeTableStatus){
+                                       liveEntries.push(entry);
+                               }
+                       };
+               });
+
+               if(this.seqnumlive && !resize){
+                       liveEntries.push(new LastMessage(this,this.machineid,this.seqnumlive))
+               }
+
+               return liveEntries;
+       }
+
+       getSequenceNumber() {
+               return this.seqnum;
+       }
+
+       getMachineID() {
+               return this.machineid;
+       }
+       
+       setDead() {
+               this.seqnumlive=false;
+               this.decrementLiveCount();
+       }
+
+       decrementLiveCount() {
+               this.livecount--;
+               if (this.livecount === 0)
+                       this.table.decrementLiveCount();
+       }
+
+       isLive() {
+               return this.livecount > 0;
+       }
+
+       toString() {
+               return '<'+this.getSequenceNumber()+'>';
+       }
+
+}
+       
\ No newline at end of file
diff --git a/version1/src/js/iotjs/orig/slotbuffer.js b/version1/src/js/iotjs/orig/slotbuffer.js
new file mode 100644 (file)
index 0000000..1e76971
--- /dev/null
@@ -0,0 +1,89 @@
+class SlotBuffer{
+       constructor(){
+               this.DEFAULT_SIZE = 128;
+               this.array = [];
+               this.head=0;
+               this.tail=0;
+               this.oldestseqn = 0;
+       }
+       size(){
+               if(this.head>=this.tail){
+                       return this.head-this.tail;
+               }
+               return (this.array.length + this.head - this.tail);
+       }
+       capacity(){
+               return this.array.length-1;
+       }
+       resize(newsize){
+               if(newsize === (this.array.length-1)){
+                       return;
+               }
+               var newarray = [];
+               var currsize = this.size();
+               var index = this.tail;
+               for(let i = 0 ; i<currsize ; i++){
+                       newarray[i]=this.array[index];
+                       if((++index) === this.array.length){
+                               index = 0;
+                       }
+                       this.array = newarray;
+                       this.tail=0;
+                       this.head=currsize; 
+               }
+       }
+       incrementHead(){
+               this.head++;
+               if(this.head >= this.array.length){
+                       this.head=0;
+               }
+       }
+       incrementTail(){
+               this.tail++;
+               if(this.tail >= this.array.length){
+                       this.tail=0;
+               }
+       }
+       putSlot(s){
+               if(!(s instanceof Slot)){
+                       throw new Error("Error with arguments. Argument should be a slot object");
+               }
+               this.array[this.head]=s;
+               this.incrementHead();
+
+               if(this.oldestseqn ===0){
+                       this.oldestseqn = s.getSequenceNumber();
+               }
+
+               if(this.head === this.tail){
+                       this.incrementTail();
+                       this.oldestseqn++;
+               }
+       }
+       getSlot(seqnum){
+               var diff = (seqnum - this.oldestseqn);
+               var index = diff + this.tail;
+               if(index >= this.array.length){
+                       if(this.head >= this.tail){
+                               return null;
+                       }
+                       index = index - this.array.length; 
+               }
+               if(index >= this.array.length){
+                       return null;
+               }
+
+               if(this.head >= this.tail && index >= this.head){
+                       return null;
+               }
+
+               return this.array[index];
+       }
+
+       getOldestSeqNum(){
+               return this.oldestseqn;
+       }
+       getNewestSeqNum(){
+               return this.oldestseqn + this.size() -1
+       }
+}
\ No newline at end of file
diff --git a/version1/src/js/iotjs/orig/slotindexer.js b/version1/src/js/iotjs/orig/slotindexer.js
new file mode 100644 (file)
index 0000000..da738ff
--- /dev/null
@@ -0,0 +1,27 @@
+class SlotIndexer{
+       constructor(_updates,_buffer){
+               // updates is an array of slot objects
+               // buffer is an instanceof slotbuffer constructor object in slotbuffer.js
+               this.updates = _updates;
+               if(_buffer && _buffer instanceof SlotBuffer){
+                       this.buffer = _buffer;
+               }else{
+                       throw new Error("Argument error Buffer should be an instance of SlotBuffer");
+               }
+               this.firstslotseqnum = this.updates[0].getSequenceNumber();     
+       }
+
+       getSlot(seqnum){
+               if(seqnum >= this.firstslotseqnum){
+                       var offset = seqnum - this.firstslotseqnum;
+                       if(offset >= this.updates.length){
+                               throw new Error('Invalid Slot Sequence Number Reference');
+                       }else{
+                               return this.updates[offset];
+                       }
+               }else{
+                       return this.buffer.getSlot(seqnum);
+               }
+       }
+
+}
\ No newline at end of file
diff --git a/version1/src/js/iotjs/orig/tablestatus.js b/version1/src/js/iotjs/orig/tablestatus.js
new file mode 100644 (file)
index 0000000..06f8f25
--- /dev/null
@@ -0,0 +1,34 @@
+class TableStatus extends Entry{
+       constructor(slot,_maxslots){
+               super(slot);
+               this.maxslots = _maxslots;
+       }
+       getMaxSlots(){
+               return this.maxslots;
+       }
+       static decode(slot,bb){
+               //bb is an object of the type bytebuffer See main.js file and its require section 
+               //for more details
+               if(!(bb instanceof ByteBuffer && slot instanceof Slot)){
+                       throw new Error('Argument Error: bb is not an instanceof Bytebuffer');
+               }
+               this.maxslots = bb.readByte();
+               return new TableStatus(slot,this.maxslots);
+       }
+       encode(bb){
+               bb.writeByte(Entry.TypeTableStatus);
+               bb.writeInt8(this.maxslots);
+       }
+       getSize(){
+               return 4+1;
+       }
+       getType(){
+               return Entry.TypeTableStatus;
+       }
+       getcopy(s){
+               if(!(s instanceof Slot)){
+                       throw new Error('Argument Error: s is not an instanceof Slot');
+               }
+               return new TableStatus(s,this.maxslots);
+       }
+}
\ No newline at end of file
diff --git a/version1/src/js/iotjs/package.json b/version1/src/js/iotjs/package.json
new file mode 100644 (file)
index 0000000..277b0ba
--- /dev/null
@@ -0,0 +1,33 @@
+{
+  "name": "iotjs",
+  "version": "0.0.0",
+  "scripts": {
+    "test": "gulp && node ./test/test.js"
+  },
+  "dependencies": {
+    "bytebuffer": "^5.0.1",
+    "crypto-js": "^3.1.6",
+    "gulp": "3.8.11",
+    "gulp-clean": "0.3.1",
+    "gulp-concat": "2.5.2",
+    "gulp-if": "1.2.5",
+    "gulp-jshint": "1.9.4",
+    "gulp-livereload": "3.8.0",
+    "gulp-load-plugins": "0.8.1",
+    "gulp-order": "1.1.1",
+    "gulp-rename": "1.2.0",
+    "gulp-sourcemaps": "1.5.1",
+    "gulp-uglify": "1.1.0",
+    "jshint-stylish": "1.0.1",
+    "minimist": "1.1.1",
+    "node-forge": "^0.6.41",
+    "object-hash": "^1.1.3",
+    "request": "^2.74.0",
+    "underscore": "^1.8.3"
+  },
+  "devDependencies": {
+    "babel-cli": "^6.11.4",
+    "babel-preset-es2015": "^6.9.0",
+    "browserify": "^13.1.0"
+  }
+}
diff --git a/version1/src/js/iotjs/src/entry.js b/version1/src/js/iotjs/src/entry.js
new file mode 100644 (file)
index 0000000..e4a47a3
--- /dev/null
@@ -0,0 +1,72 @@
+"use strict";
+
+var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+var Entry = function () {
+    function Entry(slot) {
+        _classCallCheck(this, Entry);
+
+        if (slot && slot instanceof Slot) {
+
+            this.TypeKeyValue = 1;
+            this.TypeLastmessage = 2;
+            this.TypeRejectedMessage = 3;
+            this.TypeTableStatus = 4;
+            this.liveStatus = true;
+            this.parentslot = slot;
+        }
+    }
+
+    _createClass(Entry, [{
+        key: "isLive",
+        value: function isLive() {
+            return this.liveStatus;
+        }
+    }, {
+        key: "setDead",
+        value: function setDead() {
+            this.liveStatus = false;
+            parentslot.decrementLiveCount();
+        }
+
+        //must be overriden.
+
+    }, {
+        key: "encode",
+        value: function encode(bytebuffer) {}
+    }, {
+        key: "getSize",
+        value: function getSize() {}
+    }, {
+        key: "getType",
+        value: function getType() {}
+    }, {
+        key: "getCopy",
+        value: function getCopy(slot) {
+            if (slot && slot instanceof Slot) {}
+        }
+    }], [{
+        key: "decode",
+        value: function decode(slot, bytebuffer) {
+            if (slot instanceof Slot && bytebuffer instanceof ByteBuffer) {
+                var type = bytebuffer.readByte();
+                switch (type) {
+                    case this.TypeKeyValue:
+                        return KeyValue.decode(slot, bytebuffer);
+                    case this.TypeLastmessage:
+                        return LastMessage.decode(slot, bytebuffer);
+                    case this.TypeRejectedMessage:
+                        return RejectedMessage.decode(slot, bytebuffer);
+                    case this.TypeTableStatus:
+                        return TableStatus.decode(slot, bytebuffer);
+                    default:
+                        throw new Error("Unrecognized Entry Type: " + type);
+                }
+            }
+        }
+    }]);
+
+    return Entry;
+}();
\ No newline at end of file
diff --git a/version1/src/js/iotjs/src/iotstring.js b/version1/src/js/iotjs/src/iotstring.js
new file mode 100644 (file)
index 0000000..5a350e8
--- /dev/null
@@ -0,0 +1,81 @@
+var _createClass = function() {
+    function defineProperties(target, props) {
+        for (var i = 0; i < props.length; i++) {
+            var descriptor = props[i];
+            descriptor.enumerable = descriptor.enumerable || false;
+            descriptor.configurable = true;
+            if ("value" in descriptor) descriptor.writable = true;
+            Object.defineProperty(target, descriptor.key, descriptor);
+        }
+    }
+    return function(Constructor, protoProps, staticProps) {
+        if (protoProps) defineProperties(Constructor.prototype, protoProps);
+        if (staticProps) defineProperties(Constructor, staticProps);
+        return Constructor;
+    };
+}();
+
+function _classCallCheck(instance, Constructor) {
+    if (!(instance instanceof Constructor)) {
+        throw new TypeError("Cannot call a class as a function");
+    }
+}
+var IoTString = function() {
+    function IoTString(arg) {
+        _classCallCheck(this, IoTString);
+        if (arg === undefined) {
+            this.array = new Uint8Array();
+            this.hashcode = '';
+        } else if (arg && typeof arg === "string") {
+            this.array = new Uint8Array(arg.length);
+            for (var i = 0; i < arg.length; ++i) {
+                this.array[i] = arg.charCodeAt(i);
+            }
+            this.hashcode = hash(this.array);
+        } else if (arg && arg instanceof Uint8Array) {
+            this.array = arg;
+            this.hashcode = hashcode(arg);
+        }
+    }
+    _createClass(IoTString, [{
+        key: "shallow",
+        value: function shallow(arg) {
+            if (arg && arg instanceof Uint8Array) {
+                var i = new IotString(arg);
+                return i;
+            }
+        }
+    }, {
+        key: "internalBytes",
+        value: function internalBytes() {
+            return this.array;
+        }
+    }, {
+        key: "hashCode",
+        value: function hashCode() {
+            return this.hashcode;
+        }
+    }, {
+        key: "toString",
+        value: function toString() {
+            return this.array.toString();
+        }
+    }, {
+        key: "getBytes",
+        value: function getBytes() {
+            var obj;
+            return _.extend(obj, this.array);
+        }
+    }, {
+        key: "equals",
+        value: function equals(arr) {
+            return _.isEqual(arr, this.array);
+        }
+    }, {
+        key: "length",
+        value: function length() {
+            return this.array.length;
+        }
+    }]);
+    return IoTString;
+}();
\ No newline at end of file
diff --git a/version1/src/js/iotjs/src/keyvalue.js b/version1/src/js/iotjs/src/keyvalue.js
new file mode 100644 (file)
index 0000000..a2c02d0
--- /dev/null
@@ -0,0 +1,99 @@
+'use strict';
+
+var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
+
+function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
+
+var KeyValue = function (_Entry) {
+       _inherits(KeyValue, _Entry);
+
+       function KeyValue(slot, _key, _value) {
+               _classCallCheck(this, KeyValue);
+
+               if (!(slot instanceof Slot && _key instanceof IoTString && _value instanceof IoTString)) {
+                       throw new Error('Argument error ');
+               }
+
+               var _this = _possibleConstructorReturn(this, Object.getPrototypeOf(KeyValue).call(this, slot));
+
+               _this.key = _key;
+               _this.value = _value;
+               return _this;
+       }
+
+       _createClass(KeyValue, [{
+               key: 'getKey',
+               value: function getKey() {
+                       return this.key;
+               }
+       }, {
+               key: 'getValue',
+               value: function getValue() {
+                       return this.value;
+               }
+       }, {
+               key: 'decode',
+               value: function decode(slot, bb) {
+                       if (!(slot instanceof Slot && bb instanceof ByteBuffer)) {
+                               throw new Error('Argument error');
+                       }
+                       var keylength = bb.getByte();
+                       var valuelength = bb.getByte();
+                       var key = new Uint8Array(keylength);
+                       var value = new Uint8Array(valuelength);
+                       var keystring = '';
+                       for (var i = 0; i < keylength; i++) {
+                               keystring += bb.readByte();
+                       }
+                       var valuestring = '';
+                       for (var j = 0; j < keylength; j++) {
+                               valuestring += bb.readByte();
+                       }
+                       for (var k = 0; k < keystring.length; k++) {
+                               key[k] = keystring.charCodeAt(k);
+                       }
+                       for (var l = 0; l < valuestring.length; l++) {
+                               value[l] = valuestring.charCodeAt(l);
+                       }
+                       return new KeyValue(slot, IoTString.shallow(key), IoTString.shallow(value));
+               }
+       }, {
+               key: 'encode',
+               value: function encode(bb) {
+                       if (!(bb instanceof ByteBuffer)) {
+                               throw new Error('argument error');
+                       }
+                       bb.writeByte(Entry.TypeKeyValue);
+                       bb.writeByte(this.key.length());
+                       bb.writeByte(this.value.length());
+                       bb.concat(this.key.internalBytes());
+                       bb.concat(this.value.internalBytes());
+               }
+       }, {
+               key: 'getSize',
+               value: function getSize() {
+                       return 2 * 4 + this.jey.length() + this.value.length() + 1;
+               }
+       }, {
+               key: 'getType',
+               value: function getType() {
+                       return Entry.TypeKeyValue;
+               }
+       }, {
+               key: 'toString',
+               value: function toString() {
+                       return this.value.toString();
+               }
+       }, {
+               key: 'getCopy',
+               value: function getCopy(s) {
+                       return new KeyValue(s, this.key, this.value);
+               }
+       }]);
+
+       return KeyValue;
+}(Entry);
\ No newline at end of file
diff --git a/version1/src/js/iotjs/src/lastmessage.js b/version1/src/js/iotjs/src/lastmessage.js
new file mode 100644 (file)
index 0000000..8ccb06b
--- /dev/null
@@ -0,0 +1,73 @@
+'use strict';
+
+var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
+
+function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
+
+var LastMessage = function (_Entry) {
+       _inherits(LastMessage, _Entry);
+
+       function LastMessage(slot, _machineid, _seqnum) {
+               _classCallCheck(this, LastMessage);
+
+               var _this = _possibleConstructorReturn(this, Object.getPrototypeOf(LastMessage).call(this, slot));
+
+               _this.machineid = _machineid;
+               _this.seqnum = _seqnum;
+               return _this;
+       }
+
+       _createClass(LastMessage, [{
+               key: 'getMachineID',
+               value: function getMachineID() {
+                       return this.machineid;
+               }
+       }, {
+               key: 'getSequenceNumber',
+               value: function getSequenceNumber() {
+                       return this.seqnum;
+               }
+       }, {
+               key: 'decode',
+               value: function decode(slot, bb) {
+                       //slot and bb are instancesof Slot and ByteBuffer
+                       if (!(slot instanceof Slot && bb instanceof ByteBuffer)) {
+                               throw new Error('Problem with the Arguments');
+                       }
+                       var machineid = bb.readByte();
+                       var seqnum = bb.readByte();
+                       return new LastMessage(slot, machineid, seqnum);
+               }
+       }, {
+               key: 'encode',
+               value: function encode(bb) {
+                       bb.writeByte(Entry.TypeLastMessage);
+                       bb.writeByte(this.machineid);
+                       bb.writeByte(this.seqnum);
+               }
+       }, {
+               key: 'getSize',
+               value: function getSize() {
+                       return 2 * (1 + 1);
+               }
+       }, {
+               key: 'getType',
+               value: function getType() {
+                       return Entry.TypeLastMessage;
+               }
+       }, {
+               key: 'getCopy',
+               value: function getCopy(s) {
+                       if (!(s instanceof Slot)) {
+                               throw new Error('Argument must be a slot object');
+                       }
+                       return new LastMessage(s, this.machineid, this.seqnum);
+               }
+       }]);
+
+       return LastMessage;
+}(Entry);
\ No newline at end of file
diff --git a/version1/src/js/iotjs/src/liveness.js b/version1/src/js/iotjs/src/liveness.js
new file mode 100644 (file)
index 0000000..22cbd3f
--- /dev/null
@@ -0,0 +1,5 @@
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+var Liveness = function Liveness() {
+  _classCallCheck(this, Liveness);
+};
\ No newline at end of file
diff --git a/version1/src/js/iotjs/src/main.js b/version1/src/js/iotjs/src/main.js
new file mode 100644 (file)
index 0000000..f8f03e7
--- /dev/null
@@ -0,0 +1,66 @@
+/* jshint devel:true */
+"use strict";
+console.log('Welcome to iotjs-www', '\n\n');
+// set up the base line..
+// Using browserify to set up browser exports
+var crypto = require('crypto-js');
+var _ = require('underscore');
+var ByteBuffer = require('bytebuffer');
+var hash = require('object-hash');
+var forge = require('node-forge');
+(function() {
+    var root = this;
+    // iot namespace main constructor
+    var iot = function(obj) {
+        if (obj instanceof iot) return obj;
+        if (!(this instanceof iot)) return new iot(obj);
+        this.iot = obj;
+    };
+    // export iot to the global exports
+    if (typeof exports !== 'undefined') {
+        if (typeof module !== 'undefined' && module.exports) {
+            exports = module.exports = iot;
+        }
+        exports.iot = iot;
+    } else {
+        root.iot = iot;
+    }
+
+
+    iot.baselinetest = function() {
+        // baseline test
+        console.log('its alive!!!');
+        console.log();
+
+
+        //local hash test
+        console.log(hash('hello man'));
+        console.log(typeof hash('hello man'));
+        console.log();
+
+
+        //Pair test
+        var p = new Pair(1, 2);
+        console.log(p.toString());
+        console.log();
+
+
+        //iotstring test
+        var i = new IoTString('hello');
+        console.log(i.length());
+        console.log();
+
+
+        //local crypto test
+        var data = [{id: 1}, {id: 2}];
+        // Encrypt 
+        var ciphertext = crypto.AES.encrypt(JSON.stringify(data), 'secret key 123');
+        // Decrypt 
+        var bytes = crypto.AES.decrypt(ciphertext.toString(), 'secret key 123');
+        var decryptedData = JSON.parse(bytes.toString(crypto.enc.Utf8));
+        // console.log(decryptedData);
+
+        var e = crypto.HmacMD5("Message", "Secret Passphrase");
+        console.log(typeof e.toString());
+    }
+}())
\ No newline at end of file
diff --git a/version1/src/js/iotjs/src/pair.js b/version1/src/js/iotjs/src/pair.js
new file mode 100644 (file)
index 0000000..e2467e3
--- /dev/null
@@ -0,0 +1,32 @@
+var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+var Pair = function () {
+  function Pair(a, b) {
+    _classCallCheck(this, Pair);
+
+    this.a = a;
+    this.b = b;
+  }
+
+  _createClass(Pair, [{
+    key: 'getFirst',
+    value: function getFirst() {
+      return this.a;
+    }
+  }, {
+    key: 'getSecond',
+    value: function getSecond() {
+      return this.b;
+    }
+  }, {
+    key: 'toString',
+    value: function toString() {
+      var str = '<' + this.a + ',' + this.b + '>';
+      return str;
+    }
+  }]);
+
+  return Pair;
+}();
\ No newline at end of file
diff --git a/version1/src/js/iotjs/src/rejectedmessage.js b/version1/src/js/iotjs/src/rejectedmessage.js
new file mode 100644 (file)
index 0000000..7c825c8
--- /dev/null
@@ -0,0 +1,101 @@
+"use strict";
+
+var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
+
+function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
+
+var RejectedMessage = function (_Entry) {
+    _inherits(RejectedMessage, _Entry);
+
+    function RejectedMessage(slot, _machineid, _oldseqnum, _newseqnum, _equalto) {
+        _classCallCheck(this, RejectedMessage);
+
+        var _this = _possibleConstructorReturn(this, Object.getPrototypeOf(RejectedMessage).call(this, slot));
+
+        _this.machineid = _machineid;
+        _this.oldseqnum = _oldseqnum;
+        _this.newseqnum = _newseqnum;
+        _this.equalto = _equalto;
+        _this.watchset = new Set();
+        return _this;
+    }
+
+    _createClass(RejectedMessage, [{
+        key: "getOldSeqNum",
+        value: function getOldSeqNum() {
+            return this.oldseqnum;
+        }
+    }, {
+        key: "getNewSeqNum",
+        value: function getNewSeqNum() {
+            return this.newseqnum;
+        }
+    }, {
+        key: "getEqual",
+        value: function getEqual() {
+            return this.equalto;
+        }
+    }, {
+        key: "getMachineID",
+        value: function getMachineID() {
+            return this.machineid;
+        }
+    }, {
+        key: "setWatchSet",
+        value: function setWatchSet(_watchset) {
+            this.watchset = _watchset;
+        }
+    }, {
+        key: "removeWatcher",
+        value: function removeWatcher(_machineid) {
+            if (this.watchset.remove(_machineid)) {
+                if (this.watchset.isEmpty()) {
+                    this.setDead();
+                }
+            }
+        }
+    }, {
+        key: "encode",
+        v