Michelson: get rid of tagged data notation.

This commit is contained in:
Benjamin Canou 2017-01-11 17:42:54 +01:00
parent 26e1adc143
commit 507c46bbcb
9 changed files with 202 additions and 511 deletions

View File

@ -210,9 +210,9 @@ let commands () =
(prefixes [ "run" ; "program" ] (prefixes [ "run" ; "program" ]
@@ Program.source_param @@ Program.source_param
@@ prefixes [ "on" ; "storage" ] @@ prefixes [ "on" ; "storage" ]
@@ Cli_entries.param ~name:"storage" ~desc:"the untagged storage data" parse_data @@ Cli_entries.param ~name:"storage" ~desc:"the storage data" parse_data
@@ prefixes [ "and" ; "input" ] @@ prefixes [ "and" ; "input" ]
@@ Cli_entries.param ~name:"storage" ~desc:"the untagged input data" parse_data @@ Cli_entries.param ~name:"storage" ~desc:"the input data" parse_data
@@ stop) @@ stop)
(fun program storage input cctxt -> (fun program storage input cctxt ->
let open Data_encoding in let open Data_encoding in
@ -274,7 +274,7 @@ let commands () =
| Error errs -> | Error errs ->
pp_print_error Format.err_formatter errs ; pp_print_error Format.err_formatter errs ;
cctxt.error "ill-typed program") ; cctxt.error "ill-typed program") ;
command ~group ~desc: "ask the node to typecheck a tagged data expression" command ~group ~desc: "ask the node to typecheck a data expression"
(prefixes [ "typecheck" ; "data" ] (prefixes [ "typecheck" ; "data" ]
@@ Cli_entries.param ~name:"data" ~desc:"the data to typecheck" parse_data @@ Cli_entries.param ~name:"data" ~desc:"the data to typecheck" parse_data
@@ prefixes [ "against" ; "type" ] @@ prefixes [ "against" ; "type" ]
@ -282,7 +282,7 @@ let commands () =
@@ stop) @@ stop)
(fun data exp_ty cctxt -> (fun data exp_ty cctxt ->
let open Data_encoding in let open Data_encoding in
Client_proto_rpcs.Helpers.typecheck_untagged_data cctxt Client_proto_rpcs.Helpers.typecheck_data cctxt
(block ()) (data, exp_ty) >>= function (block ()) (data, exp_ty) >>= function
| Ok () -> | Ok () ->
cctxt.message "Well typed" cctxt.message "Well typed"
@ -290,7 +290,7 @@ let commands () =
pp_print_error Format.err_formatter errs ; pp_print_error Format.err_formatter errs ;
cctxt.error "ill-typed data") ; cctxt.error "ill-typed data") ;
command ~group command ~group
~desc: "ask the node to compute the hash of an untagged data expression \ ~desc: "ask the node to compute the hash of a data expression \
using the same algorithm as script instruction H" using the same algorithm as script instruction H"
(prefixes [ "hash" ; "data" ] (prefixes [ "hash" ; "data" ]
@@ Cli_entries.param ~name:"data" ~desc:"the data to hash" parse_data @@ Cli_entries.param ~name:"data" ~desc:"the data to hash" parse_data
@ -305,7 +305,7 @@ let commands () =
pp_print_error Format.err_formatter errs ; pp_print_error Format.err_formatter errs ;
cctxt.error "ill-formed data") ; cctxt.error "ill-formed data") ;
command ~group command ~group
~desc: "ask the node to compute the hash of an untagged data expression \ ~desc: "ask the node to compute the hash of a data expression \
using the same algorithm as script instruction H, sign it using \ using the same algorithm as script instruction H, sign it using \
a given secret key, and display it using the format expected by \ a given secret key, and display it using the format expected by \
script instruction CHECK_SIGNATURE" script instruction CHECK_SIGNATURE"

View File

@ -140,11 +140,8 @@ module Helpers = struct
call_error_service1 cctxt Services.Helpers.trace_code call_error_service1 cctxt Services.Helpers.trace_code
block (code, storage, input, None, None) block (code, storage, input, None, None)
let typecheck_tagged_data cctxt = let typecheck_data cctxt =
call_error_service1 cctxt Services.Helpers.typecheck_tagged_data call_error_service1 cctxt Services.Helpers.typecheck_data
let typecheck_untagged_data cctxt =
call_error_service1 cctxt Services.Helpers.typecheck_untagged_data
let hash_data cctxt = let hash_data cctxt =
call_error_service1 cctxt Services.Helpers.hash_data call_error_service1 cctxt Services.Helpers.hash_data

View File

@ -149,10 +149,7 @@ module Helpers : sig
val typecheck_code: val typecheck_code:
Client_commands.context -> Client_commands.context ->
block -> Script.code -> Script_ir_translator.type_map tzresult Lwt.t block -> Script.code -> Script_ir_translator.type_map tzresult Lwt.t
val typecheck_tagged_data: val typecheck_data:
Client_commands.context ->
block -> Script.expr -> unit tzresult Lwt.t
val typecheck_untagged_data:
Client_commands.context -> Client_commands.context ->
block -> Script.expr * Script.expr -> unit tzresult Lwt.t block -> Script.expr * Script.expr -> unit tzresult Lwt.t
val hash_data: val hash_data:

View File

