From 2ef3defbe2f98bda83576767e694dda359901337 Mon Sep 17 00:00:00 2001 From: Dimitry Kh Date: Wed, 17 Jul 2024 10:19:53 +0200 Subject: [PATCH 1/8] coverage on every pr --- .github/workflows/coverage.yaml | 130 +++++++++++++++++++++++++++----- 1 file changed, 110 insertions(+), 20 deletions(-) diff --git a/.github/workflows/coverage.yaml b/.github/workflows/coverage.yaml index bfe1ffe762..0119fedecc 100644 --- a/.github/workflows/coverage.yaml +++ b/.github/workflows/coverage.yaml @@ -3,7 +3,7 @@ name: Evmone Coverage Report on: pull_request: paths: - - 'converted-ethereum-tests.txt' # This triggers the workflow only for changes in file.txt + - 'tests/**' # This triggers the workflow for any changes in the tests folder jobs: evmone-coverage-diff: @@ -74,14 +74,16 @@ jobs: - name: Parse converted tests from converted-ethereum-tests.txt run: | echo "New lines introduced in converted-ethereum-tests.txt:" - lines=$(git diff origin/${{ github.base_ref }} HEAD -- converted-ethereum-tests.txt | grep "^+" | grep -v "^+++") - files=$(echo "$lines" | grep -oP '(?<=\+).+\.json') - - if [ -z "$files" ]; then - echo "Error: No new JSON files found in converted-ethereum-tests.txt" - exit 1 + lines=$(git diff origin/${{ github.base_ref }} HEAD -- converted-ethereum-tests.txt | grep "^+" | grep -v "^+++" || true) + if [ -z "$lines" ]; then + echo "No new lines in converted-ethereum-tests.txt, check updates instead:" + echo "converted_skip=true" >> $GITHUB_ENV + exit 0 + else + echo "converted_skip=false" >> $GITHUB_ENV fi + files=$(echo "$lines" | grep -oP '(?<=\+).+\.json') for file in $files; do echo $file done @@ -118,7 +120,7 @@ jobs: exit 1 fi done - + # This command diffs the .py scripts introduced by a PR - name: Parse and fill introduced test sources @@ -149,13 +151,32 @@ jobs: # fill new tests # using `|| true` here because if no tests found, pyspec fill returns error code + FOUND_TEST=false mkdir -p fixtures/state_tests mkdir -p fixtures/eof_tests - echo "$files" | while read line; do + + # Use a while loop with a here-string to avoid subshell issues + while IFS= read -r line; do file=$(echo "$line" | cut -c 3-) - fill $file --until=Cancun --evm-bin evmone-t8n || true >> filloutput.log 2>&1 - (fill $file --fork=CancunEIP7692 --evm-bin evmone-t8n -k eof_test || true) > >(tee -a filloutput.log filloutputEOF.log) 2>&1 - done + if grep -q "def test_" "$file"; then + FOUND_TEST=true + fill "$file" --until=Cancun --evm-bin evmone-t8n || true >> filloutput.log 2>&1 + (fill "$file" --fork=CancunEIP7692 --evm-bin evmone-t8n -k eof_test || true) > >(tee -a filloutput.log filloutputEOF.log) 2>&1 + fi + done <<< "$files" + + echo "Tests found: $FOUND_TEST" + if [[ "$FOUND_TEST" == "false" ]]; then + if [ "${{ env.converted_skip }}" == 'false' ]; then + echo "Error converted-ethereum-tests.txt has new lines, but no test in .py files were found" + exit 1 + fi + echo "No test detected in changed .py files, exiting the script" + echo "coverage_skip=true" >> $GITHUB_ENV + exit 0 + else + echo "coverage_skip=false" >> $GITHUB_ENV + fi if grep -q "FAILURES" filloutput.log; then echo "Error: failed to generate .py tests." @@ -182,8 +203,77 @@ jobs: find fixtures/state_tests -type f -name "*.json" -exec cp {} $PATCH_TEST_PATH \; find fixtures/eof_tests -type f -name "*.json" -exec cp {} $PATCH_TEST_PATH \; + - name: Parse and fill introduced test sources from before the PR + if: ${{ (env.retesteth_skip == 'false' || matrix.driver == 'native') && env.converted_skip == 'true' && env.coverage_skip == 'false'}} + run: | + echo "--------------------" + echo "converted-ethereum-tests.txt seem untouched, try to fill pre-patched version of .py files:" + + if [ "${{ github.event.pull_request.head.repo.full_name }}" != "${{ github.repository }}" ]; then + files=$(git diff --name-status origin/${{ github.base_ref }}...origin/PR-${{ github.event.pull_request.number }} -- tests/ | grep -E '^[AM]' | grep '\.py$') + else + files=$(git diff --name-status origin/${{ github.base_ref }}...origin/${{ github.head_ref }} -- tests/ | grep -E '^[AM]' | grep '\.py$') + fi + + echo "Modified or new .py files in tests folder:" + echo "$files" | while read line; do + file=$(echo "$line" | cut -c 3-) + echo $file + done + + git checkout main + PREV_COMMIT=$(git rev-parse HEAD) + echo "Checkout head $PREV_COMMIT" + + python3 -m venv ./venv/ + source ./venv/bin/activate + + rm -r fixtures + rm filloutput.log + rm filloutputEOF.log + mkdir -p fixtures/state_tests + mkdir -p fixtures/eof_tests + + FOUND_TEST=false + while IFS= read -r line; do + file=$(echo "$line" | cut -c 3-) + if grep -q "def test_" "$file"; then + FOUND_TEST=true + fill "$file" --until=Cancun --evm-bin evmone-t8n || true >> filloutput.log 2>&1 + (fill "$file" --fork=CancunEIP7692 --evm-bin evmone-t8n -k eof_test || true) > >(tee -a filloutput.log filloutputEOF.log) 2>&1 + fi + done <<< "$files" + + echo "Tests found: $FOUND_TEST" + if [[ "$FOUND_TEST" == "false" ]]; then + echo "No test detected in .py files from before the PR, exiting the script" + echo "coverage_skip=true" >> $GITHUB_ENV + exit 0 + fi + + if grep -q "FAILURES" filloutput.log; then + echo "Error: failed to generate .py tests from before the PR." + exit 1 + fi + + filesState=$(find fixtures/state_tests -type f -name "*.json") + filesEOF=$(find fixtures/eof_tests -type f -name "*.json") + if [ -z "$filesState" ] && [ -z "$filesEOF" ]; then + echo "Error: No filled JSON fixtures found in fixtures from before the PR." + exit 1 + fi + + BASE_TEST_PATH=${{ github.workspace }}/evmtest_coverage/coverage/BASE_TESTS + mkdir -p $BASE_TEST_PATH + find fixtures/state_tests -type f -name "*.json" -exec cp {} $BASE_TEST_PATH \; + find fixtures/eof_tests -type f -name "*.json" -exec cp {} $BASE_TEST_PATH \; + for file in $BASE_TEST_PATH/*.json; do + mv "$file" "${file%.json}_$PREV_COMMIT.json" + done + + - name: Print tests that will be covered - if: ${{ env.retesteth_skip == 'false' || matrix.driver == 'native' }} + if: ${{ (env.retesteth_skip == 'false' || matrix.driver == 'native') && env.coverage_skip == 'false' }} run: | echo "Original BASE tests:" ls ${{ github.workspace }}/evmtest_coverage/coverage/BASE_TESTS @@ -193,7 +283,7 @@ jobs: - name: Run coverage of the BASE tests uses: addnab/docker-run-action@v3 - if: ${{ env.retesteth_skip == 'false' || matrix.driver == 'native' }} + if: ${{ (env.retesteth_skip == 'false' || matrix.driver == 'native') && env.coverage_skip == 'false' }} with: image: winsvega/evmone-coverage-script:latest options: -v ${{ github.workspace }}/evmtest_coverage/coverage:/tests @@ -201,7 +291,7 @@ jobs: - name: Run coverage of the PATCH tests uses: addnab/docker-run-action@v3 - if: ${{ env.retesteth_skip == 'false' || matrix.driver == 'native' }} + if: ${{ (env.retesteth_skip == 'false' || matrix.driver == 'native') && env.coverage_skip == 'false' }} with: image: winsvega/evmone-coverage-script:latest options: -v ${{ github.workspace }}/evmtest_coverage/coverage:/tests @@ -209,28 +299,28 @@ jobs: - name: Run coverage DIFF of the PATCH tests compared to BASE tests uses: addnab/docker-run-action@v3 - if: ${{ env.retesteth_skip == 'false' || matrix.driver == 'native' }} + if: ${{ (env.retesteth_skip == 'false' || matrix.driver == 'native') && env.coverage_skip == 'false' }} with: image: winsvega/evmone-coverage-script:latest options: -v ${{ github.workspace }}/evmtest_coverage/coverage:/tests run: /entrypoint.sh --mode=diff --basefile=coverage_BASE.lcov --patchfile=coverage_PATCH.lcov - name: Chmod coverage results - if: ${{ env.retesteth_skip == 'false' || matrix.driver == 'native' }} + if: ${{ (env.retesteth_skip == 'false' || matrix.driver == 'native') && env.coverage_skip == 'false' }} run: | user=$(whoami) sudo chown -R $user:$user ${{ github.workspace }}/evmtest_coverage/coverage - name: Upload coverage results uses: actions/upload-artifact@v3 - if: ${{ env.retesteth_skip == 'false' || matrix.driver == 'native' }} + if: ${{ (env.retesteth_skip == 'false' || matrix.driver == 'native') && env.coverage_skip == 'false' }} with: - name: coverage-diff + name: coverage-diff-${{ matrix.driver }} path: ${{ github.workspace }}/evmtest_coverage/coverage - name: Verify coverage results uses: addnab/docker-run-action@v3 - if: ${{ env.retesteth_skip == 'false' || matrix.driver == 'native' }} + if: ${{ (env.retesteth_skip == 'false' || matrix.driver == 'native') && env.coverage_skip == 'false' }} with: image: winsvega/evmone-coverage-script:latest options: -v ${{ github.workspace }}/evmtest_coverage/coverage:/tests From ba9c5af31a6d34060f973691b077f22914beabf1 Mon Sep 17 00:00:00 2001 From: Dimitry Kh Date: Tue, 23 Jul 2024 11:59:30 +0200 Subject: [PATCH 2/8] do not try to detect tests in files do not skip the coverage script for safety --- .github/workflows/coverage.yaml | 57 +++++++-------------------------- 1 file changed, 12 insertions(+), 45 deletions(-) diff --git a/.github/workflows/coverage.yaml b/.github/workflows/coverage.yaml index 0119fedecc..0f63a825f6 100644 --- a/.github/workflows/coverage.yaml +++ b/.github/workflows/coverage.yaml @@ -151,33 +151,16 @@ jobs: # fill new tests # using `|| true` here because if no tests found, pyspec fill returns error code - FOUND_TEST=false mkdir -p fixtures/state_tests mkdir -p fixtures/eof_tests # Use a while loop with a here-string to avoid subshell issues while IFS= read -r line; do file=$(echo "$line" | cut -c 3-) - if grep -q "def test_" "$file"; then - FOUND_TEST=true - fill "$file" --until=Cancun --evm-bin evmone-t8n || true >> filloutput.log 2>&1 - (fill "$file" --fork=CancunEIP7692 --evm-bin evmone-t8n -k eof_test || true) > >(tee -a filloutput.log filloutputEOF.log) 2>&1 - fi + fill "$file" --until=Cancun --evm-bin evmone-t8n || true >> filloutput.log 2>&1 + (fill "$file" --fork=CancunEIP7692 --evm-bin evmone-t8n -k eof_test || true) > >(tee -a filloutput.log filloutputEOF.log) 2>&1 done <<< "$files" - echo "Tests found: $FOUND_TEST" - if [[ "$FOUND_TEST" == "false" ]]; then - if [ "${{ env.converted_skip }}" == 'false' ]; then - echo "Error converted-ethereum-tests.txt has new lines, but no test in .py files were found" - exit 1 - fi - echo "No test detected in changed .py files, exiting the script" - echo "coverage_skip=true" >> $GITHUB_ENV - exit 0 - else - echo "coverage_skip=false" >> $GITHUB_ENV - fi - if grep -q "FAILURES" filloutput.log; then echo "Error: failed to generate .py tests." exit 1 @@ -190,13 +173,8 @@ jobs: echo "retesteth_skip=false" >> $GITHUB_ENV fi - filesState=$(find fixtures/state_tests -type f -name "*.json") filesEOF=$(find fixtures/eof_tests -type f -name "*.json") - if [ -z "$filesState" ] && [ -z "$filesEOF" ]; then - echo "Error: No filled JSON fixtures found in fixtures." - exit 1 - fi PATCH_TEST_PATH=${{ github.workspace }}/evmtest_coverage/coverage/PATCH_TESTS mkdir -p $PATCH_TEST_PATH @@ -204,7 +182,7 @@ jobs: find fixtures/eof_tests -type f -name "*.json" -exec cp {} $PATCH_TEST_PATH \; - name: Parse and fill introduced test sources from before the PR - if: ${{ (env.retesteth_skip == 'false' || matrix.driver == 'native') && env.converted_skip == 'true' && env.coverage_skip == 'false'}} + if: ${{ (env.retesteth_skip == 'false' || matrix.driver == 'native') && env.converted_skip == 'true' }} run: | echo "--------------------" echo "converted-ethereum-tests.txt seem untouched, try to fill pre-patched version of .py files:" @@ -234,23 +212,12 @@ jobs: mkdir -p fixtures/state_tests mkdir -p fixtures/eof_tests - FOUND_TEST=false while IFS= read -r line; do file=$(echo "$line" | cut -c 3-) - if grep -q "def test_" "$file"; then - FOUND_TEST=true - fill "$file" --until=Cancun --evm-bin evmone-t8n || true >> filloutput.log 2>&1 - (fill "$file" --fork=CancunEIP7692 --evm-bin evmone-t8n -k eof_test || true) > >(tee -a filloutput.log filloutputEOF.log) 2>&1 - fi + fill "$file" --until=Cancun --evm-bin evmone-t8n || true >> filloutput.log 2>&1 + (fill "$file" --fork=CancunEIP7692 --evm-bin evmone-t8n -k eof_test || true) > >(tee -a filloutput.log filloutputEOF.log) 2>&1 done <<< "$files" - echo "Tests found: $FOUND_TEST" - if [[ "$FOUND_TEST" == "false" ]]; then - echo "No test detected in .py files from before the PR, exiting the script" - echo "coverage_skip=true" >> $GITHUB_ENV - exit 0 - fi - if grep -q "FAILURES" filloutput.log; then echo "Error: failed to generate .py tests from before the PR." exit 1 @@ -273,7 +240,7 @@ jobs: - name: Print tests that will be covered - if: ${{ (env.retesteth_skip == 'false' || matrix.driver == 'native') && env.coverage_skip == 'false' }} + if: ${{ (env.retesteth_skip == 'false' || matrix.driver == 'native') }} run: | echo "Original BASE tests:" ls ${{ github.workspace }}/evmtest_coverage/coverage/BASE_TESTS @@ -283,7 +250,7 @@ jobs: - name: Run coverage of the BASE tests uses: addnab/docker-run-action@v3 - if: ${{ (env.retesteth_skip == 'false' || matrix.driver == 'native') && env.coverage_skip == 'false' }} + if: ${{ (env.retesteth_skip == 'false' || matrix.driver == 'native') }} with: image: winsvega/evmone-coverage-script:latest options: -v ${{ github.workspace }}/evmtest_coverage/coverage:/tests @@ -291,7 +258,7 @@ jobs: - name: Run coverage of the PATCH tests uses: addnab/docker-run-action@v3 - if: ${{ (env.retesteth_skip == 'false' || matrix.driver == 'native') && env.coverage_skip == 'false' }} + if: ${{ (env.retesteth_skip == 'false' || matrix.driver == 'native') }} with: image: winsvega/evmone-coverage-script:latest options: -v ${{ github.workspace }}/evmtest_coverage/coverage:/tests @@ -299,28 +266,28 @@ jobs: - name: Run coverage DIFF of the PATCH tests compared to BASE tests uses: addnab/docker-run-action@v3 - if: ${{ (env.retesteth_skip == 'false' || matrix.driver == 'native') && env.coverage_skip == 'false' }} + if: ${{ (env.retesteth_skip == 'false' || matrix.driver == 'native') }} with: image: winsvega/evmone-coverage-script:latest options: -v ${{ github.workspace }}/evmtest_coverage/coverage:/tests run: /entrypoint.sh --mode=diff --basefile=coverage_BASE.lcov --patchfile=coverage_PATCH.lcov - name: Chmod coverage results - if: ${{ (env.retesteth_skip == 'false' || matrix.driver == 'native') && env.coverage_skip == 'false' }} + if: ${{ (env.retesteth_skip == 'false' || matrix.driver == 'native') }} run: | user=$(whoami) sudo chown -R $user:$user ${{ github.workspace }}/evmtest_coverage/coverage - name: Upload coverage results uses: actions/upload-artifact@v3 - if: ${{ (env.retesteth_skip == 'false' || matrix.driver == 'native') && env.coverage_skip == 'false' }} + if: ${{ (env.retesteth_skip == 'false' || matrix.driver == 'native') }} with: name: coverage-diff-${{ matrix.driver }} path: ${{ github.workspace }}/evmtest_coverage/coverage - name: Verify coverage results uses: addnab/docker-run-action@v3 - if: ${{ (env.retesteth_skip == 'false' || matrix.driver == 'native') && env.coverage_skip == 'false' }} + if: ${{ (env.retesteth_skip == 'false' || matrix.driver == 'native') }} with: image: winsvega/evmone-coverage-script:latest options: -v ${{ github.workspace }}/evmtest_coverage/coverage:/tests From b20719e65c4e7477bee8084c102a558ac40c56f8 Mon Sep 17 00:00:00 2001 From: Dimitry Kh Date: Tue, 23 Jul 2024 13:54:54 +0200 Subject: [PATCH 3/8] build the changed files array once --- .github/workflows/coverage.yaml | 97 ++++++++++++++++++--------------- 1 file changed, 54 insertions(+), 43 deletions(-) diff --git a/.github/workflows/coverage.yaml b/.github/workflows/coverage.yaml index 0f63a825f6..cd0ef0d2f0 100644 --- a/.github/workflows/coverage.yaml +++ b/.github/workflows/coverage.yaml @@ -16,8 +16,38 @@ jobs: - name: Checkout code uses: actions/checkout@v3 - - name: Fetch target branch - run: git fetch origin ${{ github.base_ref }}:refs/remotes/origin/${{ github.base_ref }} + - name: Fetch github branches and detect introduces .py files + run: | + if [ "${{ github.event.pull_request.head.repo.full_name }}" != "${{ github.repository }}" ]; then + # Fetch changes when PR comes from remote repo + git fetch origin +refs/heads/${{ github.base_ref }}:refs/remotes/origin/${{ github.base_ref }} + git fetch origin +refs/pull/${{ github.event.pull_request.number }}/head:refs/remotes/origin/PR-${{ github.event.pull_request.number }} + files=$(git diff --name-status origin/${{ github.base_ref }}...origin/PR-${{ github.event.pull_request.number }} -- tests/ | grep -E '^[AM]' | grep '\.py$') + else + # Fetch the base branch and the head branch + git fetch origin ${{ github.base_ref }}:refs/remotes/origin/${{ github.base_ref }} + git fetch origin ${{ github.head_ref }}:refs/remotes/origin/${{ github.head_ref }} + files=$(git diff --name-status origin/${{ github.base_ref }}...origin/${{ github.head_ref }} -- tests/ | grep -E '^[AM]' | grep '\.py$') + fi + + # Eliminate git diff chars, select only .py paths + echo "Collect the changed .py files" + py_files=() + while read -r line; do + file_fixed=$(echo "$line" | cut -c 3-) + py_files+=("$file_fixed") + done <<< "$files" + + echo "Prepare the NEW_TESTS variable" + py_files_str=$(IFS=,; echo "${py_files[*]}") + echo "NEW_TESTS=$py_files_str" >> $GITHUB_ENV + + echo "Detected new/changed .py files:" + source $GITHUB_ENV + files2=$(echo "$NEW_TESTS" | tr ',' '\n') + while IFS= read -r file; do + echo $file + done <<< "$files2" - name: Log in to Docker Hub uses: docker/login-action@v3 @@ -125,38 +155,20 @@ jobs: # This command diffs the .py scripts introduced by a PR - name: Parse and fill introduced test sources run: | + source $GITHUB_ENV + files=$(echo "$NEW_TESTS" | tr ',' '\n') + python3 -m venv ./venv/ source ./venv/bin/activate - if [ "${{ github.event.pull_request.head.repo.full_name }}" != "${{ github.repository }}" ]; then - # Fetch changes when PR comes from remote repo - git fetch origin +refs/heads/${{ github.base_ref }}:refs/remotes/origin/${{ github.base_ref }} - git fetch origin +refs/pull/${{ github.event.pull_request.number }}/head:refs/remotes/origin/PR-${{ github.event.pull_request.number }} - files=$(git diff --name-status origin/${{ github.base_ref }}...origin/PR-${{ github.event.pull_request.number }} -- tests/ | grep -E '^[AM]' | grep '\.py$') - else - # Fetch the base branch and the head branch - git fetch origin ${{ github.base_ref }}:refs/remotes/origin/${{ github.base_ref }} - git fetch origin ${{ github.head_ref }}:refs/remotes/origin/${{ github.head_ref }} - - # Perform the diff - files=$(git diff --name-status origin/${{ github.base_ref }}...origin/${{ github.head_ref }} -- tests/ | grep -E '^[AM]' | grep '\.py$') - fi - - - echo "Modified or new .py files in tests folder:" - echo "$files" | while read line; do - file=$(echo "$line" | cut -c 3-) - echo $file - done - # fill new tests # using `|| true` here because if no tests found, pyspec fill returns error code mkdir -p fixtures/state_tests mkdir -p fixtures/eof_tests # Use a while loop with a here-string to avoid subshell issues - while IFS= read -r line; do - file=$(echo "$line" | cut -c 3-) + while IFS= read -r file; do + echo "Fill: $file" fill "$file" --until=Cancun --evm-bin evmone-t8n || true >> filloutput.log 2>&1 (fill "$file" --fork=CancunEIP7692 --evm-bin evmone-t8n -k eof_test || true) > >(tee -a filloutput.log filloutputEOF.log) 2>&1 done <<< "$files" @@ -175,6 +187,14 @@ jobs: filesState=$(find fixtures/state_tests -type f -name "*.json") filesEOF=$(find fixtures/eof_tests -type f -name "*.json") + if [ -z "$filesState" ] && [ -z "$filesEOF" ]; then + echo "Error: No filled JSON fixtures found in fixtures." + exit 1 + fi + + # Include basic evm operations into coverage by default + # As when we translate from yul/solidity some dup/push opcodes could become untouched + fill tests/homestead/coverage/test_coverage.py --until=Cancun --evm-bin evmone-t8n PATCH_TEST_PATH=${{ github.workspace }}/evmtest_coverage/coverage/PATCH_TESTS mkdir -p $PATCH_TEST_PATH @@ -187,17 +207,9 @@ jobs: echo "--------------------" echo "converted-ethereum-tests.txt seem untouched, try to fill pre-patched version of .py files:" - if [ "${{ github.event.pull_request.head.repo.full_name }}" != "${{ github.repository }}" ]; then - files=$(git diff --name-status origin/${{ github.base_ref }}...origin/PR-${{ github.event.pull_request.number }} -- tests/ | grep -E '^[AM]' | grep '\.py$') - else - files=$(git diff --name-status origin/${{ github.base_ref }}...origin/${{ github.head_ref }} -- tests/ | grep -E '^[AM]' | grep '\.py$') - fi - - echo "Modified or new .py files in tests folder:" - echo "$files" | while read line; do - file=$(echo "$line" | cut -c 3-) - echo $file - done + # load introduces .py files + source $GITHUB_ENV + files=$(echo "$NEW_TESTS" | tr ',' '\n') git checkout main PREV_COMMIT=$(git rev-parse HEAD) @@ -212,8 +224,9 @@ jobs: mkdir -p fixtures/state_tests mkdir -p fixtures/eof_tests - while IFS= read -r line; do - file=$(echo "$line" | cut -c 3-) + # Use a while loop with a here-string to avoid subshell issues + while IFS= read -r file; do + echo "Fill: $file" fill "$file" --until=Cancun --evm-bin evmone-t8n || true >> filloutput.log 2>&1 (fill "$file" --fork=CancunEIP7692 --evm-bin evmone-t8n -k eof_test || true) > >(tee -a filloutput.log filloutputEOF.log) 2>&1 done <<< "$files" @@ -225,17 +238,15 @@ jobs: filesState=$(find fixtures/state_tests -type f -name "*.json") filesEOF=$(find fixtures/eof_tests -type f -name "*.json") - if [ -z "$filesState" ] && [ -z "$filesEOF" ]; then - echo "Error: No filled JSON fixtures found in fixtures from before the PR." - exit 1 - fi BASE_TEST_PATH=${{ github.workspace }}/evmtest_coverage/coverage/BASE_TESTS mkdir -p $BASE_TEST_PATH find fixtures/state_tests -type f -name "*.json" -exec cp {} $BASE_TEST_PATH \; find fixtures/eof_tests -type f -name "*.json" -exec cp {} $BASE_TEST_PATH \; for file in $BASE_TEST_PATH/*.json; do - mv "$file" "${file%.json}_$PREV_COMMIT.json" + if [ -e "$file" ]; then + mv "$file" "${file%.json}_$PREV_COMMIT.json" + fi done From 498b5b40e714e5f159669aea00cd2cb788e1bfd6 Mon Sep 17 00:00:00 2001 From: Dimitry Kh Date: Sat, 10 Aug 2024 10:06:58 +0200 Subject: [PATCH 4/8] simplify regex for gitdiff changed files detection --- .github/workflows/coverage.yaml | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/.github/workflows/coverage.yaml b/.github/workflows/coverage.yaml index cd0ef0d2f0..bf8c21a4c6 100644 --- a/.github/workflows/coverage.yaml +++ b/.github/workflows/coverage.yaml @@ -18,25 +18,30 @@ jobs: - name: Fetch github branches and detect introduces .py files run: | + py_files=() if [ "${{ github.event.pull_request.head.repo.full_name }}" != "${{ github.repository }}" ]; then # Fetch changes when PR comes from remote repo git fetch origin +refs/heads/${{ github.base_ref }}:refs/remotes/origin/${{ github.base_ref }} git fetch origin +refs/pull/${{ github.event.pull_request.number }}/head:refs/remotes/origin/PR-${{ github.event.pull_request.number }} - files=$(git diff --name-status origin/${{ github.base_ref }}...origin/PR-${{ github.event.pull_request.number }} -- tests/ | grep -E '^[AM]' | grep '\.py$') + gitdiff=$(git diff --name-status origin/${{ github.base_ref }}...origin/PR-${{ github.event.pull_request.number }} -- tests/) else # Fetch the base branch and the head branch git fetch origin ${{ github.base_ref }}:refs/remotes/origin/${{ github.base_ref }} git fetch origin ${{ github.head_ref }}:refs/remotes/origin/${{ github.head_ref }} - files=$(git diff --name-status origin/${{ github.base_ref }}...origin/${{ github.head_ref }} -- tests/ | grep -E '^[AM]' | grep '\.py$') + + gitdiff=$(git diff --name-status origin/${{ github.base_ref }}...origin/${{ github.head_ref }} -- tests/) fi - # Eliminate git diff chars, select only .py paths - echo "Collect the changed .py files" - py_files=() - while read -r line; do - file_fixed=$(echo "$line" | cut -c 3-) - py_files+=("$file_fixed") - done <<< "$files" + echo "git diff:" + echo "$gitdiff" + paths=$(echo "$gitdiff" | grep -oE '/[^[:space:]]+') + while IFS= read -r line; do + py_files+=("tests$line") + done <<< "$paths" + echo "Extracted file paths:" + for path in "${py_files[@]}"; do + echo "$path" + done echo "Prepare the NEW_TESTS variable" py_files_str=$(IFS=,; echo "${py_files[*]}") From 635a9f5772566df337136d776cf2d3f8ae617036 Mon Sep 17 00:00:00 2001 From: Mario Vega Date: Wed, 28 Aug 2024 22:05:42 +0000 Subject: [PATCH 5/8] feat(types/eof): Allow skipping joining same-type sections in header --- src/ethereum_test_types/eof/v1/__init__.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/ethereum_test_types/eof/v1/__init__.py b/src/ethereum_test_types/eof/v1/__init__.py index df29c936a9..4282e4c4df 100644 --- a/src/ethereum_test_types/eof/v1/__init__.py +++ b/src/ethereum_test_types/eof/v1/__init__.py @@ -365,6 +365,10 @@ class Container(CopyValidateModel): Body: type section first, all code sections, data section(s), last container sections """ + skip_join_concurrent_sections_in_header: bool = False + """ + Skip joining concurrent sections in the header (code and container) + """ validity_error: EOFExceptionInstanceOrList | str | None = None """ Optional error expected for the container. @@ -435,7 +439,10 @@ def bytecode(self) -> bytes: # Join headers of the same kind in a list of lists, only if they are next to each other concurrent_sections: List[List[Section]] = [[header_sections[0]]] for s in header_sections[1:]: - if s.kind == concurrent_sections[-1][-1].kind: + if ( + s.kind == concurrent_sections[-1][-1].kind + and not self.skip_join_concurrent_sections_in_header + ): concurrent_sections[-1].append(s) else: concurrent_sections.append([s]) From fc72f80a184b9a32fe20203f1f267089c79f53c6 Mon Sep 17 00:00:00 2001 From: Mario Vega Date: Wed, 28 Aug 2024 22:06:55 +0000 Subject: [PATCH 6/8] refactor(tests): refactor `container.py` into `test_container_validation.py` --- .../eip3540_eof_v1/container.py | 694 ----------- .../eip3540_eof_v1/test_code_validation.py | 158 --- .../test_container_validation.py | 1019 ++++++++++++++++- 3 files changed, 1015 insertions(+), 856 deletions(-) delete mode 100644 tests/prague/eip7692_eof_v1/eip3540_eof_v1/container.py delete mode 100644 tests/prague/eip7692_eof_v1/eip3540_eof_v1/test_code_validation.py diff --git a/tests/prague/eip7692_eof_v1/eip3540_eof_v1/container.py b/tests/prague/eip7692_eof_v1/eip3540_eof_v1/container.py deleted file mode 100644 index 1d8f146c70..0000000000 --- a/tests/prague/eip7692_eof_v1/eip3540_eof_v1/container.py +++ /dev/null @@ -1,694 +0,0 @@ -""" -Test EVM Object Format Version 1 -""" - -from typing import List - -from ethereum_test_tools import EOFException -from ethereum_test_tools.eof.v1 import ( - VERSION_MAX_SECTION_KIND, - AutoSection, - Container, - Section, - SectionKind, -) -from ethereum_test_tools.eof.v1.constants import ( - MAX_CODE_INPUTS, - MAX_CODE_OUTPUTS, - MAX_CODE_SECTIONS, - MAX_OPERAND_STACK_HEIGHT, -) -from ethereum_test_tools.vm.opcode import Opcodes as Op - -INVALID: List[Container] = [ - Container( - name="single_code_section_no_data_section", - sections=[ - Section.Code(Op.STOP), - ], - auto_data_section=False, - validity_error=[EOFException.MISSING_DATA_SECTION, EOFException.UNEXPECTED_HEADER_KIND], - ), - Container( - name="incomplete_magic", - raw_bytes=bytes([0xEF]), - validity_error=EOFException.INVALID_MAGIC, - ), - Container( - name="no_version", - raw_bytes=bytes([0xEF, 0x00]), - validity_error=[EOFException.INVALID_VERSION, EOFException.INVALID_MAGIC], - ), - Container( - name="no_type_header", - raw_bytes=bytes([0xEF, 0x00, 0x01]), - # TODO the exception must be about missing section types - validity_error=EOFException.MISSING_HEADERS_TERMINATOR, - ), - Container( - name="no_type_section_size", - raw_bytes=bytes( - [0xEF, 0x00, 0x01, 0x01], - ), - # TODO the exception must be about incomplete section in the header - validity_error=[ - EOFException.MISSING_HEADERS_TERMINATOR, - EOFException.INVALID_TYPE_SECTION_SIZE, - ], - ), - Container( - name="no_code_header", - raw_bytes=bytes([0xEF, 0x00, 0x01, 0x01, 0x00, 0x04, 0xFE]), - validity_error=[EOFException.MISSING_CODE_HEADER, EOFException.UNEXPECTED_HEADER_KIND], - ), - Container( - name="code_section_size_incomplete_1", - raw_bytes=bytes([0xEF, 0x00, 0x01, 0x01, 0x00, 0x04, 0x02]), - validity_error=EOFException.INCOMPLETE_SECTION_NUMBER, - ), - Container( - name="code_section_size_incomplete_2", - raw_bytes=bytes([0xEF, 0x00, 0x01, 0x01, 0x00, 0x04, 0x02, 0x00]), - validity_error=EOFException.INCOMPLETE_SECTION_NUMBER, - ), - Container( - name="code_section_size_incomplete_3", - raw_bytes=bytes([0xEF, 0x00, 0x01, 0x01, 0x00, 0x04, 0x02, 0x00, 0x01]), - validity_error=[EOFException.MISSING_HEADERS_TERMINATOR, EOFException.ZERO_SECTION_SIZE], - ), - Container( - name="code_section_size_incomplete_4", - raw_bytes=bytes([0xEF, 0x00, 0x01, 0x01, 0x00, 0x04, 0x02, 0x00, 0x01, 0x00]), - validity_error=[EOFException.INCOMPLETE_SECTION_SIZE, EOFException.ZERO_SECTION_SIZE], - ), - Container( - name="code_section_count_0x8000_truncated", - raw_bytes=bytes([0xEF, 0x00, 0x01, 0x01, 0x00, 0x04, 0x02, 0x80, 0x00]), - validity_error=EOFException.TOO_MANY_CODE_SECTIONS, - ), - Container( - name="code_section_count_0xFFFF_truncated", - raw_bytes=bytes([0xEF, 0x00, 0x01, 0x01, 0x00, 0x04, 0x02, 0xFF, 0xFF]), - validity_error=EOFException.TOO_MANY_CODE_SECTIONS, - ), - Container( - name="code_section_count_0x8000", - raw_bytes=bytes( - [0xEF, 0x00, 0x01, 0x01, 0x00, 0x04, 0x02, 0x80, 0x00] + [0x00, 0x01] * 0x8000 - ), - validity_error=EOFException.CONTAINER_SIZE_ABOVE_LIMIT, - ), - Container( - name="code_section_count_0xFFFF", - raw_bytes=bytes( - [0xEF, 0x00, 0x01, 0x01, 0x00, 0x04, 0x02, 0xFF, 0xFF] + [0x00, 0x01] * 0xFFFF - ), - validity_error=EOFException.CONTAINER_SIZE_ABOVE_LIMIT, - ), - Container( - name="code_section_size_0x8000_truncated", - raw_bytes=bytes([0xEF, 0x00, 0x01, 0x01, 0x00, 0x04, 0x02, 0x00, 0x01, 0x80, 0x00]), - validity_error=EOFException.MISSING_HEADERS_TERMINATOR, - ), - Container( - name="code_section_size_0xFFFF_truncated", - raw_bytes=bytes([0xEF, 0x00, 0x01, 0x01, 0x00, 0x04, 0x02, 0x00, 0x01, 0xFF, 0xFF]), - validity_error=EOFException.MISSING_HEADERS_TERMINATOR, - ), - Container( - name="terminator_incomplete", - raw_bytes=bytes( - [0xEF, 0x00, 0x01, 0x01, 0x00, 0x04, 0x02, 0x00, 0x01, 0x00, 0x01, 0x04, 0x00, 0x00] - ), - validity_error=EOFException.MISSING_HEADERS_TERMINATOR, - ), - Container( - name="no_data_section_size", - raw_bytes=bytes( - [ - 0xEF, - 0x00, - 0x01, - 0x01, - 0x00, - 0x04, - 0x02, - 0x00, - 0x01, - 0x00, - 0x00, - 0x04, - ] - ), - # TODO it looks like data section is missing or section header of type 0x00 - validity_error=EOFException.ZERO_SECTION_SIZE, - ), - Container( - name="data_section_size_incomplete", - raw_bytes=bytes( - [ - 0xEF, - 0x00, - 0x01, - 0x01, - 0x00, - 0x04, - 0x02, - 0x00, - 0x01, - 0x00, - 0x00, - 0x03, - 0x00, - ] - ), - validity_error=EOFException.ZERO_SECTION_SIZE, - ), - Container( - name="no_sections", - sections=[], - auto_data_section=False, - auto_type_section=AutoSection.NONE, - expected_bytecode="ef0001 00", - validity_error=[EOFException.MISSING_TYPE_HEADER, EOFException.UNEXPECTED_HEADER_KIND], - ), - Container( - name="no_code_section", - sections=[ - Section(kind=SectionKind.TYPE, data=bytes([0] * 4)), - Section.Data("0x00"), - ], - auto_type_section=AutoSection.NONE, - validity_error=[EOFException.MISSING_CODE_HEADER, EOFException.UNEXPECTED_HEADER_KIND], - ), - Container( - name="too_many_code_sections", - sections=[ - Section.Code(Op.JUMPF[i + 1] if i < MAX_CODE_SECTIONS else Op.STOP) - for i in range(MAX_CODE_SECTIONS + 1) - ], - validity_error=EOFException.TOO_MANY_CODE_SECTIONS, - ), - Container( - name="zero_code_sections_header", - raw_bytes=bytes( - [ - 0xEF, - 0x00, - 0x01, - 0x01, - 0x00, - 0x04, - 0x02, - 0x00, - 0x00, - 0x03, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - ] - ), - validity_error=[EOFException.ZERO_SECTION_SIZE, EOFException.INCOMPLETE_SECTION_NUMBER], - ), - # The basic `no_section_terminator` cases just remove the terminator - # and the `00` for zeroth section inputs looks like one. Error is because - # the sections are wrongly sized. - Container( - name="no_section_terminator", - header_terminator=bytes(), - sections=[Section.Code(code=Op.STOP)], - validity_error=[ - EOFException.INVALID_SECTION_BODIES_SIZE, - EOFException.INVALID_FIRST_SECTION_TYPE, - ], - ), - Container( - name="no_section_terminator_1", - header_terminator=bytes(), - sections=[Section.Code(code=Op.STOP, custom_size=2)], - validity_error=[ - EOFException.INVALID_SECTION_BODIES_SIZE, - EOFException.INVALID_FIRST_SECTION_TYPE, - ], - ), - Container( - name="no_section_terminator_2", - header_terminator=bytes(), - sections=[Section.Code(code="0x", custom_size=3)], - validity_error=EOFException.INVALID_SECTION_BODIES_SIZE, - ), - Container( - name="no_section_terminator_3", - header_terminator=bytes(), - sections=[Section.Code(code=Op.PUSH1(0) + Op.STOP)], - validity_error=[ - EOFException.INVALID_SECTION_BODIES_SIZE, - EOFException.INVALID_FIRST_SECTION_TYPE, - ], - ), - # The following cases just remove the terminator - # and the `00` for zeroth section inputs looks like one. Section bodies - # are as the size prescribes here, so the error is about the inputs of zeroth section. - Container( - name="no_section_terminator_section_bodies_ok_1", - header_terminator=bytes(), - sections=[Section.Code(code=Op.JUMPDEST + Op.STOP, custom_size=1)], - validity_error=EOFException.INVALID_FIRST_SECTION_TYPE, - ), - Container( - name="no_section_terminator_section_bodies_ok_2", - header_terminator=bytes(), - sections=[Section.Code(code=Op.JUMPDEST * 2 + Op.STOP, custom_size=2)], - validity_error=EOFException.INVALID_FIRST_SECTION_TYPE, - ), - # Here the terminator is missing but made to look like a different section - # or arbitrary byte - Container( - name="no_section_terminator_nonzero", - header_terminator=b"01", - sections=[Section.Code(code=Op.STOP)], - validity_error=[EOFException.MISSING_TERMINATOR, EOFException.UNEXPECTED_HEADER_KIND], - ), - Container( - name="no_section_terminator_nonzero_1", - header_terminator=b"02", - sections=[Section.Code(code=Op.STOP, custom_size=2)], - validity_error=[EOFException.MISSING_TERMINATOR, EOFException.UNEXPECTED_HEADER_KIND], - ), - Container( - name="no_section_terminator_nonzero_2", - header_terminator=b"03", - sections=[Section.Code(code="0x", custom_size=3)], - validity_error=[EOFException.MISSING_TERMINATOR, EOFException.UNEXPECTED_HEADER_KIND], - ), - Container( - name="no_section_terminator_nonzero_3", - header_terminator=b"04", - sections=[Section.Code(code=Op.PUSH1(0) + Op.STOP)], - validity_error=[EOFException.MISSING_TERMINATOR, EOFException.UNEXPECTED_HEADER_KIND], - ), - Container( - name="no_section_terminator_nonzero_4", - header_terminator=b"fe", - sections=[Section.Code(code=Op.PUSH1(0) + Op.STOP)], - validity_error=[EOFException.MISSING_TERMINATOR, EOFException.UNEXPECTED_HEADER_KIND], - ), - Container( - name="no_code_section_contents", - sections=[Section.Code(code="0x", custom_size=0x01)], - validity_error=EOFException.INVALID_SECTION_BODIES_SIZE, - ), - Container( - name="incomplete_code_section_contents", - sections=[ - Section.Code(code=Op.STOP, custom_size=0x02), - ], - validity_error=EOFException.INVALID_SECTION_BODIES_SIZE, - ), - Container( - name="trailing_bytes_after_code_section", - sections=[Section.Code(code=Op.PUSH1(0) + Op.STOP)], - extra=bytes([0xDE, 0xAD, 0xBE, 0xEF]), - validity_error=EOFException.INVALID_SECTION_BODIES_SIZE, - ), - Container( - name="empty_code_section", - sections=[Section.Code(code="0x")], - # TODO the exception must be about code section EOFException.INVALID_CODE_SECTION, - validity_error=EOFException.ZERO_SECTION_SIZE, - ), - Container( - name="empty_code_section_with_non_empty_data", - sections=[ - Section.Code(code="0x"), - Section.Data(data="0xDEADBEEF"), - ], - # TODO the exception must be about code section EOFException.INVALID_CODE_SECTION, - validity_error=EOFException.ZERO_SECTION_SIZE, - ), - Container( - name="no_data_section_contents", - sections=[ - Section.Code(Op.STOP), - Section.Data(data="0x", custom_size=1), - ], - code="ef0001 010004 0200010001 040001 00 00800000 00", - validity_error=EOFException.TOPLEVEL_CONTAINER_TRUNCATED, - ), - Container( - name="data_section_contents_incomplete", - sections=[ - Section.Code(Op.STOP), - Section.Data(data="0xAABBCC", custom_size=4), - ], - validity_error=EOFException.TOPLEVEL_CONTAINER_TRUNCATED, - ), - Container( - name="data_section_preceding_code_section", - auto_data_section=False, - auto_sort_sections=AutoSection.NONE, - sections=[ - Section.Data(data="0xDEADBEEF"), - Section.Code(Op.STOP), - ], - validity_error=[EOFException.MISSING_CODE_HEADER, EOFException.UNEXPECTED_HEADER_KIND], - ), - Container( - name="data_section_without_code_section", - sections=[Section.Data(data="0xDEADBEEF")], - # TODO the actual exception should be EOFException.MISSING_CODE_HEADER - validity_error=[EOFException.ZERO_SECTION_SIZE, EOFException.UNEXPECTED_HEADER_KIND], - ), - Container( - name="no_section_terminator_3a", - header_terminator=bytes(), - sections=[Section.Code(code="0x030004")], - # TODO the exception must be about terminator - validity_error=[ - EOFException.INVALID_SECTION_BODIES_SIZE, - EOFException.INVALID_FIRST_SECTION_TYPE, - ], - ), - Container( - name="no_section_terminator_4a", - header_terminator=bytes(), - sections=[ - Section.Code(Op.STOP), - Section.Data(data="0xAABBCCDD"), - ], - # TODO: The error of this validation can be random. - validity_error=EOFException.INVALID_FIRST_SECTION_TYPE, - ), - Container( - name="trailing_bytes_after_data_section", - extra=bytes([0xEE]), - sections=[ - Section.Code(code=Op.PUSH1(0) + Op.STOP), - Section.Data(data="0xAABBCCDD"), - ], - # TODO should be more specific exception about trailing bytes - validity_error=EOFException.INVALID_SECTION_BODIES_SIZE, - ), - Container( - name="multiple_data_sections", - sections=[ - Section.Code(code=Op.PUSH1(0) + Op.STOP), - Section.Data(data="0xAABBCC"), - Section.Data(data="0xAABBCC"), - ], - validity_error=[EOFException.MISSING_TERMINATOR, EOFException.UNEXPECTED_HEADER_KIND], - ), - Container( - name="multiple_code_and_data_sections", - sections=[ - Section.Code(Op.STOP), - Section.Code(Op.STOP), - Section.Data(data="0xAA"), - Section.Data(data="0xAA"), - ], - validity_error=[EOFException.MISSING_TERMINATOR, EOFException.UNEXPECTED_HEADER_KIND], - ), - Container( - name="unknown_section_1", - sections=[ - Section.Code(Op.STOP), - Section.Data(data="0x"), - Section(kind=VERSION_MAX_SECTION_KIND + 1, data="0x01"), - ], - validity_error=[EOFException.MISSING_TERMINATOR, EOFException.UNEXPECTED_HEADER_KIND], - ), - Container( - name="unknown_section_2", - sections=[ - Section(kind=VERSION_MAX_SECTION_KIND + 1, data="0x01"), - Section.Data(data="0x"), - Section.Code(Op.STOP), - ], - # TODO the exception should be about unknown section definition - validity_error=[EOFException.MISSING_TERMINATOR, EOFException.UNEXPECTED_HEADER_KIND], - ), - Container( - name="unknown_section_empty", - sections=[ - Section.Code(Op.STOP), - Section.Data(data="0x"), - Section(kind=VERSION_MAX_SECTION_KIND + 1, data="0x"), - ], - validity_error=[EOFException.MISSING_TERMINATOR, EOFException.UNEXPECTED_HEADER_KIND], - ), - Container( - name="no_type_section", - sections=[ - Section.Code(code=Op.STOP), - Section.Data("0x00"), - ], - auto_type_section=AutoSection.NONE, - validity_error=[EOFException.MISSING_TYPE_HEADER, EOFException.UNEXPECTED_HEADER_KIND], - ), - Container( - name="too_many_type_sections", - sections=[ - Section(kind=SectionKind.TYPE, data="0x00000000"), - Section(kind=SectionKind.TYPE, data="0x00000000"), - Section.Code(Op.STOP), - ], - auto_type_section=AutoSection.NONE, - validity_error=[EOFException.MISSING_CODE_HEADER, EOFException.UNEXPECTED_HEADER_KIND], - ), - Container( - name="empty_type_section", - sections=[ - Section(kind=SectionKind.TYPE, data="0x"), - Section.Code(Op.STOP), - ], - auto_type_section=AutoSection.NONE, - # TODO the exception must be about type section EOFException.INVALID_TYPE_SECTION_SIZE, - validity_error=[EOFException.ZERO_SECTION_SIZE, EOFException.INVALID_SECTION_BODIES_SIZE], - ), - Container( - name="type_section_too_small_1", - sections=[ - Section(kind=SectionKind.TYPE, data="0x00"), - Section.Code(Op.STOP), - ], - auto_type_section=AutoSection.NONE, - validity_error=EOFException.INVALID_TYPE_SECTION_SIZE, - ), - Container( - name="type_section_too_small_2", - sections=[ - Section(kind=SectionKind.TYPE, data="0x000000"), - Section.Code(Op.STOP), - ], - auto_type_section=AutoSection.NONE, - validity_error=EOFException.INVALID_TYPE_SECTION_SIZE, - ), - Container( - name="type_section_too_big", - sections=[ - Section(kind=SectionKind.TYPE, data="0x0000000000"), - Section.Code(Op.STOP), - ], - auto_type_section=AutoSection.NONE, - validity_error=EOFException.INVALID_TYPE_SECTION_SIZE, - ), -] - -# TODO: Max initcode as specified on EIP-3860 - -""" -EIP-4750 Valid and Invalid Containers -""" - -VALID = [ - Container( - name="single_code_section_max_stack_size", - sections=[ - Section.Code( - code=(Op.CALLER * MAX_OPERAND_STACK_HEIGHT) - + (Op.POP * MAX_OPERAND_STACK_HEIGHT) - + Op.STOP, - max_stack_height=MAX_OPERAND_STACK_HEIGHT, - ), - ], - ), - Container( - name="single_code_section_input_maximum", - sections=[ - Section.Code( - code=((Op.PUSH0 * MAX_CODE_INPUTS) + Op.CALLF[1] + Op.STOP), - max_stack_height=MAX_CODE_INPUTS, - ), - Section.Code( - code=(Op.POP * MAX_CODE_INPUTS) + Op.RETF, - code_inputs=MAX_CODE_INPUTS, - code_outputs=0, - max_stack_height=MAX_CODE_INPUTS, - ), - ], - ), - Container( - name="single_code_section_output_maximum", - sections=[ - Section.Code( - code=(Op.CALLF[1] + Op.STOP), - max_stack_height=MAX_CODE_OUTPUTS, - ), - Section.Code( - code=(Op.PUSH0 * MAX_CODE_OUTPUTS) + Op.RETF, - code_inputs=0, - code_outputs=MAX_CODE_OUTPUTS, - max_stack_height=MAX_CODE_OUTPUTS, - ), - ], - ), - Container( - name="multiple_code_section_max_inputs_max_outputs", - sections=[ - Section.Code( - (Op.PUSH0 * MAX_CODE_OUTPUTS) + Op.CALLF[1] + Op.STOP, - max_stack_height=MAX_CODE_OUTPUTS, - ), - Section.Code( - code=Op.RETF, - code_inputs=MAX_CODE_INPUTS, - code_outputs=MAX_CODE_OUTPUTS, - max_stack_height=MAX_CODE_INPUTS, - ), - ], - ), -] - -INVALID += [ - Container( - name="single_code_section_non_zero_inputs", - sections=[Section.Code(code=Op.POP + Op.RETF, code_inputs=1)], - # TODO the exception must be about code or non, cause it looks legit - validity_error=EOFException.INVALID_FIRST_SECTION_TYPE, - ), - Container( - name="single_code_section_non_zero_outputs", - sections=[Section.Code(code=Op.PUSH0 + Op.RETF, code_outputs=1)], - # TODO the exception must be about code or non, cause it looks legit - validity_error=EOFException.INVALID_FIRST_SECTION_TYPE, - ), - Container( - name="multiple_code_section_non_zero_inputs", - sections=[ - Section.Code(code=Op.POP + Op.RETF, code_inputs=1), - Section.Code(Op.STOP), - ], - # TODO the actual exception should be EOFException.INVALID_TYPE_BODY, - validity_error=EOFException.INVALID_FIRST_SECTION_TYPE, - ), - Container( - name="multiple_code_section_non_zero_outputs", - sections=[ - Section.Code(code=Op.PUSH0, code_outputs=1), - Section.Code(Op.STOP), - ], - # TODO the actual exception should be EOFException.INVALID_TYPE_BODY, - validity_error=EOFException.INVALID_FIRST_SECTION_TYPE, - ), - Container( - name="data_section_before_code_with_type", - sections=[ - Section.Data(data="0xAA"), - Section.Code(Op.STOP), - ], - auto_sort_sections=AutoSection.NONE, - validity_error=[EOFException.MISSING_CODE_HEADER, EOFException.UNEXPECTED_HEADER_KIND], - ), - Container( - name="data_section_listed_in_type", - sections=[ - Section.Data(data="0x00", force_type_listing=True), - Section.Code(Op.STOP), - ], - validity_error=[ - EOFException.INVALID_TYPE_SECTION_SIZE, - EOFException.INVALID_SECTION_BODIES_SIZE, - ], - ), - Container( - name="single_code_section_incomplete_type", - sections=[ - Section(kind=SectionKind.TYPE, data="0x00", custom_size=2), - Section.Code(Op.STOP), - ], - validity_error=[ - EOFException.INVALID_SECTION_BODIES_SIZE, - EOFException.INVALID_TYPE_SECTION_SIZE, - ], - ), - Container( - name="single_code_section_input_too_large", - sections=[ - Section.Code( - code=((Op.PUSH0 * (MAX_CODE_INPUTS + 1)) + Op.CALLF[1] + Op.STOP), - max_stack_height=(MAX_CODE_INPUTS + 1), - ), - Section.Code( - code=(Op.POP * (MAX_CODE_INPUTS + 1)) + Op.RETF, - code_inputs=(MAX_CODE_INPUTS + 1), - code_outputs=0, - max_stack_height=0, - ), - ], - # TODO auto types section generation probably failed. the exception must be about code - validity_error=EOFException.INPUTS_OUTPUTS_NUM_ABOVE_LIMIT, - ), - Container( - name="invalid_inputs_to_non_returning_code_section_2", - sections=[ - Section.Code( - code=Op.PUSH1(0) * 128 + Op.CALLF[1] + Op.STOP, - max_stack_height=128, - ), - Section.Code( - Op.STOP, - code_inputs=128, - code_outputs=0, - max_stack_height=128, - ), - ], - # TODO auto types section generation probably failed. the exception must be about code - validity_error=EOFException.INPUTS_OUTPUTS_NUM_ABOVE_LIMIT, - ), - Container( - name="single_code_section_output_too_large", - sections=[ - Section.Code( - code=(Op.CALLF[1] + Op.STOP), - max_stack_height=(MAX_CODE_OUTPUTS + 2), - ), - Section.Code( - code=(Op.PUSH0 * (MAX_CODE_OUTPUTS + 2)) + Op.RETF, - code_inputs=0, - code_outputs=(MAX_CODE_OUTPUTS + 2), - max_stack_height=(MAX_CODE_OUTPUTS + 1), - ), - ], - # TODO the exception must be about code body - validity_error=EOFException.INPUTS_OUTPUTS_NUM_ABOVE_LIMIT, - ), - Container( - name="single_code_section_max_stack_size_too_large", - sections=[ - Section.Code( - code=Op.CALLER * 1024 + Op.POP * 1024 + Op.STOP, - max_stack_height=1024, - ), - ], - # TODO auto types section generation probably failed, the exception must be about code - validity_error=EOFException.MAX_STACK_HEIGHT_ABOVE_LIMIT, - ), -] diff --git a/tests/prague/eip7692_eof_v1/eip3540_eof_v1/test_code_validation.py b/tests/prague/eip7692_eof_v1/eip3540_eof_v1/test_code_validation.py deleted file mode 100644 index 127dd46985..0000000000 --- a/tests/prague/eip7692_eof_v1/eip3540_eof_v1/test_code_validation.py +++ /dev/null @@ -1,158 +0,0 @@ -""" -EOF V1 Code Validation tests -""" - -from typing import Dict, List - -import pytest - -from ethereum_test_tools import ( - EOA, - Account, - Address, - Alloc, - Environment, - EOFTestFiller, - Transaction, - compute_eofcreate_address, -) -from ethereum_test_tools.eof.v1 import Container, Initcode - -from .. import EOF_FORK_NAME - -# from .code_validation import INVALID as INVALID_CODE -# from .code_validation import VALID as VALID_CODE -# from .code_validation_function import INVALID as INVALID_FN -# from .code_validation_function import VALID as VALID_FN -# from .code_validation_jump import INVALID as INVALID_RJUMP -# from .code_validation_jump import VALID as VALID_RJUMP -from .container import INVALID as INVALID_CONTAINERS -from .container import VALID as VALID_CONTAINERS - -# from .tests_execution_function import VALID as VALID_EXEC_FN - -ALL_VALID = VALID_CONTAINERS -ALL_INVALID = INVALID_CONTAINERS -# ALL_VALID = ( -# VALID_CONTAINERS + VALID_CODE + VALID_RJUMP + VALID_FN + VALID_EXEC_FN -# ) -# ALL_INVALID = INVALID_CONTAINERS + INVALID_CODE + INVALID_RJUMP + INVALID_FN - -REFERENCE_SPEC_GIT_PATH = "EIPS/eip-3540.md" -REFERENCE_SPEC_VERSION = "8dcb0a8c1c0102c87224308028632cc986a61183" - -pytestmark = pytest.mark.valid_from(EOF_FORK_NAME) - - -@pytest.fixture -def env(): # noqa: D103 - return Environment() - - -@pytest.fixture -def sender(pre: Alloc): # noqa: D103 - return pre.fund_eoa() - - -@pytest.fixture -def create3_init_container(container: Container) -> Initcode: # noqa: D103 - return Initcode(deploy_container=container) - - -@pytest.fixture -def create3_opcode_contract_address( # noqa: D103 - pre: Alloc, - create3_init_container: Initcode, -) -> Address: - return pre.deploy_contract(create3_init_container, address=Address(0x300)) - - -@pytest.fixture -def txs( # noqa: D103 - sender: EOA, - create3_opcode_contract_address: Address, -) -> List[Transaction]: - return [ - Transaction( - to=create3_opcode_contract_address, - gas_limit=100000000, - gas_price=10, - # data=initcode, - protected=False, - sender=sender, - ) - ] - - -@pytest.fixture -def post( # noqa: D103 - create3_init_container: Initcode, - container: Container, - create3_opcode_contract_address: Address, -) -> Dict[Address, Account]: - create_opcode_created_contract_address = compute_eofcreate_address( - create3_opcode_contract_address, - 0, - bytes(create3_init_container.init_container), - ) - - new_account = Account(code=container) - - # Do not expect to create account if it is invalid - if hasattr(new_account, "code") and container.validity_error != "": - return {} - else: - return { - create_opcode_created_contract_address: new_account, - } - - -def container_name(c: Container): - """ - Return the name of the container for use in pytest ids. - """ - if hasattr(c, "name"): - return c.name - else: - return c.__class__.__name__ - - -@pytest.mark.parametrize( - "container", - ALL_VALID, - ids=container_name, -) -def test_legacy_initcode_valid_eof_v1_contract( - eof_test: EOFTestFiller, - container: Container, -): - """ - Test creating various types of valid EOF V1 contracts using legacy - initcode and a contract creating transaction. - """ - assert ( - container.validity_error is None - ), f"Valid container with validity error: {container.validity_error}" - eof_test( - data=bytes(container), - ) - - -@pytest.mark.parametrize( - "container", - ALL_INVALID, - ids=container_name, -) -def test_legacy_initcode_invalid_eof_v1_contract( - eof_test: EOFTestFiller, - container: Container, -): - """ - Test creating various types of valid EOF V1 contracts using legacy - initcode and a contract creating transaction. - """ - assert container.validity_error is not None, "Invalid container without validity error" - eof_test( - data=bytes(container), - expect_exception=container.validity_error, - ) diff --git a/tests/prague/eip7692_eof_v1/eip3540_eof_v1/test_container_validation.py b/tests/prague/eip7692_eof_v1/eip3540_eof_v1/test_container_validation.py index 3bb3424689..3d368f453d 100644 --- a/tests/prague/eip7692_eof_v1/eip3540_eof_v1/test_container_validation.py +++ b/tests/prague/eip7692_eof_v1/eip3540_eof_v1/test_container_validation.py @@ -6,9 +6,21 @@ import pytest from ethereum_test_tools import EOFException, EOFTestFiller -from ethereum_test_tools import Opcodes as Op -from ethereum_test_tools.eof.v1 import Container, ContainerKind, Section -from ethereum_test_tools.eof.v1.constants import MAX_CODE_SECTIONS +from ethereum_test_tools.eof.v1 import ( + VERSION_MAX_SECTION_KIND, + AutoSection, + Container, + ContainerKind, + Section, + SectionKind, +) +from ethereum_test_tools.eof.v1.constants import ( + MAX_CODE_INPUTS, + MAX_CODE_OUTPUTS, + MAX_CODE_SECTIONS, + MAX_OPERAND_STACK_HEIGHT, +) +from ethereum_test_tools.vm.opcode import Opcodes as Op from .. import EOF_FORK_NAME @@ -20,6 +32,1005 @@ VALID_CONTAINER = Container(sections=[Section.Code(code=Op.STOP)]) +@pytest.mark.parametrize( + "container", + [ + Container( + name="single_code_section_with_data_section", + sections=[ + Section.Code(code=Op.STOP), + Section.Data(data="0x00"), + ], + ), + Container( + name="single_code_section_max_stack_size", + sections=[ + Section.Code( + code=(Op.CALLER * MAX_OPERAND_STACK_HEIGHT) + + (Op.POP * MAX_OPERAND_STACK_HEIGHT) + + Op.STOP, + max_stack_height=MAX_OPERAND_STACK_HEIGHT, + ), + ], + ), + Container( + name="code_section_with_inputs_outputs", + sections=[ + Section.Code( + code=(Op.PUSH0 + Op.CALLF[1] + Op.STOP), + ), + Section.Code( + code=Op.POP + Op.PUSH0 + Op.RETF, + code_inputs=1, + code_outputs=1, + ), + ], + ), + Container( + name="code_section_input_maximum", + sections=[ + Section.Code( + code=((Op.PUSH0 * MAX_CODE_INPUTS) + Op.CALLF[1] + Op.STOP), + max_stack_height=MAX_CODE_INPUTS, + ), + Section.Code( + code=(Op.POP * MAX_CODE_INPUTS) + Op.RETF, + code_inputs=MAX_CODE_INPUTS, + code_outputs=0, + max_stack_height=MAX_CODE_INPUTS, + ), + ], + ), + Container( + name="code_section_output_maximum", + sections=[ + Section.Code( + code=(Op.CALLF[1] + Op.STOP), + max_stack_height=MAX_CODE_OUTPUTS, + ), + Section.Code( + code=(Op.PUSH0 * MAX_CODE_OUTPUTS) + Op.RETF, + code_inputs=0, + code_outputs=MAX_CODE_OUTPUTS, + max_stack_height=MAX_CODE_OUTPUTS, + ), + ], + ), + Container( + name="multiple_code_sections", + sections=[ + Section.Code( + Op.CALLF[1] + Op.STOP, + ), + Section.Code( + code=Op.RETF, + code_inputs=0, + code_outputs=0, + ), + ], + ), + Container( + name="multiple_code_sections_max_inputs_max_outputs", + sections=[ + Section.Code( + (Op.PUSH0 * MAX_CODE_OUTPUTS) + Op.CALLF[1] + Op.STOP, + max_stack_height=MAX_CODE_OUTPUTS, + ), + Section.Code( + code=Op.RETF, + code_inputs=MAX_CODE_INPUTS, + code_outputs=MAX_CODE_OUTPUTS, + max_stack_height=MAX_CODE_INPUTS, + ), + ], + ), + ], + ids=lambda c: c.name, +) +def test_valid_containers( + eof_test: EOFTestFiller, + container: Container, +): + """ + Test creating various types of valid EOF V1 contracts using legacy + initcode and a contract creating transaction. + """ + assert ( + container.validity_error is None + ), f"Valid container with validity error: {container.validity_error}" + eof_test( + data=bytes(container), + ) + + +@pytest.mark.parametrize( + "container", + [ + Container( + name="empty_container", + raw_bytes=b"", + validity_error=[ + EOFException.INVALID_MAGIC, + ], + ), + Container( + name="single_code_section_no_data_section", + sections=[ + Section.Code(Op.STOP), + ], + auto_data_section=False, + validity_error=[ + EOFException.MISSING_DATA_SECTION, + EOFException.UNEXPECTED_HEADER_KIND, + ], + ), + Container( + name="incomplete_magic", + raw_bytes=bytes([0xEF]), + validity_error=EOFException.INVALID_MAGIC, + ), + Container( + name="no_version", + raw_bytes=bytes([0xEF, 0x00]), + validity_error=[EOFException.INVALID_VERSION, EOFException.INVALID_MAGIC], + ), + Container( + name="no_type_header", + raw_bytes=bytes([0xEF, 0x00, 0x01]), + # TODO the exception must be about missing section types + validity_error=EOFException.MISSING_HEADERS_TERMINATOR, + ), + Container( + name="no_type_section_size", + raw_bytes=bytes( + [0xEF, 0x00, 0x01, 0x01], + ), + # TODO the exception must be about incomplete section in the header + validity_error=[ + EOFException.MISSING_HEADERS_TERMINATOR, + EOFException.INVALID_TYPE_SECTION_SIZE, + ], + ), + Container( + name="incomplete_type_section_size", + raw_bytes=bytes( + [0xEF, 0x00, 0x01, 0x01, 0x00], + ), + # TODO the exception must be about incomplete section in the header + validity_error=[ + EOFException.INCOMPLETE_SECTION_SIZE, + EOFException.INVALID_TYPE_SECTION_SIZE, + ], + ), + Container( + name="no_code_header", + raw_bytes=bytes([0xEF, 0x00, 0x01, 0x01, 0x00, 0x04]), + validity_error=[ + EOFException.MISSING_CODE_HEADER, + EOFException.MISSING_HEADERS_TERMINATOR, + ], + ), + Container( + name="no_code_header_2", + raw_bytes=bytes([0xEF, 0x00, 0x01, 0x01, 0x00, 0x04, 0xFE]), + validity_error=[EOFException.MISSING_CODE_HEADER, EOFException.UNEXPECTED_HEADER_KIND], + ), + Container( + name="no_code_header_3", + raw_bytes=bytes([0xEF, 0x00, 0x01, 0x01, 0x00, 0x04, 0x00]), + validity_error=[EOFException.MISSING_CODE_HEADER, EOFException.UNEXPECTED_HEADER_KIND], + ), + Container( + name="code_section_count_missing", + raw_bytes=bytes([0xEF, 0x00, 0x01, 0x01, 0x00, 0x04, 0x02]), + validity_error=EOFException.INCOMPLETE_SECTION_NUMBER, + ), + Container( + name="code_section_count_incomplete", + raw_bytes=bytes([0xEF, 0x00, 0x01, 0x01, 0x00, 0x04, 0x02, 0x00]), + validity_error=EOFException.INCOMPLETE_SECTION_NUMBER, + ), + Container( + name="code_section_size_missing", + raw_bytes=bytes([0xEF, 0x00, 0x01, 0x01, 0x00, 0x04, 0x02, 0x00, 0x01]), + validity_error=[ + EOFException.MISSING_HEADERS_TERMINATOR, + EOFException.ZERO_SECTION_SIZE, + ], + ), + Container( + name="code_section_size_incomplete", + raw_bytes=bytes([0xEF, 0x00, 0x01, 0x01, 0x00, 0x04, 0x02, 0x00, 0x01, 0x00]), + validity_error=[EOFException.INCOMPLETE_SECTION_SIZE, EOFException.ZERO_SECTION_SIZE], + ), + Container( + name="code_section_count_0x8000_truncated", + raw_bytes=bytes([0xEF, 0x00, 0x01, 0x01, 0x00, 0x04, 0x02, 0x80, 0x00]), + validity_error=EOFException.TOO_MANY_CODE_SECTIONS, + ), + Container( + name="code_section_count_0xFFFF_truncated", + raw_bytes=bytes([0xEF, 0x00, 0x01, 0x01, 0x00, 0x04, 0x02, 0xFF, 0xFF]), + validity_error=EOFException.TOO_MANY_CODE_SECTIONS, + ), + Container( + name="code_section_count_0x8000", + raw_bytes=bytes( + [0xEF, 0x00, 0x01, 0x01, 0x00, 0x04, 0x02, 0x80, 0x00] + [0x00, 0x01] * 0x8000 + ), + validity_error=EOFException.CONTAINER_SIZE_ABOVE_LIMIT, + ), + Container( + name="code_section_count_0xFFFF", + raw_bytes=bytes( + [0xEF, 0x00, 0x01, 0x01, 0x00, 0x04, 0x02, 0xFF, 0xFF] + [0x00, 0x01] * 0xFFFF + ), + validity_error=EOFException.CONTAINER_SIZE_ABOVE_LIMIT, + ), + Container( + name="code_section_size_0x8000_truncated", + raw_bytes=bytes([0xEF, 0x00, 0x01, 0x01, 0x00, 0x04, 0x02, 0x00, 0x01, 0x80, 0x00]), + validity_error=EOFException.MISSING_HEADERS_TERMINATOR, + ), + Container( + name="code_section_size_0xFFFF_truncated", + raw_bytes=bytes([0xEF, 0x00, 0x01, 0x01, 0x00, 0x04, 0x02, 0x00, 0x01, 0xFF, 0xFF]), + validity_error=EOFException.MISSING_HEADERS_TERMINATOR, + ), + Container( + name="terminator_incomplete", + header_terminator=b"", + sections=[ + Section(kind=SectionKind.TYPE, data=b"", custom_size=4), + Section.Code(code=b"", custom_size=0x01), + ], + expected_bytecode="ef00 01 01 0004 02 0001 0001 04 0000", + validity_error=EOFException.MISSING_HEADERS_TERMINATOR, + ), + Container( + name="truncated_header_data_section", + raw_bytes="ef00 01 01 0004 02 0001 0001", + validity_error=EOFException.MISSING_HEADERS_TERMINATOR, + ), + Container( + name="no_data_section_size", + raw_bytes="ef00 01 01 0004 02 0001 0001 04", + validity_error=EOFException.MISSING_HEADERS_TERMINATOR, + ), + Container( + name="data_section_size_incomplete", + raw_bytes="ef00 01 01 0004 02 0001 0001 04 00", + validity_error=EOFException.INCOMPLETE_SECTION_SIZE, + ), + Container( + name="truncated_header_data_section_with_container_section", + raw_bytes="ef00 01 01 0004 02 0001 0001 03 0001 0001", + validity_error=EOFException.MISSING_HEADERS_TERMINATOR, + ), + Container( + name="no_data_section_size_with_container_section", + raw_bytes="ef00 01 01 0004 02 0001 0001 03 0001 0001 04", + validity_error=EOFException.MISSING_HEADERS_TERMINATOR, + ), + Container( + name="data_section_size_incomplete_with_container_section", + raw_bytes="ef00 01 01 0004 02 0001 0001 03 0001 0001 04 00", + validity_error=EOFException.INCOMPLETE_SECTION_SIZE, + ), + Container( + name="no_sections", + sections=[], + auto_data_section=False, + auto_type_section=AutoSection.NONE, + expected_bytecode="ef0001 00", + validity_error=[EOFException.MISSING_TYPE_HEADER, EOFException.UNEXPECTED_HEADER_KIND], + ), + Container( + name="no_code_section_header", + sections=[ + Section(kind=SectionKind.TYPE, data=b"\0\x80\0\0"), + Section.Data("0x00"), + ], + expected_bytecode="ef00 01 01 0004 04 0001 00 00800000 00", + auto_type_section=AutoSection.NONE, + validity_error=[EOFException.MISSING_CODE_HEADER, EOFException.UNEXPECTED_HEADER_KIND], + ), + Container( + name="too_many_code_sections", + sections=[ + Section.Code(Op.JUMPF[i + 1] if i < MAX_CODE_SECTIONS else Op.STOP) + for i in range(MAX_CODE_SECTIONS + 1) + ], + validity_error=EOFException.TOO_MANY_CODE_SECTIONS, + ), + Container( + name="zero_code_sections_header", + raw_bytes="ef00 01 01 0004 02 0000 04 0000 00 00800000", + validity_error=[ + EOFException.ZERO_SECTION_SIZE, + EOFException.INCOMPLETE_SECTION_NUMBER, + ], + ), + Container( + name="zero_code_sections_header_empty_type_section", + raw_bytes="ef00 01 01 0000 02 0000 04 0000 00", + validity_error=[ + EOFException.ZERO_SECTION_SIZE, + EOFException.INCOMPLETE_SECTION_NUMBER, + ], + ), + # The basic `no_section_terminator` cases just remove the terminator + # and the `00` for zeroth section inputs looks like one. Error is because + # the sections are wrongly sized. + Container( + name="no_section_terminator", + header_terminator=bytes(), + sections=[Section.Code(code=Op.STOP)], + validity_error=[ + EOFException.INVALID_SECTION_BODIES_SIZE, + EOFException.INVALID_FIRST_SECTION_TYPE, + ], + ), + Container( + name="no_section_terminator_1", + header_terminator=bytes(), + sections=[Section.Code(code=Op.STOP, custom_size=2)], + validity_error=[ + EOFException.INVALID_SECTION_BODIES_SIZE, + EOFException.INVALID_FIRST_SECTION_TYPE, + ], + ), + Container( + name="no_section_terminator_2", + header_terminator=bytes(), + sections=[Section.Code(code="0x", custom_size=3)], + validity_error=EOFException.INVALID_SECTION_BODIES_SIZE, + ), + Container( + name="no_section_terminator_3", + header_terminator=bytes(), + sections=[Section.Code(code=Op.PUSH1(0) + Op.STOP)], + validity_error=[ + EOFException.INVALID_SECTION_BODIES_SIZE, + EOFException.INVALID_FIRST_SECTION_TYPE, + ], + ), + # The following cases just remove the terminator + # and the `00` for zeroth section inputs looks like one. Section bodies + # are as the size prescribes here, so the error is about the inputs of zeroth section. + Container( + name="no_section_terminator_section_bodies_ok_1", + header_terminator=bytes(), + sections=[Section.Code(code=Op.JUMPDEST + Op.STOP, custom_size=1)], + validity_error=EOFException.INVALID_FIRST_SECTION_TYPE, + ), + Container( + name="no_section_terminator_section_bodies_ok_2", + header_terminator=bytes(), + sections=[Section.Code(code=Op.JUMPDEST * 2 + Op.STOP, custom_size=2)], + validity_error=EOFException.INVALID_FIRST_SECTION_TYPE, + ), + # Here the terminator is missing but made to look like a different section + # or arbitrary byte + Container( + name="no_section_terminator_nonzero", + header_terminator=b"01", + sections=[Section.Code(code=Op.STOP)], + validity_error=[EOFException.MISSING_TERMINATOR, EOFException.UNEXPECTED_HEADER_KIND], + ), + Container( + name="no_section_terminator_nonzero_1", + header_terminator=b"02", + sections=[Section.Code(code=Op.STOP, custom_size=2)], + validity_error=[EOFException.MISSING_TERMINATOR, EOFException.UNEXPECTED_HEADER_KIND], + ), + Container( + name="no_section_terminator_nonzero_2", + header_terminator=b"03", + sections=[Section.Code(code="0x", custom_size=3)], + validity_error=[EOFException.MISSING_TERMINATOR, EOFException.UNEXPECTED_HEADER_KIND], + ), + Container( + name="no_section_terminator_nonzero_3", + header_terminator=b"04", + sections=[Section.Code(code=Op.PUSH1(0) + Op.STOP)], + validity_error=[EOFException.MISSING_TERMINATOR, EOFException.UNEXPECTED_HEADER_KIND], + ), + Container( + name="no_section_terminator_nonzero_4", + header_terminator=b"fe", + sections=[Section.Code(code=Op.PUSH1(0) + Op.STOP)], + validity_error=[EOFException.MISSING_TERMINATOR, EOFException.UNEXPECTED_HEADER_KIND], + ), + Container( + name="truncated_before_type_section", + sections=[ + Section(kind=SectionKind.TYPE, data=b"", custom_size=4), + Section.Code(code=b"", custom_size=0x01), + ], + expected_bytecode="ef00 01 01 0004 02 0001 0001 04 0000 00", + validity_error=EOFException.INVALID_SECTION_BODIES_SIZE, + ), + Container( + name="truncated_type_section_before_outputs", + sections=[ + Section(kind=SectionKind.TYPE, data=b"\0", custom_size=4), + Section.Code(code=b"", custom_size=0x01), + ], + expected_bytecode="ef00 01 01 0004 02 0001 0001 04 0000 00 00", + validity_error=EOFException.INVALID_SECTION_BODIES_SIZE, + ), + Container( + name="truncated_type_section_before_max_stack_height", + sections=[ + Section(kind=SectionKind.TYPE, data=b"\0\x80", custom_size=4), + Section.Code(code=b"", custom_size=0x01), + ], + expected_bytecode="ef00 01 01 0004 02 0001 0001 04 0000 00 0080", + validity_error=EOFException.INVALID_SECTION_BODIES_SIZE, + ), + Container( + name="truncated_type_section_truncated_max_stack_height", + sections=[ + Section(kind=SectionKind.TYPE, data=b"\0\x80\0", custom_size=4), + Section.Code(code=b"", custom_size=0x01), + ], + expected_bytecode="ef00 01 01 0004 02 0001 0001 04 0000 00 008000", + validity_error=EOFException.INVALID_SECTION_BODIES_SIZE, + ), + Container( + name="no_code_section_contents", + sections=[Section.Code(code="0x", custom_size=0x01)], + validity_error=EOFException.INVALID_SECTION_BODIES_SIZE, + ), + Container( + name="incomplete_code_section_contents", + sections=[ + Section.Code(code=Op.STOP, custom_size=0x02), + ], + validity_error=EOFException.INVALID_SECTION_BODIES_SIZE, + ), + Container( + name="trailing_bytes_after_code_section", + sections=[Section.Code(code=Op.PUSH1(0) + Op.STOP)], + extra=bytes([0xDE, 0xAD, 0xBE, 0xEF]), + validity_error=EOFException.INVALID_SECTION_BODIES_SIZE, + ), + Container( + name="empty_code_section", + sections=[Section.Code(code="0x")], + # TODO the exception must be about code section EOFException.INVALID_CODE_SECTION, + validity_error=EOFException.ZERO_SECTION_SIZE, + ), + Container( + name="empty_code_section_with_non_empty_data", + sections=[ + Section.Code(code="0x"), + Section.Data(data="0xDEADBEEF"), + ], + # TODO the exception must be about code section EOFException.INVALID_CODE_SECTION, + validity_error=EOFException.ZERO_SECTION_SIZE, + ), + Container( + name="no_data_section_contents", + sections=[ + Section.Code(Op.STOP), + Section.Data(data="0x", custom_size=1), + ], + code="ef0001 010004 0200010001 040001 00 00800000 00", + validity_error=EOFException.TOPLEVEL_CONTAINER_TRUNCATED, + ), + Container( + name="data_section_contents_incomplete", + sections=[ + Section.Code(Op.STOP), + Section.Data(data="0xAABBCC", custom_size=4), + ], + validity_error=EOFException.TOPLEVEL_CONTAINER_TRUNCATED, + ), + Container( + name="data_section_preceding_code_section", + auto_data_section=False, + auto_sort_sections=AutoSection.NONE, + sections=[ + Section.Data(data="0xDEADBEEF"), + Section.Code(Op.STOP), + ], + validity_error=[EOFException.MISSING_CODE_HEADER, EOFException.UNEXPECTED_HEADER_KIND], + ), + Container( + name="data_section_without_code_section", + sections=[Section.Data(data="0xDEADBEEF")], + # TODO the actual exception should be EOFException.MISSING_CODE_HEADER + validity_error=[EOFException.ZERO_SECTION_SIZE, EOFException.UNEXPECTED_HEADER_KIND], + ), + Container( + name="no_section_terminator_3a", + header_terminator=bytes(), + sections=[Section.Code(code="0x030004")], + # TODO the exception must be about terminator + validity_error=[ + EOFException.INVALID_SECTION_BODIES_SIZE, + EOFException.INVALID_FIRST_SECTION_TYPE, + ], + ), + Container( + name="no_section_terminator_4a", + header_terminator=bytes(), + sections=[ + Section.Code(Op.STOP), + Section.Data(data="0xAABBCCDD"), + ], + # TODO: The error of this validation can be random. + validity_error=EOFException.INVALID_FIRST_SECTION_TYPE, + ), + Container( + name="trailing_bytes_after_data_section", + extra=bytes([0xEE]), + sections=[ + Section.Code(code=Op.PUSH1(0) + Op.STOP), + Section.Data(data="0xAABBCCDD"), + ], + # TODO should be more specific exception about trailing bytes + validity_error=EOFException.INVALID_SECTION_BODIES_SIZE, + ), + Container( + name="multiple_data_sections", + sections=[ + Section.Code(code=Op.PUSH1(0) + Op.STOP), + Section.Data(data="0xAABBCC"), + Section.Data(data="0xAABBCC"), + ], + expected_bytecode=( + "ef00 01 01 0004 02 0001 0003 04 0003 04 0003 00 00800001 600000 AABBCC AABBCC" + ), + validity_error=[EOFException.MISSING_TERMINATOR, EOFException.UNEXPECTED_HEADER_KIND], + ), + Container( + name="multiple_code_headers", + sections=[ + Section.Code(Op.JUMPF[1]), + Section.Data(data="0xAA"), + Section.Code(Op.STOP), + ], + auto_sort_sections=AutoSection.ONLY_BODY, + expected_bytecode=( + "ef00 01 01 0008 02 0001 0003 04 0001 02 0001 0001 00" + "00800000 00800000 E50001 00 AA" + ), + validity_error=[EOFException.MISSING_TERMINATOR, EOFException.UNEXPECTED_HEADER_KIND], + ), + Container( + name="multiple_code_headers_2", + sections=[ + Section.Code(Op.JUMPF[1]), + Section.Code(Op.STOP), + Section.Data(data="0xAA"), + ], + skip_join_concurrent_sections_in_header=True, + expected_bytecode=( + "ef00 01 01 0008 02 0001 0003 02 0001 0001 04 0001 00" + "00800000 00800000 E50001 00 AA" + ), + validity_error=[ + EOFException.MISSING_DATA_SECTION, + EOFException.UNEXPECTED_HEADER_KIND, + ], + ), + Container( + name="duplicated_code_header", + sections=[ + Section.Code(Op.STOP), + Section.Code( + b"", + custom_size=1, + skip_types_header_listing=True, + skip_types_body_listing=True, + ), + Section.Data(data="0xAA"), + ], + skip_join_concurrent_sections_in_header=True, + expected_bytecode=( + "ef00 01 01 0004 02 0001 0001 02 0001 0001 04 0001 00 00800000 00 AA" + ), + validity_error=[ + EOFException.MISSING_DATA_SECTION, + EOFException.UNEXPECTED_HEADER_KIND, + ], + ), + Container( + name="multiple_code_and_data_sections", + sections=[ + Section.Code(Op.JUMPF[1]), + Section.Code(Op.STOP), + Section.Data(data="0xAA"), + Section.Data(data="0xAA"), + ], + expected_bytecode=( + "ef00 01 01 0008 02 0002 0003 0001 04 0001 04 0001 00" + "00800000 00800000 E50001 00 AA AA" + ), + validity_error=[EOFException.MISSING_TERMINATOR, EOFException.UNEXPECTED_HEADER_KIND], + ), + Container( + name="multiple_code_and_data_sections_2", + sections=[ + Section.Code(Op.JUMPF[1]), + Section.Code(Op.STOP), + Section.Data(data="0xAA"), + Section.Data(data="0xAA"), + ], + skip_join_concurrent_sections_in_header=True, + expected_bytecode=( + "ef00 01 01 0008 02 0001 0003 02 0001 0001 04 0001 04 0001 00" + "00800000 00800000 E50001 00 AA AA" + ), + validity_error=[ + EOFException.MISSING_DATA_SECTION, + EOFException.UNEXPECTED_HEADER_KIND, + ], + ), + Container( + name="multiple_container_headers", + sections=[ + Section.Code(Op.EOFCREATE[0](0, 0, 0, 0) + Op.EOFCREATE[1](0, 0, 0, 0) + Op.STOP), + Section.Container(Container.Code(code=Op.INVALID)), + Section.Data(data="0xAA"), + Section.Container(Container.Code(code=Op.INVALID)), + ], + auto_sort_sections=AutoSection.ONLY_BODY, + expected_bytecode=( + "ef00 01 01 0004 02 0001 0015 03 0001 0014 04 0001 03 0001 0014 00" + "00800005 6000600060006000ec00 6000600060006000ec01 00" + "ef00 01 01 0004 02 0001 0001 04 0000 00 00800000 fe" + "ef00 01 01 0004 02 0001 0001 04 0000 00 00800000 fe" + "aa" + ), + validity_error=[EOFException.MISSING_TERMINATOR, EOFException.UNEXPECTED_HEADER_KIND], + ), + Container( + name="multiple_container_headers_2", + sections=[ + Section.Code(Op.EOFCREATE[0](0, 0, 0, 0) + Op.EOFCREATE[1](0, 0, 0, 0) + Op.STOP), + Section.Container(Container.Code(code=Op.INVALID)), + Section.Container(Container.Code(code=Op.INVALID)), + Section.Data(data="0xAA"), + ], + skip_join_concurrent_sections_in_header=True, + expected_bytecode=( + "ef00 01 01 0004 02 0001 0015 03 0001 0014 03 0001 0014 04 0001 00" + "00800005 6000600060006000ec00 6000600060006000ec01 00" + "ef00 01 01 0004 02 0001 0001 04 0000 00 00800000 fe" + "ef00 01 01 0004 02 0001 0001 04 0000 00 00800000 fe" + "aa" + ), + validity_error=[ + EOFException.MISSING_DATA_SECTION, + EOFException.UNEXPECTED_HEADER_KIND, + ], + ), + Container( + name="duplicated_container_header", + sections=[ + Section.Code(Op.EOFCREATE[0](0, 0, 0, 0) + Op.STOP), + Section.Container(Container.Code(code=Op.INVALID)), + Section(kind=SectionKind.CONTAINER, data=b"", custom_size=20), + Section.Data(data="0xAA"), + ], + skip_join_concurrent_sections_in_header=True, + expected_bytecode=( + "ef00 01 01 0004 02 0001 000b 03 0001 0014 03 0001 0014 04 0001 00" + "00800004 6000600060006000ec00 00" + "ef00 01 01 0004 02 0001 0001 04 0000 00 00800000 fe" + "aa" + ), + validity_error=[ + EOFException.MISSING_DATA_SECTION, + EOFException.UNEXPECTED_HEADER_KIND, + ], + ), + Container( + name="unknown_section_1", + sections=[ + Section.Code(Op.STOP), + Section.Data(data="0x"), + Section(kind=VERSION_MAX_SECTION_KIND + 1, data="0x01"), + ], + validity_error=[EOFException.MISSING_TERMINATOR, EOFException.UNEXPECTED_HEADER_KIND], + ), + Container( + name="unknown_section_2", + sections=[ + Section(kind=VERSION_MAX_SECTION_KIND + 1, data="0x01"), + Section.Data(data="0x"), + Section.Code(Op.STOP), + ], + # TODO the exception should be about unknown section definition + validity_error=[EOFException.MISSING_TERMINATOR, EOFException.UNEXPECTED_HEADER_KIND], + ), + Container( + name="unknown_section_empty", + sections=[ + Section.Code(Op.STOP), + Section.Data(data="0x"), + Section(kind=VERSION_MAX_SECTION_KIND + 1, data="0x"), + ], + validity_error=[EOFException.MISSING_TERMINATOR, EOFException.UNEXPECTED_HEADER_KIND], + ), + Container( + name="no_type_section", + sections=[ + Section.Code(code=Op.STOP), + Section.Data("0x00"), + ], + auto_type_section=AutoSection.NONE, + validity_error=[EOFException.MISSING_TYPE_HEADER, EOFException.UNEXPECTED_HEADER_KIND], + ), + Container( + name="too_many_type_sections", + sections=[ + Section(kind=SectionKind.TYPE, data="0x00000000"), + Section(kind=SectionKind.TYPE, data="0x00000000"), + Section.Code(Op.STOP), + ], + auto_type_section=AutoSection.NONE, + validity_error=[EOFException.MISSING_CODE_HEADER, EOFException.UNEXPECTED_HEADER_KIND], + ), + Container( + name="too_many_type_sections_2", + sections=[ + Section(kind=SectionKind.TYPE, data="0x00800000"), + Section(kind=SectionKind.TYPE, data="0x00800000"), + Section.Code(Op.STOP), + ], + auto_type_section=AutoSection.NONE, + validity_error=[EOFException.MISSING_CODE_HEADER, EOFException.UNEXPECTED_HEADER_KIND], + ), + Container( + name="empty_type_section", + sections=[ + Section(kind=SectionKind.TYPE, data="0x"), + Section.Code(Op.STOP), + ], + expected_bytecode="ef00 01 01 0000 02 0001 0001 04 0000 00 00", + validity_error=[ + EOFException.ZERO_SECTION_SIZE, + EOFException.INVALID_SECTION_BODIES_SIZE, + ], + ), + Container( + name="type_section_too_small_single_code_section_1", + sections=[ + Section(kind=SectionKind.TYPE, data="0x00"), + Section.Code(Op.STOP), + ], + auto_type_section=AutoSection.NONE, + validity_error=EOFException.INVALID_TYPE_SECTION_SIZE, + ), + Container( + name="type_section_too_small_single_code_section_2", + sections=[ + Section(kind=SectionKind.TYPE, data="0x008000"), + Section.Code(Op.STOP), + ], + auto_type_section=AutoSection.NONE, + validity_error=EOFException.INVALID_TYPE_SECTION_SIZE, + ), + Container( + name="type_section_too_big_single_code_section", + sections=[ + Section(kind=SectionKind.TYPE, data="0x0080000000"), + Section.Code(Op.STOP), + ], + auto_type_section=AutoSection.NONE, + validity_error=EOFException.INVALID_TYPE_SECTION_SIZE, + ), + Container( + name="type_section_too_small_multiple_code_sections_1", + sections=[ + Section(kind=SectionKind.TYPE, data="0x0080000000"), + Section.Code(Op.STOP), + Section.Code(Op.STOP), + ], + auto_type_section=AutoSection.NONE, + validity_error=EOFException.INVALID_TYPE_SECTION_SIZE, + ), + Container( + name="type_section_too_small_multiple_code_sections_2", + sections=[ + Section(kind=SectionKind.TYPE, data="0x008000000080"), + Section.Code(Op.STOP), + Section.Code(Op.STOP), + ], + auto_type_section=AutoSection.NONE, + validity_error=EOFException.INVALID_TYPE_SECTION_SIZE, + ), + Container( + name="type_section_too_big_multiple_code_sections", + sections=[ + Section(kind=SectionKind.TYPE, data="0x008000000080000000"), + Section.Code(Op.STOP), + Section.Code(Op.STOP), + ], + auto_type_section=AutoSection.NONE, + validity_error=EOFException.INVALID_TYPE_SECTION_SIZE, + ), + Container( + name="invalid_first_code_section_inputs_0x01", + sections=[Section.Code(code=Op.POP + Op.RETF, code_inputs=1)], + validity_error=EOFException.INVALID_FIRST_SECTION_TYPE, + ), + Container( + name="invalid_first_code_section_inputs_0x80", + sections=[Section.Code(code=Op.POP + Op.RETF, code_inputs=0x80)], + validity_error=EOFException.INVALID_FIRST_SECTION_TYPE, + ), + Container( + name="invalid_first_code_section_inputs_0xff", + sections=[Section.Code(code=Op.POP + Op.RETF, code_inputs=0xFF)], + validity_error=EOFException.INVALID_FIRST_SECTION_TYPE, + ), + Container( + name="invalid_first_code_section_outputs_0x00", + sections=[Section.Code(code=Op.PUSH0 + Op.RETF, code_outputs=0)], + validity_error=EOFException.INVALID_FIRST_SECTION_TYPE, + ), + Container( + name="invalid_first_code_section_outputs_0x7f", + sections=[Section.Code(code=Op.PUSH0 + Op.RETF, code_outputs=0x7F)], + validity_error=EOFException.INVALID_FIRST_SECTION_TYPE, + ), + Container( + name="invalid_first_code_section_outputs_0x81", + sections=[Section.Code(code=Op.PUSH0 + Op.RETF, code_outputs=0x81)], + validity_error=EOFException.INVALID_FIRST_SECTION_TYPE, + ), + Container( + name="invalid_first_code_section_outputs_0xff", + sections=[Section.Code(code=Op.PUSH0 + Op.RETF, code_outputs=0xFF)], + validity_error=EOFException.INVALID_FIRST_SECTION_TYPE, + ), + Container( + name="multiple_code_section_non_zero_inputs", + sections=[ + Section.Code(code=Op.POP + Op.RETF, code_inputs=1), + Section.Code(Op.STOP), + ], + # TODO the actual exception should be EOFException.INVALID_TYPE_BODY, + validity_error=EOFException.INVALID_FIRST_SECTION_TYPE, + ), + Container( + name="multiple_code_section_non_zero_outputs", + sections=[ + Section.Code(code=Op.PUSH0, code_outputs=1), + Section.Code(Op.STOP), + ], + # TODO the actual exception should be EOFException.INVALID_TYPE_BODY, + validity_error=EOFException.INVALID_FIRST_SECTION_TYPE, + ), + Container( + name="data_section_before_code_with_type", + sections=[ + Section.Data(data="0xAA"), + Section.Code(Op.STOP), + ], + auto_sort_sections=AutoSection.NONE, + validity_error=[EOFException.MISSING_CODE_HEADER, EOFException.UNEXPECTED_HEADER_KIND], + ), + Container( + name="data_section_listed_in_type", + sections=[ + Section.Data(data="0x00", force_type_listing=True), + Section.Code(Op.STOP), + ], + validity_error=[ + EOFException.INVALID_TYPE_SECTION_SIZE, + EOFException.INVALID_SECTION_BODIES_SIZE, + ], + ), + Container( + name="single_code_section_incomplete_type", + sections=[ + Section(kind=SectionKind.TYPE, data="0x00", custom_size=2), + Section.Code(Op.STOP), + ], + validity_error=[ + EOFException.INVALID_SECTION_BODIES_SIZE, + EOFException.INVALID_TYPE_SECTION_SIZE, + ], + ), + Container( + name="code_section_input_too_large", + sections=[ + Section.Code( + code=((Op.PUSH0 * (MAX_CODE_INPUTS + 1)) + Op.CALLF[1] + Op.STOP), + max_stack_height=(MAX_CODE_INPUTS + 1), + ), + Section.Code( + code=(Op.POP * (MAX_CODE_INPUTS + 1)) + Op.RETF, + code_inputs=(MAX_CODE_INPUTS + 1), + code_outputs=0, + max_stack_height=0, + ), + ], + validity_error=EOFException.INPUTS_OUTPUTS_NUM_ABOVE_LIMIT, + ), + Container( + name="invalid_inputs_to_non_returning_code_section_2", + sections=[ + Section.Code( + code=Op.PUSH1(0) * 128 + Op.CALLF[1] + Op.STOP, + max_stack_height=128, + ), + Section.Code( + Op.STOP, + code_inputs=128, + code_outputs=0, + max_stack_height=128, + ), + ], + validity_error=EOFException.INPUTS_OUTPUTS_NUM_ABOVE_LIMIT, + ), + Container( + name="code_section_output_too_large", + sections=[ + Section.Code( + code=(Op.CALLF[1] + Op.STOP), + max_stack_height=(MAX_CODE_OUTPUTS + 2), + ), + Section.Code( + code=(Op.PUSH0 * (MAX_CODE_OUTPUTS + 2)) + Op.RETF, + code_inputs=0, + code_outputs=(MAX_CODE_OUTPUTS + 2), + max_stack_height=(MAX_CODE_OUTPUTS + 2), + ), + ], + validity_error=EOFException.INPUTS_OUTPUTS_NUM_ABOVE_LIMIT, + ), + Container( + name="code_section_output_too_large_2", + sections=[ + Section.Code( + code=Op.JUMPF[1], + ), + Section.Code( + code=(Op.PUSH0 * (MAX_CODE_OUTPUTS + 1)) + Op.RETF, + code_inputs=0, + code_outputs=(MAX_CODE_OUTPUTS + 1), + max_stack_height=(MAX_CODE_OUTPUTS + 1), + ), + ], + validity_error=EOFException.INVALID_NON_RETURNING_FLAG, + ), + Container( + name="single_code_section_max_stack_size_too_large", + sections=[ + Section.Code( + code=Op.CALLER * 1024 + Op.POP * 1024 + Op.STOP, + max_stack_height=1024, + ), + ], + # TODO auto types section generation probably failed, the exception must be about code + validity_error=EOFException.MAX_STACK_HEIGHT_ABOVE_LIMIT, + ), + ], + ids=lambda c: c.name, +) +def test_invalid_containers( + eof_test: EOFTestFiller, + container: Container, +): + """ + Test creating various types of valid EOF V1 contracts using legacy + initcode and a contract creating transaction. + """ + assert container.validity_error is not None, "Invalid container without validity error" + eof_test( + data=bytes(container), + expect_exception=container.validity_error, + ) + + @pytest.mark.parametrize("magic_0", [0, 1, 0xEE, 0xEF, 0xF0, 0xFF]) @pytest.mark.parametrize("magic_1", [0, 1, 2, 0xFE, 0xFF]) def test_magic_validation( @@ -81,7 +1092,7 @@ def test_single_code_section( sections.append(Section.Data(data=b"\0")) eof_test( data=Container( - name="max_code_sections", + name="single_code_section", sections=sections, kind=ContainerKind.INITCODE if plus_container else ContainerKind.RUNTIME, ), From b11654c14287133af2e6127abc82dfef8781dc5a Mon Sep 17 00:00:00 2001 From: Mario Vega Date: Wed, 28 Aug 2024 22:07:13 +0000 Subject: [PATCH 7/8] fix(docs): EOF tracker updates --- tests/prague/eip7692_eof_v1/tracker.md | 124 ++++++++++++------------- 1 file changed, 61 insertions(+), 63 deletions(-) diff --git a/tests/prague/eip7692_eof_v1/tracker.md b/tests/prague/eip7692_eof_v1/tracker.md index 26d5d22b7c..07c19001a9 100644 --- a/tests/prague/eip7692_eof_v1/tracker.md +++ b/tests/prague/eip7692_eof_v1/tracker.md @@ -1,70 +1,68 @@ # EOF Testing Coverage Tracker - [ ] Example Test Case 1 -- [x] Example Test Case 2 (./eip3540_eof_v1/test_example_valid_invalid.py::test_example_valid_invalid) -- [ ] Example Test Case 3 (ethereum/tests: ./src/EOFTestsFiller/validInvalidFiller.yml) +- [x] Example Test Case 2 (`tests/prague/eip7692_eof_v1/eip3540_eof_v1test_example_valid_invalid.py::test_example_valid_invalid`) ## EIP-3540: EOF - EVM Object Format v1 ### Validation -- [ ] Empty code is not a valid EOF (ethereum/tests: src/EOFTestsFiller/efValidation/validate_empty_code_Copier.json) -- [ ] Valid container without data section (ethereum/tests: ./src/EOFTestsFiller/EIP3540/validInvalidFiller.yml src/EOFTestsFiller/efValidation/minimal_valid_EOF1_code_Copier.json) -- [ ] Valid container with data section (ethereum/tests: ./src/EOFTestsFiller/EIP3540/validInvalidFiller.yml src/EOFTestsFiller/efValidation/minimal_valid_EOF1_code_with_data_Copier.json) -- [ ] Valid container with truncated data section (ethereum/tests: ./src/EOFTestsFiller/EIP3540/validInvalidFiller.yml src/EOFTestsFiller/efValidation/EOF1_truncated_section_Copier.json) -- [ ] Valid container with data section truncated to empty (ethereum/tests: ./src/EOFTestsFiller/EIP3540/validInvalidFiller.yml) -- [ ] Valid containers with multiple code sections (ethereum/tests: ./src/EOFTestsFiller/validInvalidFiller.yml src/EOFTestsFiller/efValidation/minimal_valid_EOF1_multiple_code_sections_Copier.json) -- [ ] Valid containers with max number of code sections (ethereum/tests: src/EOFTestsFiller/efValidation/many_code_sections_1024_Copier.json src/EOFTestsFiller/EIP4750/validInvalidFiller.yml) -- [ ] Too many code sections (ethereum/tests: ./src/EOFTestsFiller/efValidation/EOF1_too_many_code_sections_Copier.json src/EOFTestsFiller/efValidation/too_many_code_sections_Copier.json) -- [ ] Truncated magic (ethereum/tests: ./src/EOFTestsFiller/EIP3540/validInvalidFiller.yml) -- [x] Valid container except magic (./eip3540_eof_v1/test_container_validation.py::test_magic_validation ethereum/tests: ./src/EOFTestsFiller/EIP3540/validInvalidFiller.yml src/EOFTestsFiller/efValidation/validate_EOF_prefix_Copier.json) -- [ ] Truncated before version (ethereum/tests: ./src/EOFTestsFiller/EIP3540/validInvalidFiller.yml) -- [x] Valid container except version (./eip3540_eof_v1/test_container_validation.py::test_version_validation ethereum/tests: ./src/EOFTestsFiller/EIP3540/validInvalidFiller.yml src/EOFTestsFiller/efValidation/validate_EOF_version_Copier.json) -- [ ] Truncated before type section header (ethereum/tests: ./src/EOFTestsFiller/EIP3540/validInvalidFiller.yml) -- [ ] Truncated before type section size (ethereum/tests: ./src/EOFTestsFiller/EIP3540/validInvalidFiller.yml src/EOFTestsFiller/efValidation/EOF1_incomplete_section_size_Copier.json) -- [ ] Truncated type section size (ethereum/tests: ./src/EOFTestsFiller/EIP3540/validInvalidFiller.yml src/EOFTestsFiller/efValidation/EOF1_incomplete_section_size_Copier.json) -- [ ] No type section header (ethereum/tests: src/EOFTestsFiller/efValidation/EOF1_no_type_section_Copier.json) -- [ ] Truncated before code section header (ethereum/tests: ./src/EOFTestsFiller/validInvalidFiller.yml) -- [ ] Truncated before code section number (ethereum/tests: ./src/EOFTestsFiller/EIP3540/validInvalidFiller.yml ) -- [ ] Truncated code section number (ethereum/tests: ./src/EOFTestsFiller/EIP3540/validInvalidFiller.yml src/EOFTestsFiller/efValidation/EOF1_incomplete_section_size_Copier.json) -- [ ] Truncated before code section size (ethereum/tests: ./src/EOFTestsFiller/EIP3540/validInvalidFiller.yml) -- [ ] Truncated code section size (ethereum/tests: ./src/EOFTestsFiller/EIP3540/validInvalidFiller.yml src/EOFTestsFiller/efValidation/EOF1_incomplete_section_size_Copier.json) -- [ ] No code section header (ethereum/tests: ./src/EOFTestsFiller/efValidation/EOF1_code_section_missing_Copier.json) -- [ ] 0 code section number (ethereum/tests: ./src/EOFTestsFiller/validInvalidFiller.yml) -- [ ] 0 code section size (ethereum/tests: ./src/EOFTestsFiller/EIP3540/validInvalidFiller.yml ./src/EOFTestsFiller/efValidation/EOF1_code_section_0_size_Copier.json) -- [ ] 0 code section size with non-empty data section (ethereum/tests: ./src/EOFTestsFiller/EIP3540/validInvalidFiller.yml) -- [ ] No container sections, truncated before data section header (ethereum/tests: ./src/EOFTestsFiller/EIP3540/validInvalidFiller.yml) -- [ ] Container sections present, truncated before data section header (ethereum/tests: ./src/EOFTestsFiller/validInvalidFiller.yml) -- [ ] Truncated before data section size (ethereum/tests: ./src/EOFTestsFiller/EIP3540/validInvalidFiller.yml src/EOFTestsFiller/efValidation/EOF1_incomplete_section_size_Copier.json) -- [ ] Truncated data section size (ethereum/tests: ./src/EOFTestsFiller/EIP3540/validInvalidFiller.yml src/EOFTestsFiller/efValidation/EOF1_incomplete_section_size_Copier.json) -- [x] Truncated before header terminator (ethereum/tests: src/EOFTestsFiller/efValidation/EOF1_header_not_terminated_Copier.json) -- [ ] Truncated before header terminator (ethereum/tests: ./src/EOFTestsFiller/EIP3540/validInvalidFiller.yml) -- [ ] Truncated before type section (ethereum/tests: ./src/EOFTestsFiller/EIP3540/validInvalidFiller.yml src/EOFTestsFiller/efValidation/EOF1_truncated_section_Copier.json) -- [ ] Type section truncated before outputs (ethereum/tests: ./src/EOFTestsFiller/EIP3540/validInvalidFiller.yml) -- [ ] Type section truncated before max_stack_height (ethereum/tests: ./src/EOFTestsFiller/EIP3540/validInvalidFiller.yml) -- [ ] Type section truncated max_stack_height (ethereum/tests: ./src/EOFTestsFiller/EIP3540/validInvalidFiller.yml src/EOFTestsFiller/efValidation/EOF1_truncated_section_Copier.json) -- [ ] Truncated before code sections (ethereum/tests: ./src/EOFTestsFiller/EIP3540/validInvalidFiller.yml) -- [ ] Truncated code section (ethereum/tests: ./src/EOFTestsFiller/EIP3540/validInvalidFiller.yml src/EOFTestsFiller/efValidation/EOF1_truncated_section_Copier.json) -- [ ] Data section empty, trailing bytes (ethereum/tests: ./src/EOFTestsFiller/EIP3540/validInvalidFiller.yml src/EOFTestsFiller/efValidation/EOF1_trailing_bytes_Copier.json) -- [ ] Data section non-empty, trailing bytes (ethereum/tests: ./src/EOFTestsFiller/EIP3540/validInvalidFiller.yml src/EOFTestsFiller/efValidation/EOF1_trailing_bytes_Copier.json) -- [ ] Wrong order of sections (ethereum/tests: ./src/EOFTestsFiller/EIP3540/validInvalidFiller.yml src/EOFTestsFiller/efValidation/EOF1_section_order_Copier.json ./src/EOFTestsFiller/efValidation/EOF1_data_section_before_code_section_Copier.json ./src/EOFTestsFiller/efValidation/EOF1_data_section_before_types_section_Copier.json src/EOFTestsFiller/efValidation/EOF1_type_section_not_first_Copier.json) -- [ ] No data section header (ethereum/tests: ./src/EOFTestsFiller/validInvalidFiller.yml src/EOFTestsFiller/efValidation/data_section_missing_Copier.json) -- [ ] Multiple data sections (ethereum/tests: ./src/EOFTestsFiller/EIP3540/validInvalidFiller.yml) -- [ ] Unknown section id (ethereum/tests: ./src/EOFTestsFiller/EIP3540/validInvalidFiller.yml src/EOFTestsFiller/efValidation/EOF1_unknown_section_Copier.json) -- [ ] Type section size != 4 * code section number (ethereum/tests: ./src/EOFTestsFiller/validInvalidFiller.yml src/EOFTestsFiller/efValidation/EOF1_invalid_type_section_size_Copier.json src/EOFTestsFiller/efValidation/EOF1_types_section_0_size_Copier.json) -- [ ] Code section with max max_stack_height (ethereum/tests: ./src/EOFTestsFiller/efExample/validInvalidFiller.yml) -- [ ] Code section with max_stack_height above limit (ethereum/tests: ./src/EOFTestsFiller/efExample/validInvalidFiller.yml src/EOFTestsFiller/efValidation/max_stack_height_Copier.json) -- [ ] Valid code sections with inputs/outputs (ethereum/tests: ./src/EOFTestsFiller/EIP4750/validInvalidFiller.yml) -- [ ] Valid code section with max inputs -- [ ] Valid code section with max outputs -- [ ] Code sections with invalid number of inputs/outputs (above limit) -- [ ] 0 section with inputs/outputs (ethereum/tests: ./src/EOFTestsFiller/efExample/validInvalidFiller.yml src/EOFTestsFiller/efValidation/EOF1_invalid_section_0_type_Copier.json src/EOFTestsFiller/EIP4750/validInvalidFiller.yml) -- [ ] Multiple type section headers (ethereum/tests: ./src/EOFTestsFiller/efValidation/EOF1_multiple_type_sections_Copier.json) -- [ ] Multiple code section headers (ethereum/tests: src/EOFTestsFiller/efValidation/multiple_code_sections_headers_Copier.json) -- [ ] Multiple data section headers (ethereum/tests: src/EOFTestsFiller/efValidation/EOF1_multiple_data_sections_Copier.json) -- [ ] Container without type section (ethereum/tests: ./src/EOFTestsFiller/efExample/validInvalidFiller.yml src/EOFTestsFiller/efValidation/EOF1_type_section_missing_Copier.json src/EOFTestsFiller/efValidation/EOF1_types_section_missing_Copier.json) -- [ ] Container without code sections (ethereum/tests: ./src/EOFTestsFiller/EIP3540/validInvalidFiller.yml) -- [ ] Container without data section (ethereum/tests: ./src/EOFTestsFiller/EIP3540/validInvalidFiller.yml) +- [x] Empty code is not a valid EOF (`tests/prague/eip7692_eof_v1/eip3540_eof_v1test_container_validation.py::test_invalid_containers -k empty_container`) +- [x] Valid container without data section (`tests/prague/eip7692_eof_v1/eip3540_eof_v1test_container_validation.py::test_invalid_containers -k single_code_section_no_data_section`) +- [x] Valid container with data section (`tests/prague/eip7692_eof_v1/eip3540_eof_v1test_container_validation.py::test_valid_containers -k single_code_section_with_data_section`) +- [x] Valid container with truncated data section (`tests/prague/eip7692_eof_v1/eip3540_eof_v1test_container_validation.py::test_invalid_containers -k data_section_contents_incomplete`, `tests/prague/eip7692_eof_v1/eip3540_eof_v1test_migrated_valid_invalid.py::test_migrated_valid_invalid -k data_section_contents_incomplete`) +- [x] Valid container with data section truncated to empty (`tests/prague/eip7692_eof_v1/eip3540_eof_v1test_container_validation.py::test_invalid_containers -k no_data_section_contents`, `tests/prague/eip7692_eof_v1/eip3540_eof_v1test_migrated_valid_invalid.py::test_migrated_valid_invalid -k no_data_section_contents`) +- [x] Valid containers with multiple code sections (`tests/prague/eip7692_eof_v1/tests/prague/eip7692_eof_v1/eip3540_eof_v1test_container_validation.py::test_valid_containers -k multiple_code_sections`) +- [x] Valid containers with max number of code sections (`tests/prague/eip7692_eof_v1/eip3540_eof_v1/test_container_validation.py::test_max_code_sections`) +- [x] Too many code sections (`tests/prague/eip7692_eof_v1/eip3540_eof_v1/test_container_validation.py::test_invalid_containers -k too_many_code_sections`) +- [x] Truncated magic (`tests/prague/eip7692_eof_v1/eip3540_eof_v1/test_container_validation.py::test_invalid_containers -k incomplete_magic`) +- [x] Valid container except magic (`tests/prague/eip7692_eof_v1/eip3540_eof_v1test_container_validation.py::test_magic_validation`) +- [x] Truncated before version (`tests/prague/eip7692_eof_v1/eip3540_eof_v1/test_container_validation.py::test_invalid_containers -k no_version`) +- [x] Valid container except version (`tests/prague/eip7692_eof_v1/eip3540_eof_v1test_container_validation.py::test_version_validation`) +- [x] Truncated before type section header (`tests/prague/eip7692_eof_v1/eip3540_eof_v1/test_container_validation.py::test_invalid_containers -k no_type_header`) +- [x] Truncated before type section size (`tests/prague/eip7692_eof_v1/eip3540_eof_v1/test_container_validation.py::test_invalid_containers -k no_type_section_size`) +- [x] Truncated type section size (`tests/prague/eip7692_eof_v1/eip3540_eof_v1/test_container_validation.py::test_invalid_containers -k incomplete_type_section_size`) +- [x] No type section header (`tests/prague/eip7692_eof_v1/eip3540_eof_v1/test_section_order.py::test_section_order -k test_position_CasePosition.HEADER-section_test_SectionTest.MISSING-section_kind_TYPE`) +- [x] Truncated before code section header (`tests/prague/eip7692_eof_v1/eip3540_eof_v1/test_container_validation.py::test_invalid_containers -k no_code_header`) +- [x] Truncated before code section number (`tests/prague/eip7692_eof_v1/eip3540_eof_v1/test_container_validation.py::test_invalid_containers -k code_section_count_missing`) +- [x] Truncated code section number (`tests/prague/eip7692_eof_v1/eip3540_eof_v1/test_container_validation.py::test_invalid_containers -k code_section_count_incomplete`) +- [x] Truncated before code section size (`tests/prague/eip7692_eof_v1/eip3540_eof_v1/test_container_validation.py::test_invalid_containers -k code_section_size_missing`) +- [x] Truncated code section size (`tests/prague/eip7692_eof_v1/eip3540_eof_v1/test_container_validation.py::test_invalid_containers -k code_section_size_incomplete`) +- [x] No code section header (`tests/prague/eip7692_eof_v1/eip3540_eof_v1/test_section_order.py::test_section_order -k test_position_CasePosition.HEADER-section_test_SectionTest.MISSING-section_kind_CODE`) +- [x] Zero code section number (`tests/prague/eip7692_eof_v1/eip3540_eof_v1/test_container_validation.py::test_invalid_containers -k zero_code_sections_header`) +- [x] Zero code section size (`tests/prague/eip7692_eof_v1/eip3540_eof_v1/test_container_validation.py::test_invalid_containers -k empty_code_section`) +- [x] Zero code section size with non-empty data section (`tests/prague/eip7692_eof_v1/eip3540_eof_v1/test_container_validation.py::test_invalid_containers -k empty_code_section_with_non_empty_data`) +- [x] No container sections, truncated before data section header (`tests/prague/eip7692_eof_v1/eip3540_eof_v1/test_container_validation.py::test_invalid_containers -k truncated_header_data_section`) +- [x] Container sections present, truncated before data section header (`tests/prague/eip7692_eof_v1/eip3540_eof_v1/test_container_validation.py::test_invalid_containers -k truncated_header_data_section_with_container_section`) +- [x] Truncated before data section size (`tests/prague/eip7692_eof_v1/eip3540_eof_v1/test_container_validation.py::test_invalid_containers -k no_data_section_size`) +- [x] Truncated data section size (`tests/prague/eip7692_eof_v1/eip3540_eof_v1/test_container_validation.py::test_invalid_containers -k data_section_size_incomplete`) +- [x] Truncated before header terminator (`tests/prague/eip7692_eof_v1/eip3540_eof_v1/test_container_validation.py::test_invalid_containers -k terminator_incomplete`) +- [x] Truncated before type section (`tests/prague/eip7692_eof_v1/eip3540_eof_v1/test_container_validation.py::test_invalid_containers -k truncated_before_type_section`) +- [x] Type section truncated before outputs (`tests/prague/eip7692_eof_v1/eip3540_eof_v1/test_container_validation.py::test_invalid_containers -k truncated_type_section_before_outputs`) +- [x] Type section truncated before max_stack_height (`tests/prague/eip7692_eof_v1/eip3540_eof_v1/test_container_validation.py::test_invalid_containers -k truncated_type_section_before_max_stack_height`) +- [x] Type section truncated max_stack_height (`tests/prague/eip7692_eof_v1/eip3540_eof_v1/test_container_validation.py::test_invalid_containers -k truncated_type_section_truncated_max_stack_height`) +- [x] Truncated before code sections (`tests/prague/eip7692_eof_v1/eip3540_eof_v1/test_container_validation.py::test_invalid_containers -k no_code_section_contents`) +- [x] Truncated code section (`tests/prague/eip7692_eof_v1/eip3540_eof_v1/test_container_validation.py::test_invalid_containers -k incomplete_code_section_contents`) +- [x] Data section empty, trailing bytes (`tests/prague/eip7692_eof_v1/eip3540_eof_v1/test_container_validation.py::test_invalid_containers -k no_data_section_contents`) +- [x] Data section non-empty, trailing bytes (`tests/prague/eip7692_eof_v1/eip3540_eof_v1/test_container_validation.py::test_invalid_containers -k trailing_bytes_after_data_section`) +- [x] Wrong order of sections (`tests/prague/eip7692_eof_v1/eip3540_eof_v1/test_section_order.py`) +- [x] No data section header (`tests/prague/eip7692_eof_v1/eip3540_eof_v1/test_section_order.py::test_section_order -k test_position_CasePosition.HEADER-section_test_SectionTest.MISSING-section_kind_DATA`) +- [x] Multiple data sections (`tests/prague/eip7692_eof_v1/eip3540_eof_v1/test_container_validation.py::test_invalid_containers -k multiple_data_sections`, `tests/prague/eip7692_eof_v1/eip3540_eof_v1/test_container_validation.py::test_invalid_containers -k multiple_code_and_data_sections`) +- [x] Unknown section id (`tests/prague/eip7692_eof_v1/eip3540_eof_v1/test_container_validation.py::test_invalid_containers -k unknown_section_1`, `tests/prague/eip7692_eof_v1/eip3540_eof_v1/test_container_validation.py::test_invalid_containers -k unknown_section_2`) +- [x] Type section size != 4 * code section number (`tests/prague/eip7692_eof_v1/eip3540_eof_v1/test_container_validation.py -k type_section_too`) +- [x] Code section with max max_stack_height (`tests/prague/eip7692_eof_v1/eip3540_eof_v1/test_container_validation.py::test_valid_containers -k single_code_section_max_stack_size`) +- [x] Code section with max_stack_height above limit (`tests/prague/eip7692_eof_v1/eip3540_eof_v1/test_container_validation.py::test_invalid_containers -k single_code_section_max_stack_size_too_large`) +- [x] Valid code sections with inputs/outputs (`tests/prague/eip7692_eof_v1/eip3540_eof_v1/test_container_validation.py -k code_section_with_inputs_outputs`) +- [x] Valid code section with max inputs (`tests/prague/eip7692_eof_v1/eip3540_eof_v1/test_container_validation.py -k code_section_input_maximum`) +- [x] Valid code section with max outputs (`tests/prague/eip7692_eof_v1/eip3540_eof_v1/test_container_validation.py -k code_section_output_maximum`) +- [x] Code sections with invalid number of inputs/outputs (`tests/prague/eip7692_eof_v1/eip3540_eof_v1/test_container_validation.py -k code_section_input_too_large`, `tests/prague/eip7692_eof_v1/eip3540_eof_v1/test_container_validation.py -k code_section_output_too_large`) +- [x] First section with inputs/outputs (`tests/prague/eip7692_eof_v1/eip3540_eof_v1/test_container_validation.py -k invalid_first_code_section`) +- [x] Multiple type section headers (`tests/prague/eip7692_eof_v1/eip3540_eof_v1/test_container_validation.py -k too_many_type_sections`) +- [x] Multiple code section headers (`tests/prague/eip7692_eof_v1/eip3540_eof_v1/test_container_validation.py -k multiple_code_headers`) +- [x] Multiple data section headers (`tests/prague/eip7692_eof_v1/eip3540_eof_v1/test_container_validation.py -k multiple_data_sections`) +- [x] Container without type section (`tests/prague/eip7692_eof_v1/eip3540_eof_v1/test_section_order.py::test_section_order -k 'SectionTest.MISSING-section_kind_TYPE'`) +- [x] Container without code sections (`tests/prague/eip7692_eof_v1/eip3540_eof_v1/test_section_order.py::test_section_order -k 'SectionTest.MISSING-section_kind_CODE'`) +- [x] Container without data section (`tests/prague/eip7692_eof_v1/eip3540_eof_v1/test_section_order.py::test_section_order -k 'SectionTest.MISSING-section_kind_DATA'`) - [ ] Valid containers without data section and with subcontainers (ethereum/tests: ./src/EOFTestsFiller/efValidation/EOF1_embedded_container_Copier.json) - [ ] Valid containers with data section and with subcontainers (ethereum/tests: ./src/EOFTestsFiller/efValidation/EOF1_embedded_container_Copier.json) - [ ] Valid container with maximum number of subcontainers (ethereum/tests: ./src/EOFTestsFiller/efValidation/EOF1_embedded_container_Copier.json) @@ -72,8 +70,8 @@ - [ ] Subcontainer section header truncated before subcontainer number (ethereum/tests: ./src/EOFTestsFiller/efValidation/EOF1_embedded_container_invalid_Copier.json) - [ ] Subcontainer section header truncated before subcontainer size (ethereum/tests: ./src/EOFTestsFiller/efValidation/EOF1_embedded_container_invalid_Copier.json) - [ ] Truncated subcontainer size (ethereum/tests: ./src/EOFTestsFiller/efValidation/EOF1_embedded_container_invalid_Copier.json) -- [ ] 0 container section number (ethereum/tests: ./src/EOFTestsFiller/efValidation/EOF1_embedded_container_invalid_Copier.json) -- [ ] 0 container size (ethereum/tests: ./src/EOFTestsFiller/efValidation/EOF1_embedded_container_invalid_Copier.json) +- [ ] Zero container section number (ethereum/tests: ./src/EOFTestsFiller/efValidation/EOF1_embedded_container_invalid_Copier.json) +- [ ] Zero container size (ethereum/tests: ./src/EOFTestsFiller/efValidation/EOF1_embedded_container_invalid_Copier.json) - [ ] Truncated container section body (ethereum/tests: ./src/EOFTestsFiller/efValidation/EOF1_embedded_container_invalid_Copier.json) - [ ] Multiple container section headers - [ ] Invalid subcontainer @@ -331,8 +329,8 @@ ### Validation -- [ ] 0 section returning (ethereum/tests: ./src/EOFTestsFiller/efExample/validInvalidFiller.yml src/EOFTestsFiller/EIP4750/validInvalidFiller.yml) -- [ ] 0 section declared non-returning but ends with RETF (ethereum/tests: src/EOFTestsFiller/EIP4750/validInvalidFiller.yml) +- [ ] Zero section returning (ethereum/tests: ./src/EOFTestsFiller/efExample/validInvalidFiller.yml src/EOFTestsFiller/EIP4750/validInvalidFiller.yml) +- [ ] Zero section declared non-returning but ends with RETF (ethereum/tests: src/EOFTestsFiller/EIP4750/validInvalidFiller.yml) - [ ] CALLF into non-returning function (ethereum/tests: src/EOFTestsFiller/efValidation/callf_into_nonreturning_Copier.json) - [ ] Valid JUMPF into sections with equal number of outputs (ethereum/tests: src/EOFTestsFiller/efValidation/jumpf_equal_outputs_Copier.json) - [ ] Valid JUMPF into sections with different but compatible number of outputs (ethereum/tests: src/EOFTestsFiller/efValidation/jumpf_compatible_outputs_Copier.json) From f423b9d0fd9c7eaa6eabb8612f6807c140a27ecb Mon Sep 17 00:00:00 2001 From: Mario Vega Date: Wed, 28 Aug 2024 22:57:47 +0000 Subject: [PATCH 8/8] fix(docs/tests): more EOF tracker updates --- .../test_container_validation.py | 72 +++++++++++++++++++ tests/prague/eip7692_eof_v1/tracker.md | 30 ++++---- 2 files changed, 87 insertions(+), 15 deletions(-) diff --git a/tests/prague/eip7692_eof_v1/eip3540_eof_v1/test_container_validation.py b/tests/prague/eip7692_eof_v1/eip3540_eof_v1/test_container_validation.py index 3d368f453d..0cae0db27c 100644 --- a/tests/prague/eip7692_eof_v1/eip3540_eof_v1/test_container_validation.py +++ b/tests/prague/eip7692_eof_v1/eip3540_eof_v1/test_container_validation.py @@ -124,6 +124,21 @@ ), ], ), + Container( + name="single_subcontainer_without_data", + sections=[ + Section.Code(Op.EOFCREATE[0](0, 0, 0, 0) + Op.STOP), + Section.Container(Container.Code(Op.INVALID)), + ], + ), + Container( + name="single_subcontainer_with_data", + sections=[ + Section.Code(Op.EOFCREATE[0](0, 0, 0, 0) + Op.STOP), + Section.Container(Container.Code(Op.INVALID)), + Section.Data(data="0xAA"), + ], + ), ], ids=lambda c: c.name, ) @@ -302,6 +317,46 @@ def test_valid_containers( raw_bytes="ef00 01 01 0004 02 0001 0001 04 00", validity_error=EOFException.INCOMPLETE_SECTION_SIZE, ), + Container( + name="no_container_section_count", + raw_bytes="ef00 01 01 0004 02 0001 0001 03", + validity_error=EOFException.INCOMPLETE_SECTION_NUMBER, + ), + Container( + name="incomplete_container_section_count", + raw_bytes="ef00 01 01 0004 02 0001 0001 03 00", + validity_error=EOFException.INCOMPLETE_SECTION_NUMBER, + ), + Container( + name="zero_container_section_count", + raw_bytes="ef00 01 01 0004 02 0001 0001 03 0000 04 0000 00 00800000 00", + validity_error=EOFException.ZERO_SECTION_SIZE, + ), + Container( + name="no_container_section_size", + raw_bytes="ef00 01 01 0004 02 0001 0001 03 0001", + validity_error=EOFException.MISSING_HEADERS_TERMINATOR, + ), + Container( + name="incomplete_container_section_size", + raw_bytes="ef00 01 01 0004 02 0001 0001 03 0001 00", + validity_error=EOFException.INCOMPLETE_SECTION_SIZE, + ), + Container( + name="incomplete_container_section_size_2", + raw_bytes="ef00 01 01 0004 02 0001 0001 03 0002 0001", + validity_error=EOFException.INCOMPLETE_SECTION_SIZE, + ), + Container( + name="incomplete_container_section_size_3", + raw_bytes="ef00 01 01 0004 02 0001 0001 03 0002 0001 00", + validity_error=EOFException.INCOMPLETE_SECTION_SIZE, + ), + Container( + name="zero_size_container_section", + raw_bytes="ef00 01 01 0004 02 0001 0001 03 0001 0000 04 0000 00 00800000 00", + validity_error=EOFException.ZERO_SECTION_SIZE, + ), Container( name="truncated_header_data_section_with_container_section", raw_bytes="ef00 01 01 0004 02 0001 0001 03 0001 0001", @@ -511,6 +566,23 @@ def test_valid_containers( # TODO the exception must be about code section EOFException.INVALID_CODE_SECTION, validity_error=EOFException.ZERO_SECTION_SIZE, ), + Container( + name="no_container_section_contents", + sections=[ + Section.Code(Op.EOFCREATE[0](0, 0, 0, 0) + Op.STOP), + Section(kind=SectionKind.CONTAINER, data=b"", custom_size=20), + ], + validity_error=EOFException.INVALID_SECTION_BODIES_SIZE, + ), + Container( + name="no_container_section_contents_with_data", + sections=[ + Section.Code(Op.EOFCREATE[0](0, 0, 0, 0) + Op.STOP), + Section(kind=SectionKind.CONTAINER, data=b"", custom_size=20), + Section.Data(b"\0" * 20), + ], + validity_error=EOFException.TOPLEVEL_CONTAINER_TRUNCATED, + ), Container( name="no_data_section_contents", sections=[ diff --git a/tests/prague/eip7692_eof_v1/tracker.md b/tests/prague/eip7692_eof_v1/tracker.md index 07c19001a9..64e02f28a5 100644 --- a/tests/prague/eip7692_eof_v1/tracker.md +++ b/tests/prague/eip7692_eof_v1/tracker.md @@ -63,21 +63,21 @@ - [x] Container without type section (`tests/prague/eip7692_eof_v1/eip3540_eof_v1/test_section_order.py::test_section_order -k 'SectionTest.MISSING-section_kind_TYPE'`) - [x] Container without code sections (`tests/prague/eip7692_eof_v1/eip3540_eof_v1/test_section_order.py::test_section_order -k 'SectionTest.MISSING-section_kind_CODE'`) - [x] Container without data section (`tests/prague/eip7692_eof_v1/eip3540_eof_v1/test_section_order.py::test_section_order -k 'SectionTest.MISSING-section_kind_DATA'`) -- [ ] Valid containers without data section and with subcontainers (ethereum/tests: ./src/EOFTestsFiller/efValidation/EOF1_embedded_container_Copier.json) -- [ ] Valid containers with data section and with subcontainers (ethereum/tests: ./src/EOFTestsFiller/efValidation/EOF1_embedded_container_Copier.json) -- [ ] Valid container with maximum number of subcontainers (ethereum/tests: ./src/EOFTestsFiller/efValidation/EOF1_embedded_container_Copier.json) -- [ ] Container with number of subcontainers above the limit (ethereum/tests: ./src/EOFTestsFiller/efValidation/EOF1_embedded_container_invalid_Copier.json) -- [ ] Subcontainer section header truncated before subcontainer number (ethereum/tests: ./src/EOFTestsFiller/efValidation/EOF1_embedded_container_invalid_Copier.json) -- [ ] Subcontainer section header truncated before subcontainer size (ethereum/tests: ./src/EOFTestsFiller/efValidation/EOF1_embedded_container_invalid_Copier.json) -- [ ] Truncated subcontainer size (ethereum/tests: ./src/EOFTestsFiller/efValidation/EOF1_embedded_container_invalid_Copier.json) -- [ ] Zero container section number (ethereum/tests: ./src/EOFTestsFiller/efValidation/EOF1_embedded_container_invalid_Copier.json) -- [ ] Zero container size (ethereum/tests: ./src/EOFTestsFiller/efValidation/EOF1_embedded_container_invalid_Copier.json) -- [ ] Truncated container section body (ethereum/tests: ./src/EOFTestsFiller/efValidation/EOF1_embedded_container_invalid_Copier.json) -- [ ] Multiple container section headers -- [ ] Invalid subcontainer -- [ ] Invalid subcontainer on a deep nesting level -- [ ] Max number of inputs/outputs in a section (ethereum/tests: src/EOFTestsFiller/efValidation/max_arguments_count_Copier.json) -- [ ] Number of inputs/outputs in a section above the limit (ethereum/tests: src/EOFTestsFiller/efValidation/max_arguments_count_Copier.json) +- [x] Valid containers without data section and with subcontainers (`tests/prague/eip7692_eof_v1/eip3540_eof_v1/test_container_validation.py::test_valid_containers[fork_CancunEIP7692-eof_test-single_subcontainer_without_data]`) +- [x] Valid containers with data section and with subcontainers (`tests/prague/eip7692_eof_v1/eip3540_eof_v1/test_container_validation.py::test_valid_containers[fork_CancunEIP7692-eof_test-single_subcontainer_with_data]`) +- [x] Valid container with maximum number of subcontainers (`tests/prague/eip7692_eof_v1/eip7620_eof_create/test_subcontainer_validation.py::test_wide_container[fork_CancunEIP7692-eof_test-256]`) +- [x] Container with number of subcontainers above the limit (`tests/prague/eip7692_eof_v1/eip7620_eof_create/test_subcontainer_validation.py::test_wide_container[fork_CancunEIP7692-eof_test-257]`) +- [x] Subcontainer section header truncated before subcontainer number (`tests/prague/eip7692_eof_v1/eip3540_eof_v1/test_container_validation.py -k no_container_section_count`) +- [x] Subcontainer section header truncated before subcontainer size (`tests/prague/eip7692_eof_v1/eip3540_eof_v1/test_container_validation.py -k incomplete_container_section_count`) +- [x] Truncated subcontainer size (`tests/prague/eip7692_eof_v1/eip3540_eof_v1/test_container_validation.py -k no_container_section_size`, `tests/prague/eip7692_eof_v1/eip3540_eof_v1/test_container_validation.py -k incomplete_container_section_size`) +- [x] Zero container section number (`tests/prague/eip7692_eof_v1/eip3540_eof_v1/test_container_validation.py -k zero_container_section_count`) +- [ ] Zero container section size (`tests/prague/eip7692_eof_v1/eip3540_eof_v1/test_container_validation.py -k zero_size_container_section`) +- [x] Truncated container section body (`tests/prague/eip7692_eof_v1/eip3540_eof_v1/test_container_validation.py -k no_container_section_contents`) +- [ ] Multiple container section headers (`tests/prague/eip7692_eof_v1/eip3540_eof_v1/test_container_validation.py -k multiple_container_headers`) +- [x] Invalid subcontainer (`tests/prague/eip7692_eof_v1/eip7620_eof_create/test_subcontainer_validation.py -k invalid`) +- [x] Invalid subcontainer on a deep nesting level (`tests/prague/eip7692_eof_v1/eip7620_eof_create/test_subcontainer_validation.py::test_deep_container`) +- [x] Max number of inputs/outputs in a section (`tests/prague/eip7692_eof_v1/eip3540_eof_v1/test_container_validation.py::test_valid_containers[fork_CancunEIP7692-eof_test-code_section_input_maximum]`, `tests/prague/eip7692_eof_v1/eip3540_eof_v1/test_container_validation.py::test_valid_containers[fork_CancunEIP7692-eof_test-code_section_output_maximum]`) +- [x] Number of inputs/outputs in a section above the limit (`tests/prague/eip7692_eof_v1/eip3540_eof_v1/test_container_validation.py -k code_section_input_too_large`, `tests/prague/eip7692_eof_v1/eip3540_eof_v1/test_container_validation.py -k code_section_output_too_large`) ### Execution