diff --git a/isabelle/Core/Semantics.thy b/isabelle/Core/Semantics.thy index 1629372f..c003c390 100644 --- a/isabelle/Core/Semantics.thy +++ b/isabelle/Core/Semantics.thy @@ -726,34 +726,80 @@ and maxTimeCase :: "Case \ int" where subsection "calculateNonAmbiguousInterval" +text "Helper functions for \<^emph>\calculateNonAmbiguousInterval\" fun gtIfNone :: "int option \ int \ bool" where "gtIfNone None _ = True" | "gtIfNone (Some x) y = (x > y)" fun geIfNone :: "int option \ int \ bool" where "geIfNone None _ = True" | -"geIfNone (Some x) y = (x \ y)" +"geIfNone (Some x) y = (x \ y) " fun subIfSome :: "int option \ int \ int option" where "subIfSome None _ = None" | "subIfSome (Some x) y = Some (x - y)" +text \ +A TimeInterval (startTime, endTime) can be ambiguous wrt a When's timeout if startTime < timeout \ endTime + +\ + +text \The \<^emph>\calculateNonAmbiguousInterval\ function can help a user to calculate a TimeInterval that +won't be ambiguous for the next \<^emph>\n\ inputs of a contract.\ + +text \The only Contract constructor that can yield a \<^term>\TEAmbiguousTimeIntervalError\ is the \<^term>\When\ case. +Computing a transaction of a contract that starts in a non quiescent state (\<^term>\Let\, \<^term>\Pay\, \<^term>\If\, \<^term>\Assert\) +can end in a \<^term>\TEAmbiguousTimeIntervalError\ iff there is a \<^term>\When\ case that makes it ambiguous. +\ + +text \A TimeInterval expressed as the tuple \<^term>\(startTime \ endTime)\ can be ambiguous wrt a \<^term>\When\'s timeout +iff \<^emph>\startTime < timeout \ endTime\ +\ + +text +\ It parameters of \<^emph>\calculateNonAmbiguousInterval\ are: +\<^item> An optional number of Inputs to check. The number of inputs corresponds to the number of "When". +If None is passed, it means that we should check for transactions of any number of inputs. +\<^item> A lower bound (normally the current time). +\<^item> The Contract to check. + +The function returns an Optionally Bound Time Interval, as defined in the \<^emph>\OptBoundTimeInterval.thy\ theory. +In the \<^emph>\TimeRange.thy\ theory we prove that computing a transaction with these bounds doesn't end with an ambiguous error. +\ +\ \TODO: The intersectInterval can produce an invalid time interval, which would mean that not suitable TimeInterval was found\ fun calculateNonAmbiguousInterval :: "int option \ POSIXTime \ Contract \ OptBoundTimeInterval" -where + where +\ \A Close contract can't be ambiguous, so an Unbounded interval is returned \ "calculateNonAmbiguousInterval _ _ Close = (Unbounded, Unbounded)" | +\ \A Pay contract isn't ambiguous by itself, so we calculate for the continuation\ "calculateNonAmbiguousInterval n t (Pay _ _ _ _ c) = calculateNonAmbiguousInterval n t c" | -"calculateNonAmbiguousInterval n t (If _ ct cf) = intersectInterval (calculateNonAmbiguousInterval n t ct) +\ \If we branch, we intersect the result of both possibilites. \ +\ \TODO: Note that not knowing which branch can be selected beforehand means that we return a smaller TimeInterval than +possible. Maybe we could improve this by using the actual Input instead of the number of inputs\ +"calculateNonAmbiguousInterval n t (If _ ct cf) = intersectInterval + (calculateNonAmbiguousInterval n t ct) (calculateNonAmbiguousInterval n t cf)" | -"calculateNonAmbiguousInterval n t (When Nil timeout tcont) = +\ \We treat the When contract in two parts. The base case (when no actions are available) and a recursive +case, when we have a particular action \ +"calculateNonAmbiguousInterval n t (When [] timeout tcont) = (if t < timeout + \ \If the When's timeout is in the future, we can generate a non-ambiguous time interval + by restricting the endTime to be strictly lower than the timeout\ then (Unbounded, Bounded (timeout - 1)) + \ \If the timeout is in the past, we need to restrict the startTime to be larger or equal than + the timeout\ else intersectInterval (Bounded timeout, Unbounded) (calculateNonAmbiguousInterval n t tcont))" | -"calculateNonAmbiguousInterval n t (When (Cons (Case _ cont ) tail) timeout tcont) = + +"calculateNonAmbiguousInterval n t (When (Case _ cont # restCases) timeout tcont) = (if gtIfNone n 0 +\ \If n is none (check all) or n > 0 we recursively calculate the intersection for all the continuations\ then intersectInterval (calculateNonAmbiguousInterval (subIfSome n 1) t cont) - (calculateNonAmbiguousInterval n t (When tail timeout tcont)) - else calculateNonAmbiguousInterval n t (When tail timeout tcont))" | + (calculateNonAmbiguousInterval n t (When restCases timeout tcont)) +\ \If n \ 0 we don't calculate for the current case and we iterate until we reach the base case\ +\ \TODO: we should be able to change restCases for [] to check the base case directly\ + else calculateNonAmbiguousInterval n t (When restCases timeout tcont))" | +\ \A Let or Assert contracts aren't ambiguous by themselves, so we calculate for the continuation\ "calculateNonAmbiguousInterval n t (Let _ _ c) = calculateNonAmbiguousInterval n t c" | "calculateNonAmbiguousInterval n t (Assert _ c) = calculateNonAmbiguousInterval n t c"