@ -1061,7 +1061,7 @@ for under/overflows.
the global data and returns it to be stored and retrieved on the the global data and returns it to be stored and retrieved on the
next transaction. These data are initialized by another next transaction. These data are initialized by another
parameter. The calling convention for the code is as follows: parameter. The calling convention for the code is as follows:
(Pair (Pair amount arg) globals)) -> (Pair ret globals), as `(Pair (Pair amount arg) globals)) -> (Pair ret globals)`, as
extrapolable from the instruction type. The first parameters are extrapolable from the instruction type. The first parameters are
the manager, optional delegate, then spendable and delegatable the manager, optional delegate, then spendable and delegatable
flags and finally the initial amount taken from the currently flags and finally the initial amount taken from the currently
@ -1154,22 +1154,14 @@ for under/overflows.
VIII - Concrete syntax VIII - Concrete syntax
---------------------- ----------------------
The structure of the concrete language is extremely simple. An The concrete language is very close to the formal notation of the
expression in the language can only be one of the three following specification. Its structure is extremely simple: an expression in the
constructs. language can only be one of the three following constructs.
1. A constant. 1. A constant (integer or string).
2. The application of a primitive to a sequence of expressions. 2. The application of a primitive to a sequence of expressions.
3. A sequence of expressions. 3. A sequence of expressions.
As in Python or Haskell, the concrete syntax of the language is
indentation sensitive. The elements of a syntactical block, such as
all the elements of a sequence, or all the parameters of a primitive,
must be written with the exact same left margin in the program source
code. This is unlike in C-like languages, where blocks are delimited
with braces and the margin is ignored by the compiled. The exact
parsing policy is described just after.
### Constants ### Constants
There are two kinds of constants: There are two kinds of constants:
@ -1181,30 +1173,20 @@ There are two kinds of constants:
characters can be escaped by 3 digits decimal codes `\ddd` or characters can be escaped by 3 digits decimal codes `\ddd` or
2 digit hexadecimal codes `\xHH`. 2 digit hexadecimal codes `\xHH`.
All domain specific constants are strings:
- `tez` amounts are written using the same notation as JSON schemas
and the command line client: thousands are optionally separated by
comas, and centiles, if present, must be prefixed by a period.
- in regexp form: `([0-9]{1,3}(,[0-9]{3})+)|[0-9]+(\.[0.9]{2})?`
- `"1234567"` means 123456700 tez centiles
- `"1,234,567"` means 123456700 tez centiles
- `"1234567.89"` means 123456789 tez centiles
- `"1,234,567.00"` means 123456789 tez centiles
- `"1234,567"` is invalid
- `"1,234,567."` is invalid
- `"1,234,567.0"` is invalid
- `timestamp`s are written using `RFC 339` notation.
- `contract`s are the raw strings returned by JSON RPCs or the command
line interface and cannot be forged by hand so their format is of
no interest here.
- `key`s are `Sha256` hashes of `ed25519` public keys encoded in
`base48` format with the following custom alphabet:
`"eXMNE9qvHPQDdcFx5J86rT7VRm2atAypGhgLfbS3CKjnksB4"`.
- `signature`s are `ed25519` signatures as a series of hex-encoded bytes.
### Primitive applications ### Primitive applications
In the specification, primitive applications always luckily fit on a
single line. In this case, the concrete syntax is exactly the formal
notation. However, it is sometimes necessary to break lines in a real
program, which can be done as follows.
As in Python or Haskell, the concrete syntax of the language is
indentation sensitive. The elements of a syntactical block, such as
all the elements of a sequence, or all the parameters of a primitive,
must be written with the exact same left margin in the program source
code. This is unlike in C-like languages, where blocks are delimited
with braces and the margin is ignored by the compiled.
The simplest form requires to break the line after the primitive name The simplest form requires to break the line after the primitive name
and after every argument. Argument must be indented by at least one and after every argument. Argument must be indented by at least one
more space than the primitive, and all arguments must sit on the exact more space than the primitive, and all arguments must sit on the exact
@ -1271,10 +1253,61 @@ example is:
### Sequences ### Sequences
Successive instructions can be grouped as a single one by grouping Successive expression can be grouped as a single sequence expression
them inside braces, separated by semicolons. To prevent errors, using braces delimiters and semicolon separators.
control flow primitives that take instructions as parameters require
sequences in the concrete syntax. { expr1 ; expr2 ; expr3 ; expr4 }
A sequence block can be split on several lines. In this situation, the
whole block, including the closing brace, must be indented with
respect to the first instruction.
{ expr1 ; expr2
expr3 ; expr4 }
Blocks can be passed as argument to a primitive.
PRIM arg1 arg2
{ arg3_expr1 ; arg3_expr2
arg3_expr3 ; arg3_expr4 }
### Conventions
The concrete syntax follows the same lexical conventions as the
specification: instructions are represented by uppercase identifiers,
type constructors by lowercase identifiers, and constant constructors
are Capitalised.
Lists can be written in a single shot instead of a succession of `Cons`
(List 1 2 3) = (Cons 1 (Cons 2 (Cons 3 Nil)))
All domain specific constants are strings with specific formats:
- `tez` amounts are written using the same notation as JSON schemas
and the command line client: thousands are optionally separated by
comas, and centiles, if present, must be prefixed by a period.
- in regexp form: `([0-9]{1,3}(,[0-9]{3})+)|[0-9]+(\.[0.9]{2})?`
- `"1234567"` means 123456700 tez centiles
- `"1,234,567"` means 123456700 tez centiles
- `"1234567.89"` means 123456789 tez centiles
- `"1,234,567.00"` means 123456789 tez centiles
- `"1234,567"` is invalid
- `"1,234,567."` is invalid
- `"1,234,567.0"` is invalid
- `timestamp`s are written using `RFC 339` notation.
- `contract`s are the raw strings returned by JSON RPCs or the command
line interface and cannot be forged by hand so their format is of
no interest here.
- `key`s are `Sha256` hashes of `ed25519` public keys encoded in
`base48` format with the following custom alphabet:
`"eXMNE9qvHPQDdcFx5J86rT7VRm2atAypGhgLfbS3CKjnksB4"`.
- `signature`s are `ed25519` signatures as a series of hex-encoded bytes.
To prevent errors, control flow primitives that take instructions as
parameters require sequences in the concrete syntax.
IF { instr1_true ; instr2_true ; ... } { instr1_false ; instr2_false ; ... } IF { instr1_true ; instr2_true ; ... } { instr1_false ; instr2_false ; ... }
@ -1282,78 +1315,13 @@ sequences in the concrete syntax.
{ instr1_true ; instr2_true ; ... } { instr1_true ; instr2_true ; ... }
{ instr1_false ; instr2_false ; ... } { instr1_false ; instr2_false ; ... }
A sequence block can be split on several lines. In this situation, the ### Main program structure
whole block, including the closing brace, must be indented with
respect to the first instruction.
LAMBDA t_arg t_ret The toplevel of a smart contract file must be an undelimited sequence
{ instr1 ; instr2 of four primitive applications (in no particular order) that provide
instr3 ; instr4 } its `parameter`, `return` and `storage` types, as well as its `code`.
### Lexical conventions See the next section for a concrete example.
Instructions are represented by uppercase identifiers, type
constructor are lowercase identifiers and constant constructors are
Capitalised.
* Types, in lowercase, in prefixed notation as in this specification:
string
pair string (pair int8 tez)
lambda int8 int16
Of course, types can be split over multiple lines using the
common indented notation.
map
string
uint32
* Constants are built using constructors (starting with a capital)
followed by the actual value.
Int8 1
Compound constants such as lists, in order not to repeat the same
constant constructor for each element, take the type(s) of inner
values as first argument(s), and then the values without their
constructors.
List int8 1 2 3 4 5
Pair int8 int16 1 2
For constructors whose type cannot be completely deduced fron a
single value, the free type variables must be specified. For this,
some constant constructors take extra types arguments as follows.
List int8
None tez
Left (Int8 3) int16
Right int16 (Int8 3)
When the type is already completely specified, by a parent
constructor or as in the instruction PUSH, these annotations must
be omitted.
Pair int8 (list int16) 1 (List 2 3)
Pair (option (pair unit int8)) unit
None
Unit
Pair (or int8 string) (or int8 string)
Left 3
Right "text"
* Instructions, in uppercase:
ADD
### Comments ### Comments
@ -1361,8 +1329,8 @@ A hash sign (`#`) anywhere outside of a string literal will make the
rest of the line (and itself) completely ignored, as in the following rest of the line (and itself) completely ignored, as in the following
example. example.
PUSH (Int8 1) # pushes 1 PUSH int8 1 # pushes 1
PUSH (Int8 2) # pushes 2 PUSH int8 2 # pushes 2
ADD # computes 2 + 1 ADD # computes 2 + 1
IX - Examples IX - Examples
@ -1386,7 +1354,14 @@ contract of such a type must take a `unit` argument, an amount in `tez`,
and transform a unit global storage, and must thus be of type `(lambda and transform a unit global storage, and must thus be of type `(lambda
(pair (pair tez unit) unit) (pair unit unit))`. (pair (pair tez unit) unit) (pair unit unit))`.
Such a minimal contract is thus `{ CDR ; UNIT ; PAIR }`. Such a minimal contract code is thus `{ CDR ; UNIT ; PAIR }`.
A valid contract source file would be as follows.
code { CDR ; UNIT ; PAIR }
storage unit
parameter unit
return unit
### Reservoir contract ### Reservoir contract
@ -1435,11 +1410,11 @@ its code is
COMPARE ; LE COMPARE ; LE
IF { } # nothing to do IF { } # nothing to do
{ DUP ; CDDDR # B { DUP ; CDDDR # B
BALANCE ; PUSH Unit ; TRANSFER_TOKENS ; DROP } } BALANCE ; UNIT ; TRANSFER_TOKENS ; DROP } }
{ DUP ; CDDAR ; # A { DUP ; CDDAR ; # A
BALANCE ; BALANCE ;
PUSH Unit ; TRANSFER_TOKENS ; DROP } UNIT ; TRANSFER_TOKENS ; DROP }
CDR ; PUSH Unit ; PAIR CDR ; UNIT ; PAIR
### Reservoir contract (variant with broker and status) ### Reservoir contract (variant with broker and status)
@ -1468,7 +1443,7 @@ example and must be updated according to the actual Tezos minmal
value for contract balance. value for contract balance.
DUP ; CDAR # S DUP ; CDAR # S
PUSH (String "open") ; PUSH string "open" ;
COMPARE ; NEQ ; COMPARE ; NEQ ;
IF { FAIL ; CDR } # on "success", "timeout" or a bad init value IF { FAIL ; CDR } # on "success", "timeout" or a bad init value
{ DUP ; CDDAR ; # T { DUP ; CDDAR ; # T
@ -1476,7 +1451,7 @@ value for contract balance.
COMPARE ; LT ; COMPARE ; LT ;
IF { # Before timeout IF { # Before timeout
# We compute ((1 + P) + N) tez for keeping the contract alive # We compute ((1 + P) + N) tez for keeping the contract alive
PUSH (Tez "1.00") ; PUSH tez "1.00" ;
DIP { DUP ; CDDDAAR } ; ADD ; # P DIP { DUP ; CDDDAAR } ; ADD ; # P
DIP { DUP ; CDDDADR } ; ADD ; # N DIP { DUP ; CDDDADR } ; ADD ; # N
# We compare to the cumulated amount # We compare to the cumulated amount
@ -1488,32 +1463,32 @@ value for contract balance.
{ # We transfer the fee to the broker { # We transfer the fee to the broker
DUP ; CDDDAAR ; # P DUP ; CDDDAAR ; # P
DIP { DUP ; CDDDDAR } # A DIP { DUP ; CDDDDAR } # A
PUSH Unit ; TRANSFER_TOKENS ; DROP ; UNIT ; TRANSFER_TOKENS ; DROP ;
# We transfer the rest to the destination # We transfer the rest to the destination
DUP ; CDDDADR ; # N DUP ; CDDDADR ; # N
DIP { DUP ; CDDDDDR } # B DIP { DUP ; CDDDDDR } # B
PUSH Unit ; TRANSFER_TOKENS ; DROP ; UNIT ; TRANSFER_TOKENS ; DROP ;
# We update the global # We update the global
CDR ; CDR ; PUSH (String "success") ; PAIR } } CDR ; CDR ; PUSH string "success" ; PAIR } }
{ # After timeout { # After timeout
# We try to transfer P tez to A # We try to transfer P tez to A
PUSH (Tez "1.00") ; BALANCE ; SUB ; # available PUSH tez "1.00" ; BALANCE ; SUB ; # available
DIP { DUP ; CDDDAAR } ;# P DIP { DUP ; CDDDAAR } ;# P
COMPARE ; LT ; # available < P COMPARE ; LT ; # available < P
IF { PUSH (Tez "1.00") ; BALANCE ; SUB ; # available IF { PUSH tez "1.00" ; BALANCE ; SUB ; # available
DIP { DUP ; CDDDDAR } # A DIP { DUP ; CDDDDAR } # A
PUSH Unit ; TRANSFER_TOKENS ; DROP } UNIT ; TRANSFER_TOKENS ; DROP }
{ DUP ; CDDDAAR ; # P { DUP ; CDDDAAR ; # P
DIP { DUP ; CDDDDAR } # A DIP { DUP ; CDDDDAR } # A
PUSH Unit ; TRANSFER_TOKENS ; DROP } UNIT ; TRANSFER_TOKENS ; DROP }
# We transfer the rest to B # We transfer the rest to B
PUSH (Tez "1.00") ; BALANCE ; SUB ; # available PUSH tez "1.00" ; BALANCE ; SUB ; # available
DIP { DUP ; CDDDDDR } # B DIP { DUP ; CDDDDDR } # B
PUSH Unit ; TRANSFER_TOKENS ; DROP ; UNIT ; TRANSFER_TOKENS ; DROP ;
# We update the global # We update the global
CDR ; CDR ; PUSH (String "timeout") ; PAIR } } CDR ; CDR ; PUSH string "timeout" ; PAIR } }
# return Unit # return Unit
PUSH Unit ; PAIR UNIT ; PAIR
### Forward contract ### Forward contract
@ -1613,65 +1588,65 @@ with the minimum amount, set to `(Tez "1.00")`.
The code of the contract is thus as follows. The code of the contract is thus as follows.
DUP ; CDDADDR ; # Z DUP ; CDDADDR ; # Z
PUSH (Uint64 86400) ; SWAP ; ADD ; # one day in second PUSH uint64 86400 ; SWAP ; ADD ; # one day in second
NOW ; COMPARE ; LT ; NOW ; COMPARE ; LT ;
IF { # Before Z + 24 IF { # Before Z + 24
DUP ; CADR ; # we must receive (Left "buyer") or (Left "seller") DUP ; CADR ; # we must receive (Left "buyer") or (Left "seller")
IF_LEFT IF_LEFT
{ DUP ; PUSH (String "buyer") ; COMPARE ; EQ ; { DUP ; PUSH string "buyer" ; COMPARE ; EQ ;
IF { DROP ; IF { DROP ;
DUP ; CDADAR ; # amount already versed by the buyer DUP ; CDADAR ; # amount already versed by the buyer
DIP { DUP ; CAAR } ; ADD ; # transaction DIP { DUP ; CAAR } ; ADD ; # transaction
# then we rebuild the globals # then we rebuild the globals
DIP { DUP ; CDADDR } ; PAIR ; # seller amount DIP { DUP ; CDADDR } ; PAIR ; # seller amount
PUSH (Uint32 0) ; PAIR ; # delivery counter at 0 PUSH uint32 0 ; PAIR ; # delivery counter at 0
DIP { CDDR } ; PAIR ; # parameters DIP { CDDR } ; PAIR ; # parameters
# and return Unit # and return Unit
PUSH Unit ; PAIR } UNIT ; PAIR }
{ PUSH (String "seller") ; COMPARE ; EQ ; { PUSH string "seller" ; COMPARE ; EQ ;
IF { DUP ; CDADDR ; # amount already versed by the seller IF { DUP ; CDADDR ; # amount already versed by the seller
DIP { DUP ; CAAR } ; ADD ; # transaction DIP { DUP ; CAAR } ; ADD ; # transaction
# then we rebuild the globals # then we rebuild the globals
DIP { DUP ; CDADAR } ; SWAP ; PAIR ; # buyer amount DIP { DUP ; CDADAR } ; SWAP ; PAIR ; # buyer amount
PUSH (Uint32 0) ; PAIR ; # delivery counter at 0 PUSH uint32 0 ; PAIR ; # delivery counter at 0
DIP { CDDR } ; PAIR ; # parameters DIP { CDDR } ; PAIR ; # parameters
# and return Unit # and return Unit
PUSH Unit ; PAIR } UNIT ; PAIR }
{ FAIL ; CDR ; PUSH Unit ; PAIR }}} # (Left _) { FAIL ; CDR ; UNIT ; PAIR }}} # (Left _)
{ FAIL ; DROP ; CDR ; PUSH Unit ; PAIR }} # (Right _) { FAIL ; DROP ; CDR ; UNIT ; PAIR }} # (Right _)
{ # After Z + 24 { # After Z + 24
# test if the required amount is reached # test if the required amount is reached
DUP ; CDDAAR ; # Q DUP ; CDDAAR ; # Q
DIP { DUP ; CDDDADR } ; MUL ; # C DIP { DUP ; CDDDADR } ; MUL ; # C
PUSH (Uint8 2) ; MUL ; PUSH uint8 2 ; MUL ;
PUSH (Tez "1.00") ; ADD ; PUSH tez "1.00" ; ADD ;
BALANCE ; COMPARE ; LT ; # balance < 2 * (Q * C) + 1 BALANCE ; COMPARE ; LT ; # balance < 2 * (Q * C) + 1
IF { # refund the parties IF { # refund the parties
DUP ; CDADAR ; # amount versed by the buyer DUP ; CDADAR ; # amount versed by the buyer
DIP { DUP ; CDDDDAAR } # B DIP { DUP ; CDDDDAAR } # B
PUSH Unit ; TRANSFER_TOKENS ; DROP UNIT ; TRANSFER_TOKENS ; DROP
DUP ; CDADDR ; # amount versed by the seller DUP ; CDADDR ; # amount versed by the seller
DIP { DUP ; CDDDDADR } # S DIP { DUP ; CDDDDADR } # S
PUSH Unit ; TRANSFER_TOKENS ; DROP UNIT ; TRANSFER_TOKENS ; DROP
BALANCE ; # bonus to the warehouse to destroy the account BALANCE ; # bonus to the warehouse to destroy the account
DIP { DUP ; CDDDDDR } # W DIP { DUP ; CDDDDDR } # W
PUSH Unit ; TRANSFER_TOKENS ; DROP UNIT ; TRANSFER_TOKENS ; DROP
# return unit, don't change the global # return unit, don't change the global
# since the contract will be destroyed # since the contract will be destroyed
CDR ; PUSH Unit ; PAIR } CDR ; UNIT ; PAIR }
{ # otherwise continue { # otherwise continue
DUP ; CDDADAR # T DUP ; CDDADAR # T
NOW ; COMPARE ; LT NOW ; COMPARE ; LT
IF { FAIL ; CDR ; PUSH Unit ; PAIR } # Between Z + 24 and T IF { FAIL ; CDR ; UNIT ; PAIR } # Between Z + 24 and T
{ # after T { # after T
DUP ; CDDADAR # T DUP ; CDDADAR # T
PUSH (Uint64 86400) ; ADD # one day in second PUSH uint64 86400 ; ADD # one day in second
NOW ; COMPARE ; LT NOW ; COMPARE ; LT
IF { # Between T and T + 24 IF { # Between T and T + 24
# we only accept transactions from the buyer # we only accept transactions from the buyer
DUP ; CADR ; # we must receive (Left "buyer") DUP ; CADR ; # we must receive (Left "buyer")
IF_LEFT IF_LEFT
{ PUSH (String "buyer") ; COMPARE ; EQ ; { PUSH string "buyer" ; COMPARE ; EQ ;
IF { DUP ; CDADAR ; # amount already versed by the buyer IF { DUP ; CDADAR ; # amount already versed by the buyer
DIP { DUP ; CAAR } ; ADD ; # transaction DIP { DUP ; CAAR } ; ADD ; # transaction
# The amount must not exceed Q * K # The amount must not exceed Q * K
@ -1682,12 +1657,12 @@ The code of the contract is thus as follows.
IF { FAIL } { } } ; # abort or continue IF { FAIL } { } } ; # abort or continue
# then we rebuild the globals # then we rebuild the globals
DIP { DUP ; CDADDR } ; PAIR ; # seller amount DIP { DUP ; CDADDR } ; PAIR ; # seller amount
PUSH (Uint32 0) ; PAIR ; # delivery counter at 0 PUSH uint32 0 ; PAIR ; # delivery counter at 0
DIP { CDDR } ; PAIR ; # parameters DIP { CDDR } ; PAIR ; # parameters
# and return Unit # and return Unit
PUSH Unit ; PAIR } UNIT ; PAIR }
{ FAIL ; CDR ; PUSH Unit ; PAIR }} # (Left _) { FAIL ; CDR ; UNIT ; PAIR }} # (Left _)
{ FAIL ; DROP ; CDR ; PUSH Unit ; PAIR }} # (Right _) { FAIL ; DROP ; CDR ; UNIT ; PAIR }} # (Right _)
{ # After T + 24 { # After T + 24
# test if the required payment is reached # test if the required payment is reached
DUP ; CDDAAR ; # Q DUP ; CDDAAR ; # Q
@ -1697,13 +1672,13 @@ The code of the contract is thus as follows.
IF { # not reached, pay the seller and destroy the contract IF { # not reached, pay the seller and destroy the contract
BALANCE ; BALANCE ;
DIP { DUP ; CDDDDADR } # S DIP { DUP ; CDDDDADR } # S
PUSH Unit ; TRANSFER_TOKENS ; DROP ; UNIT ; TRANSFER_TOKENS ; DROP ;
# and return Unit # and return Unit
CDR ; PUSH Unit ; PAIR } CDR ; UNIT ; PAIR }
{ # otherwise continue { # otherwise continue
DUP ; CDDADAR # T DUP ; CDDADAR # T
PUSH (Uint64 86400) ; ADD ; PUSH uint64 86400 ; ADD ;
PUSH (Uint64 86400) ; ADD ; # two days in second PUSH uint64 86400 ; ADD ; # two days in second
NOW ; COMPARE ; LT NOW ; COMPARE ; LT
IF { # Between T + 24 and T + 48 IF { # Between T + 24 and T + 48
# We accept only delivery notifications, from W # We accept only delivery notifications, from W
@ -1713,13 +1688,13 @@ The code of the contract is thus as follows.
IF { FAIL } {} # fail if not the warehouse IF { FAIL } {} # fail if not the warehouse
DUP ; CADR ; # we must receive (Right amount) DUP ; CADR ; # we must receive (Right amount)
IF_LEFT IF_LEFT
{ FAIL ; DROP ; CDR ; PUSH Unit ; PAIR } # (Left _) { FAIL ; DROP ; CDR ; UNIT ; PAIR } # (Left _)
{ # We increment the counter { # We increment the counter
DIP { DUP ; CDAAR } ; ADD ; DIP { DUP ; CDAAR } ; ADD ;
# And rebuild the globals in advance # And rebuild the globals in advance
DIP { DUP ; CDADR } ; PAIR ; DIP { DUP ; CDADR } ; PAIR ;
DIP CDDR ; PAIR ; DIP CDDR ; PAIR ;
PUSH Unit ; PAIR ; UNIT ; PAIR ;
# We test if enough have been delivered # We test if enough have been delivered
DUP ; CDAAR ; DUP ; CDAAR ;
DIP { DUP ; CDDAAR } ; DIP { DUP ; CDDAAR } ;
@ -1728,13 +1703,13 @@ The code of the contract is thus as follows.
{ # Transfer all the money to the seller { # Transfer all the money to the seller
BALANCE ; # and destroy the contract BALANCE ; # and destroy the contract
DIP { DUP ; CDDDDADR } # S DIP { DUP ; CDDDDADR } # S
PUSH Unit ; TRANSFER_TOKENS ; DROP }}} UNIT ; TRANSFER_TOKENS ; DROP }}}
{ # after T + 48, transfer everything to the buyer { # after T + 48, transfer everything to the buyer
BALANCE ; # and destroy the contract BALANCE ; # and destroy the contract
DIP { DUP ; CDDDDAAR } # B DIP { DUP ; CDDDDAAR } # B
PUSH Unit ; TRANSFER_TOKENS ; DROP ; UNIT ; TRANSFER_TOKENS ; DROP ;
# and return unit # and return unit
CDR ; PUSH Unit ; PAIR }}}}}} CDR ; UNIT ; PAIR }}}}}}
X - Full grammar X - Full grammar
---------------- ----------------
@ -1750,21 +1725,21 @@ X - Full grammar
| Unit | Unit
| True | True
| False | False
| Pair <untagged data> <untagged data> | Pair <data> <data>
| Left <untagged data> | Left <data>
| Right <untagged data> | Right <data>
| Some <untagged data> | Some <data>
| None | None
| List <untagged data> ... | List <data> ...
| Set <untagged data> ... | Set <data> ...
| Map (Item <untagged data> <untagged data>) ... | Map (Item <data> <data>) ...
| instruction | instruction
<instruction> ::= <instruction> ::=
| { <instruction> ... } | { <instruction> ... }
| DROP | DROP
| DUP | DUP
| SWAP | SWAP
| PUSH <tagged data> | PUSH <type> <data>
| SOME | SOME
| NONE <type> | NONE <type>
| IF_NONE { <instruction> ... } { <instruction> ... } | IF_NONE { <instruction> ... } { <instruction> ... }

