From f7ef0472be5cac59aefe96dd1318d7c5ef5aa92c Mon Sep 17 00:00:00 2001 From: Tom Jack Date: Mon, 25 Nov 2019 17:30:12 -0600 Subject: [PATCH] Add command for measuring contracts --- src/bin/cli.ml | 16 + src/bin/expect_tests/contract_tests.ml | 385 +++++++++++++++++- src/bin/expect_tests/help_tests.ml | 4 + vendors/ligo-utils/tezos-utils/x_michelson.ml | 5 + 4 files changed, 408 insertions(+), 2 deletions(-) diff --git a/src/bin/cli.ml b/src/bin/cli.ml index 4b8245e73..c2f1ec9f7 100644 --- a/src/bin/cli.ml +++ b/src/bin/cli.ml @@ -98,6 +98,21 @@ let compile_file = let docs = "Subcommand: compile a contract. See `ligo " ^ cmdname ^ " --help' for a list of options specific to this subcommand." in (term , Term.info ~docs cmdname) +let measure_contract = + let f source_file entry_point syntax display_format = + toplevel ~display_format @@ + let%bind contract = + trace (simple_info "compiling contract to michelson") @@ + Ligo.Compile.Of_source.compile_file_contract_entry source_file entry_point (Syntax_name syntax) in + let open Tezos_utils in + ok @@ Format.asprintf "%d bytes\n" (Michelson.measure contract) + in + let term = + Term.(const f $ source_file 0 $ entry_point 1 $ syntax $ display_format) in + let cmdname = "measure-contract" in + let doc = "Subcommand: measure a contract's compiled size in bytes." in + (term , Term.info ~doc cmdname) + let compile_parameter = let f source_file entry_point expression syntax display_format michelson_format = toplevel ~display_format @@ @@ -190,6 +205,7 @@ let compile_expression = let run ?argv () = Term.eval_choice ?argv main [ compile_file ; + measure_contract ; compile_parameter ; compile_storage ; compile_expression ; diff --git a/src/bin/expect_tests/contract_tests.ml b/src/bin/expect_tests/contract_tests.ml index fef145694..b78762e37 100644 --- a/src/bin/expect_tests/contract_tests.ml +++ b/src/bin/expect_tests/contract_tests.ml @@ -3,7 +3,22 @@ open Cli_expect let contract basename = "../../test/contracts/" ^ basename -let %expect_test _ = +let%expect_test _ = + run_ligo_good [ "measure-contract" ; contract "coase.ligo" ; "main" ] ; + [%expect {| 3098 bytes |}] ; + + run_ligo_good [ "measure-contract" ; contract "multisig.ligo" ; "main" ] ; + [%expect {| 1367 bytes |}] ; + + run_ligo_good [ "measure-contract" ; contract "multisig-v2.ligo" ; "main" ] ; + [%expect {| 861 bytes |}] ; + + run_ligo_good [ "measure-contract" ; contract "vote.mligo" ; "main" ] ; + [%expect {| 1344 bytes |}] ; + + () + +let%expect_test _ = run_ligo_good [ "compile-contract" ; contract "coase.ligo" ; "main" ] ; [%expect {| { parameter @@ -288,4 +303,370 @@ let %expect_test _ = DIP { DIP 6 { DUP } ; DIG 6 } ; EXEC ; DIP { DROP 2 } } ; - DIP { DROP 6 } } } |} ] ; + DIP { DROP 6 } } } |} ] + +let%expect_test _ = + run_ligo_good [ "compile-contract" ; contract "multisig.ligo" ; "main" ] ; + [%expect {| + { parameter + (pair (pair (nat %counter) (lambda %message unit (list operation))) + (list %signatures (pair key_hash signature))) ; + storage + (pair (pair (list %auth key) (nat %counter)) (pair (string %id) (nat %threshold))) ; + code { DUP ; + LAMBDA + (pair (pair (pair (nat %counter) (lambda %message unit (list operation))) + (list %signatures (pair key_hash signature))) + (pair (pair (list %auth key) (nat %counter)) (pair (string %id) (nat %threshold)))) + (pair (list operation) + (pair (pair (list %auth key) (nat %counter)) (pair (string %id) (nat %threshold)))) + { DUP ; + CAR ; + DIP { DUP } ; + SWAP ; + CDR ; + DIP { DUP } ; + SWAP ; + CAR ; + CDR ; + DIP 2 { DUP } ; + DIG 2 ; + CAR ; + CAR ; + DIP { DIP { DUP } ; SWAP ; CAR ; CDR } ; + COMPARE ; + NEQ ; + IF { PUSH string "Counters does not match" ; FAILWITH } + { DUP ; + DIP { DIP 2 { DUP } ; DIG 2 ; CAR ; CAR } ; + PAIR ; + DIP { DIP { DUP } ; SWAP ; CDR ; CAR ; CHAIN_ID ; SWAP ; PAIR } ; + PAIR ; + PACK ; + PUSH nat 0 ; + DIP 3 { DUP } ; + DIG 3 ; + CAR ; + CAR ; + DIP 5 { DUP } ; + DIG 5 ; + CDR ; + DIP { DUP ; DIP { DIP { DUP } ; SWAP } ; PAIR } ; + ITER { SWAP ; + PAIR ; + DUP ; + CAR ; + DIP { DUP } ; + SWAP ; + CDR ; + DIP { DUP } ; + SWAP ; + CAR ; + IF_CONS + { DIP { DUP } ; + SWAP ; + DIP { DIP 3 { DUP } ; DIG 3 ; CDR } ; + PAIR ; + DIP 4 { DROP } ; + DUG 3 ; + DIP 2 { DUP } ; + DIG 2 ; + CAR ; + DIP { DUP ; HASH_KEY } ; + COMPARE ; + EQ ; + IF { DUP ; + DIP { DIP 2 { DUP } ; DIG 2 ; CDR ; DIP { DIP 7 { DUP } ; DIG 7 } } ; + CHECK_SIGNATURE ; + IF { DIP 3 { DUP } ; + DIG 3 ; + CDR ; + PUSH nat 1 ; + ADD ; + DIP { DIP 3 { DUP } ; DIG 3 ; CAR } ; + SWAP ; + PAIR ; + DIP 4 { DROP } ; + DUG 3 ; + PUSH unit Unit } + { PUSH string "Invalid signature" ; FAILWITH } } + { PUSH unit Unit } ; + DIP { DROP 2 } } + { PUSH unit Unit } ; + DROP ; + DIP { DUP } ; + SWAP ; + DIP { DROP 3 } } ; + DUP ; + CAR ; + DIP { DIP { DUP } ; SWAP ; DROP } ; + SWAP ; + DIP { DIP { DROP } } ; + DUP ; + CDR ; + DIP { DIP 2 { DUP } ; DIG 2 ; DROP } ; + DIP 3 { DROP } ; + DUG 2 ; + DROP ; + DIP { DUP } ; + SWAP ; + DIP { DIP 4 { DUP } ; DIG 4 ; CDR ; CDR } ; + COMPARE ; + LT ; + IF { PUSH string "Not enough signatures passed the check" ; FAILWITH } + { DIP 4 { DUP } ; + DIG 4 ; + CAR ; + CDR ; + PUSH nat 1 ; + ADD ; + DIP { DIP 4 { DUP } ; DIG 4 ; DUP ; CDR ; SWAP ; CAR ; CAR } ; + SWAP ; + PAIR ; + PAIR ; + DIP 5 { DROP } ; + DUG 4 ; + PUSH unit Unit } ; + DIP { DROP 3 } } ; + DROP ; + DUP ; + UNIT ; + EXEC ; + DIP { DIP { DUP } ; SWAP } ; + PAIR ; + DIP { DROP 4 } } ; + SWAP ; + CAR ; + DIP 2 { DUP } ; + DIG 2 ; + CDR ; + DIP { DUP } ; + SWAP ; + DUP ; + DIP { DIP { DUP } ; SWAP } ; + PAIR ; + DIP { DIP 3 { DUP } ; DIG 3 } ; + EXEC ; + DIP { DROP 5 } } } |} ] + +let%expect_test _ = + run_ligo_good [ "compile-contract" ; contract "multisig-v2.ligo" ; "main" ] ; + [%expect {| + { parameter (lambda unit (list operation)) ; + storage + (pair (pair (set %auth address) (big_map %message_store bytes (set address))) + (nat %threshold)) ; + code { DUP ; + LAMBDA + (pair (lambda unit (list operation)) + (pair (pair (set %auth address) (big_map %message_store bytes (set address))) + (nat %threshold))) + (pair (list operation) + (pair (pair (set %auth address) (big_map %message_store bytes (set address))) + (nat %threshold))) + { DUP ; + CAR ; + DIP { DUP } ; + SWAP ; + CDR ; + DUP ; + CAR ; + CAR ; + SENDER ; + MEM ; + NOT ; + IF { PUSH string "Unauthorized address" ; FAILWITH } { PUSH unit Unit } ; + DROP ; + DIP { DUP } ; + SWAP ; + DUP ; + PACK ; + DUP ; + NIL operation ; + SWAP ; + DIP { DIP 3 { DUP } ; DIG 3 ; CAR ; CDR } ; + GET ; + IF_NONE + { EMPTY_SET address } + { DUP ; PUSH bool True ; SENDER ; UPDATE ; DIP { DROP } } ; + DUP ; + SIZE ; + DIP { DIP 4 { DUP } ; DIG 4 ; CDR } ; + COMPARE ; + GE ; + IF { DIP 2 { DUP } ; + DIG 2 ; + DIP { DIP 4 { DUP } ; DIG 4 ; CAR ; CDR ; NONE (set address) } ; + UPDATE ; + DIP { DIP 4 { DUP } ; DIG 4 ; DUP ; CDR ; SWAP ; CAR ; CAR } ; + SWAP ; + PAIR ; + PAIR ; + DIP 5 { DROP } ; + DUG 4 ; + DIP 3 { DUP } ; + DIG 3 ; + UNIT ; + EXEC ; + DIP { DIP { DUP } ; SWAP ; DROP } ; + SWAP ; + DIP { DIP { DROP } } ; + PUSH unit Unit } + { DIP 2 { DUP } ; + DIG 2 ; + DIP { DUP ; SOME ; DIP { DIP 4 { DUP } ; DIG 4 ; CAR ; CDR } } ; + UPDATE ; + DIP { DIP 4 { DUP } ; DIG 4 ; DUP ; CDR ; SWAP ; CAR ; CAR } ; + SWAP ; + PAIR ; + PAIR ; + DIP 5 { DROP } ; + DUG 4 ; + PUSH unit Unit } ; + DROP ; + DIP { DUP } ; + SWAP ; + DIP { DIP 4 { DUP } ; DIG 4 } ; + PAIR ; + DIP { DROP 7 } } ; + SWAP ; + CAR ; + DIP 2 { DUP } ; + DIG 2 ; + CDR ; + DIP { DUP } ; + SWAP ; + DUP ; + DIP { DIP { DUP } ; SWAP } ; + PAIR ; + DIP { DIP 3 { DUP } ; DIG 3 } ; + EXEC ; + DIP { DROP 5 } } } |} ] + +let%expect_test _ = + run_ligo_good [ "compile-contract" ; contract "vote.mligo" ; "main" ] ; + [%expect {| + { parameter + (or (pair %init + (pair (timestamp %beginning_time) (timestamp %finish_time)) + (string %title)) + (string %vote)) ; + storage + (pair (pair (pair (timestamp %beginning_time) (map %candidates string int)) + (pair (timestamp %finish_time) (string %title))) + (set %voters address)) ; + code { LAMBDA + (pair (pair (pair (timestamp %beginning_time) (timestamp %finish_time)) (string %title)) + (pair (pair (pair (timestamp %beginning_time) (map %candidates string int)) + (pair (timestamp %finish_time) (string %title))) + (set %voters address))) + (pair (list operation) + (pair (pair (pair (timestamp %beginning_time) (map %candidates string int)) + (pair (timestamp %finish_time) (string %title))) + (set %voters address))) + { DUP ; + CAR ; + PUSH int 0 ; + SOME ; + DIP { PUSH int 0 ; + SOME ; + EMPTY_MAP string int ; + SWAP ; + PUSH string "Yes" ; + UPDATE } ; + PUSH string "No" ; + UPDATE ; + DIP { DUP } ; + SWAP ; + CAR ; + CAR ; + DIP { DUP } ; + PAIR ; + DIP { DIP { DUP } ; + SWAP ; + CAR ; + CDR ; + DIP { DIP { DUP } ; SWAP ; CDR } ; + PAIR } ; + PAIR ; + EMPTY_SET address ; + SWAP ; + PAIR ; + NIL operation ; + PAIR ; + DIP { DROP 3 } } ; + LAMBDA + (pair string + (pair (pair (pair (timestamp %beginning_time) (map %candidates string int)) + (pair (timestamp %finish_time) (string %title))) + (set %voters address))) + (pair (list operation) + (pair (pair (pair (timestamp %beginning_time) (map %candidates string int)) + (pair (timestamp %finish_time) (string %title))) + (set %voters address))) + { DUP ; + CAR ; + DIP { DUP } ; + SWAP ; + CDR ; + NOW ; + SOURCE ; + DIP 3 { DUP } ; + DIG 3 ; + DIP { DIP 2 { DUP } ; DIG 2 ; CAR ; CAR ; CDR } ; + GET ; + IF_NONE { PUSH string "MAP FIND" ; FAILWITH } {} ; + DIP 3 { DUP } ; + DIG 3 ; + CAR ; + CAR ; + CAR ; + DIP { DIP 4 { DUP } ; + DIG 4 ; + DIP { DUP ; + PUSH int 1 ; + ADD ; + SOME ; + DIP { DIP 3 { DUP } ; DIG 3 ; CAR ; CAR ; CDR } } ; + UPDATE } ; + PAIR ; + DIP { DIP 3 { DUP } ; + DIG 3 ; + CAR ; + CDR ; + CAR ; + DIP { DIP 3 { DUP } ; DIG 3 ; CAR ; CDR ; CDR } ; + PAIR } ; + PAIR ; + DIP { DIP { DUP } ; + SWAP ; + DIP { DIP 3 { DUP } ; DIG 3 ; CDR ; PUSH bool True } ; + UPDATE } ; + PAIR ; + NIL operation ; + PAIR ; + DIP { DROP 6 } } ; + DIP 2 { DUP } ; + DIG 2 ; + CAR ; + DIP 3 { DUP } ; + DIG 3 ; + CDR ; + DIP { DUP } ; + SWAP ; + IF_LEFT + { DUP ; + DUP ; + DIP { DIP 2 { DUP } ; DIG 2 } ; + PAIR ; + DIP { DIP 5 { DUP } ; DIG 5 } ; + EXEC ; + DIP { DROP 2 } } + { DUP ; + DUP ; + DIP { DIP 2 { DUP } ; DIG 2 } ; + PAIR ; + DIP { DIP 4 { DUP } ; DIG 4 } ; + EXEC ; + DIP { DROP 2 } } ; + DIP { DROP 5 } } } |}] diff --git a/src/bin/expect_tests/help_tests.ml b/src/bin/expect_tests/help_tests.ml index c16365feb..7c9609234 100644 --- a/src/bin/expect_tests/help_tests.ml +++ b/src/bin/expect_tests/help_tests.ml @@ -48,6 +48,10 @@ let%expect_test _ = dry-run + COMMANDS + measure-contract + Subcommand: measure a contract's compiled size in bytes. + OPTIONS --help[=FMT] (default=auto) Show this help in format FMT. The value FMT must be one of `auto', diff --git a/vendors/ligo-utils/tezos-utils/x_michelson.ml b/vendors/ligo-utils/tezos-utils/x_michelson.ml index 1267b3b2f..c6af850a3 100644 --- a/vendors/ligo-utils/tezos-utils/x_michelson.ml +++ b/vendors/ligo-utils/tezos-utils/x_michelson.ml @@ -106,3 +106,8 @@ let pp_hex ppf (michelson : michelson) = let bytes = Tezos_data_encoding.Binary_writer.to_bytes_exn Script_repr.expr_encoding canonical in let hex = Hex.of_bytes bytes in Format.fprintf ppf "%a" Hex.pp hex + +let measure (michelson : michelson) = + let canonical = strip_locations michelson in + let bytes = Tezos_data_encoding.Binary_writer.to_bytes_exn Script_repr.expr_encoding canonical in + Bytes.length bytes