├── .gitignore ├── doc └── language-spec.md └── tezos.v /.gitignore: -------------------------------------------------------------------------------- 1 | *.vo 2 | *.glob 3 | ~* 4 | *.swp 5 | -------------------------------------------------------------------------------- /doc/language-spec.md: -------------------------------------------------------------------------------- 1 | Tezos Contract Script Language Specification 2 | ============================================ 3 | 4 | The language is stack based, with high level data types and primitives 5 | and scrict static type checking. Its design is insipired by Forth, 6 | Scheme, ML and Cat. 7 | 8 | This specification gives the complete instruction set, type system and 9 | semantics of the language. It is meant as a precise reference manual, 10 | not an easy introduction. Even though, some examples are provided at 11 | the end of the document and can be read first or at the same time as 12 | the specification. 13 | 14 | 15 | Table of contents 16 | ----------------- 17 | 18 | * I - Type system 19 | * II - Semantics 20 | * III - Core instructions 21 | * IV - Data types 22 | * V - Operations 23 | * VI - Domain specific data types 24 | * VII - Domain specific operations 25 | * VIII - Concrete syntax 26 | * IX - Examples 27 | * X - Full grammar 28 | * XI - Reference implementation 29 | 30 | I - Type system 31 | --------------- 32 | 33 | The types `T` of values in the stack are written using notations 34 | 35 | * `bool`, `string`, `void`, `u?int{8|16|32|64}`, `float`, 36 | the core primitive types, 37 | * `identifier` for a primitive data-type, 38 | * `T identifier` for a parametric data-type with one parameter type `T`, 39 | * `identifier T_0 ... T_n` for a parametric data-type with several 40 | parameters, 41 | * `'a` for a type variable, 42 | * `_` for an anonymous type variable, 43 | * `[ P ]` for a code quotation whose program type is `P`, 44 | * `lambda T_arg T_ret` is a shortcut for `[ T_arg :: [] -> T_ret :: []]`. 45 | * other specific notations for compound types, described later. 46 | 47 | Instructions, programs and primitives of the language are also typed, 48 | their types `P` are written using the following notation, where `S` 49 | the type of a stack. 50 | 51 | :: S before -> S after 52 | 53 | A stack type `S` can be written 54 | 55 | * `[]` for the empty stack, 56 | * `T_top : S_rest` for the stack whose first value has type `Ttop` and queue `Srest`, 57 | * `'A` for a stack type variable, 58 | * `_` for an anonymous stack type variable. 59 | 60 | 61 | II - Semantics 62 | -------------- 63 | 64 | The instructions are specified as follows, giving their mnemonic, type 65 | in the previously defined syntax, and small step semantics as a list 66 | of rewriting rules of the form 67 | 68 | > pre state => result state 69 | 70 | where the preconditions of all rules are to be read in order, the first 71 | match selecting the behaviour of the instruction, so that the choice 72 | is deterministic. Only the valid pre states are described, any other 73 | cannot happen thanks to static typing. 74 | 75 | 76 | The pre and post result states are described as 77 | 78 | * pairs `code / stack` for stack manipulation primitives, 79 | * triples `code / stack / memory` for primitives that also manipulate memory, 80 | * `[FAIL]` for a fatal failure state. 81 | 82 | The notations used are 83 | 84 | * `;` to represent the concatenation of instructions or sequences, 85 | * `[]` for the empty code sequence, 86 | * `top : tail` for stack consing, as in types, 87 | * `identifier` for variable stack and code elements, 88 | * `` for variable memory locations, 89 | * `_` for elements whose value does not affect the semantics. 90 | 91 | The memory is described as a relation between locations and constants of 92 | the form `variable = constant, ...`. 93 | 94 | The constants are of one of the following forms. 95 | 96 | * integers with their sign and size, e.g. `(Uint8 3)`, 97 | * floats in libc-style notation, e.g. `(Float 4.5e2)`, 98 | * `Void`, the unique value of type `void` 99 | * booleans `True` and `False`, 100 | * string literals, as in `(String "contents")`, 101 | * structured constants of compound types described later. 102 | 103 | 104 | III - Core instructions 105 | ----------------------- 106 | 107 | ### Control structures 108 | 109 | * `(I :: [ 'A -> 'B ]) ; (C :: [ 'B -> 'C ])`: Sequence operator. 110 | 111 | :: 'A -> 'C 112 | 113 | > I ; C / SA => C / SB iff I / SA => [] / SB 114 | 115 | * `IF bt bf`: Conditional branching. 116 | 117 | :: bool : 'A -> 'B 118 | iff bt :: [ 'A -> 'B ] 119 | bf :: [ 'A -> 'B ] 120 | 121 | > IF ; C / True : S => bt ; C / S 122 | > IF ; C / False : S => bf ; C / S 123 | 124 | * `LOOP body`: A generic loop. 125 | 126 | :: bool : 'A -> 'A 127 | iff body :: [ 'A -> bool : 'A ] 128 | 129 | > LOOP body ; C / True : S => body ; LOOP body ; C / S 130 | > LOOP body ; C / False : S => C / S 131 | 132 | * `DIP code`: Runs code protecting the top of the stack. 133 | 134 | :: 'b : 'A -> 'b : 'C 135 | iff code :: [ 'A -> 'C ] 136 | 137 | > DIP code ; C / x : S => code ; PUSH x ; C / S 138 | 139 | * `DII+P code`: A sugar syntax for working deeper in the stack. 140 | 141 | > DII(\rest)P code ; C / S => DIP (DI(\rest)P code) ; C / S 142 | 143 | * `LAMBDA 'a 'b code`: Push a function onto the stack. 144 | 145 | :: 'C -> lambda 'a 'b : 'C 146 | iff code :: lambda 'a 'b 147 | 148 | > LAMBDA 'a 'b code ; C / S => C / code : S 149 | 150 | * `EXEC`: Execute a function from the stack. 151 | 152 | :: 'a : lambda 'a 'b : 'C -> 'b : 'C 153 | 154 | > EXEC ; C / a : f : S => f ; C / a : S 155 | 156 | ### Stack operations 157 | 158 | * `DROP`: Drop the top element of the stack. 159 | 160 | :: _ : 'A -> 'A 161 | 162 | > DROP ; C / _ : S => C / S 163 | 164 | * `DUP`: Duplicate the top of the stack. 165 | 166 | :: 'a : 'A -> 'a : 'a : 'A 167 | 168 | > DUP ; C / x : S => C / x : x : S 169 | 170 | * `DUP n`: Duplicate the `n`th element of the stack. 171 | 172 | > DUP (n > 0) ; C / S => DIP { DUP (n - 1) } ; SWAP ; C / S 173 | > DUP 0 ; C / S => DUP ; C / S 174 | 175 | This variant of `DUP` with an optional argument is syntactic 176 | sugar for combining `DIP`, `SWAP` and `DUP` in order to access 177 | elements in the stack by their depth, `DUP 0` being equivqlent to 178 | a simple `DUP`. 179 | 180 | * `SWAP`: Exchange the top two elements of the stack. 181 | 182 | :: 'a : 'b : 'A -> 'b : 'a : 'A 183 | 184 | > SWAP ; C / x : y : S => C / y : x : S 185 | 186 | * `PUSH x`: Push a value onto the stack. 187 | 188 | 189 | :: 'A -> 'a : 'A 190 | iff x :: 'a 191 | 192 | > PUSH x ; C / S => C / x : S 193 | 194 | * `DROP`: Drop the top element of the stack. 195 | 196 | :: _ : 'A -> 'A 197 | 198 | > DROP ; C / _ : S => C / S 199 | 200 | * `VOID`: Push a void value onto the stack. 201 | 202 | :: 'A -> void : 'A 203 | 204 | > VOID ; C / S => C / () : S 205 | 206 | ### Generic comparison 207 | 208 | Comparison only works on a class of types that we call comparable. A 209 | `COMPARE` operation is defined in an ad hoc way for each comparable 210 | type, but the result of compare is always an `int64`, which can in turn 211 | be checked in a generic manner using the following combinators. The 212 | result of `COMPARE` is `0` if the compared values are equal, negative if 213 | the first is less than the second, and positive otherwise. 214 | 215 | * `EQ`: Checks that the top if the stack EQuals zero. 216 | 217 | :: int64 : 'S -> bool : 'S 218 | 219 | > EQ ; C / Int64 (0) : S => C / True : S 220 | > EQ ; C / _ : S => C / False : S 221 | 222 | 223 | * `NEQ`: Checks that the top if the stack does Not EQual zero. 224 | 225 | :: int64 : 'S -> bool : 'S 226 | 227 | > NEQ ; C / Int64 (0) : S => C / False : S 228 | > NEQ ; C / _ : S => C / True : S 229 | 230 | * `LT`: Checks that the top if the stack is Less Than zero. 231 | 232 | :: int64 : 'S -> bool : 'S 233 | 234 | > LT ; C / Int64 (v) : S => C / True : S iff v < 0 235 | > LT ; C / _ : S => C / False : S 236 | 237 | * `GT`: Checks that the top if the stack is Greater Than zero. 238 | 239 | :: int64 : 'S -> bool : 'S 240 | 241 | > GT ; C / Int64 (v) : S => C / True : S iff v > 0 242 | > GT ; C / _ : S => C / False : S 243 | 244 | * `LE`: Checks that the top if the stack is Less Than of Equal to zero. 245 | 246 | :: int64 : 'S -> bool : 'S 247 | 248 | > LE ; C / Int64 (v) : S => C / True : S iff v <= 0 249 | > LE ; C / _ : S => C / False : S 250 | 251 | * `GE`: Checks that the top if the stack is Greater Than of Equal to zero. 252 | 253 | :: int64 : 'S -> bool : 'S 254 | 255 | > GE ; C / Int64 (v) : S => C / True : S iff v >= 0 256 | > GE ; C / _ : S => C / False : S 257 | 258 | Syntactic sugar exists for merging `COMPARE` and comparison 259 | combinators, and also for branching. 260 | 261 | * `CMP{EQ|NEQ|LT|GT|LE|GE}` 262 | 263 | > CMP(\op) ; C / S => COMPARE ; (\op) ; C / S 264 | 265 | * `IF{EQ|NEQ|LT|GT|LE|GE} bt bf` 266 | 267 | > IFCMP(\op) ; C / S => (\op) ; IF bt bf ; C / S 268 | 269 | * `IFCMP{EQ|NEQ|LT|GT|LE|GE} bt bf` 270 | 271 | > IFCMP(\op) ; C / S => COMPARE ; IF(\op) bt bf ; C / S 272 | 273 | 274 | IV - Data types 275 | --------------- 276 | 277 | * `bool`, `string`, `void`, `u?int{8|16|32|64}`, `float`: 278 | The core primitive types. 279 | 280 | * `list 'a`: 281 | A single, immutable, homogeneous linked list, whose elements are 282 | of type 'a, and that we note Nil for the empty list or 283 | (Cons head tail). 284 | 285 | * `pair 'a 'b`: 286 | A pair of values a and b of types 'a and 'b, that we write (Pair a b). 287 | 288 | * `option 'a`: 289 | Optional value that we note (None) or (Some v). 290 | 291 | * `or 'a 'b`: 292 | A union of two types, a value holding either a value a of type 'a 293 | or a value b of type 'b, that we write (Left a) or (Right b). 294 | 295 | * `ref 'a`: 296 | Classical imperative stores, that we note (Ref const). 297 | 298 | * `set 'a`, `map 'a 'b`: 299 | Imperative map and sets, optimized in the db. 300 | 301 | 302 | V - Operations 303 | -------------- 304 | 305 | ### Operations on booleans 306 | 307 | * `OR` 308 | 309 | :: bool : bool : 'S -> bool : 'S 310 | 311 | > OR ; C / x : y : S => C / (x | y) : S 312 | 313 | * `AND` 314 | 315 | :: bool : bool : 'S -> bool : 'S 316 | 317 | > AND ; C / x : y : S => C / (x & y) : S 318 | 319 | * `XOR` 320 | 321 | :: bool : bool : 'S -> bool : 'S 322 | 323 | > XOR ; C / x : y : S => C / (x ^ y) : S 324 | 325 | * `NOT` 326 | 327 | :: bool : 'S -> bool : 'S 328 | 329 | > NOT ; C / x : S => C / ~x : S 330 | 331 | ### Operations on integers 332 | 333 | Integers can be of size 1, 2, 4 or 8 bytes, signed or unsigned. 334 | Integer Operations are homogeneous, so that performing computations 335 | between values of different int types must be done via explicit casts. 336 | 337 | For specifying arithmetics, we consider that integers are all stored 338 | on 64 bits (the largest integer size) so that we can express the 339 | operations, in particular casts, using usual bitwise masks. In this 340 | context, the type indicator functions are defined as follows (which 341 | can be read both as a constraint on the bitpatttern and as a 342 | conversion operation). 343 | 344 | Uint64 (x) = Int64 (x) = x 345 | Uint32 (x) = x & 0x00000000FFFFFFFF 346 | Int32 (x) = x & 0x00000000FFFFFFFF 347 | | (x & 0x80000000 ? 0xFFFFFFFF00000000 : 0) 348 | Uint16 (x) = x & 0x000000000000FFFF 349 | Int16 (x) = x & 0x000000000000FFFF 350 | | (x & 0x8000 ? 0xFFFFFFFFFFFF0000 : 0) 351 | Uint8 (x) = x & 0x00000000000000FF 352 | Int8 (x) = x & 0x00000000000000FF 353 | | (x & 0x80 ? 0xFFFFFFFFFFFFFF00 : 0) 354 | 355 | We also use the function `bits (t)` that retrieve the meaningful number 356 | of bits for a given integer type (e.g. `bits (int8) = 8`). 357 | 358 | * `NEG` 359 | 360 | :: t : 'S -> t : 'S where t in int{8|16|32|64} 361 | 362 | > NEG ; C / t (x) : S => C / t (-x) : S 363 | 364 | With cycling semantics for overflows (min (t) = -min (t)). 365 | 366 | * `ABS` 367 | 368 | :: t : 'S -> t : 'S where t in int{8|16|32|64} 369 | 370 | > ABS ; C / t (x) : S => C / t (abs (x)) : S 371 | 372 | With cycling semantics for overflows (abs (min (t)) = min (t)). 373 | 374 | * `ADD` 375 | 376 | :: t : t : 'S -> t : 'S where t in u?int{8|16|32|64} 377 | 378 | > ADD ; C / t (x) : t (y) : S => C / t (x + y) : S 379 | 380 | With cycling semantics for overflows. 381 | 382 | * `SUB` 383 | 384 | :: t : t : 'S -> t : 'S where t in u?int{8|16|32|64} 385 | 386 | > SUB ; C / t (x) : t (y) : S => C / t (x + y) : S 387 | 388 | With cycling semantics for overflows. 389 | 390 | * `MUL` 391 | 392 | :: t : t : 'S -> t : 'S where t in u?int{8|16|32|64} 393 | 394 | > MUL ; C / t (x) : t (y) : S => C / t (x + y) : S 395 | 396 | Unckeched for overflows. 397 | 398 | * `DIV` 399 | 400 | :: t : t : 'S -> t : 'S where t in u?int{8|16|32|64} 401 | 402 | > DIV ; C / t (x) : t (0) : S => C / [FAIL] 403 | > DIV ; C / t (x) : t (y) : S => C / t (x / y) : S 404 | 405 | * `MOD` 406 | 407 | :: t : t : 'S -> t : 'S where t in u?int{8|16|32|64} 408 | 409 | > MOD ; C / t (x) : t (0) : S => C / [FAIL] 410 | > MOD ; C / t (x) : t (y) : S => C / t (x % y) : S 411 | 412 | * `CAST t_to` where `t_to in u?int{8|16|32|64}` 413 | 414 | :: t_from : 'S -> t_to : 'S where t_from in u?int{8|16|32|64} 415 | 416 | > CAST t_to ; C / t_from (x) : S => C / t_to (x) : S 417 | 418 | Alternative operators are defined that check for overflows. 419 | 420 | * `CHECKED_NEG` 421 | 422 | :: t : 'S -> t : 'S where t in int{8|16|32|64} 423 | 424 | > CHECKED_NEG ; C / t (x) : S => [FAIL] on overflow 425 | > CHECKED_NEG ; C / t (x) : S => C / t (-x) : S 426 | 427 | * `CHECKED_ABS` 428 | 429 | :: t : 'S -> t : 'S where t in int{8|16|32|64} 430 | 431 | > CHECKED_ABS ; C / t (x) : S => [FAIL] on overflow 432 | > CHECKED_ABS ; C / t (x) : S => C / t (abs (x)) : S 433 | 434 | * `CHECKED_ADD` 435 | 436 | :: t : t : 'S -> t : 'S where t in u?int{8|16|32|64} 437 | 438 | > CHECKED_ADD ; C / t (x) : t (y) : S => [FAIL] on overflow 439 | > CHECKED_ADD ; C / t (x) : t (y) : S => C / t (x + y) : S 440 | 441 | * `CHECKED_SUB` 442 | 443 | :: t : t : 'S -> t : 'S where t in u?int{8|16|32|64} 444 | 445 | > CHECKED_SUB ; C / t (x) : t (y) : S => [FAIL] on overflow 446 | > CHECKED_SUB ; C / t (x) : t (y) : S => C / t (x - y) : S 447 | 448 | * `CHECKED_MUL` 449 | 450 | :: t : t : 'S -> t : 'S where t in u?int{8|16|32|64} 451 | 452 | > CHECKED_MUL ; C / t (x) : t (y) : S => [FAIL] on overflow 453 | > CHECKED_MUL ; C / t (x) : t (y) : S => C / t (x * y) : S 454 | 455 | * `CHECKED_CAST t_to` where `t_to in u?int{8|16|32|64}` 456 | 457 | :: t_from : 'S -> t_to : 'S where t_from in u?int{8|16|32|64} 458 | 459 | > CHECKED_CAST t_to ; C / t_from (x) : S => C / t_to (x) : S 460 | iff t_from (x) = t_to (x) 461 | > CHECKED_CAST t_to ; C / t_from (x) : S => [FAIL] 462 | 463 | Bitwise logical operators are also available on unsigned integers. 464 | 465 | * `OR` 466 | 467 | :: t : t : 'S -> t : 'S where t in uint{8|16|32|64} 468 | 469 | > OR ; C / t (x) : t (y) : S => C / t (x | y) : S 470 | 471 | * `AND` 472 | 473 | :: t : t : 'S -> t : 'S where t in uint{8|16|32|64} 474 | 475 | > AND ; C / t (x) : t (y) : S => C / t (x & y) : S 476 | 477 | * `XOR` 478 | 479 | :: t : t : 'S -> t : 'S where t in uint{8|16|32|64} 480 | 481 | > XOR ; C / t (x) : t (y) : S => C / t (x ^ y) : S 482 | 483 | * `NOT` 484 | 485 | :: t : 'S -> t : 'S where t in uint{8|16|32|64} 486 | 487 | > NOT ; C / t (x) : S => C / t (~x) : S 488 | 489 | * `LSL` 490 | 491 | :: t : uint8 (s) : 'S -> t : 'S where t in uint{8|16|32|64} 492 | 493 | > LSL ; C / t (x) : uint8 (s) : S => C / t (x << s) : S 494 | iff s <= bits (t) 495 | > LSL ; C / t (x) : uint8 (s) : S => [FAIL] 496 | 497 | * `LSR` 498 | 499 | :: t : uint8 (s) : 'S -> t : 'S where t in uint{8|16|32|64} 500 | 501 | > LSR ; C / t (x) : uint8 (s) : S => C / t (x >>> s) : S 502 | iff s <= bits (t) 503 | > LSR ; C / t (x) : uint8 (s) : S => [FAIL] 504 | 505 | * `COMPARE`: 506 | Integer comparison (signed or unsigned according to the type) 507 | 508 | :: t : t : 'S -> int64 : 'S where t in uint{8|16|32|64} 509 | 510 | ### Operations on Floats 511 | 512 | The float type uses double precision IEEE754 semantics, including NaN 513 | and infinite values. 514 | 515 | * `ADD` 516 | 517 | :: float : float : 'S -> float : 'S 518 | 519 | > ADD ; C / x : y : S => C / (x + y) : S 520 | 521 | * `SUB` 522 | 523 | :: float : float : 'S -> float : 'S 524 | 525 | > SUB ; C / x : y : S => C / (x - y) : S 526 | 527 | * `MUL` 528 | 529 | :: float : float : 'S -> float : 'S 530 | 531 | > MUL ; C / x : y : S => C / (x * y) : S 532 | 533 | * `DIV` 534 | 535 | :: float : float : 'S -> float : 'S 536 | 537 | > DIV ; C / x : y : S => C / (x / y) : S 538 | 539 | * `MOD` 540 | 541 | :: float : float : 'S -> float : 'S 542 | 543 | > MOD ; C / x : y : S => C / (fmod (x, y)) : S 544 | 545 | * `ABS` 546 | 547 | :: float : 'S -> float : 'S 548 | 549 | > ABS ; C / x : S => C / (abs (x)) : S 550 | 551 | * `NEG` 552 | 553 | :: float : 'S -> float : 'S 554 | 555 | > NEG ; C / x : S => C / (-x) : S 556 | 557 | * `FLOOR` 558 | 559 | :: float : 'S -> float : 'S 560 | 561 | > FLOOR ; C / x : S => C / (floor (x)) : S 562 | 563 | * `CEIL` 564 | 565 | :: float : 'S -> float : 'S 566 | 567 | > CEIL ; C / x : S => C / (ceil (x)) : S 568 | 569 | * `INF` 570 | 571 | :: 'S -> float : 'S 572 | 573 | > INF ; C / S => C / +Inf : S 574 | 575 | * `NAN` 576 | 577 | :: 'S -> float : 'S 578 | 579 | > NAN ; C / S => C / NaN : S 580 | 581 | * `ISNAN` 582 | 583 | :: float : 'S -> bool : 'S 584 | 585 | > ISNAN ; C / NaN : S => C / true : S 586 | > ISNAN ; C / _ : S => C / false : S 587 | 588 | * `NANAN` 589 | 590 | :: float : 'S -> 'S 591 | 592 | > NANAN ; C / NaN : S => [FAIL] 593 | > NANAN ; C / _ : S => C / S 594 | 595 | * `CAST float`: 596 | Conversion from integers. 597 | 598 | :: t_from : 'S -> float : 'S where t_from in u?int{8|16|32|64} 599 | 600 | > CAST float ; C / x : S => C / float (x) : S 601 | 602 | * `CAST t_to` where `t_to in u?int{8|16|32|64}`: 603 | Conversion to integers. 604 | 605 | :: float : 'S -> t_to : 'S 606 | 607 | > CAST t_to ; C / NaN : S => C / t_to (0) : S 608 | > CAST t_to ; C / +/-Inf : S => C / t_to (0) : S 609 | > CAST t_to ; C / x : S => C / t_to (floor (x)) : S 610 | 611 | * `CHECKED_CAST float`: 612 | Conversion from integers with overflow checking. 613 | 614 | :: t_from : 'S -> float : 'S where t_from in u?int{8|16|32|64} 615 | 616 | > CHECKED_CAST float ; C / x : S => [FAIL] on overflow 617 | > CHECKED_CAST float ; C / x : S => C / float (x) : S 618 | 619 | * `CHECKED_CAST t_to` where `t_to in u?int{8|16|32|64}`: 620 | Conversion to integers with overflow checking. 621 | 622 | :: float : 'S -> t_to : 'S 623 | 624 | > CHECKED_CAST t_to ; C / x : S => [FAIL] on overflow or NaN 625 | > CHECKED_CAST t_to ; C / x : S => C / t_to (floor (x)) : S 626 | 627 | 628 | * `COMPARE`: 629 | IEEE754 comparison 630 | 631 | :: float : float : 'S -> int64 : 'S 632 | 633 | ### Operations on strings 634 | 635 | Strings are mostly used for naming things without having to rely on 636 | external ID databases. So what can be done is basically use string 637 | constants as is, concatenate them and use them as keys. 638 | 639 | * `CONCAT`: 640 | String concatenation. 641 | 642 | :: string : string : 'S -> string : 'S 643 | 644 | * `COMPARE`: 645 | Lexicographic comparison. 646 | 647 | :: string : string : 'S -> int64 : 'S 648 | 649 | ### Operations on timestamps 650 | 651 | Timestamp immediates can be obtained by the `NOW` operation, or 652 | retrieved from script parameters or globals. The only valid operations 653 | are the addition of a (positive) number of seconds and the comparison. 654 | 655 | * `ADD` 656 | Increment / decrement a timestamp of the given number of seconds. 657 | 658 | :: timestamp : float : 'S -> timestamp : 'S 659 | 660 | > ADD ; C / t : period : S => [FAIL] iff period < 0 661 | > ADD ; C / t : period : S => C / (t + period seconds) : S 662 | 663 | * `ADD` 664 | Increment / decrement a timestamp of the given number of seconds. 665 | 666 | :: timestamp : uint{8|16|32|64} : 'S -> timestamp : 'S 667 | 668 | > ADD ; C / t : seconds : S => [FAIL] on overflow 669 | > ADD ; C / t : seconds : S => C / (t + seconds) : S 670 | 671 | * `COMPARE`: 672 | Timestamp comparison. 673 | 674 | :: timestamp : timestamp : 'S -> int64 : 'S 675 | 676 | ### Operations on pairs 677 | 678 | * `PAIR`: 679 | Build a pair from the stack's top two elements. 680 | 681 | :: 'a : 'b : 'S -> pair 'a 'b : 'S 682 | 683 | > PAIR ; C / a : b : S => C / (Pair a b) : S 684 | 685 | * `P(A*AI)+R`: 686 | A syntactic sugar for building nested pairs in bulk. 687 | 688 | > PA{N}AI(\rest)R ; C / S => DIP (PA{n-1}AIR) ; P(\rest)R ; C / S 689 | > PAIR ; C / S => PAIR ; C / S 690 | > PR ; C / S => C / S 691 | 692 | * `CAR`: 693 | Access the left part of a pair. 694 | 695 | :: pair 'a _ : 'S -> 'a : 'S 696 | 697 | > Car ; C / (Pair a _) : S => C / a : S 698 | 699 | * `CDR`: 700 | Access the left part of a pair. 701 | 702 | :: pair _ 'b : 'S -> 'b : 'S 703 | 704 | > Car ; C / (Pair _ b) : S => C / b : S 705 | 706 | * `C[AD]+R`: 707 | A sugary syntax for accessing fields in nested pairs. 708 | 709 | > CA(\rest)R ; C / S => CAR ; C(\rest)R ; C / S 710 | > CD(\rest)R ; C / S => CDR ; C(\rest)R ; C / S 711 | > CR ; C / S => C / S 712 | 713 | ### Operations on refs 714 | 715 | * `REF`: 716 | Build a ref from its initial contents. 717 | 718 | :: 'a : 'S -> ref 'a : 'S 719 | 720 | > REF ; C / a : S / M => C / l : S / l = (Ref a), M 721 | 722 | * `DEREF`: 723 | Access the contents of a ref. 724 | 725 | :: ref 'a : 'S -> 'a : 'S 726 | 727 | > DEREF ; C / l : S / l = (Ref a), M => C / a : S / l = (Ref a), M 728 | 729 | * `SET` 730 | Update the contents of a ref. 731 | 732 | :: 'a : ref 'a : 'S -> 'S 733 | 734 | > SET ; C / v :: l : S / l = (Ref _), M => C / S / l = (Ref v), M 735 | 736 | * `INCR step`: 737 | Increments a counter. 738 | 739 | :: ref 'a : 'S -> 'S 740 | iff step :: 'a, operator ADD defined on 'a 741 | 742 | > INCR step ; C / l : S / M => DUP ; DEREF ; PUSH step ; ADD ; Set ; C / S / M 743 | 744 | * `DECR step`: 745 | Decrements a counter. 746 | 747 | :: ref 'a : 'S -> 'S 748 | iff step :: 'a, operator SUB defined on 'a 749 | 750 | > DECR step ; C / l : S / M => DUP ; DEREF ; PUSH step ; SUB ; Set ; C / S / M 751 | 752 | ### Operations on sets 753 | 754 | * `EMPTY_SET 'elt`: 755 | Build a new, empty imperative set for elements of a given type. 756 | 757 | :: 'S -> set 'elt : 'S 758 | 759 | The `'elt` type must be comparable (the `COMPARE` primitive must 760 | be defined over it). 761 | 762 | * `MEM`: 763 | Check for the presence of an element in a set. 764 | 765 | :: 'key : set 'elt : 'S -> bool : 'S 766 | 767 | * `UPDATE`: 768 | Inserts or removes an element in a set, replacing a previous value. 769 | 770 | :: 'elt : bool : set 'elt : 'S -> 'S 771 | 772 | * `ITER`: 773 | Apply an imperative function over all the elements of a set. 774 | 775 | :: lambda 'elt void : set 'elt : 'S -> 'S 776 | 777 | * `REDUCE`: 778 | Apply a function on a set passing the result of each 779 | application to the next one and return the last. 780 | 781 | :: lambda (pair 'elt * 'b) 'b : set 'elt : 'b : 'S -> 'b : 'S 782 | 783 | ### Operations on maps 784 | 785 | * `EMPTY_MAP 'key 'val`: 786 | Build a new, empty imperative map. 787 | 788 | The `'key` type must be comparable (the `COMPARE` primitive must be 789 | defined over it). 790 | 791 | :: 'S -> map 'key 'val : 'S 792 | 793 | * `GET`: 794 | Access an element in a map, returns an optional value to be 795 | checked with `IF_SOME`. 796 | 797 | :: 'key : map 'key 'val : 'S -> option 'val : 'S 798 | 799 | * `MEM`: 800 | Check for the presence of an element in a map. 801 | 802 | :: 'key : map 'key 'val : 'S -> bool : 'S 803 | 804 | * `UPDATE`: 805 | Assign or remove an element in a map. 806 | 807 | :: 'key : option 'val : map 'key 'val : 'S -> 'S 808 | 809 | * `ITER`: 810 | Apply an imperative function over all the bindings of a map. 811 | 812 | :: lambda (pair 'key 'val) void : map 'key 'val : 'S -> 'S 813 | 814 | * `MAP`: 815 | Apply a function on a map and return the map of results under 816 | the same bindings. 817 | 818 | :: lambda (pair 'key 'val) 'b : map 'key 'val : 'S -> map 'key 'b : 'S 819 | 820 | * `REDUCE`: 821 | Apply a function on a map passing the result of each 822 | application to the next one and return the last. 823 | 824 | :: lambda (pair (pair 'key 'val) 'b) 'b : map 'key 'val : 'b : 'S -> 'b : 'S 825 | 826 | ### Operations on optional values 827 | 828 | * `SOME`: 829 | Pack a present optional value. 830 | 831 | :: 'a : 'S -> 'a? : 'S 832 | 833 | > SOME ; C / v :: S => C / (Some v) :: S 834 | 835 | * `NONE 'a`: 836 | The absent optional value. 837 | 838 | :: 'S -> 'a? : 'S 839 | 840 | > NONE ; C / v :: S => C / None :: S 841 | 842 | * `IF_SOME bt bf`: 843 | Inspect an optional value. 844 | 845 | :: 'a? : 'S -> 'b : 'S 846 | iff bt :: [ 'a : 'S -> 'b : 'S] 847 | bf :: [ 'S -> 'b : 'S] 848 | 849 | > IF_SOME ; C / (Some a) : S => bt ; C / a : S 850 | > IF_SOME ; C / (None) : S => bf ; C / S 851 | 852 | ### Operations on unions 853 | 854 | * `LEFT 'b`: 855 | Pack a value in a union (left case). 856 | 857 | :: 'a : 'S -> or 'a 'b : 'S 858 | 859 | > LEFT ; C / v :: S => C / (Left v) :: S 860 | 861 | * `RIGHT 'a`: 862 | Pack a value in a union (right case). 863 | 864 | :: 'b : 'S -> or 'a 'b : 'S 865 | 866 | > RIGHT ; C / v :: S => C / (Right v) :: S 867 | 868 | * `IF_LEFT bt bf`: 869 | Inspect an optional value. 870 | 871 | :: or 'a 'b : 'S -> 'c : 'S 872 | iff bt :: [ 'a : 'S -> 'c : 'S] 873 | bf :: [ 'b : 'S -> 'c : 'S] 874 | 875 | > IF_LEFT ; C / (Left a) : S => bt ; C / a : S 876 | > IF_LEFT ; C / (Right b) : S => bf ; C / b : S 877 | 878 | ### Operations on lists 879 | 880 | * `CONS`: 881 | Prepend an element to a list. 882 | 883 | :: 'a : list 'a : 'S -> list 'a : 'S 884 | 885 | > CONS ; C / a : l : S => C / (Cons a l) : S 886 | 887 | * `NIL 'a`: 888 | The empty list. 889 | 890 | :: 'S -> list 'a : 'S 891 | 892 | > NIL ; C / S => C / Nil : S 893 | 894 | * `IF_CONS bt bf`: 895 | Inspect an optional value. 896 | 897 | :: list 'a : 'S -> 'b : 'S 898 | iff bt :: [ 'a : list 'a : 'S -> 'b : 'S] 899 | bf :: [ 'S -> 'b : 'S] 900 | 901 | > IF_CONS ; C / (Cons a rest) : S => bt ; C / a : rest : S 902 | > IF_CONS ; C / Nil : S => bf ; C / S 903 | 904 | * `ITER`: 905 | Apply a function on a list from left to right. 906 | 907 | :: lambda 'a void : list 'a : 'S -> 'S 908 | 909 | * `MAP`: 910 | Apply a function on a list from left to right and 911 | return the list of results in the same order. 912 | 913 | :: lambda 'a 'b : list 'a : 'S -> list 'b : 'S 914 | 915 | * `REDUCE`: 916 | Apply a function on a list from left to right 917 | passing the result of each application to the next one 918 | and return the last. 919 | 920 | :: lambda (pair 'a 'b) 'b : list 'a : 'b : 'S -> 'b : 'S 921 | 922 | 923 | VI - Domain specific data types 924 | ------------------------------- 925 | 926 | * `tez`: 927 | A special numeric type for manipulating currency. 928 | 929 | * `contract 'param 'result`: 930 | A contract, with the type of its code. 931 | 932 | * `key`: 933 | A public cryptography key. 934 | 935 | * `signature`: 936 | A cryptographic signature. 937 | 938 | 939 | VII - Domain specific operations 940 | -------------------------------- 941 | 942 | ### Operations on Tez 943 | 944 | Operations on tez are limited to prevent overflow and mixing them with 945 | other numerical types by mistake. They are also mandatorily checked 946 | for under/overflows. 947 | 948 | * `ADD`: 949 | 950 | :: tez : tez : 'S -> tez : 'S 951 | 952 | > Add ; C / x : y : S => [FAIL] on overflow 953 | > Add ; C / x : y : S => C / (x + y) : S 954 | 955 | * `SUB`: 956 | 957 | :: tez : tez : 'S -> tez : 'S 958 | 959 | > Sub ; C / x : y : S => [FAIL] iff x < y 960 | > Sub ; C / x : y : S => C / (x - y) : S 961 | 962 | * `MUL` 963 | 964 | :: tez : u?int{8|16|32|64} : 'S -> tez : 'S 965 | 966 | > Mul ; C / x : y : S => [FAIL] on overflow 967 | > Mul ; C / x : y : S => C / (x * y) : S 968 | 969 | * `COMPARE`: 970 | 971 | :: tez : tez : 'S -> int64 : 'S 972 | 973 | ### Operations on contracts 974 | 975 | * `MANAGER`: 976 | Access the manager of a contract. 977 | 978 | :: contract 'p 'r : 'S -> key : 'S 979 | 980 | * `CREATE_CONTRACT`: 981 | Forge a new contract. 982 | 983 | 984 | :: key : key? : bool : bool : tez : lambda (pair (pair tez 'p) 'g) (pair 'r 'g) : 'g : 'S 985 | -> contract 'p 'r : 'S 986 | 987 | As with non code-emitted originations the 988 | contract code takes as argument the transfered amount plus an 989 | ad-hoc argument and returns an ad-hoc value. The code also takes 990 | the global data and returns it to be stored and retrieved on the 991 | next transaction. These data are initialized by another 992 | parameter. The calling convention for the code is as follows: 993 | (Pair (Pair amount arg) globals)) -> (Pair ret globals), as 994 | extrapolable from the instruction type. The first parameters are 995 | the manager, optional delegate, then spendable and delegatable 996 | flags and finally the initial amount taken from the currently 997 | executed contract. The contract is returned as a first class 998 | value to be called immediately or stored. 999 | 1000 | * `CREATE_ACCOUNT`: 1001 | Forge an account (a contract without code). 1002 | 1003 | :: key : key? : bool : tez : 'S -> contract void void : 'S 1004 | 1005 | Take as argument the manager, optional delegate, the delegatable 1006 | flag and finally the initial amount taken from the currently 1007 | executed contract. 1008 | 1009 | * `TRANSFER_FUNDS`: 1010 | Forge and evaluate a transaction. 1011 | 1012 | :: 'p : tez : contract 'p 'r : 'g : [] -> 'r : 'g : [] 1013 | 1014 | The parameter and return value must be consistent with the ones 1015 | expected by the contract, void for an account. To preserve the 1016 | global consistency of the system, the current contract's storage 1017 | must be updated before passing the control to another script. For 1018 | this, the script must put the partially updated storage on the 1019 | stack ('g is the type of the contract's storage). If a recursive 1020 | call to the current contract happened, the updated storage is put 1021 | on the stack next to the return value. Nothing else can remain 1022 | on the stack during a nested call. If some local values have to 1023 | be kept for after the nested call, they have to be stored 1024 | explicitly in a transient part of the storage. A trivial example 1025 | of that is to reserve a boolean in the storage, initialized to 1026 | false, reset to false at the end of each contract execution, and 1027 | set to true during a nested call. This thus gives an easy way 1028 | for a contract to prevent recursive call (the contract just fails 1029 | if the boolean is true). 1030 | 1031 | * `BALANCE`: 1032 | Push the current amount of tez of the current contract. 1033 | 1034 | :: 'S -> tez :: 'S 1035 | 1036 | * `SOURCE 'p 'r`: 1037 | Push the source contract of the current transaction. 1038 | 1039 | :: 'S -> contract 'p 'r :: 'S 1040 | 1041 | * `SELF`: 1042 | Push the current contract. 1043 | 1044 | :: 'S -> contract 'p 'r :: 'S 1045 | where contract 'p 'r is the type of the current contract 1046 | 1047 | * `AMOUNT`: 1048 | Push the amount of the current transaction. 1049 | 1050 | :: 'S -> tez :: 'S 1051 | 1052 | ### Special operations 1053 | 1054 | * `STEPS_TO_QUOTA`: 1055 | Push the remaining steps before the contract execution must terminate. 1056 | 1057 | :: 'S -> uint32 :: 'S 1058 | 1059 | * `NOW`: 1060 | Push the timestamp of the block whose validation triggered this 1061 | execution (does not change during the execution of the contract). 1062 | 1063 | :: 'S -> timestamp :: 'S 1064 | 1065 | * `FAIL`: 1066 | Explicitly abort the current transaction (and all of its parents). 1067 | 1068 | :: _ -> _ 1069 | 1070 | > FAIL ; _ / _ => [FAIL] 1071 | 1072 | ### Cryptographic primitives 1073 | 1074 | * `H`: 1075 | Compute a cryptographic hash of the value contents using the 1076 | Sha256 cryptographic algorithm. 1077 | 1078 | :: 'a : 'S -> signature : 'S 1079 | 1080 | * `CHECK_SIGNATURE` 1081 | Check that a sequence of bytes has been signed with a given key. 1082 | 1083 | :: key : pair signature string : 'S -> bool : 'S 1084 | 1085 | * `COMPARE` 1086 | 1087 | :: key : key : 'S -> int64 : 'S 1088 | 1089 | 1090 | VIII - Concrete syntax 1091 | ---------------------- 1092 | 1093 | The structure of the concrete language is extremely simple. An 1094 | expression in the language can only be one of the three following 1095 | constructs. 1096 | 1097 | 1. A constant. 1098 | 2. The application of a primitive to a sequence of expressions. 1099 | 3. A sequence of expressions. 1100 | 1101 | As in Python or Haskell, the concrete syntax of the language is 1102 | indentation sensitive. The elements of a syntactical block, such as 1103 | all the elements of a sequence, or all the parameters of a primitive, 1104 | must be written with the exact same left margin in the program source 1105 | code. This is unlike in C-like languages, where blocks are delimited 1106 | with braces and the margin is ignored by the compiled. The exact 1107 | parsing policy is described just after. 1108 | 1109 | ### Constants 1110 | 1111 | There are three kinds of constants: 1112 | 1113 | 1. Integers in decimal (no prefix), hexadecimal (0x prefix), octal 1114 | (0o prefix) or binary (0b prefix). 1115 | 2. Floating point IEEE754 doubles in libc-style notation. 1116 | 3. Strings with usual escapes `\n`, `\t`, `\b`, `\r`, `\\`, `\"`. 1117 | Strings are encoding agnostic sequences of bytes. Non printable 1118 | characters can be escaped by 3 digits decimal codes `\ddd` or 1119 | 2 digit hexadecimal codes `\xHH`. 1120 | 1121 | ### Primitive applications 1122 | 1123 | The simplest form requires to break the line after the primitive name 1124 | and after every argument. Argument must be indented by at least one 1125 | more space than the primitive, and all arguments must sit on the exact 1126 | same column. 1127 | 1128 | PRIM 1129 | arg1 1130 | arg2 1131 | ... 1132 | 1133 | If an argument of a primitive application is a primitive application 1134 | itself, its arguments must be pushed even further on the right, to 1135 | lift any ambiguity, as in the following example. 1136 | 1137 | PRIM1 1138 | PRIM2 1139 | arg1_prim2 1140 | arg2_prim2 1141 | arg2_prim1 1142 | 1143 | It is possible to put successive arguments on a single line using 1144 | a semicolon as a separator: 1145 | 1146 | PRIM 1147 | arg1; arg2 1148 | arg3; arg4 1149 | 1150 | It is also possible to add arguments on the same line as the primitive 1151 | as a lighter way to write simple expressions. An other representation 1152 | of the first example is: 1153 | 1154 | PRIM arg1 arg2 ... 1155 | 1156 | It is possible to mix both notations as in: 1157 | 1158 | PRIM arg1 arg2 1159 | arg3 1160 | arg4 1161 | 1162 | Or even: 1163 | 1164 | PRIM arg1 arg2 1165 | arg3; arg4 1166 | 1167 | Both equivalent to: 1168 | 1169 | PRIM 1170 | arg1 1171 | arg2 1172 | arg3 1173 | arg4 1174 | 1175 | Trayling semicolons are ignored: 1176 | 1177 | PRIM 1178 | arg1; 1179 | arg2 1180 | 1181 | Calling a primitive with a compound argument on a single line is 1182 | allowed by wrapping with parentheses. Another notation for the second 1183 | example is: 1184 | 1185 | PRIM1 (PRIM2 arg1_prim2 arg2_prim2) arg2_prim1 1186 | 1187 | ### Sequences 1188 | 1189 | Successive instructions can be grouped as a single one by grouping 1190 | them inside braces, separated by semicolons. To prevent errors, 1191 | control flow primitives that take instructions as parameters require 1192 | sequences in the concrete syntax. 1193 | 1194 | IF { instr1_true ; instr2_true ; ... } { instr1_false ; instr2_false ; ... } 1195 | 1196 | IF 1197 | { instr1_true ; instr2_true ; ... } 1198 | { instr1_false ; instr2_false ; ... } 1199 | 1200 | A sequence block can be split on several lines. In this situation, the 1201 | whole block, including the closing brace, must be indented with 1202 | respect to the first instruction. 1203 | 1204 | LAMBDA t_arg t_ret 1205 | { instr1 ; instr2 1206 | instr3 ; instr4 } 1207 | 1208 | ### Lexical conventions 1209 | 1210 | Instructions are represented by uppercase identifiers, type 1211 | constructor are lowercase identifiers and constant constructors are 1212 | Capitalised. 1213 | 1214 | * Types, in lowercase, in prefixed notation as in this specification: 1215 | 1216 | string 1217 | 1218 | pair string (pair int8 tez) 1219 | 1220 | lambda int8 int16 1221 | 1222 | Of course, types can be split over multiple lines using the 1223 | common indented notation. 1224 | 1225 | map 1226 | string 1227 | uint32 1228 | 1229 | * Constants are built using constructors (starting with a capital) 1230 | followed by the actual value. 1231 | 1232 | Int8 1 1233 | 1234 | Float 3.5e12 1235 | 1236 | Compound constants such as lists, in order not to repeat the same 1237 | constant constructor for each element, take the type(s) of inner 1238 | values as first argument(s), and then the values without their 1239 | constructors. 1240 | 1241 | List int8 1 2 3 4 5 1242 | 1243 | Pair int8 int16 1 2 1244 | 1245 | For constructors whose type cannot be completely deduced fron a 1246 | single value, the free type variables must be specified. For this, 1247 | some constant constructors take extra types arguments as follows. 1248 | 1249 | List int8 1250 | 1251 | None tez 1252 | 1253 | Left (Int8 3) int16 1254 | 1255 | Right int16 (Int8 3) 1256 | 1257 | When the type is already completely specified, by a parent 1258 | constructor or as in the instruction PUSH, these annotations must 1259 | be omitted. 1260 | 1261 | Pair int8 (list int16) 1 (List 2 3) 1262 | 1263 | Pair (option (pair void int8)) void 1264 | None 1265 | Void 1266 | 1267 | Pair (or int8 string) (or int8 string) 1268 | Left 3 1269 | Right "text" 1270 | 1271 | * Instructions, in uppercase: 1272 | 1273 | ADD 1274 | 1275 | ### Comments 1276 | 1277 | A hash sign (`#`) anywhere outside of a string literal will make the 1278 | rest of the line (and itself) completely ignored, as in the following 1279 | example. 1280 | 1281 | PUSH (Int8 1) # pushes 1 1282 | PUSH (Int8 2) # pushes 2 1283 | ADD # computes 2 + 1 1284 | 1285 | IX - Examples 1286 | ------------- 1287 | 1288 | Contracts in the system are stored as a piece of code and a global 1289 | data storage. The type of the global data of the storage is fixed for 1290 | each contract at origination time. This is ensured statically by 1291 | checking on origination that the code preserves the type of the global 1292 | data. For this, the code of the contract is checked to be of the 1293 | following type lambda (pair (pair tez 'arg) 'global) -> (pair 'ret 1294 | 'global) where 'global is the type of the original global store given 1295 | on origination. The contract also takes a parameter and an amount, and 1296 | returns a value, hence the complete calling convention above. The 1297 | global values can be updated either by rewriting the object, or by 1298 | putting mutable values in it and performing side effects on them, 1299 | allowing both imperative and functional style. 1300 | 1301 | ### Empty contract 1302 | 1303 | Because of the calling convention, the empty sequence is not a valid 1304 | contract of type `(contract void void)`. The code for building a 1305 | contract of such a type must take a `void` argument, an amount in `tez`, 1306 | and transform a void global storage, and must thus be of type `(lambda 1307 | (pair (pair tez void) void) (pair void void))`. 1308 | 1309 | Such a minimal contract is thus `{ CDR ; VOID ; PAIR }`. 1310 | 1311 | ### Reservoir contract 1312 | 1313 | We want to create a contract that stores tez until a timestamp `T` or a 1314 | maximum amount `N` is reached. Whenever `N` is reached before `T`, all funds 1315 | are reversed to an account `B` (and the contract is automatically 1316 | deleted). Any call to the contract's code performed after `T` will 1317 | otherwise transfer the funds to another account `A`. 1318 | 1319 | We want to build this contract in a reusable manner, so we do not 1320 | hard-code the parameters. Instead, we assume that the global data of 1321 | the contract are `(Pair (Pair T N) (Pair A B))`. 1322 | 1323 | Hence, the global data of the contract has the following type 1324 | 1325 | 'g = 1326 | pair 1327 | pair timestamp tez 1328 | pair (contract void void) (contract void void) 1329 | 1330 | Following the contract calling convention, the code is a lambda of type 1331 | 1332 | lambda 1333 | pair (pair tez void) 'g 1334 | pair void 'g 1335 | 1336 | writen as 1337 | 1338 | lambda 1339 | pair (pair tez void) 1340 | pair 1341 | pair timestamp tez 1342 | pair (contract void void) (contract void void) 1343 | pair void 1344 | pair 1345 | pair timestamp tez 1346 | pair (contract void void) (contract void void) 1347 | 1348 | its code is 1349 | 1350 | DUP ; CDAAR # T 1351 | NOW 1352 | COMPARE ; LE 1353 | IF { DUP ; CDADR # N 1354 | BALANCE 1355 | COMPARE ; LE 1356 | IF { } # nothing to do 1357 | { DUP ; CDDDR # B 1358 | BALANCE ; PUSH Void ; TRANSFER_FUNDS ; DROP } } 1359 | { DUP ; CDDAR ; # A 1360 | BALANCE ; 1361 | PUSH Void ; TRANSFER_FUNDS ; DROP } 1362 | CDR ; PUSH Void ; PAIR 1363 | 1364 | ### Reservoir contract (variant with broker and status) 1365 | 1366 | We basically want the same contract as the previous one, but instead 1367 | of destroying it, we want to keep it alive, storing a flag `S` so that 1368 | we can afterwards if the funds have been transfered to `A` or `B`. We also 1369 | want the broker `A` to get some fee `P` in any case. 1370 | 1371 | We thus add variables `P` and `S` to the global data of the contract, 1372 | which becomes `(Pair (S, Pair (T, Pair (Pair P N) (Pair A B))))`. `P` 1373 | is the fee for broker `A`, `S` is the state, as a string `"open"`, 1374 | `"timeout"` or `"success"`. 1375 | 1376 | At the beginning of the transaction: 1377 | 1378 | S is accessible via a CDAR 1379 | T via a CDDAR 1380 | P via a CDDDAAR 1381 | N via a CDDDADR 1382 | A via a CDDDDAR 1383 | B via a CDDDDDR 1384 | 1385 | For the contract to stay alive, we test that all least `(Tez 1_00)` is 1386 | still available after each transaction. This value is given as an 1387 | example and must be updated according to the actual Tezos minmal 1388 | value for contract balance. 1389 | 1390 | DUP ; CDAR # S 1391 | PUSH (String "open") ; 1392 | COMPARE ; NEQ ; 1393 | IF { FAIL ; CDR } # on "success", "timeout" or a bad init value 1394 | { DUP ; CDDAR ; # T 1395 | NOW ; 1396 | COMPARE ; LT ; 1397 | IF { # Before timeout 1398 | # We compute ((1 + P) + N) tez for keeping the contract alive 1399 | PUSH (Tez 1_00) ; 1400 | DIP { DUP ; CDDDAAR } ; ADD ; # P 1401 | DIP { DUP ; CDDDADR } ; ADD ; # N 1402 | # We compare to the cumulated amount 1403 | BALANCE ; 1404 | COMPARE; LT ; 1405 | IF { # Not enough cash, we accept the transaction 1406 | # and leave the global 1407 | CDR } 1408 | { # We transfer the fee to the broker 1409 | DUP ; CDDDAAR ; # P 1410 | DIP { DUP ; CDDDDAR } # A 1411 | PUSH Void ; TRANSFER_FUNDS ; DROP ; 1412 | # We transfer the rest to the destination 1413 | DUP ; CDDDADR ; # N 1414 | DIP { DUP ; CDDDDDR } # B 1415 | PUSH Void ; TRANSFER_FUNDS ; DROP ; 1416 | # We update the global 1417 | CDR ; CDR ; PUSH (String "success") ; PAIR } } 1418 | { # After timeout 1419 | # We try to transfer P tez to A 1420 | PUSH (Tez 1_00) ; BALANCE ; SUB ; # available 1421 | DIP { DUP ; CDDDAAR } ;# P 1422 | COMPARE ; LT ; # available < P 1423 | IF { PUSH (Tez 1_00) ; BALANCE ; SUB ; # available 1424 | DIP { DUP ; CDDDDAR } # A 1425 | PUSH Void ; TRANSFER_FUNDS ; DROP } 1426 | { DUP ; CDDDAAR ; # P 1427 | DIP { DUP ; CDDDDAR } # A 1428 | PUSH Void ; TRANSFER_FUNDS ; DROP } 1429 | # We transfer the rest to B 1430 | PUSH (Tez 1_00) ; BALANCE ; SUB ; # available 1431 | DIP { DUP ; CDDDDDR } # B 1432 | PUSH Void ; TRANSFER_FUNDS ; DROP ; 1433 | # We update the global 1434 | CDR ; CDR ; PUSH (String "timeout") ; PAIR } } 1435 | # return Void 1436 | PUSH Void ; PAIR 1437 | 1438 | ### Forward contract 1439 | 1440 | We want to write a forward contract on dried peas. The contract takes 1441 | as global data the tons of peas `Q`, the expected delivery date `T`, the 1442 | contract agreement date `Z`, a strike `K`, a collateral `C` per ton of dried 1443 | peas, and the accounts of the buyer `B`, the seller `S` and the warehouse 1444 | `W`. 1445 | 1446 | These parameters as grouped in the global storage as follows: 1447 | 1448 | Pair 1449 | (pair uint32 (pair timestamp timestamp)) 1450 | pair 1451 | pair tez tez 1452 | pair (pair account account) account 1453 | Pair (Pair Q (Pair T Z)) 1454 | Pair (Pair K C) (Pair (Pair B S) W) 1455 | 1456 | The 24 hours after timestamp `Z` are for the buyer and seller to store 1457 | their collateral `(Q * C)`. For this, the contract takes a string as 1458 | parameter, matching `"buyer"` or `"seller"` indicating the party for which 1459 | the funds are transfered. At the end of this day, each of them can 1460 | send a transaction to send its funds back. For this, we need to store 1461 | who already paid and how much, as a `(pair tez tez)` where the left 1462 | component is the buyer and the right one the seller. 1463 | 1464 | After the first day, nothing cam happen until `T`. 1465 | 1466 | During the 24 hours after `T`, the buyer must pay `(Q * K)` to the 1467 | contract, minus the amount already sent. 1468 | 1469 | After this day, if the buyer didn't pay enough then any transaction 1470 | will send all the funds to the seller. 1471 | 1472 | Otherwise, the seller must deliver at least `Q` tons of dried peas to 1473 | the warehouse, in the next 24 hours. When the amount is equal to or 1474 | exceeds `Q`, all the funds are transfered to the seller and the contract 1475 | is destroyed. For storing the quantity of peas already delivered, we 1476 | add a counter of type `uint32` in the global storage. For knowing this 1477 | quantity, we accept messages from W with a partial amount of delivered 1478 | peas as argument. 1479 | 1480 | After this day, any transaction will send all the funds to the buyer 1481 | (not enough peas have been delivered in time). 1482 | 1483 | Hence, the global storage is a pair, with the counters on the left, 1484 | and the constant parameters on the right, initially as follows. 1485 | 1486 | Pair 1487 | pair unit32 (pair tez tez) 1488 | pair 1489 | pair uint32 (pair timestamp timestamp) 1490 | pair 1491 | pair tez tez 1492 | pair (pair account account) account 1493 | Pair 0 (Pair 0_00 0_00) 1494 | Pair 1495 | Pair (Pair Q (Pair T Z)) 1496 | Pair (Pair K C) (Pair (Pair B S) W) 1497 | 1498 | The parameter of the transaction will be either a transfer from the 1499 | buyer or the seller or a delivery notification from the warehouse of 1500 | type `(or string uint32)`. 1501 | 1502 | At the beginning of the transaction: 1503 | 1504 | Q is accessible via a CDDAAR 1505 | T via a CDDADAR 1506 | Z via a CDDADDR 1507 | K via a CDDDAAR 1508 | C via a CDDDADR 1509 | B via a CDDDDAAR 1510 | S via a CDDDDADR 1511 | W via a CDDDDDR 1512 | the delivery counter via a CDAAR 1513 | the amount versed by the buyer via a CDADAR 1514 | the amount versed by the seller via a CDADDR 1515 | the argument via a CADR 1516 | 1517 | The contract returns a void value, and we assume that it is created 1518 | with the minimum amount, set to `(Tez 1_00)`. 1519 | 1520 | The code of the contract is thus as follows. 1521 | 1522 | DUP ; CDDADDR ; # Z 1523 | PUSH (Uint64 86400) ; SWAP ; ADD ; # one day in second 1524 | NOW ; COMPARE ; LT ; 1525 | IF { # Before Z + 24 1526 | DUP ; CADR ; # we must receive (Left "buyer") or (Left "seller") 1527 | IF_LEFT 1528 | { DUP ; PUSH (String "buyer") ; COMPARE ; EQ ; 1529 | IF { DROP ; 1530 | DUP ; CDADAR ; # amount already versed by the buyer 1531 | DIP { DUP ; CAAR } ; ADD ; # transaction 1532 | # then we rebuild the globals 1533 | DIP { DUP ; CDADDR } ; PAIR ; # seller amount 1534 | PUSH (Uint32 0) ; PAIR ; # delivery counter at 0 1535 | DIP { CDDR } ; PAIR ; # parameters 1536 | # and return Void 1537 | PUSH Void ; PAIR } 1538 | { PUSH (String "seller") ; COMPARE ; EQ ; 1539 | IF { DUP ; CDADDR ; # amount already versed by the seller 1540 | DIP { DUP ; CAAR } ; ADD ; # transaction 1541 | # then we rebuild the globals 1542 | DIP { DUP ; CDADAR } ; SWAP ; PAIR ; # buyer amount 1543 | PUSH (Uint32 0) ; PAIR ; # delivery counter at 0 1544 | DIP { CDDR } ; PAIR ; # parameters 1545 | # and return Void 1546 | PUSH Void ; PAIR } 1547 | { FAIL ; CDR ; PUSH Void ; PAIR }}} # (Left _) 1548 | { FAIL ; DROP ; CDR ; PUSH Void ; PAIR }} # (Right _) 1549 | { # After Z + 24 1550 | # test if the required amount is reached 1551 | DUP ; CDDAAR ; # Q 1552 | DIP { DUP ; CDDDADR } ; MUL ; # C 1553 | PUSH (Uint8 2) ; MUL ; 1554 | PUSH (Tez 1_00) ; ADD ; 1555 | BALANCE ; COMPARE ; LT ; # balance < 2 * (Q * C) + 1 1556 | IF { # refund the parties 1557 | DUP ; CDADAR ; # amount versed by the buyer 1558 | DIP { DUP ; CDDDDAAR } # B 1559 | PUSH Void ; TRANSFER_FUNDS ; DROP 1560 | DUP ; CDADDR ; # amount versed by the seller 1561 | DIP { DUP ; CDDDDADR } # S 1562 | PUSH Void ; TRANSFER_FUNDS ; DROP 1563 | BALANCE ; # bonus to the warehouse to destroy the account 1564 | DIP { DUP ; CDDDDDR } # W 1565 | PUSH Void ; TRANSFER_FUNDS ; DROP 1566 | # return void, don't change the global 1567 | # since the contract will be destroyed 1568 | CDR ; PUSH Void ; PAIR } 1569 | { # otherwise continue 1570 | DUP ; CDDADAR # T 1571 | NOW ; COMPARE ; LT 1572 | IF { FAIL ; CDR ; PUSH Void ; PAIR } # Between Z + 24 and T 1573 | { # after T 1574 | DUP ; CDDADAR # T 1575 | PUSH (Uint64 86400) ; ADD # one day in second 1576 | NOW ; COMPARE ; LT 1577 | IF { # Between T and T + 24 1578 | # we only accept transactions from the buyer 1579 | DUP ; CADR ; # we must receive (Left "buyer") 1580 | IF_LEFT 1581 | { PUSH (String "buyer") ; COMPARE ; EQ ; 1582 | IF { DUP ; CDADAR ; # amount already versed by the buyer 1583 | DIP { DUP ; CAAR } ; ADD ; # transaction 1584 | # The amount must not exceed Q * K 1585 | DUP ; 1586 | DIIP { DUP ; CDDAAR ; # Q 1587 | DIP { DUP ; CDDDAAR } ; MUL ; } ; # K 1588 | DIP { COMPARE ; GT ; # new amount > Q * K 1589 | IF { FAIL } { } } ; # abort or continue 1590 | # then we rebuild the globals 1591 | DIP { DUP ; CDADDR } ; PAIR ; # seller amount 1592 | PUSH (Uint32 0) ; PAIR ; # delivery counter at 0 1593 | DIP { CDDR } ; PAIR ; # parameters 1594 | # and return Void 1595 | PUSH Void ; PAIR } 1596 | { FAIL ; CDR ; PUSH Void ; PAIR }} # (Left _) 1597 | { FAIL ; DROP ; CDR ; PUSH Void ; PAIR }} # (Right _) 1598 | { # After T + 24 1599 | # test if the required payment is reached 1600 | DUP ; CDDAAR ; # Q 1601 | DIP { DUP ; CDDDAAR } ; MUL ; # K 1602 | DIP { DUP ; CDADAR } ; # amount already versed by the buyer 1603 | COMPARE ; NEQ ; 1604 | IF { # not reached, pay the seller and destroy the contract 1605 | BALANCE ; 1606 | DIP { DUP ; CDDDDADR } # S 1607 | PUSH Void ; TRANSFER_FUNDS ; DROP ; 1608 | # and return Void 1609 | CDR ; PUSH Void ; PAIR } 1610 | { # otherwise continue 1611 | DUP ; CDDADAR # T 1612 | PUSH (Uint64 86400) ; ADD ; 1613 | PUSH (Uint64 86400) ; ADD ; # two days in second 1614 | NOW ; COMPARE ; LT 1615 | IF { # Between T + 24 and T + 48 1616 | # We accept only delivery notifications, from W 1617 | DUP ; CDDDDDR ; MANAGER ; # W 1618 | SOURCE void void ; MANAGER ; 1619 | COMPARE ; NEQ ; 1620 | IF { FAIL } {} # fail if not the warehouse 1621 | DUP ; CADR ; # we must receive (Right amount) 1622 | IF_LEFT 1623 | { FAIL ; DROP ; CDR ; PUSH Void ; PAIR } # (Left _) 1624 | { # We increment the counter 1625 | DIP { DUP ; CDAAR } ; ADD ; 1626 | # And rebuild the globals in advance 1627 | DIP { DUP ; CDADR } ; PAIR ; 1628 | DIP CDDR ; PAIR ; 1629 | PUSH Void ; PAIR ; 1630 | # We test if enough have been delivered 1631 | DUP ; CDAAR ; 1632 | DIP { DUP ; CDDAAR } ; 1633 | COMPARE ; LT ; # counter < Q 1634 | IF { } # wait for more 1635 | { # Transfer all the money to the seller 1636 | BALANCE ; # and destroy the contract 1637 | DIP { DUP ; CDDDDADR } # S 1638 | PUSH Void ; TRANSFER_FUNDS ; DROP }}} 1639 | { # after T + 48, transfer everything to the buyer 1640 | BALANCE ; # and destroy the contract 1641 | DIP { DUP ; CDDDDAAR } # B 1642 | PUSH Void ; TRANSFER_FUNDS ; DROP ; 1643 | # and return void 1644 | CDR ; PUSH Void ; PAIR }}}}}} 1645 | 1646 | X - Full grammar 1647 | ---------------- 1648 | 1649 | ::= 1650 | | Int8 1651 | | Int16 1652 | | Int32 1653 | | Int64 1654 | | Uint8 1655 | | Uint16 1656 | | Uint32 1657 | | Uint64 1658 | | Void 1659 | | True 1660 | | False 1661 | | 1662 | | 1663 | | Timestamp 1664 | | Signature 1665 | | Tez 1666 | | Key 1667 | | Left 1668 | | Right 1669 | | Or 1670 | | Ref 1671 | | Ref 1672 | | Some 1673 | | Some 1674 | | None 1675 | | Option 1676 | | Pair 1677 | | Pair 1678 | | List ... 1679 | | Set ... 1680 | | Map (Item ) ... 1681 | | Contract 1682 | | Lambda { ... } 1683 | ::= 1684 | | 1685 | | 1686 | | 1687 | | 1688 | | 1689 | | 1690 | | 1691 | | 1692 | | Void 1693 | | True 1694 | | False 1695 | | Pair 1696 | | Left 1697 | | Right 1698 | | Ref 1699 | | Some 1700 | | None 1701 | | List ... 1702 | | Set ... 1703 | | Map (Item ) ... 1704 | ::= 1705 | | { ... } 1706 | | DROP 1707 | | DUP 1708 | | SWAP 1709 | | PUSH 1710 | | SOME 1711 | | NONE 1712 | | IF_NONE { ... } { ... } 1713 | | PAIR 1714 | | CAR 1715 | | CDR 1716 | | LEFT 1717 | | RIGHT 1718 | | IF_LEFT { ... } { ... } 1719 | | NIL 1720 | | CONS 1721 | | IF_CONS { ... } { ... } 1722 | | EMPTY_SET 1723 | | EMPTY_MAP 1724 | | ITER 1725 | | MAP 1726 | | REDUCE 1727 | | MEM 1728 | | GET 1729 | | UPDATE 1730 | | REF 1731 | | DEREF 1732 | | SET 1733 | | IF { ... } { ... } 1734 | | LOOP { ... } 1735 | | LAMBDA { ... } 1736 | | EXEC 1737 | | DIP { ... } 1738 | | FAIL 1739 | | NOP 1740 | | CONCAT 1741 | | ADD 1742 | | SUB 1743 | | MUL 1744 | | DIV 1745 | | ABS 1746 | | NEG 1747 | | MOD 1748 | | LSL 1749 | | LSR 1750 | | OR 1751 | | AND 1752 | | XOR 1753 | | NOT 1754 | | COMPARE 1755 | | EQ 1756 | | NEQ 1757 | | LT 1758 | | GT 1759 | | LE 1760 | | GE 1761 | | CAST 1762 | | CHECKED_ABS 1763 | | CHECKED_NEG 1764 | | CHECKED_ADD 1765 | | CHECKED_SUB 1766 | | CHECKED_MUL 1767 | | CHECKED_CAST 1768 | | FLOOR 1769 | | CEIL 1770 | | INF 1771 | | NAN 1772 | | ISNAN 1773 | | NANAN 1774 | | MANAGER 1775 | | TRANSFER_FUNDS 1776 | | CREATE_ACCOUNT 1777 | | CREATE_CONTRACT 1778 | | NOW 1779 | | AMOUNT 1780 | | BALANCE 1781 | | CHECK_SIGNATURE 1782 | | H 1783 | | STEPS_TO_QUOTA 1784 | | SOURCE 1785 | ::= 1786 | | int8 1787 | | int16 1788 | | int32 1789 | | int64 1790 | | uint8 1791 | | uint16 1792 | | uint32 1793 | | uint64 1794 | | void 1795 | | string 1796 | | float 1797 | | tez 1798 | | bool 1799 | | key 1800 | | timestamp 1801 | | signature 1802 | | ref 1803 | | option 1804 | | list 1805 | | set 1806 | | contract 1807 | | pair 1808 | | union 1809 | | lambda 1810 | | map 1811 | ::= 1812 | | int8 1813 | | int16 1814 | | int32 1815 | | int64 1816 | | uint8 1817 | | uint16 1818 | | uint32 1819 | | uint64 1820 | | string 1821 | | float 1822 | | tez 1823 | | bool 1824 | | key 1825 | | timestamp 1826 | 1827 | XI - Reference implementation 1828 | ----------------------------- 1829 | 1830 | The language is implemented in OCaml as follows: 1831 | 1832 | * The lower internal representation is written as a GADT whose type 1833 | parameters encode exactly the typing rules given in this 1834 | specification. In other words, if a program written in this 1835 | representation is accepted by OCaml's typechecker, it is 1836 | mandatorily type-safe. This of course also valid for programs not 1837 | handwritten but generated by OCaml code, so we are sure that any 1838 | manipulated code is type-safe. 1839 | 1840 | In the end, what remains to be checked is the encoding of the 1841 | typing rules as OCaml types, which boils down to half a line of 1842 | code for each instruction. Everything else is left to the 1843 | venerable and well trusted OCaml. 1844 | 1845 | * The interpreter is basically the direct transcription of the 1846 | rewriting rules presented above. It takes an instruction, a stack 1847 | and transforms it. OCaml's typechecker ensures that the 1848 | transformation respects the pre and post stack types declared by 1849 | the GADT case for each instruction. 1850 | 1851 | The only things that remain to we reviewed are value dependent 1852 | choices, such as that we did not swap true and false when 1853 | interpreting the If instruction. 1854 | 1855 | * The input, untyped internal representation is an OCaml ADT which 1856 | has the exact same shape as the GADT, except for the stack 1857 | invariants. It is the target language for the parser, since not 1858 | all parsable programs are well typed, and thus could simply not be 1859 | constructed using the GADT. 1860 | 1861 | * The typechecker is a simple function that transform each untyped 1862 | instruction to its typed counterpart. It is just a checker, not an 1863 | inferer, and thus takes some annotations (basically the inpout and 1864 | output of the program, of lambdas and of uninitialized imperative 1865 | structures). It works by performing a symbolic evaluation of the 1866 | program, transforming a symbolic stack. It only needs one pass 1867 | over the whole program. 1868 | 1869 | Here again, OCaml does most of the checking, the structure of the 1870 | function is very simple, what we have to check is that we 1871 | transform an If into a typed If, a Dup into a typed Dup, etc. 1872 | -------------------------------------------------------------------------------- /tezos.v: -------------------------------------------------------------------------------- 1 | From Coq 2 | Require Import ZArith String List. 3 | Import ListNotations. 4 | From mathcomp.ssreflect 5 | Require Import ssreflect ssrfun ssrbool ssrnat seq. 6 | 7 | Set Implicit Arguments. 8 | 9 | Section Data. 10 | 11 | (* Inductive tez := Tez : nat -> tez. *) 12 | Axiom tez : Type. 13 | Axiom timestamp : Type. 14 | Axiom int64 : Type. 15 | 16 | (* for now, many items are commented as we are trying to get the 17 | architecture right and don't want to get clogged with very similar 18 | cases over and over. As we get more confident that we got things 19 | right, we will uncomment new elements *) 20 | 21 | Inductive tagged_data:= 22 | | Int8 : Z -> tagged_data 23 | (* | Int16 : Z -> tagged_data *) 24 | (* | Int32 : Z -> tagged_data *) 25 | | Int64 : int64 -> tagged_data 26 | (* | Uint8 : Z -> tagged_data *) 27 | (* | Uint16 : Z -> tagged_data *) 28 | (* | Uint32 : Z -> tagged_data *) 29 | (* | Uint64 : Z -> tagged_data *) 30 | | Void 31 | | Dtrue 32 | | Dfalse 33 | | DString : string -> tagged_data 34 | (* | *) 35 | | Timestamp : timestamp -> tagged_data 36 | (* | Signature *) 37 | | DTez : tez -> tagged_data 38 | (* | Key *) 39 | (* | Left *) 40 | (* | Right *) 41 | (* | Or *) 42 | (* | Ref *) 43 | (* | Ref *) 44 | (* | Some *) 45 | (* | Some *) 46 | (* | None *) 47 | (* | Option *) 48 | | DPair : tagged_data -> tagged_data -> tagged_data. 49 | (* | Pair *) 50 | (* | List ... *) 51 | (* | Set ... *) 52 | (* | Map (Item ) ... *) 53 | (* | Contract *) 54 | (* | Lambda { ... } *) 55 | 56 | 57 | Definition stack := list tagged_data. 58 | 59 | Definition is_comparable (d : tagged_data) : bool := 60 | match d with 61 | | Int8 z => true 62 | | Int64 i => true 63 | | Dtrue | Dfalse => true 64 | | DTez t => true 65 | | _ => false 66 | end. 67 | 68 | End Data. 69 | 70 | Section Program. 71 | 72 | (* In what follows, the "nested inductive types" approach calls for a custom (user-defined) induction principle *) 73 | 74 | (* XXX: should we use a notation for `list instr` here? *) 75 | Inductive instr := 76 | | Drop : instr 77 | | Dup : instr 78 | | Push : tagged_data -> instr 79 | | Pair : instr 80 | | If : list instr -> list instr -> instr 81 | | Loop : list instr -> instr 82 | | Le : instr 83 | | Transfer_funds : instr 84 | | Now : instr 85 | | Balance : instr. 86 | 87 | Definition program := list instr. 88 | 89 | (* The custom induction principle for the `instr` datatype. 90 | * We need it because the autogenerated `instr_ind` is too 91 | * weak for proofs. 92 | * Based on the approach described in 93 | * "Certified Programming with Dependent Types" book by A. Chlipala: 94 | * http://adam.chlipala.net/cpdt/html/InductiveTypes.html#lab32 95 | *) 96 | Variable P : instr -> Prop. 97 | Hypothesis Drop_case : P Drop. 98 | Hypothesis Dup_case : P Dup. 99 | Hypothesis Push_case : forall (d : tagged_data), P (Push d). 100 | Hypothesis Pair_case : P Pair. 101 | Hypothesis If_case : forall pgm1 pgm2 : program, 102 | Forall P pgm1 -> Forall P pgm2 -> P (If pgm1 pgm2). 103 | Hypothesis Loop_case : forall pgm : program, 104 | Forall P pgm -> P (Loop pgm). 105 | Hypothesis Le_case : P Le. 106 | Hypothesis Transfer_funds_case : P Transfer_funds. 107 | Hypothesis Now_case : P Now. 108 | Hypothesis Balance_case : P Balance. 109 | 110 | Fixpoint instr_ind' (i : instr) : P i := 111 | let list_instr_ind := 112 | (fix list_instr_ind (pgm : program) : Forall P pgm := 113 | match pgm with 114 | | [] => Forall_nil _ 115 | | i' :: pgm' => Forall_cons _ (instr_ind' i') (list_instr_ind pgm') 116 | end) in 117 | match i with 118 | | Drop => Drop_case 119 | | Dup => Dup_case 120 | | Push d => Push_case d 121 | | Pair => Pair_case 122 | | If pgm1 pgm2 => If_case (list_instr_ind pgm1) (list_instr_ind pgm2) 123 | | Loop pgm => Loop_case (list_instr_ind pgm) 124 | | Le => Le_case 125 | | Transfer_funds => Transfer_funds_case 126 | | Now => Now_case 127 | | Balance => Balance_case 128 | end. 129 | 130 | End Program. 131 | 132 | Section Types. 133 | 134 | Inductive instr_type := 135 | | Pre_post : stack_type -> stack_type -> instr_type 136 | 137 | with stack_type := 138 | | empty_stack : stack_type 139 | | cons_stack : type -> stack_type -> stack_type 140 | 141 | with type := 142 | | t_int8 : type 143 | | t_void : type 144 | | t_bool : type 145 | | t_string : type 146 | | t_tez : tez -> type 147 | | t_contract : type -> type -> type 148 | | t_quotation : instr_type -> type. 149 | 150 | (* * `lambda T_arg T_ret` is a shortcut for `[ T_arg :: [] -> T_ret :: []]`. *) 151 | Definition lambda t_arg t_ret := 152 | t_quotation (Pre_post (cons_stack t_arg empty_stack) (cons_stack t_ret empty_stack)). 153 | 154 | End Types. 155 | 156 | Section Typing. 157 | (* Here we want to talk about typing judgements, for data, 158 | program and programs *) 159 | 160 | Inductive has_prog_type : program -> instr_type -> Prop := 161 | | PT_empty : forall st, 162 | has_prog_type nil (Pre_post st st) 163 | | PT_seq : forall x xs s sa sb sc, 164 | has_instr_type x s (Pre_post sa sb) -> 165 | has_prog_type xs (Pre_post sb sc) -> 166 | has_prog_type (x::xs) (Pre_post sa sc) 167 | 168 | with has_instr_type : instr -> stack -> instr_type -> Prop := 169 | | IT_Drop : forall x s (t : type) (st : stack_type), 170 | has_stack_type s st -> 171 | has_type x t -> 172 | has_instr_type Drop (x::s) (Pre_post (cons_stack t st) (st)) 173 | 174 | | IT_Dup : forall x s (t : type) (st : stack_type), 175 | has_stack_type s st -> 176 | has_type x t -> 177 | has_instr_type Dup (x::s) (Pre_post (cons_stack t st) (cons_stack t (cons_stack t st))) 178 | 179 | | IT_If : forall bvar sta stb bt bf xs, 180 | has_type bvar t_bool -> 181 | has_stack_type xs sta -> 182 | has_prog_type bt (Pre_post sta stb) -> 183 | has_prog_type bf (Pre_post sta stb) -> 184 | has_instr_type (If bt bf) (bvar::xs) (Pre_post (cons_stack t_bool sta) stb) 185 | | IT_Loop : forall s a body, 186 | has_stack_type s (cons_stack t_bool a) -> 187 | has_prog_type body (Pre_post a (cons_stack t_bool a)) -> 188 | has_instr_type (Loop body) s (Pre_post (cons_stack t_bool a) a) 189 | 190 | with has_stack_type : stack -> stack_type -> Prop := 191 | | ST_empty : has_stack_type nil empty_stack 192 | | ST_cons : forall x xs t st, 193 | has_type x t -> 194 | has_stack_type xs st -> 195 | has_stack_type (x::xs) (cons_stack t st) 196 | 197 | with has_type : tagged_data -> type -> Prop := 198 | | T_boolT : has_type Dtrue t_bool 199 | | T_boolF : has_type Dfalse t_bool. 200 | 201 | (* is this useful? *) 202 | Scheme has_prog_type_ind' := Induction for has_prog_type Sort Prop 203 | with has_instr_type_ind' := Induction for has_instr_type Sort Prop 204 | with has_stack_type_ind' := Induction for has_stack_type Sort Prop 205 | with has_type_ind' := Induction for has_type Sort Prop. 206 | 207 | (* Print has_prog_type_ind. *) 208 | (* Print has_prog_type_ind'. *) 209 | 210 | Hint Constructors has_prog_type. 211 | Hint Constructors has_instr_type. 212 | Hint Constructors has_stack_type. 213 | Hint Constructors has_type. 214 | 215 | (* test *) 216 | Example Drop_typing_with_empty_stack : 217 | has_prog_type [::Drop] (Pre_post (cons_stack t_bool empty_stack) 218 | (empty_stack)). 219 | Proof. 220 | by repeat econstructor. 221 | Qed. 222 | 223 | Lemma PT_instr_to_prog i s t : 224 | has_instr_type i s t -> 225 | has_prog_type [::i] t. 226 | Proof. 227 | by case: t; eauto. 228 | Qed. 229 | 230 | (* the clumsiness of this next one illustrates that it's probably not 231 | a good idea to type an instruction against a stack, but to type a 232 | program independently *) 233 | Lemma PT_prog_to_instr i t : 234 | has_prog_type [::i] t -> 235 | exists s, has_instr_type i s t. 236 | Proof. 237 | case: t => s0 s1 H. 238 | inversion H; subst. 239 | inversion H5; subst. 240 | by exists s. 241 | Qed. 242 | 243 | End Typing. 244 | 245 | Section Semantics. 246 | 247 | (* To be changed once we know what we want *) 248 | Variables memory : Type. 249 | 250 | (* until we get a better sense of what works best, we will try two 251 | ways to do the small steps semantics: one with an inductive type of 252 | reduction rules, and one with a step function. *) 253 | 254 | (* First version: inductive semantics *) 255 | Section Ind_semantics. 256 | 257 | Inductive step : instr * program * stack * memory -> 258 | program * stack * memory -> Prop := 259 | | stepDrop : forall pgm x s m, 260 | step (Drop, pgm, x::s, m) 261 | (pgm, s, m) 262 | | stepIfTrue : forall cont pgmT pgmF s m, 263 | step (If pgmT pgmF, cont, Dtrue :: s, m) 264 | (pgmT ++ cont, s, m) 265 | | stepIfFalse : forall cont pgmT pgmF s m, 266 | step (If pgmT pgmF, cont, Dfalse :: s, m) 267 | (pgmF ++ cont, s, m) 268 | | stepLoopGo : forall cont body s m, 269 | step (Loop body, cont, Dtrue :: s, m) 270 | (body ++ (Loop body :: cont), s, m) 271 | | stepLoopEnd : forall cont body s m, 272 | step (Loop body, cont, Dfalse :: s, m) 273 | (cont, s, m) 274 | . 275 | 276 | End Ind_semantics. 277 | 278 | 279 | (* Second version: with a step function *) 280 | Section Fun_semantics. 281 | 282 | (* I'm guessing these will be replaced by accesses to memory, with a 283 | precise spec *) 284 | Axiom get_timestamp : unit -> timestamp. 285 | Axiom get_current_amount : unit -> tez. 286 | 287 | (* these axioms to model the behavior of Transfer_funds, which I do 288 | not understand as of now *) 289 | Axiom get_new_global : tagged_data -> tagged_data. 290 | Axiom get_return_value : tagged_data -> tagged_data. 291 | 292 | Axiom get_le : tagged_data -> int64. 293 | 294 | Fixpoint step_fun (i : instr) (pgm : program) (s : stack) (m : memory) : option (program * stack * memory) := 295 | match i with 296 | | Drop => if s is x::xs then Some(pgm,xs,m) else None 297 | | Dup => if s is x::xs then Some(pgm,x::x::xs,m) else None 298 | | Push d => Some(pgm,d::s,m) 299 | | Pair => if s is a::b::s then Some(pgm,(DPair a b)::s,m) else None 300 | | If bt bf => if s is x::s then 301 | match x with 302 | | Dtrue => Some(bt++pgm,s,m) 303 | | Dfalse => Some(bf++pgm,s,m) 304 | | _ => None 305 | end else None 306 | | Loop body => if s is x::s then 307 | match x with 308 | | Dtrue => Some(body++(Loop body :: pgm),s,m) 309 | | Dfalse => Some(pgm,s,m) 310 | | _ => None 311 | end else None 312 | | Le => if s is x::s then if is_comparable x then Some(pgm,(Int64 (get_le x))::s,m) else None else None 313 | | Transfer_funds => if s is p::amount::contract::g::nil then 314 | Some(pgm,[::get_return_value contract;get_new_global g],m) else None 315 | | Now => Some(pgm,Timestamp (get_timestamp tt)::s,m) 316 | | Balance => Some(pgm,DTez (get_current_amount tt)::s,m) 317 | end. 318 | 319 | Fixpoint evaluate (pgm : program) (s : stack) (m : memory) (f : nat) : option (stack * memory) := 320 | match f with 321 | | 0 => None 322 | | S f => match pgm with 323 | | nil => Some (s,m) 324 | | i::pgm => match (step_fun i pgm s m) with 325 | | None => None 326 | | Some(pgm',s',m') => evaluate pgm' s' m' f 327 | end 328 | end 329 | end. 330 | 331 | Lemma has_prog_type_cat : forall p q st1 st2 st3, 332 | has_prog_type p (Pre_post st1 st2) -> 333 | has_prog_type q (Pre_post st2 st3) -> 334 | has_prog_type (p++q) (Pre_post st1 st3). 335 | Proof. 336 | elim => [|p ps Hps] q st1 st2 st3. 337 | - by move => Hnil; inversion Hnil. 338 | - by move => Hp Hq; inversion Hp; econstructor; eauto. 339 | Qed. 340 | 341 | Lemma step_fun_preserves_type pgm st1 st2 s m f : 342 | has_prog_type pgm (Pre_post st1 st2) -> 343 | has_stack_type s st1 -> 344 | match (evaluate pgm s m f) with 345 | | Some (s',m') => has_stack_type s' st2 346 | | None => True 347 | end. 348 | Proof. 349 | move: f pgm st1 st2 s m. 350 | elim => [|f HIf] pgm st1 st2 s m //. 351 | case: pgm => [| i pgm] // . 352 | by move => HPT; inversion HPT => HST //=. 353 | case: i => [| | (* Push *) d| | (* If *) bt bf| (* Loop *)body| (* Le *) | | |] /=. 354 | - case: s => [| x s]// . 355 | move => HPT HST. 356 | inversion HPT. 357 | inversion HST. 358 | inversion H2. 359 | apply: HIf. 360 | exact: H4. 361 | rewrite -H8 in H10. 362 | case: H10. 363 | by move => _; rewrite -H11 => -> . 364 | - admit. (* TODO : Dup *) 365 | - admit. (* TODO : Push *) 366 | - admit. (* TODO : Pair *) 367 | - case: s => [| x s] //; case: x => // . 368 | + move => HPT HST. 369 | inversion HPT. 370 | inversion H2. 371 | apply: HIf. 372 | apply: has_prog_type_cat. 373 | exact: H12. 374 | exact: H4. 375 | rewrite -H7 in HST. 376 | by inversion HST. 377 | + move => HPT HST. 378 | inversion HPT. 379 | inversion H2. 380 | apply: HIf. 381 | apply: has_prog_type_cat. 382 | exact: H13. 383 | exact: H4. 384 | rewrite -H7 in HST. 385 | by inversion HST. 386 | - case: s => [| x s] //; case: x => // ; last first. 387 | + move => HPT HST. 388 | inversion HPT. 389 | apply: HIf. 390 | exact: H4. 391 | inversion HST. 392 | inversion H2. 393 | rewrite -H8 in H11. 394 | case: H11 => _. 395 | by rewrite -H12 => -> . 396 | + move => HPT HST. 397 | inversion HPT. 398 | inversion H2. 399 | apply: HIf. 400 | * apply: has_prog_type_cat. 401 | exact: H10. 402 | apply: PT_seq. 403 | apply: IT_Loop. 404 | exact: H9. 405 | exact: H10. 406 | exact: H4. 407 | * inversion HST. 408 | rewrite -H6 in H14. 409 | case: H14 => _. 410 | by rewrite -H7 => <- . 411 | - admit. (* TODO : Le *) 412 | - admit. (* TODO : Transfer_funds *) 413 | - admit. (* TODO : Now *) 414 | - admit. (* TODO : Balance *) 415 | Admitted. 416 | 417 | End Fun_semantics. 418 | 419 | End Semantics. --------------------------------------------------------------------------------