View File

@ -70,7 +70,7 @@ let rec unparse_stack
= function = function
| Empty, Empty_t -> [] | Empty, Empty_t -> []
| Item (v, rest), Item_t (ty, rest_ty) -> | Item (v, rest), Item_t (ty, rest_ty) ->
unparse_tagged_data ty v :: unparse_stack (rest, rest_ty) unparse_data ty v :: unparse_stack (rest, rest_ty)
let rec interp let rec interp
: type p r. : type p r.
@ -396,7 +396,7 @@ let rec interp
Contract.unconditional_spend ctxt source amount >>=? fun ctxt -> Contract.unconditional_spend ctxt source amount >>=? fun ctxt ->
Contract.credit ctxt destination amount >>=? fun ctxt -> Contract.credit ctxt destination amount >>=? fun ctxt ->
Contract.get_script ctxt destination >>=? fun destination_script -> Contract.get_script ctxt destination >>=? fun destination_script ->
let sto = unparse_untagged_data storage_type sto in let sto = unparse_data storage_type sto in
Contract.update_script_storage ctxt source sto >>=? fun ctxt -> Contract.update_script_storage ctxt source sto >>=? fun ctxt ->
begin match destination_script with begin match destination_script with
| No_script -> | No_script ->
@ -405,20 +405,20 @@ let rec interp
record_trace (Invalid_contract (loc, destination))) >>=? fun (Eq _) -> record_trace (Invalid_contract (loc, destination))) >>=? fun (Eq _) ->
return (ctxt, qta) return (ctxt, qta)
| Script { code ; storage } -> | Script { code ; storage } ->
let p = unparse_untagged_data tp p in let p = unparse_data tp p in
execute source destination ctxt storage code amount p qta execute source destination ctxt storage code amount p qta
>>=? fun (csto, ret, qta, ctxt) -> >>=? fun (csto, ret, qta, ctxt) ->
Contract.update_script_storage Contract.update_script_storage
ctxt destination csto >>=? fun ctxt -> ctxt destination csto >>=? fun ctxt ->
trace trace
(Invalid_contract (loc, destination)) (Invalid_contract (loc, destination))
(parse_untagged_data ctxt Unit_t ret) >>=? fun () -> (parse_data ctxt Unit_t ret) >>=? fun () ->
return (ctxt, qta) return (ctxt, qta)
end >>=? fun (ctxt, qta) -> end >>=? fun (ctxt, qta) ->
Contract.get_script ctxt source >>=? (function Contract.get_script ctxt source >>=? (function
| No_script -> assert false | No_script -> assert false
| Script { storage = { storage } } -> | Script { storage = { storage } } ->
parse_untagged_data ctxt storage_type storage >>=? fun sto -> parse_data ctxt storage_type storage >>=? fun sto ->
logged_return (Item ((), Item (sto, Empty)), qta - 1, ctxt)) logged_return (Item ((), Item (sto, Empty)), qta - 1, ctxt))
end end
| Transfer_tokens storage_type, | Transfer_tokens storage_type,
@ -428,20 +428,20 @@ let rec interp
Contract.get_script ctxt destination >>=? function Contract.get_script ctxt destination >>=? function
| No_script -> fail (Invalid_contract (loc, destination)) | No_script -> fail (Invalid_contract (loc, destination))
| Script { code ; storage } -> | Script { code ; storage } ->
let sto = unparse_untagged_data storage_type sto in let sto = unparse_data storage_type sto in
Contract.update_script_storage ctxt source sto >>=? fun ctxt -> Contract.update_script_storage ctxt source sto >>=? fun ctxt ->
let p = unparse_untagged_data tp p in let p = unparse_data tp p in
execute source destination ctxt storage code amount p qta execute source destination ctxt storage code amount p qta
>>=? fun (sto, ret, qta, ctxt) -> >>=? fun (sto, ret, qta, ctxt) ->
Contract.update_script_storage Contract.update_script_storage
ctxt destination sto >>=? fun ctxt -> ctxt destination sto >>=? fun ctxt ->
trace trace
(Invalid_contract (loc, destination)) (Invalid_contract (loc, destination))
(parse_untagged_data ctxt tr ret) >>=? fun v -> (parse_data ctxt tr ret) >>=? fun v ->
Contract.get_script ctxt source >>=? (function Contract.get_script ctxt source >>=? (function
| No_script -> assert false | No_script -> assert false
| Script { storage = { storage } } -> | Script { storage = { storage } } ->
parse_untagged_data ctxt storage_type storage >>=? fun sto -> parse_data ctxt storage_type storage >>=? fun sto ->
logged_return (Item (v, Item (sto, Empty)), qta - 1, ctxt)) logged_return (Item (v, Item (sto, Empty)), qta - 1, ctxt))
end end
| Create_account, | Create_account,
@ -457,7 +457,7 @@ let rec interp
Item (Lam (_, code), Item (init, rest)))))) -> Item (Lam (_, code), Item (init, rest)))))) ->
let code, storage = let code, storage =
{ code; arg_type = unparse_ty p; ret_type = unparse_ty r; storage_type = unparse_ty g }, { code; arg_type = unparse_ty p; ret_type = unparse_ty r; storage_type = unparse_ty g },
{ storage = unparse_untagged_data g init; storage_type = unparse_ty g } in { storage = unparse_data g init; storage_type = unparse_ty g } in
let storage_fee = Script.storage_cost storage in let storage_fee = Script.storage_cost storage in
let code_fee = Script.code_cost code in let code_fee = Script.code_cost code in
Lwt.return Tez.(code_fee +? storage_fee) >>=? fun script_fee -> Lwt.return Tez.(code_fee +? storage_fee) >>=? fun script_fee ->
@ -484,7 +484,7 @@ let rec interp
let res = Ed25519.check_signature key signature message in let res = Ed25519.check_signature key signature message in
logged_return (Item (res, rest), qta - 1, ctxt) logged_return (Item (res, rest), qta - 1, ctxt)
| H ty, Item (v, rest) -> | H ty, Item (v, rest) ->
let hash = Script.hash_expr (unparse_untagged_data ty v) in let hash = Script.hash_expr (unparse_data ty v) in
logged_return (Item (hash, rest), qta - 1, ctxt) logged_return (Item (hash, rest), qta - 1, ctxt)
| Steps_to_quota, rest -> | Steps_to_quota, rest ->
let steps = Script_int.of_int64 Uint32 (Int64.of_int qta) in let steps = Script_int.of_int64 Uint32 (Int64.of_int qta) in
@ -514,13 +514,13 @@ and execute ?log orig source ctxt storage script amount arg qta =
let arg_type_full = Pair_t (Pair_t (Tez_t, arg_type), storage_type) in let arg_type_full = Pair_t (Pair_t (Tez_t, arg_type), storage_type) in
let ret_type_full = Pair_t (ret_type, storage_type) in let ret_type_full = Pair_t (ret_type, storage_type) in
parse_lambda ctxt arg_type_full ret_type_full code >>=? fun lambda -> parse_lambda ctxt arg_type_full ret_type_full code >>=? fun lambda ->
parse_untagged_data ctxt arg_type arg >>=? fun arg -> parse_data ctxt arg_type arg >>=? fun arg ->
parse_untagged_data ctxt storage_type storage >>=? fun storage -> parse_data ctxt storage_type storage >>=? fun storage ->
interp ?log qta orig source amount ctxt lambda ((amount, arg), storage) interp ?log qta orig source amount ctxt lambda ((amount, arg), storage)
>>=? fun (ret, qta, ctxt) -> >>=? fun (ret, qta, ctxt) ->
let ret, storage = ret in let ret, storage = ret in
return (unparse_untagged_data storage_type storage, return (unparse_data storage_type storage,
unparse_untagged_data ret_type ret, unparse_data ret_type ret,
qta, ctxt) qta, ctxt)
let trace orig source ctxt storage script amount arg qta = let trace orig source ctxt storage script amount arg qta =

