From a663e43f1805ecdc0cd38c882beb0de807cae102 Mon Sep 17 00:00:00 2001 From: Milo Davis Date: Mon, 24 Jul 2017 15:06:56 +0200 Subject: [PATCH] Michelson: Add a test suite --- test/Makefile | 4 + test/contracts/and.tz | 5 + test/contracts/balance.tz | 4 + test/contracts/build_list.tz | 7 + test/contracts/check_signature.tz | 5 + test/contracts/compare.tz | 10 + test/contracts/concat_hello.tz | 4 + test/contracts/concat_list.tz | 5 + test/contracts/contains_all.tz | 8 + test/contracts/create_account.tz | 5 + test/contracts/create_contract.tz | 7 + .../default_account.tz} | 0 test/contracts/empty_map.tz | 4 + test/contracts/exec_concat.tz | 4 + test/{scripts/fail.tez => contracts/fail.tz} | 0 .../fail_amount.tz} | 0 test/contracts/get_map_value.tz | 4 + .../hardlimit.tez => contracts/hardlimit.tz} | 0 test/contracts/hash_string.tz | 4 + test/contracts/if.tz | 4 + test/contracts/max_in_list.tz | 10 + test/{scripts/noop.tez => contracts/noop.tz} | 0 test/contracts/not.tz | 4 + test/contracts/or.tz | 5 + test/{scripts => contracts}/originator.tz | 0 test/contracts/ret_int.tz | 4 + test/contracts/reverse.tz | 7 + test/contracts/set_member.tz | 4 + test/contracts/steps_to_quota.tz | 4 + test/contracts/store_input.tz | 4 + test/contracts/store_now.tz | 4 + test/contracts/str_id.tz | 4 + test/contracts/swap_left_right.tz | 4 + test/contracts/tez_add_sub.tz | 6 + test/contracts/transfer_amount.tz | 4 + test/contracts/transfer_to.tz | 4 + test/contracts/weather_insurance.tz | 16 ++ test/contracts/xor.tz | 4 + test/test-basic.sh | 109 +++------- test/test-contracts.sh | 194 ++++++++++++++++++ test/test-utils.sh | 153 ++++++++++++++ 41 files changed, 544 insertions(+), 84 deletions(-) create mode 100644 test/contracts/and.tz create mode 100644 test/contracts/balance.tz create mode 100644 test/contracts/build_list.tz create mode 100644 test/contracts/check_signature.tz create mode 100644 test/contracts/compare.tz create mode 100644 test/contracts/concat_hello.tz create mode 100644 test/contracts/concat_list.tz create mode 100644 test/contracts/contains_all.tz create mode 100644 test/contracts/create_account.tz create mode 100644 test/contracts/create_contract.tz rename test/{scripts/default_account.tez => contracts/default_account.tz} (100%) create mode 100644 test/contracts/empty_map.tz create mode 100644 test/contracts/exec_concat.tz rename test/{scripts/fail.tez => contracts/fail.tz} (100%) rename test/{scripts/fail_amount.tez => contracts/fail_amount.tz} (100%) create mode 100644 test/contracts/get_map_value.tz rename test/{scripts/hardlimit.tez => contracts/hardlimit.tz} (100%) create mode 100644 test/contracts/hash_string.tz create mode 100644 test/contracts/if.tz create mode 100644 test/contracts/max_in_list.tz rename test/{scripts/noop.tez => contracts/noop.tz} (100%) create mode 100644 test/contracts/not.tz create mode 100644 test/contracts/or.tz rename test/{scripts => contracts}/originator.tz (100%) create mode 100644 test/contracts/ret_int.tz create mode 100644 test/contracts/reverse.tz create mode 100644 test/contracts/set_member.tz create mode 100644 test/contracts/steps_to_quota.tz create mode 100644 test/contracts/store_input.tz create mode 100644 test/contracts/store_now.tz create mode 100644 test/contracts/str_id.tz create mode 100644 test/contracts/swap_left_right.tz create mode 100644 test/contracts/tez_add_sub.tz create mode 100644 test/contracts/transfer_amount.tz create mode 100644 test/contracts/transfer_to.tz create mode 100644 test/contracts/weather_insurance.tz create mode 100644 test/contracts/xor.tz create mode 100755 test/test-contracts.sh create mode 100755 test/test-utils.sh diff --git a/test/Makefile b/test/Makefile index a3f973035..3b144f946 100644 --- a/test/Makefile +++ b/test/Makefile @@ -14,6 +14,7 @@ build: run: ${MAKE} ${addprefix run-,${DIR}} ${MAKE} run-basic.sh + ${MAKE} run-contracts.sh clean: ${MAKE} -C lib clean ${MAKE} ${addprefix clean-,${DIR}} @@ -27,3 +28,6 @@ ${addprefix clean-,${DIR}}: clean-%: run-basic.sh: ./test-basic.sh + +run-contracts.sh: + ./test-contracts.sh diff --git a/test/contracts/and.tz b/test/contracts/and.tz new file mode 100644 index 000000000..8a2d6e9ee --- /dev/null +++ b/test/contracts/and.tz @@ -0,0 +1,5 @@ +parameter (pair bool bool); +return bool; +storage unit; +code {DUP; CADR; CAR; SWAP; CADR; CDR; AND; + UNIT; SWAP; PAIR}; diff --git a/test/contracts/balance.tz b/test/contracts/balance.tz new file mode 100644 index 000000000..2bd161da6 --- /dev/null +++ b/test/contracts/balance.tz @@ -0,0 +1,4 @@ +parameter unit; +storage unit; +return tez; +code {DROP; UNIT; BALANCE; PAIR}; diff --git a/test/contracts/build_list.tz b/test/contracts/build_list.tz new file mode 100644 index 000000000..97611a20b --- /dev/null +++ b/test/contracts/build_list.tz @@ -0,0 +1,7 @@ +parameter uint64; +return (list uint64); +storage unit; +code {CADR; NIL uint64; SWAP; DUP; PUSH uint64 0; CMPNEQ; + LOOP {DUP; DIP {SWAP}; CONS; SWAP; PUSH uint64 1; SWAP; SUB; + DUP; PUSH uint64 0; CMPNEQ}; + CONS; UNIT; SWAP; PAIR}; diff --git a/test/contracts/check_signature.tz b/test/contracts/check_signature.tz new file mode 100644 index 000000000..abe354528 --- /dev/null +++ b/test/contracts/check_signature.tz @@ -0,0 +1,5 @@ +parameter key; +storage (pair signature string); +return bool; +code {DUP; DUP; DIP{CDR; DUP; CAR; DIP{CDR; H}; PAIR}; + CADR; CHECK_SIGNATURE; DIP{CDR}; PAIR}; diff --git a/test/contracts/compare.tz b/test/contracts/compare.tz new file mode 100644 index 000000000..7f09a9a4c --- /dev/null +++ b/test/contracts/compare.tz @@ -0,0 +1,10 @@ +parameter (pair tez tez); +return (list bool); +storage unit; +code {CADR; DUP; DUP; DUP; DUP; DIIIIIP {NIL bool}; + DIIIIP {DUP; CAR; DIP {CDR}; COMPARE; LE; CONS}; + DIIIP {DUP; CAR; DIP {CDR}; COMPARE; GE; CONS}; + DIIP{DUP; CAR; DIP {CDR}; COMPARE; LT; CONS}; + DIP {DUP; CAR; DIP {CDR}; COMPARE; GT; CONS} + DUP; CAR; DIP {CDR}; COMPARE; EQ; CONS; + UNIT; SWAP; PAIR}; diff --git a/test/contracts/concat_hello.tz b/test/contracts/concat_hello.tz new file mode 100644 index 000000000..d8726cdb5 --- /dev/null +++ b/test/contracts/concat_hello.tz @@ -0,0 +1,4 @@ +parameter (list string); +return (list string); +storage unit; +code {CADR; LAMBDA string string {PUSH string "Hello "; CONCAT}; MAP; UNIT; SWAP; PAIR}; diff --git a/test/contracts/concat_list.tz b/test/contracts/concat_list.tz new file mode 100644 index 000000000..345cf24d0 --- /dev/null +++ b/test/contracts/concat_list.tz @@ -0,0 +1,5 @@ +parameter (list string); +return string; +storage unit; +code {CADR; PUSH string ""; SWAP; LAMBDA (pair string string) string {DUP; CAR; SWAP; CDR; SWAP; CONCAT}; REDUCE; + UNIT; SWAP; PAIR}; diff --git a/test/contracts/contains_all.tz b/test/contracts/contains_all.tz new file mode 100644 index 000000000..f67b14521 --- /dev/null +++ b/test/contracts/contains_all.tz @@ -0,0 +1,8 @@ +parameter (pair (list string) (list string)); +storage unit; +return bool; +code {CADR; DUP; CAR; DIP{CDR}; EMPTY_SET string; SWAP; + LAMBDA (pair string (set string)) (set string) {DUP; CAR; DIP{CDR}; PUSH bool True; SWAP; UPDATE}; + REDUCE; PUSH bool True; SWAP; PAIR; SWAP; + LAMBDA (pair string (pair (set string) bool)) (pair (set string) bool) {DUP; DUP; CAR; DIP{CDAR; DIP{CDDR}; DUP}; MEM; DIP{SWAP}; AND; SWAP; PAIR}; + REDUCE; CDR; UNIT; SWAP; PAIR}; diff --git a/test/contracts/create_account.tz b/test/contracts/create_account.tz new file mode 100644 index 000000000..989bb9024 --- /dev/null +++ b/test/contracts/create_account.tz @@ -0,0 +1,5 @@ +parameter key; +return unit; +storage (contract unit unit); +code {CADR; DIP{PUSH tez "100.00"; PUSH bool False; NONE key}; CREATE_ACCOUNT; + UNIT; PAIR}; diff --git a/test/contracts/create_contract.tz b/test/contracts/create_contract.tz new file mode 100644 index 000000000..be0e3c19e --- /dev/null +++ b/test/contracts/create_contract.tz @@ -0,0 +1,7 @@ +parameter key; +storage string; +return unit; +code {CADR; DIP{UNIT; LAMBDA (pair (pair tez string) unit) (pair string unit) {CADR; UNIT; SWAP; PAIR}; + PUSH tez "100.00"; PUSH bool False; PUSH bool False; NONE key}; + CREATE_CONTRACT; DIP{PUSH string ""}; PUSH tez "0.00"; PUSH string "abcdefg"; TRANSFER_TOKENS; + DIP{DROP}; UNIT; PAIR}; diff --git a/test/scripts/default_account.tez b/test/contracts/default_account.tz similarity index 100% rename from test/scripts/default_account.tez rename to test/contracts/default_account.tz diff --git a/test/contracts/empty_map.tz b/test/contracts/empty_map.tz new file mode 100644 index 000000000..8a85874ab --- /dev/null +++ b/test/contracts/empty_map.tz @@ -0,0 +1,4 @@ +storage unit; +return (map string string); +parameter unit; +code {DROP; EMPTY_MAP string string; PUSH string "world"; SOME; PUSH string "hello"; UPDATE; UNIT; SWAP; PAIR}; diff --git a/test/contracts/exec_concat.tz b/test/contracts/exec_concat.tz new file mode 100644 index 000000000..216b05f65 --- /dev/null +++ b/test/contracts/exec_concat.tz @@ -0,0 +1,4 @@ +parameter string; +return string; +storage unit; +code {CADR; LAMBDA string string {PUSH string "_abc"; SWAP; CONCAT}; SWAP; EXEC; UNIT; SWAP; PAIR}; diff --git a/test/scripts/fail.tez b/test/contracts/fail.tz similarity index 100% rename from test/scripts/fail.tez rename to test/contracts/fail.tz diff --git a/test/scripts/fail_amount.tez b/test/contracts/fail_amount.tz similarity index 100% rename from test/scripts/fail_amount.tez rename to test/contracts/fail_amount.tz diff --git a/test/contracts/get_map_value.tz b/test/contracts/get_map_value.tz new file mode 100644 index 000000000..544b26d57 --- /dev/null +++ b/test/contracts/get_map_value.tz @@ -0,0 +1,4 @@ +parameter string; +storage (map string string); +return (option string); +code {DUP; CADR; DIP{CDR; DUP}; GET; PAIR}; diff --git a/test/scripts/hardlimit.tez b/test/contracts/hardlimit.tz similarity index 100% rename from test/scripts/hardlimit.tez rename to test/contracts/hardlimit.tz diff --git a/test/contracts/hash_string.tz b/test/contracts/hash_string.tz new file mode 100644 index 000000000..a72d6e90d --- /dev/null +++ b/test/contracts/hash_string.tz @@ -0,0 +1,4 @@ +parameter string; +return string; +storage unit; +code {CADR; H; UNIT; SWAP; PAIR}; diff --git a/test/contracts/if.tz b/test/contracts/if.tz new file mode 100644 index 000000000..537637eb9 --- /dev/null +++ b/test/contracts/if.tz @@ -0,0 +1,4 @@ +parameter bool; +storage unit; +return bool; +code {CADR; IF {PUSH bool True} {PUSH bool False}; UNIT; SWAP; PAIR}; diff --git a/test/contracts/max_in_list.tz b/test/contracts/max_in_list.tz new file mode 100644 index 000000000..2ce85a4f9 --- /dev/null +++ b/test/contracts/max_in_list.tz @@ -0,0 +1,10 @@ +parameter (list int32); +storage unit; +return (option int32); +code {CADR; DIP{NONE int32}; + LAMBDA + (pair int32 (option int32)) + (option int32) + {DUP; DUP; CAR; SWAP; CDR; + IF_NONE {DIP{DROP}; SOME} {CMPGT; IF {CDR} {CAR; SOME}}}; + REDUCE; UNIT; SWAP; PAIR}; diff --git a/test/scripts/noop.tez b/test/contracts/noop.tz similarity index 100% rename from test/scripts/noop.tez rename to test/contracts/noop.tz diff --git a/test/contracts/not.tz b/test/contracts/not.tz new file mode 100644 index 000000000..4d17f16ae --- /dev/null +++ b/test/contracts/not.tz @@ -0,0 +1,4 @@ +parameter bool; +return bool; +storage unit; +code {CADR; NOT; UNIT; SWAP; PAIR}; diff --git a/test/contracts/or.tz b/test/contracts/or.tz new file mode 100644 index 000000000..caf0007e7 --- /dev/null +++ b/test/contracts/or.tz @@ -0,0 +1,5 @@ +parameter (pair bool bool); +return bool; +storage unit; +code {CADR; DUP; CAR; SWAP; CDR; OR; + UNIT; SWAP; PAIR}; diff --git a/test/scripts/originator.tz b/test/contracts/originator.tz similarity index 100% rename from test/scripts/originator.tz rename to test/contracts/originator.tz diff --git a/test/contracts/ret_int.tz b/test/contracts/ret_int.tz new file mode 100644 index 000000000..732bb1b7f --- /dev/null +++ b/test/contracts/ret_int.tz @@ -0,0 +1,4 @@ +parameter unit; +code {CADR; PUSH uint32 300; PAIR}; +return uint32; +storage unit; diff --git a/test/contracts/reverse.tz b/test/contracts/reverse.tz new file mode 100644 index 000000000..f8891fb58 --- /dev/null +++ b/test/contracts/reverse.tz @@ -0,0 +1,7 @@ +parameter (list string); +storage unit; +return (list string); +code {CADR; DIP {NIL string}; SWAP; PUSH bool True; + # INV: BOOL : ORIG_LIST : REV_LIST : [] + LOOP {IF_CONS {DIP {SWAP}; CONS; SWAP; PUSH bool True} {NIL string; PUSH bool False}}; + DROP; UNIT; SWAP; PAIR}; diff --git a/test/contracts/set_member.tz b/test/contracts/set_member.tz new file mode 100644 index 000000000..2f708ba02 --- /dev/null +++ b/test/contracts/set_member.tz @@ -0,0 +1,4 @@ +parameter string; +storage (set string); +return bool; +code {DUP; CADR; DIP{CDR}; MEM; DIP{EMPTY_SET string}; PAIR}; diff --git a/test/contracts/steps_to_quota.tz b/test/contracts/steps_to_quota.tz new file mode 100644 index 000000000..69991f36b --- /dev/null +++ b/test/contracts/steps_to_quota.tz @@ -0,0 +1,4 @@ +parameter unit; +return uint32; +storage unit; +code {DROP; UNIT; STEPS_TO_QUOTA; PAIR}; diff --git a/test/contracts/store_input.tz b/test/contracts/store_input.tz new file mode 100644 index 000000000..010364736 --- /dev/null +++ b/test/contracts/store_input.tz @@ -0,0 +1,4 @@ +parameter string; +return unit; +storage string; +code {CADR; UNIT; PAIR}; diff --git a/test/contracts/store_now.tz b/test/contracts/store_now.tz new file mode 100644 index 000000000..c88f7980f --- /dev/null +++ b/test/contracts/store_now.tz @@ -0,0 +1,4 @@ +parameter unit; +storage timestamp; +return unit; +code {DROP; NOW; UNIT; PAIR}; diff --git a/test/contracts/str_id.tz b/test/contracts/str_id.tz new file mode 100644 index 000000000..2df99b5d5 --- /dev/null +++ b/test/contracts/str_id.tz @@ -0,0 +1,4 @@ +parameter string; +return string; +storage unit; +code {CADR; UNIT; SWAP; PAIR}; diff --git a/test/contracts/swap_left_right.tz b/test/contracts/swap_left_right.tz new file mode 100644 index 000000000..8046c696e --- /dev/null +++ b/test/contracts/swap_left_right.tz @@ -0,0 +1,4 @@ +parameter (or bool string); +return (or string bool); +storage unit; +code {CADR; IF_LEFT {RIGHT string} {LEFT bool}; UNIT; SWAP; PAIR}; diff --git a/test/contracts/tez_add_sub.tz b/test/contracts/tez_add_sub.tz new file mode 100644 index 000000000..2d9479585 --- /dev/null +++ b/test/contracts/tez_add_sub.tz @@ -0,0 +1,6 @@ +parameter (pair tez tez); +storage unit; +return (pair tez tez); +code {CADR; DUP; DUP; CAR; DIP{CDR}; ADD; + DIP{DUP; CAR; DIP{CDR}; SUB}; + PAIR; UNIT; SWAP; PAIR}; diff --git a/test/contracts/transfer_amount.tz b/test/contracts/transfer_amount.tz new file mode 100644 index 000000000..d19c62101 --- /dev/null +++ b/test/contracts/transfer_amount.tz @@ -0,0 +1,4 @@ +parameter unit; +storage tez; +return unit; +code {DROP; AMOUNT; UNIT; PAIR}; diff --git a/test/contracts/transfer_to.tz b/test/contracts/transfer_to.tz new file mode 100644 index 000000000..26e71bd46 --- /dev/null +++ b/test/contracts/transfer_to.tz @@ -0,0 +1,4 @@ +parameter (contract unit unit); +return unit; +storage unit; +code {CADR; DIP{UNIT}; PUSH tez "100.00"; UNIT; TRANSFER_TOKENS; PAIR}; diff --git a/test/contracts/weather_insurance.tz b/test/contracts/weather_insurance.tz new file mode 100644 index 000000000..739c89d67 --- /dev/null +++ b/test/contracts/weather_insurance.tz @@ -0,0 +1,16 @@ +# (pair signed_weather_data actual_level) +parameter (pair signature uint16); +# (pair (under_key over_key) (pair weather_service_key (pair rain_level days_in_future))) +storage (pair (pair (contract unit unit) (contract unit unit)) (pair uint16 key)); +return unit; +code {DUP; DUP; + CADR; DUP; DIP{CDR; H}; CAR; PAIR; + SWAP; CDDDR; CHECK_SIGNATURE; # Check if the data has been correctly signed + IF {NOP} {FAIL} # If signature is not correct, end the execution + DUP; DUP; DUP; DIIIP{CDR}; # Place storage type on bottom of stack + DIIP{CDAR}; # Place contracts below numbers + DIP{CADDR}; # Get actual rain + CDDAR; # Get rain threshold + CMPLT; IF {CAR} {CDR}; # Select contract to receive tokens + BALANCE; UNIT; TRANSFER_TOKENS; # Setup and execute transfer + PAIR}; # Save storage diff --git a/test/contracts/xor.tz b/test/contracts/xor.tz new file mode 100644 index 000000000..90055e027 --- /dev/null +++ b/test/contracts/xor.tz @@ -0,0 +1,4 @@ +parameter (pair bool bool); +return bool; +storage unit; +code {CADR; DUP; CAR; DIP{CDR}; XOR; UNIT; SWAP; PAIR}; diff --git a/test/test-basic.sh b/test/test-basic.sh index 01d160c8b..45a777e1a 100755 --- a/test/test-basic.sh +++ b/test/test-basic.sh @@ -1,104 +1,45 @@ -#! /bin/sh +#!/bin/bash set -e -DIR=$(dirname "$0") -cd "${DIR}" +source test-utils.sh -DATA_DIR="$(mktemp -d -t tezos_node.XXXXXXXXXX)" -CLIENT_DIR="$(mktemp -d -t tezos_client.XXXXXXXXXX)" +${TZCLIENT} list known identities -cleanup() { - [ -z "${NODE_PID}" ] || kill -9 ${NODE_PID} || true - echo - echo "Node's log:" - echo - cat $DATA_DIR/LOG - rm -fr ${DATA_DIR} ${CLIENT_DIR} -} -trap cleanup EXIT QUIT INT +${TZCLIENT} transfer 1000 from bootstrap1 to ${KEY1} +${TZCLIENT} transfer 2000 from bootstrap1 to ${KEY2} -NODE=../tezos-node -CLIENT="../tezos-client -base-dir ${CLIENT_DIR}" +${TZCLIENT} get balance for ${KEY1} | assert "1,000.00 ꜩ" +${TZCLIENT} get balance for ${KEY2} | assert "2,000.00 ꜩ" -CUSTOM_PARAM="--sandbox ./sandbox.json" -${NODE} run --data-dir "${DATA_DIR}" ${CUSTOM_PARAM} --rpc-addr "[::]:8732" > "$DATA_DIR"/LOG 2>&1 & -NODE_PID="$!" +${TZCLIENT} transfer 1000 from ${KEY2} to ${KEY1} -echo "Created node, pid: ${NODE_PID}, log: $DATA_DIR/LOG" - -sleep 3 - -${CLIENT} -block genesis list versions - -${CLIENT} -block genesis \ - activate \ - protocol ProtoALphaALphaALphaALphaALphaALphaALphaALphaDdp3zK \ - with fitness 1 \ - and key edskRhxswacLW6jF6ULavDdzwqnKJVS4UcDTNiCyiH6H8ZNnn2pmNviL7pRNz9kRxxaWQFzEQEcZExGHKbwmuaAcoMegj5T99z - -${CLIENT} add identity bootstrap1 tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx -${CLIENT} add public key bootstrap1 edpkuBknW28nW72KG6RoHtYW7p12T6GKc7nAbwYX5m8Wd9sDVC9yav -${CLIENT} add secret key bootstrap1 edskRuR1azSfboG86YPTyxrQgosh5zChf5bVDmptqLTb5EuXAm9rsnDYfTKhq7rDQujdn5WWzwUMeV3agaZ6J2vPQT58jJAJPi -${CLIENT} add identity bootstrap2 tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN -${CLIENT} add identity bootstrap3 tz1faswCTDciRzE4oJ9jn2Vm2dvjeyA9fUzU -${CLIENT} add identity bootstrap4 tz1b7tUupMgCNw2cCLpKTkSD1NZzB5TkP2sv -${CLIENT} add identity bootstrap5 tz1ddb9NMYHZi5UzPdzTZMYQQZoMub195zgv - -sleep 2 - -KEY1=foo -KEY2=bar - -${CLIENT} gen keys ${KEY1} -${CLIENT} gen keys ${KEY2} - -${CLIENT} list known identities - -${CLIENT} transfer 1000 from bootstrap1 to ${KEY1} -${CLIENT} transfer 2000 from bootstrap1 to ${KEY2} - -assert() { - local expected="$1" - local result="$(cat)" - if [ "${result}" != "${expected}" ]; then - echo "Unexpected result: \"${result}\"" - echo "Expected: \"${expected}\"" - exit 2 - fi -} - -${CLIENT} get balance for ${KEY1} | assert "1,000.00 ꜩ" -${CLIENT} get balance for ${KEY2} | assert "2,000.00 ꜩ" - -${CLIENT} transfer 1000 from ${KEY2} to ${KEY1} - -${CLIENT} get balance for ${KEY1} | assert "2,000.00 ꜩ" -${CLIENT} get balance for ${KEY2} | assert "999.95 ꜩ" +${TZCLIENT} get balance for ${KEY1} | assert "2,000.00 ꜩ" +${TZCLIENT} get balance for ${KEY2} | assert "999.95 ꜩ" # Should fail -# ${CLIENT} transfer 999.95 from ${KEY2} to ${KEY1} +# ${TZCLIENT} transfer 999.95 from ${KEY2} to ${KEY1} -${CLIENT} mine for bootstrap1 +${TZCLIENT} mine for bootstrap1 -${CLIENT} remember program noop file:scripts/noop.tez -${CLIENT} typecheck program noop -${CLIENT} originate contract noop \ +${TZCLIENT} remember program noop file:contracts/noop.tz +${TZCLIENT} typecheck program noop +${TZCLIENT} originate contract noop \ for ${KEY1} transferring 1000 from bootstrap1 \ running noop -${CLIENT} transfer 10 from bootstrap1 to noop -arg "Unit" +${TZCLIENT} transfer 10 from bootstrap1 to noop -arg "Unit" -${CLIENT} originate contract hardlimit \ +${TZCLIENT} originate contract hardlimit \ for ${KEY1} transferring 1000 from bootstrap1 \ - running file:scripts/hardlimit.tez -init "3" -${CLIENT} transfer 10 from bootstrap1 to hardlimit -arg "Unit" -${CLIENT} transfer 10 from bootstrap1 to hardlimit -arg "Unit" -# ${CLIENT} transfer 10 from bootstrap1 to hardlimit -arg "unit" # should fail + running file:contracts/hardlimit.tz -init "3" +${TZCLIENT} transfer 10 from bootstrap1 to hardlimit -arg "Unit" +${TZCLIENT} transfer 10 from bootstrap1 to hardlimit -arg "Unit" +# ${TZCLIENT} transfer 10 from bootstrap1 to hardlimit -arg "unit" # should fail -${CLIENT} originate free account free_account for ${KEY1} -${CLIENT} get delegate for free_account -${CLIENT} set delegate for free_account to ${KEY2} -${CLIENT} get delegate for free_account +${TZCLIENT} originate free account free_account for ${KEY1} +${TZCLIENT} get delegate for free_account +${TZCLIENT} set delegate for free_account to ${KEY2} +${TZCLIENT} get delegate for free_account echo echo End of test diff --git a/test/test-contracts.sh b/test/test-contracts.sh new file mode 100755 index 000000000..5381a7d91 --- /dev/null +++ b/test/test-contracts.sh @@ -0,0 +1,194 @@ +#!/bin/bash + +set -e + +source test-utils.sh + +CONTRACT_PATH=contracts + +# FORMAT: assert_output contract_file storage input expected_result + +assert_output $CONTRACT_PATH/ret_int.tz Unit Unit 300 +assert_output $CONTRACT_PATH/str_id.tz Unit '"Hello"' '"Hello"' +assert_output $CONTRACT_PATH/str_id.tz Unit '"abcd"' '"abcd"' + +# Logical not +assert_output $CONTRACT_PATH/not.tz Unit True False +assert_output $CONTRACT_PATH/not.tz Unit False True + +# Logical and +assert_output $CONTRACT_PATH/and.tz Unit "(Pair False False)" False +assert_output $CONTRACT_PATH/and.tz Unit "(Pair False True)" False +assert_output $CONTRACT_PATH/and.tz Unit "(Pair True False)" False +assert_output $CONTRACT_PATH/and.tz Unit "(Pair True True)" True + +# Logical or +assert_output $CONTRACT_PATH/or.tz Unit "(Pair False False)" False +assert_output $CONTRACT_PATH/or.tz Unit "(Pair False True)" True +assert_output $CONTRACT_PATH/or.tz Unit "(Pair True False)" True +assert_output $CONTRACT_PATH/or.tz Unit "(Pair True True)" True + +# XOR +assert_output $CONTRACT_PATH/xor.tz Unit "(Pair False False)" False +assert_output $CONTRACT_PATH/xor.tz Unit "(Pair False True)" True +assert_output $CONTRACT_PATH/xor.tz Unit "(Pair True False)" True +assert_output $CONTRACT_PATH/xor.tz Unit "(Pair True True)" False + + +# Build list +assert_output $CONTRACT_PATH/build_list.tz Unit 0 "(List 0)" +assert_output $CONTRACT_PATH/build_list.tz Unit 3 "(List 0 1 2 3)" +assert_output $CONTRACT_PATH/build_list.tz Unit 10 \ + "(List 0 1 2 3 4 5 6 7 8 9 10)" + +# Concatenate all strings of a list into one string +assert_output $CONTRACT_PATH/concat_list.tz Unit '(List "a" "b" "c")' '"abc"' +assert_output $CONTRACT_PATH/concat_list.tz Unit '(List )' '""' +assert_output $CONTRACT_PATH/concat_list.tz \ + Unit '(List "Hello" " " "World" "!")' '"Hello World!"' + +# Find maximum int32 in list -- returns None if not found +assert_output $CONTRACT_PATH/max_in_list.tz Unit '(List)' 'None' +assert_output $CONTRACT_PATH/max_in_list.tz Unit '(List 1)' '(Some 1)' +assert_output $CONTRACT_PATH/max_in_list.tz Unit '(List -1)' '(Some -1)' +assert_output $CONTRACT_PATH/max_in_list.tz Unit \ + '(List 10 -1 -20 100 0)' '(Some 100)' +assert_output $CONTRACT_PATH/max_in_list.tz Unit \ + '(List 10 -1 -20 100 0)' '(Some 100)' +assert_output $CONTRACT_PATH/max_in_list.tz Unit \ + '(List -10 -1 -20 -100)' '(Some -1)' + +# Set member -- set is in storage +assert_output $CONTRACT_PATH/set_member.tz '(Set)' '"Hi"' 'False' +assert_output $CONTRACT_PATH/set_member.tz '(Set "Hi")' '"Hi"' 'True' +assert_output $CONTRACT_PATH/set_member.tz '(Set "Hello" "World")' '""' 'False' + +# Contains all elements -- does the second list contain all of the same elements +# as the first one? I'm ignoring element multiplicity +assert_output $CONTRACT_PATH/contains_all.tz \ + Unit '(Pair (List) (List))' 'True' +assert_output $CONTRACT_PATH/contains_all.tz \ + Unit '(Pair (List "a") (List "B"))' 'False' +assert_output $CONTRACT_PATH/contains_all.tz \ + Unit '(Pair (List "A") (List "B"))' 'False' +assert_output $CONTRACT_PATH/contains_all.tz \ + Unit '(Pair (List "B") (List "B"))' 'True' +assert_output $CONTRACT_PATH/contains_all.tz Unit \ + '(Pair (List "B" "C" "asdf") (List "B" "B" "asdf" "C"))' 'True' +assert_output $CONTRACT_PATH/contains_all.tz Unit \ + '(Pair (List "B" "B" "asdf" "C") (List "B" "C" "asdf"))' 'True' + +# Concatenate the string in storage with all strings in the given list +assert_output $CONTRACT_PATH/concat_hello.tz Unit \ + '(List "World!")' '(List "Hello World!")' +assert_output $CONTRACT_PATH/concat_hello.tz Unit \ + '(List)' 'List' +assert_output $CONTRACT_PATH/concat_hello.tz Unit \ + '(List "test1" "test2")' '(List "Hello test1" "Hello test2")' + +# Create an empty map and add a string to it +assert_output $CONTRACT_PATH/empty_map.tz Unit Unit \ + '(Map (Item "hello" "world"))' + +# Get the value stored at the given key in the map +assert_output $CONTRACT_PATH/get_map_value.tz '(Map (Item "hello" "hi"))' \ + '"hello"' '(Some "hi")' +assert_output $CONTRACT_PATH/get_map_value.tz '(Map (Item "hello" "hi"))' \ + '""' 'None' +assert_output $CONTRACT_PATH/get_map_value.tz \ + '(Map (Item "1" "one") (Item "2" "two"))' \ + '"1"' '(Some "one")' + +# Return True if True branch of if was taken and False otherwise +assert_output $CONTRACT_PATH/if.tz Unit True True +assert_output $CONTRACT_PATH/if.tz Unit False False + +# Generate a pair of or types +assert_output $CONTRACT_PATH/swap_left_right.tz Unit '(Left True)' '(Right True)' +assert_output $CONTRACT_PATH/swap_left_right.tz Unit '(Right "a")' '(Left "a")' + +# Reverse a list +assert_output $CONTRACT_PATH/reverse.tz Unit '(List )' 'List' +assert_output $CONTRACT_PATH/reverse.tz Unit '(List "c" "b" "a")' '(List "a" "b" "c")' + +# Exec concat contract +assert_output $CONTRACT_PATH/exec_concat.tz Unit '""' '"_abc"' +assert_output $CONTRACT_PATH/exec_concat.tz Unit '"test"' '"test_abc"' + +# Get current steps to quota +assert_output $CONTRACT_PATH/steps_to_quota.tz Unit Unit 16382 + +# Get the current balance of the contract +assert_output $CONTRACT_PATH/balance.tz Unit Unit '"4,000,000.00"' + +# Test comparisons on tez (List EQ GT LT GE LE) +assert_output $CONTRACT_PATH/compare.tz Unit '(Pair "1.00" "2.00")' '(List False False True False True)' +assert_output $CONTRACT_PATH/compare.tz Unit '(Pair "2.00" "1.00")' '(List False True False True False)' +assert_output $CONTRACT_PATH/compare.tz Unit '(Pair "2.37" "2.37")' '(List True False False True True)' + +# Test addition and subtraction on tez +assert_output $CONTRACT_PATH/tez_add_sub.tz Unit '(Pair "2.00" "1.00")' '(Pair "3.00" "1.00")' +assert_output $CONTRACT_PATH/tez_add_sub.tz Unit '(Pair "2.31" "1.01")' '(Pair "3.32" "1.30")' + +# Hash input string +# Test assumed to be correct -- hash is based on encoding of AST +assert_output $CONTRACT_PATH/hash_string.tz Unit '"abcdefg"' '"exprv3MnhXvjthGzZ7jDtXRRFremZyey9rsGtL7JRkeaQX1fThN7WF"' +assert_output $CONTRACT_PATH/hash_string.tz Unit '"12345"' '"expru81QVHsW2qaWLNHnMHSxDNhqtat17ajadri6mKUvXyc2EWHZC3"' + +# Did the given key sign the string? +assert_output $CONTRACT_PATH/check_signature.tz \ +'(Pair "26981d372a7b3866621bf79713d249197fe6d518ef702fa65738e1715bde9da54df04fefbcc84287ecaa9f74ad9296462731aa24bbcece63c6bf73a8f5752309" "hello")' \ +'"tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx"' True + +assert_output $CONTRACT_PATH/check_signature.tz \ +'(Pair "26981d372a7b3866621bf79713d249197fe6d518ef702fa65738e1715bde9da54df04fefbcc84287ecaa9f74ad9296462731aa24bbcece63c6bf73a8f5752309" "abcd")' \ +'"tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx"' False + + +${TZCLIENT} transfer 1000 from bootstrap1 to ${KEY1} +${TZCLIENT} transfer 2000 from bootstrap1 to ${KEY2} + +assert_balance ${KEY1} "1,000.00 ꜩ" +assert_balance ${KEY2} "2,000.00 ꜩ" + +# Create a contract and transfer 100 ꜩ to it +init_with_transfer $CONTRACT_PATH/store_input.tz ${KEY1} '""' 100 bootstrap1 +${TZCLIENT} transfer 100 from bootstrap1 to store_input -arg '"abcdefg"' +assert_balance store_input "200.00 ꜩ" +assert_storage_contains store_input '"abcdefg"' +${TZCLIENT} transfer 100 from bootstrap1 to store_input -arg '"xyz"' +assert_storage_contains store_input '"xyz"' + +init_with_transfer $CONTRACT_PATH/transfer_amount.tz ${KEY1} '"0"' "100" bootstrap1 +${TZCLIENT} transfer 500 from bootstrap1 to transfer_amount -arg Unit +assert_storage_contains transfer_amount 500 + +# This tests the `NOW` instruction. +# This test may fail if timings are marginal, though I have not yet seen this happen +init_with_transfer $CONTRACT_PATH/store_now.tz ${KEY1} '"2017-07-13T09:19:01Z"' "100" bootstrap1 +${TZCLIENT} transfer 500 from bootstrap1 to store_now -arg Unit +assert_storage_contains store_now "$(${TZCLIENT} get timestamp)" + +# Tests TRANSFER_TO +${TZCLIENT} originate account "test_transfer_account1" for ${KEY1} transferring 100 from bootstrap1 +${TZCLIENT} originate account "test_transfer_account2" for ${KEY1} transferring 20 from bootstrap1 +init_with_transfer $CONTRACT_PATH/transfer_to.tz ${KEY2} Unit 1000 bootstrap1 +assert_balance test_transfer_account1 "100.00 ꜩ" +${TZCLIENT} transfer 100 from bootstrap1 to transfer_to \ + -arg "\"$(get_contract_addr test_transfer_account1)\"" +assert_balance test_transfer_account1 "200.00 ꜩ" # Why isn't this 200 ꜩ? Mining fee? +${TZCLIENT} transfer 100 from bootstrap1 to transfer_to \ + -arg "\"$(get_contract_addr test_transfer_account2)\"" +assert_balance test_transfer_account2 "120.00 ꜩ" # Why isn't this 120 ꜩ? Mining fee? + +# Tests create_account +init_with_transfer $CONTRACT_PATH/create_account.tz ${KEY2} \ + "\"$(get_contract_addr test_transfer_account1)\"" 1000 bootstrap1 +${TZCLIENT} transfer 100 from bootstrap1 to create_account \ + -arg '"tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx"' | assert_in_output "New contract" + +# Creates a contract, transfers data to it and stores the data +init_with_transfer $CONTRACT_PATH/create_contract.tz ${KEY2} \ + "\"$(get_contract_addr test_transfer_account1)\"" 1000 bootstrap1 +${TZCLIENT} transfer 0.00 from bootstrap1 to create_contract -arg '"tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx"' +assert_storage_contains create_contract '"abcdefg"' diff --git a/test/test-utils.sh b/test/test-utils.sh new file mode 100755 index 000000000..5606d9f6a --- /dev/null +++ b/test/test-utils.sh @@ -0,0 +1,153 @@ +#!/bin/bash +# Run this as a command in scripts to test if a contract produces the correct output +# Write `source test-michelson.sh` + +DATA_DIR="$(mktemp -d -t tezos_node.XXXXXXXXXX)" +CLIENT_DIR="$(mktemp -d -t tezos_client.XXXXXXXXXX)" + +TZCLIENT="../tezos-client -base-dir ${CLIENT_DIR}" +TZNODE=../tezos-node + +cleanup() { + [ -z "${TZNODE_PID}" ] || kill -9 ${TZNODE_PID} || true + printf "\nNode's log:\n" > /dev/stderr + cat $DATA_DIR/LOG > /dev/stderr + rm -fr ${DATA_DIR} ${CLIENT_DIR} +} +trap cleanup EXIT QUIT INT SIGINT SIGKILL + +CUSTOM_PARAM="--sandbox sandbox.json" +${TZNODE} run --data-dir "${DATA_DIR}" ${CUSTOM_PARAM} --rpc-addr "[::]:8732" > "$DATA_DIR"/LOG 2>&1 & +TZNODE_PID="$!" + +echo "Created node, pid: ${TZNODE_PID}, log: $DATA_DIR/LOG" > /dev/stderr + +sleep 3 + +${TZCLIENT} -block genesis \ + activate \ + protocol ProtoALphaALphaALphaALphaALphaALphaALphaALphaDdp3zK \ + with fitness 1 \ + and key edskRhxswacLW6jF6ULavDdzwqnKJVS4UcDTNiCyiH6H8ZNnn2pmNviL7pRNz9kRxxaWQFzEQEcZExGHKbwmuaAcoMegj5T99z + + +run_contract_file () { + local contract=$1; + local storage=$2; + local input=$3; + ${TZCLIENT} run program "$contract" on storage "$storage" and input "$input"; +} + +assert_output () { + local contract=$1; + local input=$2; + local storage=$3; + local expected=$4; + local output=$(run_contract_file "$contract" "$input" "$storage" | sed '1,/output/d' | + sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//' || + { printf '\nTest failed with error at line %s\n' "$(caller)" > /dev/stderr; + exit 1; }); + if [ "$expected" != "$output" ]; then + echo "Test at" `caller` failed > /dev/stderr; + printf "Expected %s but got %s" "$expected" "$output" > /dev/stderr; + exit 1; + fi +} + +assert_balance () { + local KEY="$1" + local EXPECTED_BALANCE="$2" + local RESULT=$(${TZCLIENT} get balance for ${KEY}) + if [ "${RESULT}" != "${EXPECTED_BALANCE}" ]; then + printf "Balance assertion failed for ${KEY} on line '%s'. Expected %s but got %s.\n" \ + "$(caller)" "${EXPECTED_BALANCE}" "${RESULT}" + exit 2 + fi +} + +contract_name_of_file () { + basename ${FILE} ".tz" +} + +init_contract_from_file () { + local FILE="$1" + local NAME=$(contract_name_of_file ${FILE}) + ${TZCLIENT} remember program "${NAME}" "file:${FILE}" +} + +init_with_transfer () { + local FILE="$1" + local NAME=$(contract_name_of_file ${FILE}) + local KEY="$2" + local INITIAL_STORAGE="$3" + local TRANSFER_AMT="$4" + local TRANSFER_SRC=${5-bootstrap1} + ${TZCLIENT} originate contract ${NAME} \ + for ${KEY} transferring "${TRANSFER_AMT}" \ + from ${TRANSFER_SRC} running "${FILE}" -init "${INITIAL_STORAGE}" +} + +# Takes a grep regexp and fails with an error message if command does not include +# the regexp +assert_in_output () { + local MATCHING="$1" + local INPUT=${2-/dev/stdin} + if ! grep -q "${MATCHING}" ${INPUT}; then + printf "Failure on line %s. Expected to find %s in output." \ + "$(caller)" "${MATCHING}" + exit 1 + fi +} + +get_contract_addr () { + local CONTRACT_NAME="$1" + ${TZCLIENT} show known contract "${CONTRACT_NAME}" +} + +contract_storage () { + local CONTRACT_NAME="$1" # Can be either an alias or hash + ${TZCLIENT} get storage for ${CONTRACT_NAME} +} + +assert_storage_contains () { + local CONTRACT_NAME="$1" + local EXPECTED_STORAGE="$2" + contract_storage ${CONTRACT_NAME} | assert_in_output ${EXPECTED_STORAGE} +} + +assert() { + local expected="$1" + local result="$(cat)" + if [ "${result}" != "${expected}" ]; then + echo "Unexpected result: \"${result}\"" + echo "Expected: \"${expected}\"" + exit 2 + fi +} + +BOOTSTRAP1_IDENTITY=tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx +BOOTSTRAP1_PUBLIC=edpkuBknW28nW72KG6RoHtYW7p12T6GKc7nAbwYX5m8Wd9sDVC9yav +BOOTSTRAP1_SECRET=edskRuR1azSfboG86YPTyxrQgosh5zChf5bVDmptqLTb5EuXAm9rsnDYfTKhq7rDQujdn5WWzwUMeV3agaZ6J2vPQT58jJAJPi +BOOTSTRAP2_IDENTITY=tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN +BOOTSTRAP3_IDENTITY=tz1faswCTDciRzE4oJ9jn2Vm2dvjeyA9fUzU +BOOTSTRAP4_IDENTITY=tz1b7tUupMgCNw2cCLpKTkSD1NZzB5TkP2sv +BOOTSTRAP5_IDENTITY=tz1ddb9NMYHZi5UzPdzTZMYQQZoMub195zgv + +KEY1=foo +KEY2=bar + +${TZCLIENT} add identity bootstrap1 ${BOOTSTRAP1_IDENTITY} +${TZCLIENT} add public key bootstrap1 ${BOOTSTRAP1_PUBLIC} +${TZCLIENT} add secret key bootstrap1 ${BOOTSTRAP1_SECRET} +${TZCLIENT} add identity bootstrap2 ${BOOTSTRAP2_IDENTITY} +${TZCLIENT} add identity bootstrap3 ${BOOTSTRAP3_IDENTITY} +${TZCLIENT} add identity bootstrap4 ${BOOTSTRAP4_IDENTITY} +${TZCLIENT} add identity bootstrap5 ${BOOTSTRAP5_IDENTITY} + +sleep 2 + +${TZCLIENT} gen keys ${KEY1} +${TZCLIENT} gen keys ${KEY2} + +# For ease of use outside of the script +alias client="${TZCLIENT}"