mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
[libevmasm] Add support to import evm assembly json.
This commit is contained in:
+151
-2
@@ -23,6 +23,18 @@
|
||||
# ast import/export tests:
|
||||
# - first exporting a .sol file to JSON, then loading it into the compiler
|
||||
# and exporting it again. The second JSON should be identical to the first.
|
||||
#
|
||||
# evm-assembly import/export tests:
|
||||
# - first a .sol file will be exported to a combined json file, containing outputs
|
||||
# for "asm" "bin" "bin-runtime" "opcodes" "srcmap" and "srcmap-runtime" (expected output).
|
||||
# The "asm" output will then be used as import, where its output "bin" "bin-runtime"
|
||||
# "opcodes" "srcmap" "srcmap-runtime" (obtained output) will be compared with the expected output.
|
||||
# The expected output needs to be identical with the obtained output.
|
||||
#
|
||||
# Additionally to this, the direct import/export is tested by importing an
|
||||
# evm-assembly json with --import-asm-json and directly exporting it again with
|
||||
# --asm-json using the same solc invocation. The original asm json file used for the
|
||||
# import and the resulting exported asm json file need to be identical.
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
@@ -40,7 +52,7 @@ source "${REPO_ROOT}/scripts/common.sh"
|
||||
|
||||
function print_usage
|
||||
{
|
||||
echo "Usage: ${0} ast [--exit-on-error|--help]."
|
||||
echo "Usage: ${0} ast|evm-assembly [--exit-on-error|--help]."
|
||||
}
|
||||
|
||||
function print_used_commands
|
||||
@@ -81,6 +93,7 @@ for PARAM in "$@"
|
||||
do
|
||||
case "$PARAM" in
|
||||
ast) check_import_test_type_unset ; IMPORT_TEST_TYPE="ast" ;;
|
||||
evm-assembly) check_import_test_type_unset ; IMPORT_TEST_TYPE="evm-assembly" ;;
|
||||
--help) print_usage ; exit 0 ;;
|
||||
--exit-on-error) EXIT_ON_ERROR=1 ;;
|
||||
*) fail "Unknown option '$PARAM'. Aborting. $(print_usage)" ;;
|
||||
@@ -89,6 +102,7 @@ done
|
||||
|
||||
SYNTAXTESTS_DIR="${REPO_ROOT}/test/libsolidity/syntaxTests"
|
||||
ASTJSONTESTS_DIR="${REPO_ROOT}/test/libsolidity/ASTJSON"
|
||||
SEMANTICTESTS_DIR="${REPO_ROOT}/test/libsolidity/semanticTests"
|
||||
|
||||
FAILED=0
|
||||
UNCOMPILABLE=0
|
||||
@@ -153,6 +167,125 @@ function test_ast_import_export_equivalence
|
||||
TESTED=$((TESTED + 1))
|
||||
}
|
||||
|
||||
function test_evmjson_import_export_equivalence
|
||||
{
|
||||
local sol_file="$1"
|
||||
local input_files=( "${@:2}" )
|
||||
local outputs=( "asm" "bin" "bin-runtime" "opcodes" "srcmap" "srcmap-runtime" )
|
||||
local export_command=("$SOLC" --combined-json "$(IFS=, ; echo "${outputs[*]}")" --pretty-json --json-indent 4 "${input_files[@]}")
|
||||
local success=1
|
||||
if ! "${export_command[@]}" > expected.json 2> expected.error
|
||||
then
|
||||
success=0
|
||||
printError "ERROR: (export) EVM Assembly JSON reimport failed for ${sol_file}"
|
||||
if (( EXIT_ON_ERROR == 1 ))
|
||||
then
|
||||
print_used_commands "$(pwd)" "${export_command[*]}" ""
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
if ! "${export_command[@]}" "--optimize" > expected.optimize.json 2> expected.optimize.error
|
||||
then
|
||||
success=0
|
||||
printError "ERROR: (export with --optimize) EVM Assembly JSON reimport failed for ${sol_file}"
|
||||
if (( EXIT_ON_ERROR == 1 ))
|
||||
then
|
||||
print_used_commands "$(pwd)" "${export_command[*]} --optimize" ""
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
|
||||
for input_json in "expected.json" "expected.optimize.json"
|
||||
do
|
||||
local optimize_param=""
|
||||
if [[ "$input_json" == "expected.optimize.json" ]]
|
||||
then
|
||||
optimize_param="--optimize"
|
||||
fi
|
||||
|
||||
# Note that we have some test files, that only consist of free functions.
|
||||
# Those files don't define any contracts, so the resulting JSON does not have any
|
||||
# keys. In this case `jq` returns an error like `jq: error: null (null) has no keys`.
|
||||
# To not get spammed by these errors, errors are redirected to /dev/null.
|
||||
for contract in $(jq '.contracts | keys | .[]' "$input_json" 2> /dev/null)
|
||||
do
|
||||
for output in "${outputs[@]}"
|
||||
do
|
||||
jq --raw-output ".contracts.${contract}.\"${output}\"" "$input_json" > "expected.${output}.json"
|
||||
done
|
||||
|
||||
assembly=$(cat expected.asm.json)
|
||||
[[ $assembly != "" && $assembly != "null" ]] || continue
|
||||
|
||||
local import_command=("${SOLC}" --combined-json "bin,bin-runtime,opcodes,asm,srcmap,srcmap-runtime" --pretty-json --json-indent 4 --import-asm-json expected.asm.json)
|
||||
if ! "${import_command[@]}" > obtained.json 2> obtained.error
|
||||
then
|
||||
success=0
|
||||
printError "ERROR: (import) EVM Assembly JSON reimport failed for ${sol_file}"
|
||||
if (( EXIT_ON_ERROR == 1 ))
|
||||
then
|
||||
print_used_commands "$(pwd)" "${export_command[*]} ${optimize_param}" "${import_command[*]}"
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
|
||||
for output in "${outputs[@]}"
|
||||
do
|
||||
for obtained_contract in $(jq '.contracts | keys | .[]' obtained.json 2> /dev/null)
|
||||
do
|
||||
jq --raw-output ".contracts.${obtained_contract}.\"${output}\"" obtained.json > "obtained.${output}.json"
|
||||
# compare expected and obtained evm assembly json
|
||||
if ! diff_files "expected.${output}.json" "obtained.${output}.json"
|
||||
then
|
||||
success=0
|
||||
printError "ERROR: (${output}) EVM Assembly JSON reimport failed for ${sol_file}"
|
||||
if (( EXIT_ON_ERROR == 1 ))
|
||||
then
|
||||
print_used_commands "$(pwd)" "${export_command[*]} ${optimize_param}" "${import_command[*]}"
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
done
|
||||
done
|
||||
|
||||
# direct export via --asm-json, if imported with --import-asm-json.
|
||||
if ! "${SOLC}" --asm-json --import-asm-json expected.asm.json --pretty-json --json-indent 4 | tail -n+2 > obtained_direct_import_export.json 2> obtained_direct_import_export.error
|
||||
then
|
||||
success=0
|
||||
printError "ERROR: (direct) EVM Assembly JSON reimport failed for ${sol_file}"
|
||||
if (( EXIT_ON_ERROR == 1 ))
|
||||
then
|
||||
print_used_commands "$(pwd)" "${SOLC} --asm-json --import-asm-json expected.asm.json --pretty-json --json-indent 4 | tail -n+4" ""
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
|
||||
# reformat json files using jq.
|
||||
jq . expected.asm.json > expected.asm.json.pretty
|
||||
jq . obtained_direct_import_export.json > obtained_direct_import_export.json.pretty
|
||||
|
||||
# compare expected and obtained evm assembly.
|
||||
if ! diff_files expected.asm.json.pretty obtained_direct_import_export.json.pretty
|
||||
then
|
||||
success=0
|
||||
printError "ERROR: EVM Assembly JSON reimport failed for ${sol_file}"
|
||||
if (( EXIT_ON_ERROR == 1 ))
|
||||
then
|
||||
print_used_commands "$(pwd)" "${export_command[*]} ${optimize_param}" "${import_command[*]}"
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
done
|
||||
done
|
||||
|
||||
if (( success == 1 ))
|
||||
then
|
||||
TESTED=$((TESTED + 1))
|
||||
else
|
||||
FAILED=$((FAILED + 1))
|
||||
fi
|
||||
}
|
||||
|
||||
# function tests whether exporting and importing again is equivalent.
|
||||
# Results are recorded by incrementing the FAILED or UNCOMPILABLE global variable.
|
||||
# Also, in case of a mismatch a diff is printed
|
||||
@@ -168,6 +301,7 @@ function test_import_export_equivalence {
|
||||
|
||||
case "$IMPORT_TEST_TYPE" in
|
||||
ast) compile_test="--ast-compact-json" ;;
|
||||
evm-assembly) compile_test="--bin" ;;
|
||||
*) assertFail "Unknown import test type '${IMPORT_TEST_TYPE}'. Aborting." ;;
|
||||
esac
|
||||
|
||||
@@ -181,6 +315,7 @@ function test_import_export_equivalence {
|
||||
then
|
||||
case "$IMPORT_TEST_TYPE" in
|
||||
ast) test_ast_import_export_equivalence "${sol_file}" "${input_files[@]}" ;;
|
||||
evm-assembly) test_evmjson_import_export_equivalence "${sol_file}" "${input_files[@]}" ;;
|
||||
*) assertFail "Unknown import test type '${IMPORT_TEST_TYPE}'. Aborting." ;;
|
||||
esac
|
||||
else
|
||||
@@ -191,7 +326,20 @@ function test_import_export_equivalence {
|
||||
# and print some details about the corresponding solc invocation.
|
||||
if (( solc_return_code == 2 ))
|
||||
then
|
||||
fail "\n\nERROR: Uncaught Exception while executing '$SOLC ${compile_test} ${input_files[*]}':\n${output}\n"
|
||||
# For the evm-assembly import/export tests, this script uses only the
|
||||
# old code generator. Some semantic test can only be compiled with
|
||||
# --via-ir (some need to be additionally compiled with --optimize).
|
||||
# The tests that are meant to be compiled with --via-ir are throwing
|
||||
# an UnimplementedFeatureError exception (e.g. Copying of type struct C.S
|
||||
# memory[] memory to storage not yet supported, Copying nested calldata
|
||||
# dynamic arrays to storage is not implemented in the old code generator.)
|
||||
# We will just ignore these kind of exceptions for now.
|
||||
# However, any other exception will be treated as a fatal error and the
|
||||
# script execution will be terminated with an error.
|
||||
if [[ "$output" != *"UnimplementedFeatureError"* ]]
|
||||
then
|
||||
fail "\n\nERROR: Uncaught Exception while executing '$SOLC ${compile_test} ${input_files[*]}':\n${output}\n"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
}
|
||||
@@ -203,6 +351,7 @@ command_available jq --version
|
||||
|
||||
case "$IMPORT_TEST_TYPE" in
|
||||
ast) TEST_DIRS=("${SYNTAXTESTS_DIR}" "${ASTJSONTESTS_DIR}") ;;
|
||||
evm-assembly) TEST_DIRS=("${SEMANTICTESTS_DIR}") ;;
|
||||
*) assertFail "Import test type not defined. $(print_usage)" ;;
|
||||
esac
|
||||
|
||||
|
||||
Reference in New Issue
Block a user