View File

@ -441,190 +441,7 @@ let comparable_ty_of_ty
| Timestamp_t -> ok Timestamp_key | Timestamp_t -> ok Timestamp_key
| ty -> error (Incomparable_type (Ty ty)) | ty -> error (Incomparable_type (Ty ty))
type ex_tagged_data = Ex : 'a ty * 'a -> ex_tagged_data let rec parse_data
let rec parse_tagged_data
: context -> Script.expr -> ex_tagged_data tzresult Lwt.t
= fun ctxt script_data ->
match script_data with
| Prim (_, "Unit", []) ->
return @@ Ex (Unit_t, ())
| Prim (loc, "Unit", l) ->
fail @@ Invalid_arity (loc, Constant, "Unit", 0, List.length l)
| String (_, v) ->
return @@ Ex (String_t, v)
| Prim (_, "String", [ arg ]) ->
parse_untagged_data ctxt String_t arg >>=? fun v ->
return @@ Ex (String_t, v)
| Prim (loc, "String", l) ->
fail @@ Invalid_arity (loc, Constant, "String", 1, List.length l)
| Prim (_, "True", []) ->
return @@ Ex (Bool_t, true)
| Prim (loc, "True", l) ->
fail @@ Invalid_arity (loc, Constant, "True", 0, List.length l)
| Prim (_, "False", []) ->
return @@ Ex (Bool_t, false)
| Prim (loc, "False", l) ->
fail @@ Invalid_arity (loc, Constant, "False", 0, List.length l)
| Prim (_, "Bool", [ arg ]) ->
parse_untagged_data ctxt Bool_t arg >>=? fun v ->
return @@ Ex (Bool_t, v)
| Prim (loc, "Bool", l) ->
fail @@ Invalid_arity (loc, Constant, "Bool", 1, List.length l)
| Prim (_, "Timestamp", [ arg ]) ->
parse_untagged_data ctxt Timestamp_t arg >>=? fun v ->
return @@ Ex (Timestamp_t, v)
| Prim (loc, "Timestamp", l) ->
fail @@ Invalid_arity (loc, Constant, "Timestamp", 1, List.length l)
| Prim (_, "Signature", [ arg ]) ->
parse_untagged_data ctxt Signature_t arg >>=? fun v ->
return @@ Ex (Signature_t, v)
| Prim (loc, "Signature", l) ->
fail @@ Invalid_arity (loc, Constant, "Signature", 1, List.length l)
| Prim (_, "Tez", [ arg ]) ->
parse_untagged_data ctxt Tez_t arg >>=? fun v ->
return @@ Ex (Tez_t, v)
| Prim (loc, "Tez", l) ->
fail @@ Invalid_arity (loc, Constant, "Tez", 1, List.length l)
| Prim (_, "Key", [ arg ]) ->
parse_untagged_data ctxt Key_t arg >>=? fun v ->
return @@ Ex (Key_t, v)
| Prim (loc, "Key", l) ->
fail @@ Invalid_arity (loc, Constant, "Key", 1, List.length l)
| Prim (_, "Int8", [ arg ]) ->
parse_untagged_data ctxt (Int_t Int8) arg >>=? fun v ->
return @@ Ex (Int_t Int8, v)
| Prim (loc, "Int8", l) ->
fail @@ Invalid_arity (loc, Constant, "Int8", 1, List.length l)
| Prim (_, "Int16", [ arg ]) ->
parse_untagged_data ctxt (Int_t Int16) arg >>=? fun v ->
return @@ Ex (Int_t Int16, v)
| Prim (loc, "Int16", l) ->
fail @@ Invalid_arity (loc, Constant, "Int16", 1, List.length l)
| Prim (_, "Int32", [ arg ]) ->
parse_untagged_data ctxt (Int_t Int32) arg >>=? fun v ->
return @@ Ex (Int_t Int32, v)
| Prim (loc, "Int32", l) ->
fail @@ Invalid_arity (loc, Constant, "Int32", 1, List.length l)
| Prim (_, "Int64", [ arg ]) ->
parse_untagged_data ctxt (Int_t Int64) arg >>=? fun v ->
return @@ Ex (Int_t Int64, v)
| Prim (loc, "Int64", l) ->
fail @@ Invalid_arity (loc, Constant, "Int64", 1, List.length l)
| Prim (_, "Uint8", [ arg ]) ->
parse_untagged_data ctxt (Int_t Uint8) arg >>=? fun v ->
return @@ Ex (Int_t Uint8, v)
| Prim (loc, "Uint8", l) ->
fail @@ Invalid_arity (loc, Constant, "Uint8", 1, List.length l)
| Prim (_, "Uint16", [ arg ]) ->
parse_untagged_data ctxt (Int_t Uint16) arg >>=? fun v ->
return @@ Ex (Int_t Uint16, v)
| Prim (loc, "Uint16", l) ->
fail @@ Invalid_arity (loc, Constant, "Uint16", 1, List.length l)
| Prim (_, "Uint32", [ arg ]) ->
parse_untagged_data ctxt (Int_t Uint32) arg >>=? fun v ->
return @@ Ex (Int_t Uint32, v)
| Prim (loc, "Uint32", l) ->
fail @@ Invalid_arity (loc, Constant, "Uint32", 1, List.length l)
| Prim (_, "Uint64", [ arg ]) ->
parse_untagged_data ctxt (Int_t Uint64) arg >>=? fun v ->
return @@ Ex (Int_t Uint64, v)
| Prim (loc, "Uint64", l) ->
fail @@ Invalid_arity (loc, Constant, "Uint64", 1, List.length l)
| Prim (_, "Left", [ l; tr ]) ->
parse_ty tr >>=? fun (Ex tr) ->
parse_tagged_data ctxt l >>=? fun (Ex (tl, l)) ->
return @@ Ex (Union_t (tl, tr), L l)
| Prim (loc, "Left", l) ->
fail @@ Invalid_arity (loc, Constant, "Left", 2, List.length l)
| Prim (_, "Right", [ tl; r ]) ->
parse_ty tl >>=? fun (Ex tl) ->
parse_tagged_data ctxt r >>=? fun (Ex (tr, r)) ->
return @@ Ex (Union_t (tl, tr), R r)
| Prim (loc, "Right", l) ->
fail @@ Invalid_arity (loc, Constant, "Right", 2, List.length l)
| Prim (_, "Or", [ tl; tr; arg ]) ->
parse_ty tl >>=? fun (Ex tl) ->
parse_ty tr >>=? fun (Ex tr) ->
parse_untagged_data ctxt (Union_t (tl, tr)) arg >>=? fun v ->
return @@ Ex (Union_t (tl, tr), v)
| Prim (loc, "Or", l) ->
fail @@ Invalid_arity (loc, Constant, "Or", 3, List.length l)
| Prim (_, "Some", [ r ]) ->
parse_tagged_data ctxt r >>=? fun (Ex (tr, r)) ->
return @@ Ex (Option_t tr, Some r)
| Prim (_, "Some", [ tr; r ]) ->
parse_ty tr >>=? fun (Ex tr) ->
parse_untagged_data ctxt tr r >>=? fun r ->
return @@ Ex (Option_t tr, Some r)
| Prim (loc, "Some", l) ->
fail @@ Invalid_arity (loc, Constant, "Some", 1, List.length l)
| Prim (_, "None", [ tr ]) ->
parse_ty tr >>=? fun (Ex tr) ->
return @@ Ex (Option_t tr, None)
| Prim (loc, "None", l) ->
fail @@ Invalid_arity (loc, Constant, "None", 1, List.length l)
| Prim (_, "Option", [ tr; r ]) ->
parse_ty tr >>=? fun (Ex tr) ->
parse_untagged_data ctxt (Option_t tr) r >>=? fun r ->
return @@ Ex (Option_t tr, r)
| Prim (loc, "Option", l) ->
fail @@ Invalid_arity (loc, Constant, "Option", 2, List.length l)
| Prim (_, "Pair", [ tl; tr; l; r ]) ->
parse_ty tl >>=? fun (Ex tl) ->
parse_ty tr >>=? fun (Ex tr) ->
parse_untagged_data ctxt tl l >>=? fun l ->
parse_untagged_data ctxt tr r >>=? fun r ->
return @@ Ex (Pair_t (tl, tr), (l, r))
| Prim (_, "Pair", [ l; r ]) ->
parse_tagged_data ctxt l >>=? fun (Ex (tl, l)) ->
parse_tagged_data ctxt r >>=? fun (Ex (tr, r)) ->
return @@ Ex (Pair_t (tl, tr), (l, r))
| Prim (loc, "Pair", l) ->
fail @@ Invalid_arity (loc, Constant, "Pair", 4, List.length l)
| Prim (loc, "List", t :: items) ->
parse_ty t >>=? fun (Ex t) ->
parse_untagged_data ctxt
(List_t t) (Prim (loc, "List", items)) >>=? fun l ->
return @@ Ex (List_t t, l)
| Prim (loc, "List", l) ->
fail @@ Invalid_arity (loc, Constant, "List", 1, List.length l)
| Prim (loc, "Set", t :: items) ->
parse_comparable_ty t >>=? fun (Ex t) ->
parse_untagged_data ctxt
(Set_t t) (Prim (loc, "Set", items)) >>=? fun l ->
return @@ Ex (Set_t t, l)
| Prim (loc, "Set", l) ->
fail @@ Invalid_arity (loc, Constant, "Set", 1, List.length l)
| Prim (loc, "Map", kt :: vt :: items) ->
parse_comparable_ty kt >>=? fun (Ex kt) ->
parse_ty vt >>=? fun (Ex vt) ->
parse_untagged_data ctxt
(Map_t (kt, vt)) (Prim (loc, "Map", items)) >>=? fun l ->
return @@ Ex (Map_t (kt, vt), l)
| Prim (loc, "Map", l) ->
fail @@ Invalid_arity (loc, Constant, "Map", 2, List.length l)
| Prim (_, "Contract", [ at; rt; c ]) ->
parse_ty at >>=? fun (Ex at) ->
parse_ty rt >>=? fun (Ex rt) ->
parse_untagged_data ctxt (Contract_t (at, rt)) c >>=? fun l ->
return @@ Ex (Contract_t (at, rt), l)
| Prim (loc, "Contract", l) ->
fail @@ Invalid_arity (loc, Constant, "Contract", 3, List.length l)
| Prim (loc, "Lambda", [ at ; rt ; code ]) ->
expect_sequence_parameter loc Constant "Lambda" 2 code >>=? fun () ->
parse_ty at >>=? fun (Ex at) ->
parse_ty rt >>=? fun (Ex rt) ->
parse_untagged_data ctxt (Lambda_t (at, rt)) code >>=? fun l ->
return @@ Ex (Lambda_t (at, rt), l)
| Prim (loc, "Lambda", l) ->
fail @@ Invalid_arity (loc, Constant, "Lambda", 3, List.length l)
| Prim (loc, name, _) ->
fail @@ Invalid_primitive (loc, Constant, name)
| Seq (loc, _) | Int (loc, _) ->
fail @@ Invalid_expression_kind loc
and parse_untagged_data
: type a. context -> a ty -> Script.expr -> a tzresult Lwt.t : type a. context -> a ty -> Script.expr -> a tzresult Lwt.t
= fun ctxt ty script_data -> = fun ctxt ty script_data ->
match ty, script_data with match ty, script_data with
@ -704,8 +521,8 @@ and parse_untagged_data
fail @@ Invalid_constant (loc, "contract") fail @@ Invalid_constant (loc, "contract")
(* Pairs *) (* Pairs *)
| Pair_t (ta, tb), Prim (_, "Pair", [ va; vb ]) -> | Pair_t (ta, tb), Prim (_, "Pair", [ va; vb ]) ->
parse_untagged_data ctxt ta va >>=? fun va -> parse_data ctxt ta va >>=? fun va ->
parse_untagged_data ctxt tb vb >>=? fun vb -> parse_data ctxt tb vb >>=? fun vb ->
return (va, vb) return (va, vb)
| Pair_t _, Prim (loc, "Pair", l) -> | Pair_t _, Prim (loc, "Pair", l) ->
fail @@ Invalid_arity (loc, Constant, "Pair", 2, List.length l) fail @@ Invalid_arity (loc, Constant, "Pair", 2, List.length l)
@ -713,12 +530,12 @@ and parse_untagged_data
fail @@ Invalid_constant (loc, "pair") fail @@ Invalid_constant (loc, "pair")
(* Unions *) (* Unions *)
| Union_t (tl, _), Prim (_, "Left", [ v ]) -> | Union_t (tl, _), Prim (_, "Left", [ v ]) ->
parse_untagged_data ctxt tl v >>=? fun v -> parse_data ctxt tl v >>=? fun v ->
return (L v) return (L v)
| Union_t _, Prim (loc, "Left", l) -> | Union_t _, Prim (loc, "Left", l) ->
fail @@ Invalid_arity (loc, Constant, "Left", 1, List.length l) fail @@ Invalid_arity (loc, Constant, "Left", 1, List.length l)
| Union_t (_, tr), Prim (_, "Right", [ v ]) -> | Union_t (_, tr), Prim (_, "Right", [ v ]) ->
parse_untagged_data ctxt tr v >>=? fun v -> parse_data ctxt tr v >>=? fun v ->
return (R v) return (R v)
| Union_t _, Prim (loc, "Right", l) -> | Union_t _, Prim (loc, "Right", l) ->
fail @@ Invalid_arity (loc, Constant, "Right", 1, List.length l) fail @@ Invalid_arity (loc, Constant, "Right", 1, List.length l)
@ -731,7 +548,7 @@ and parse_untagged_data
fail @@ Invalid_constant (loc, "lambda") fail @@ Invalid_constant (loc, "lambda")
(* Options *) (* Options *)
| Option_t t, Prim (_, "Some", [ v ]) -> | Option_t t, Prim (_, "Some", [ v ]) ->
parse_untagged_data ctxt t v >>=? fun v -> parse_data ctxt t v >>=? fun v ->
return (Some v) return (Some v)
| Option_t _, Prim (loc, "Some", l) -> | Option_t _, Prim (loc, "Some", l) ->
fail @@ Invalid_arity (loc, Constant, "Some", 1, List.length l) fail @@ Invalid_arity (loc, Constant, "Some", 1, List.length l)
@ -745,7 +562,7 @@ and parse_untagged_data
| List_t t, Prim (_, "List", vs) -> | List_t t, Prim (_, "List", vs) ->
fold_left_s fold_left_s
(fun rest v -> (fun rest v ->
parse_untagged_data ctxt t v >>=? fun v -> parse_data ctxt t v >>=? fun v ->
return (v :: rest)) return (v :: rest))
[] vs [] vs
| List_t _, (Prim (loc, _, _) | Int (loc, _) | String (loc, _) | Seq (loc, _)) -> | List_t _, (Prim (loc, _, _) | Int (loc, _) | String (loc, _) | Seq (loc, _)) ->
@ -754,7 +571,7 @@ and parse_untagged_data
| Set_t t, Prim (_, "Set", vs) -> | Set_t t, Prim (_, "Set", vs) ->
fold_left_s fold_left_s
(fun acc v -> (fun acc v ->
parse_untagged_comparable_data ctxt t v >>=? fun v -> parse_comparable_data ctxt t v >>=? fun v ->
return (set_update v true acc)) return (set_update v true acc))
(empty_set t) vs (empty_set t) vs
| Set_t _, (Prim (loc, _, _) | Int (loc, _) | String (loc, _) | Seq (loc, _)) -> | Set_t _, (Prim (loc, _, _) | Int (loc, _) | String (loc, _) | Seq (loc, _)) ->
@ -764,8 +581,8 @@ and parse_untagged_data
fold_left_s fold_left_s
(fun acc -> function (fun acc -> function
| Prim (_, "Item", [ k; v ]) -> | Prim (_, "Item", [ k; v ]) ->
parse_untagged_comparable_data ctxt tk k >>=? fun k -> parse_comparable_data ctxt tk k >>=? fun k ->
parse_untagged_data ctxt tv v >>=? fun v -> parse_data ctxt tv v >>=? fun v ->
return (map_update k (Some v) acc) return (map_update k (Some v) acc)
| Prim (loc, "Item", l) -> | Prim (loc, "Item", l) ->
fail @@ Invalid_arity (loc, Constant, "Item", 2, List.length l) fail @@ Invalid_arity (loc, Constant, "Item", 2, List.length l)
@ -775,10 +592,10 @@ and parse_untagged_data
| Map_t _, (Prim (loc, _, _) | Int (loc, _) | String (loc, _) | Seq (loc, _)) -> | Map_t _, (Prim (loc, _, _) | Int (loc, _) | String (loc, _) | Seq (loc, _)) ->
fail @@ Invalid_constant (loc, "map") fail @@ Invalid_constant (loc, "map")
and parse_untagged_comparable_data and parse_comparable_data
: type a. context -> a comparable_ty -> Script.expr -> a tzresult Lwt.t : type a. context -> a comparable_ty -> Script.expr -> a tzresult Lwt.t
= fun ctxt ty script_data -> = fun ctxt ty script_data ->
parse_untagged_data ctxt (ty_of_comparable_ty ty) script_data parse_data ctxt (ty_of_comparable_ty ty) script_data
and parse_lambda and parse_lambda
: type arg ret storage. context -> : type arg ret storage. context ->
@ -817,9 +634,10 @@ and parse_instr
| Prim (loc, "SWAP", []), | Prim (loc, "SWAP", []),
Item_t (v, Item_t (w, rest)) -> Item_t (v, Item_t (w, rest)) ->
return (typed loc (Swap, Item_t (w, Item_t (v, rest)))) return (typed loc (Swap, Item_t (w, Item_t (v, rest))))
| Prim (loc, "PUSH", [ td ]), | Prim (loc, "PUSH", [ t ; d ]),
stack -> stack ->
parse_tagged_data ctxt td >>=? fun (Ex (t, v)) -> parse_ty t >>=? fun (Ex t) ->
parse_data ctxt t d >>=? fun v ->
return (typed loc (Const v, Item_t (t, stack))) return (typed loc (Const v, Item_t (t, stack)))
(* options *) (* options *)
| Prim (loc, "SOME", []), | Prim (loc, "SOME", []),
@ -1497,7 +1315,7 @@ let rec unparse_ty
let tr = unparse_ty utr in let tr = unparse_ty utr in
Prim (-1, "map", [ ta; tr ]) Prim (-1, "map", [ ta; tr ])
let rec unparse_untagged_data let rec unparse_data
: type a. a ty -> a -> Script.expr : type a. a ty -> a -> Script.expr
= fun ty a -> match ty, a with = fun ty a -> match ty, a with
| Unit_t, () -> | Unit_t, () ->
@ -1524,29 +1342,29 @@ let rec unparse_untagged_data
| Key_t, k -> | Key_t, k ->
String (-1, Ed25519.Public_key_hash.to_b48check k) String (-1, Ed25519.Public_key_hash.to_b48check k)
| Pair_t (tl, tr), (l, r) -> | Pair_t (tl, tr), (l, r) ->
let l = unparse_untagged_data tl l in let l = unparse_data tl l in
let r = unparse_untagged_data tr r in let r = unparse_data tr r in
Prim (-1, "Pair", [ l; r ]) Prim (-1, "Pair", [ l; r ])
| Union_t (tl, _), L l -> | Union_t (tl, _), L l ->
let l = unparse_untagged_data tl l in let l = unparse_data tl l in
Prim (-1, "Left", [ l ]) Prim (-1, "Left", [ l ])
| Union_t (_, tr), R r -> | Union_t (_, tr), R r ->
let r = unparse_untagged_data tr r in let r = unparse_data tr r in
Prim (-1, "Right", [ r ]) Prim (-1, "Right", [ r ])
| Option_t t, Some v -> | Option_t t, Some v ->
let v = unparse_untagged_data t v in let v = unparse_data t v in
Prim (-1, "Some", [ v ]) Prim (-1, "Some", [ v ])
| Option_t _, None -> | Option_t _, None ->
Prim (-1, "None", []) Prim (-1, "None", [])
| List_t t, items -> | List_t t, items ->
let items = List.map (unparse_untagged_data t) items in let items = List.map (unparse_data t) items in
Prim (-1, "List", items) Prim (-1, "List", items)
| Set_t t, set -> | Set_t t, set ->
let t = ty_of_comparable_ty t in let t = ty_of_comparable_ty t in
let items = let items =
set_fold set_fold
(fun item acc -> (fun item acc ->
unparse_untagged_data t item :: acc ) unparse_data t item :: acc )
set [] in set [] in
Prim (-1, "Set", items) Prim (-1, "Set", items)
| Map_t (kt, vt), map -> | Map_t (kt, vt), map ->
@ -1554,92 +1372,14 @@ let rec unparse_untagged_data
let items = let items =
map_fold (fun k v acc -> map_fold (fun k v acc ->
Prim (-1, "Item", Prim (-1, "Item",
[ unparse_untagged_data kt k; [ unparse_data kt k;
unparse_untagged_data vt v ]) unparse_data vt v ])
:: acc) :: acc)
map [] in map [] in
Prim (-1, "Map", items) Prim (-1, "Map", items)
| Lambda_t _, Lam (_, original_code) -> | Lambda_t _, Lam (_, original_code) ->
original_code original_code
let rec unparse_tagged_data
: type a. a ty -> a -> Script.expr
= fun ty a -> match ty, a with
| Unit_t, () ->
Prim (-1, "Unit", [])
| Int_t k, v ->
Prim (-1, string_of_int_kind k, [ String (-1, Int64.to_string (to_int64 k v))])
| String_t, s ->
Prim (-1, "String", [ String (-1, s) ])
| Bool_t, true ->
Prim (-1, "Bool", [ Prim (-1, "True", []) ])
| Bool_t, false ->
Prim (-1, "Bool", [ Prim (-1, "False", []) ])
| Timestamp_t, t ->
Prim (-1, "Timestamp", [ String (-1, Timestamp.to_notation t) ])
| Contract_t (ta, tr), (_, _, c) ->
let ta = unparse_ty ta in
let tr = unparse_ty tr in
Prim (-1, "Contract", [ ta; tr; String (-1, Contract.to_b48check c) ])
| Signature_t, s ->
let text =
Hex_encode.hex_encode
(MBytes.to_string (Data_encoding.Binary.to_bytes Ed25519.signature_encoding s)) in
Prim (-1, "Signature", [ String (-1, text) ])
| Tez_t, v ->
Prim (-1, "Tez", [ String (-1, Tez.to_string v) ])
| Key_t, k ->
Prim (-1, "Key", [ String (-1, Ed25519.Public_key_hash.to_b48check k)])
| Pair_t (tl, tr), (l, r) ->
let l = unparse_untagged_data tl l in
let r = unparse_untagged_data tr r in
let tl = unparse_ty tl in
let tr = unparse_ty tr in
Prim (-1, "Pair", [ tl; tr; l; r ])
| Union_t (tl, tr), L l ->
let l = unparse_tagged_data tl l in
let tr = unparse_ty tr in
Prim (-1, "Left", [ l; tr ])
| Union_t (tl, tr), R r ->
let r = unparse_tagged_data tr r in
let tl = unparse_ty tl in
Prim (-1, "Right", [ tl; r ])
| Option_t t, Some v ->
let v = unparse_tagged_data t v in
Prim (-1, "Some", [ v ])
| Option_t t, None ->
let t = unparse_ty t in
Prim (-1, "None", [ t ])
| List_t t, items ->
let items = List.map (unparse_untagged_data t) items in
let t = unparse_ty t in
Prim (-1, "List", t :: items)
| Set_t t, set ->
let t = ty_of_comparable_ty t in
let items =
set_fold
(fun item acc ->
unparse_untagged_data t item :: acc )
set [] in
let t = unparse_ty t in
Prim (-1, "Set", t :: items)
| Map_t (kt, vt), map ->
let kt = ty_of_comparable_ty kt in
let items =
map_fold (fun k v acc ->
Prim (-1, "Item",
[ unparse_untagged_data kt k;
unparse_untagged_data vt v ])
:: acc)
map [] in
let kt = unparse_ty kt in
let vt = unparse_ty vt in
Prim (-1, "Map", kt :: vt :: items)
| Lambda_t (ta, tr), Lam (_, original_code) ->
let ta = unparse_ty ta in
let tr = unparse_ty tr in
Prim (-1, "Lambda", [ ta; tr; original_code ])
type ex_script = Ex : ('a, 'b, 'c) script -> ex_script type ex_script = Ex : ('a, 'b, 'c) script -> ex_script
let parse_script let parse_script
@ -1650,7 +1390,7 @@ let parse_script
parse_ty storage_type >>=? fun (Ex storage_type) -> parse_ty storage_type >>=? fun (Ex storage_type) ->
let arg_type_full = Pair_t (Pair_t (Tez_t, arg_type), storage_type) in let arg_type_full = Pair_t (Pair_t (Tez_t, arg_type), storage_type) in
let ret_type_full = Pair_t (ret_type, storage_type) in let ret_type_full = Pair_t (ret_type, storage_type) in
parse_untagged_data ctxt storage_type storage >>=? fun storage -> parse_data ctxt storage_type storage >>=? fun storage ->
parse_lambda ctxt ~storage_type arg_type_full ret_type_full code >>=? fun code -> parse_lambda ctxt ~storage_type arg_type_full ret_type_full code >>=? fun code ->
return (Ex { code; arg_type; ret_type; storage; storage_type }) return (Ex { code; arg_type; ret_type; storage; storage_type })
@ -1720,15 +1460,9 @@ let typecheck_code
>>=? fun (Lam (descr,_)) -> >>=? fun (Lam (descr,_)) ->
return (type_map descr) return (type_map descr)
let typecheck_tagged_data let typecheck_data
: context -> Script.expr -> unit tzresult Lwt.t
= fun ctxt data ->
parse_tagged_data ctxt data >>=? fun (Ex _) ->
return ()
let typecheck_untagged_data
: context -> Script.expr * Script.expr -> unit tzresult Lwt.t : context -> Script.expr * Script.expr -> unit tzresult Lwt.t
= fun ctxt (data, exp_ty) -> = fun ctxt (data, exp_ty) ->
parse_ty exp_ty >>=? fun (Ex exp_ty) -> parse_ty exp_ty >>=? fun (Ex exp_ty) ->
parse_untagged_data ctxt exp_ty data >>=? fun _ -> parse_data ctxt exp_ty data >>=? fun _ ->
return () return ()

View File

@ -368,27 +368,19 @@ module Helpers = struct
~output: (wrap_tzerror Script_ir_translator.type_map_enc) ~output: (wrap_tzerror Script_ir_translator.type_map_enc)
RPC.Path.(custom_root / "helpers" / "typecheck_code") RPC.Path.(custom_root / "helpers" / "typecheck_code")
let typecheck_tagged_data custom_root = let typecheck_data custom_root =
RPC.service RPC.service
~description: "Check that some tagged data expression is well formed \ ~description: "Check that some data expression is well formed \
and well typed in the current context"
~input: (obj1 (req "data" Script.expr_encoding))
~output: (wrap_tzerror empty)
RPC.Path.(custom_root / "helpers" / "typecheck_tagged_data")
let typecheck_untagged_data custom_root =
RPC.service
~description: "Check that some untagged data expression is well formed \
and of a given type in the current context" and of a given type in the current context"
~input: (obj2 ~input: (obj2
(req "data" Script.expr_encoding) (req "data" Script.expr_encoding)
(req "type" Script.expr_encoding)) (req "type" Script.expr_encoding))
~output: (wrap_tzerror empty) ~output: (wrap_tzerror empty)
RPC.Path.(custom_root / "helpers" / "typecheck_untagged_data") RPC.Path.(custom_root / "helpers" / "typecheck_data")
let hash_data custom_root = let hash_data custom_root =
RPC.service RPC.service
~description: "Computes the hash of some (untagged) data expression \ ~description: "Computes the hash of some data expression \
using the same algorithm as script instruction H" using the same algorithm as script instruction H"
~input: (obj1 (req "data" Script.expr_encoding)) ~input: (obj1 (req "data" Script.expr_encoding))
~output: (wrap_tzerror @@ ~output: (wrap_tzerror @@

View File

@ -226,12 +226,8 @@ let () =
Script_ir_translator.typecheck_code Script_ir_translator.typecheck_code
let () = let () =
register1 Services.Helpers.typecheck_tagged_data register1 Services.Helpers.typecheck_data
Script_ir_translator.typecheck_tagged_data Script_ir_translator.typecheck_data
let () =
register1 Services.Helpers.typecheck_untagged_data
Script_ir_translator.typecheck_untagged_data
let () = let () =
register1 Services.Helpers.hash_data register1 Services.Helpers.hash_data

View File

@ -1,8 +1,8 @@
parameter unit parameter unit
code code
{ # This contract stop to accept transactions after N incoming transactions { # This contract stop to accept transactions after N incoming transactions
CDR ; PUSH (Uint32 1) ; SWAP ; SUB ; CDR ; PUSH uint32 1 ; SWAP ; SUB ;
DUP ; PUSH (Uint32 0) ; COMPARE ; EQ ; IF { FAIL } {} ; DUP ; PUSH uint32 0 ; COMPARE ; EQ ; IF { FAIL } {} ;
UNIT ; PAIR } UNIT ; PAIR }
return unit return unit
storage uint32 storage uint32