23
23
# ast import/export tests:
24
24
# - first exporting a .sol file to JSON, then loading it into the compiler
25
25
# and exporting it again. The second JSON should be identical to the first.
26
+ #
27
+ # evm-assembly import/export tests:
28
+ # - first a .sol file will be compiled and the EVM Assembly will be exported
29
+ # to JSON format using --asm-json command-line option.
30
+ # The EVM Assembly JSON output is then imported with --import-asm-json
31
+ # and compiled again. The binary generated initially and after the import
32
+ # should be identical.
26
33
27
34
set -euo pipefail
28
35
29
36
READLINK=readlink
30
37
if [[ " $OSTYPE " == " darwin" * ]]; then
31
38
READLINK=greadlink
32
39
fi
40
+ EXPR=" expr"
41
+ if [[ " $OSTYPE " == " darwin" * ]]; then
42
+ EXPR=" gexpr"
43
+ fi
44
+
33
45
REPO_ROOT=$( ${READLINK} -f " $( dirname " $0 " ) " /..)
34
46
SOLIDITY_BUILD_DIR=${SOLIDITY_BUILD_DIR:- ${REPO_ROOT} / build}
35
47
SOLC=" ${SOLIDITY_BUILD_DIR} /solc/solc"
36
48
SPLITSOURCES=" ${REPO_ROOT} /scripts/splitSources.py"
37
49
38
50
# shellcheck source=scripts/common.sh
39
51
source " ${REPO_ROOT} /scripts/common.sh"
52
+ # shellcheck source=scripts/common_cmdline.sh
53
+ source " ${REPO_ROOT} /scripts/common_cmdline.sh"
40
54
41
55
function print_usage
42
56
{
43
- echo " Usage: ${0} ast [--exit-on-error|--help]."
57
+ echo " Usage: ${0} ast|evm-assembly [--exit-on-error|--help]."
44
58
}
45
59
46
60
function print_used_commands
47
61
{
48
62
local test_directory=" $1 "
49
63
local export_command=" $2 "
50
64
local import_command=" $3 "
51
- printError " You can find the files used for this test here: ${test_directory} "
52
- printError " Used commands for test:"
65
+ echo
66
+ printError " You can find the files used for this test in ${test_directory} "
67
+ printError " Commands used in the test:"
53
68
printError " # export"
54
69
echo " $ ${export_command} " >&2
55
70
printError " # import"
@@ -81,6 +96,7 @@ for PARAM in "$@"
81
96
do
82
97
case " $PARAM " in
83
98
ast) check_import_test_type_unset ; IMPORT_TEST_TYPE=" ast" ;;
99
+ evm-assembly) check_import_test_type_unset ; IMPORT_TEST_TYPE=" evm-assembly" ;;
84
100
--help) print_usage ; exit 0 ;;
85
101
--exit-on-error) EXIT_ON_ERROR=1 ;;
86
102
* ) fail " Unknown option '$PARAM '. Aborting. $( print_usage) " ;;
89
105
90
106
SYNTAXTESTS_DIR=" ${REPO_ROOT} /test/libsolidity/syntaxTests"
91
107
ASTJSONTESTS_DIR=" ${REPO_ROOT} /test/libsolidity/ASTJSON"
108
+ SEMANTICTESTS_DIR=" ${REPO_ROOT} /test/libsolidity/semanticTests"
92
109
93
110
FAILED=0
94
111
UNCOMPILABLE=0
@@ -153,6 +170,92 @@ function test_ast_import_export_equivalence
153
170
TESTED=$(( TESTED + 1 ))
154
171
}
155
172
173
+ function run_solc
174
+ {
175
+ local parameters=( " ${@ } " )
176
+
177
+ if ! " ${SOLC} " " ${parameters[@]} " > /dev/null 2> solc_stderr
178
+ then
179
+ printError " ERROR: ${parameters[*]} "
180
+ printError " ${PWD} "
181
+ # FIXME: EXIT_ON_ERROR seems to be ignored here and in some other places.
182
+ # We just exit unconditionally instead.
183
+ fail " $( cat solc_stderr) "
184
+ fi
185
+ rm solc_stderr
186
+ }
187
+
188
+ function run_solc_store_stdout
189
+ {
190
+ local output_file=$1
191
+ local parameters=( " ${@: 2} " )
192
+
193
+ if ! " ${SOLC} " " ${parameters[@]} " > " ${output_file} " 2> " ${output_file} .error"
194
+ then
195
+ printError " ERROR: ${parameters[*]} "
196
+ printError " ${PWD} "
197
+ fail " $( cat " ${output_file} .error" ) "
198
+ fi
199
+ rm " ${output_file} .error"
200
+ }
201
+
202
+ function test_evmjson_import_export_equivalence
203
+ {
204
+ local sol_file=" $1 "
205
+ local input_files=( " ${@: 2} " )
206
+
207
+ # Generate bytecode and EVM assembly JSON through normal complication
208
+ mkdir -p export/
209
+ local export_options=(--bin --asm-json " ${input_files[@]} " --output-dir export/)
210
+ run_solc " ${export_options[@]} "
211
+
212
+ # NOTE: If there is no bytecode, the compiler produces a JSON file that contains just 'null'.
213
+ # This is not accepted by assembly import though so we must skip such contracts.
214
+ echo -n null > null
215
+ find export/ -name ' *.json' -exec cmp --quiet --bytes=4 {} null \; -delete
216
+
217
+ find export/ -name ' *.bin' -size 0 -delete
218
+
219
+ for asm_json_file in export/* .json
220
+ do
221
+ mv " ${asm_json_file} " " ${asm_json_file/ _evm/ } "
222
+ done
223
+
224
+ # Import EVM assembly JSON
225
+ mkdir -p import/
226
+ for asm_json_file in export/* .json
227
+ do
228
+ local bin_file_from_asm_import
229
+ bin_file_from_asm_import=" import/$( basename " ${asm_json_file} " .json) .bin"
230
+
231
+ local import_options=(--bin --import-asm-json " ${asm_json_file} " )
232
+ run_solc_store_stdout " ${bin_file_from_asm_import} " " ${import_options[@]} "
233
+
234
+ stripCLIDecorations < " $bin_file_from_asm_import " > tmpfile
235
+ mv tmpfile " $bin_file_from_asm_import "
236
+ done
237
+
238
+ # Compare bytecode from compilation with bytecode from import
239
+ for bin_file in export/* .bin
240
+ do
241
+ local bin_file_from_asm_import=${bin_file/ export/ import}
242
+ if ! diff --strip-trailing-cr --ignore-all-space " ${bin_file} " " ${bin_file_from_asm_import} " > diff_error
243
+ then
244
+ printError " ERROR: Bytecode from compilation (${bin_file} ) differs from bytecode from EVM asm import (${bin_file_from_asm_import} ):"
245
+ printError " $( cat diff_error) "
246
+ if (( EXIT_ON_ERROR == 1 ))
247
+ then
248
+ # NOTE: The import_options we print here refers to the wrong file (the last one
249
+ # processed by the previous loop) - but it's still a good starting point for debugging ;)
250
+ print_used_commands " ${PWD} " " ${SOLC} ${export_options[*]} " " ${SOLC} ${import_options[*]} "
251
+ return 1
252
+ fi
253
+ FAILED=$(( FAILED + 1 ))
254
+ fi
255
+ done
256
+ TESTED=$(( TESTED + 1 ))
257
+ }
258
+
156
259
# function tests whether exporting and importing again is equivalent.
157
260
# Results are recorded by incrementing the FAILED or UNCOMPILABLE global variable.
158
261
# Also, in case of a mismatch a diff is printed
@@ -168,6 +271,7 @@ function test_import_export_equivalence {
168
271
169
272
case " $IMPORT_TEST_TYPE " in
170
273
ast) compile_test=" --ast-compact-json" ;;
274
+ evm-assembly) compile_test=" --bin" ;;
171
275
* ) assertFail " Unknown import test type '${IMPORT_TEST_TYPE} '. Aborting." ;;
172
276
esac
173
277
@@ -181,6 +285,7 @@ function test_import_export_equivalence {
181
285
then
182
286
case " $IMPORT_TEST_TYPE " in
183
287
ast) test_ast_import_export_equivalence " ${sol_file} " " ${input_files[@]} " ;;
288
+ evm-assembly) test_evmjson_import_export_equivalence " ${sol_file} " " ${input_files[@]} " ;;
184
289
* ) assertFail " Unknown import test type '${IMPORT_TEST_TYPE} '. Aborting." ;;
185
290
esac
186
291
else
@@ -191,16 +296,30 @@ function test_import_export_equivalence {
191
296
# and print some details about the corresponding solc invocation.
192
297
if (( solc_return_code == 2 ))
193
298
then
194
- fail " \n\nERROR: Uncaught Exception while executing '$SOLC ${compile_test} ${input_files[*]} ':\n${output} \n"
299
+ # For the evm-assembly import/export tests, this script uses only the old code generator.
300
+ # Some semantic tests can only be compiled with --via-ir (some need to be additionally
301
+ # compiled with --optimize). The tests that are meant to be compiled with --via-ir are
302
+ # throwing an UnimplementedFeatureError exception, e.g.:
303
+ # "Copying of type struct C.S memory[] memory to storage not yet supported",
304
+ # "Copying nested calldata dynamic arrays to storage is not implemented in the old code generator".
305
+ # We will just ignore these kind of exceptions for now. However, any other exception
306
+ # will be treated as a fatal error and the script execution will be terminated with an error.
307
+ if [[ " ${output} " != * " UnimplementedFeatureError" * ]]
308
+ then
309
+ fail " \n\nERROR: Uncaught exception while executing '${SOLC} ${compile_test} ${input_files[*]} ':\n${output} \n"
310
+ fi
195
311
fi
196
312
fi
197
313
}
198
314
199
315
command_available " $SOLC " --version
200
316
command_available jq --version
317
+ command_available " $EXPR " --version
318
+ command_available " $READLINK " --version
201
319
202
320
case " $IMPORT_TEST_TYPE " in
203
321
ast) TEST_DIRS=(" ${SYNTAXTESTS_DIR} " " ${ASTJSONTESTS_DIR} " ) ;;
322
+ evm-assembly) TEST_DIRS=(" ${SEMANTICTESTS_DIR} " ) ;;
204
323
* ) assertFail " Import test type not defined. $( print_usage) " ;;
205
324
esac
206
325
0 commit comments