|
20 | 20 | #------------------------------------------------------------------------------
|
21 | 21 | set -e
|
22 | 22 |
|
23 |
| -# Requires "${REPO_ROOT}/scripts/common.sh" to be included before. |
| 23 | +# Requires $REPO_ROOT to be defined and "${REPO_ROOT}/scripts/common.sh" to be included before. |
24 | 24 |
|
25 | 25 | CURRENT_EVM_VERSION=london
|
26 | 26 |
|
@@ -207,9 +207,19 @@ function force_truffle_compiler_settings
|
207 | 207 | echo "Compiler version (full): ${SOLCVERSION}"
|
208 | 208 | echo "-------------------------------------"
|
209 | 209 |
|
210 |
| - # Forcing the settings should always work by just overwriting the solc object. Forcing them by using a |
211 |
| - # dedicated settings objects should only be the fallback. |
212 |
| - echo "module.exports['compilers'] = $(truffle_compiler_settings "$solc_path" "$preset" "$evm_version");" >> "$config_file" |
| 210 | + local compiler_settings gas_reporter_settings |
| 211 | + compiler_settings=$(truffle_compiler_settings "$solc_path" "$preset" "$evm_version") |
| 212 | + gas_reporter_settings=$(eth_gas_reporter_settings "$preset") |
| 213 | + |
| 214 | + { |
| 215 | + echo "require('eth-gas-reporter');" |
| 216 | + echo "module.exports['mocha'] = {" |
| 217 | + echo " reporter: 'eth-gas-reporter'," |
| 218 | + echo " reporterOptions: ${gas_reporter_settings}" |
| 219 | + echo "};" |
| 220 | + |
| 221 | + echo "module.exports['compilers'] = ${compiler_settings};" |
| 222 | + } >> "$config_file" |
213 | 223 | }
|
214 | 224 |
|
215 | 225 | function name_hardhat_default_export
|
@@ -278,16 +288,21 @@ function force_hardhat_compiler_settings
|
278 | 288 | echo "Compiler version (full): ${SOLCVERSION}"
|
279 | 289 | echo "-------------------------------------"
|
280 | 290 |
|
281 |
| - local settings |
282 |
| - settings=$(hardhat_compiler_settings "$SOLCVERSION_SHORT" "$preset" "$evm_version") |
| 291 | + local compiler_settings gas_reporter_settings |
| 292 | + compiler_settings=$(hardhat_compiler_settings "$SOLCVERSION_SHORT" "$preset" "$evm_version") |
| 293 | + gas_reporter_settings=$(eth_gas_reporter_settings "$preset") |
283 | 294 | if [[ $config_file == *\.js ]]; then
|
284 | 295 | [[ $config_var_name == "" ]] || assertFail
|
285 |
| - echo "module.exports['solidity'] = ${settings}" >> "$config_file" |
| 296 | + echo "require('hardhat-gas-reporter');" |
| 297 | + echo "module.exports.gasReporter = ${gas_reporter_settings};" |
| 298 | + echo "module.exports.solidity = ${compiler_settings};" |
286 | 299 | else
|
287 | 300 | [[ $config_file == *\.ts ]] || assertFail
|
288 | 301 | [[ $config_var_name != "" ]] || assertFail
|
289 |
| - echo "${config_var_name}.solidity = {compilers: [${settings}]}" >> "$config_file" |
290 |
| - fi |
| 302 | + echo 'import "hardhat-gas-reporter";' |
| 303 | + echo "${config_var_name}.gasReporter = ${gas_reporter_settings};" |
| 304 | + echo "${config_var_name}.solidity = {compilers: [${compiler_settings}]};" |
| 305 | + fi >> "$config_file" |
291 | 306 | }
|
292 | 307 |
|
293 | 308 | function truffle_verify_compiler_version
|
@@ -368,6 +383,21 @@ function replace_global_solc
|
368 | 383 | export PATH="$PWD:$PATH"
|
369 | 384 | }
|
370 | 385 |
|
| 386 | +function eth_gas_reporter_settings |
| 387 | +{ |
| 388 | + local preset="$1" |
| 389 | + |
| 390 | + echo "{" |
| 391 | + echo " enabled: true," |
| 392 | + echo " gasPrice: 1," # Gas price does not matter to us at all. Set to whatever to avoid API call. |
| 393 | + echo " noColors: true," |
| 394 | + echo " showTimeSpent: false," # We're not interested in test timing |
| 395 | + echo " onlyCalledMethods: true," # Exclude entries with no gas for shorter report |
| 396 | + echo " showMethodSig: true," # Should make diffs more stable if there are overloaded functions |
| 397 | + echo " outputFile: \"$(gas_report_path "$preset")\"" |
| 398 | + echo "}" |
| 399 | +} |
| 400 | + |
371 | 401 | function truffle_compiler_settings
|
372 | 402 | {
|
373 | 403 | local solc_path="$1"
|
@@ -495,3 +525,121 @@ function external_test
|
495 | 525 | rm -rf "$DIR"
|
496 | 526 | echo "Done."
|
497 | 527 | }
|
| 528 | + |
| 529 | +function gas_report_path |
| 530 | +{ |
| 531 | + local preset="$1" |
| 532 | + |
| 533 | + echo "${DIR}/gas-report-${preset}.rst" |
| 534 | +} |
| 535 | + |
| 536 | +function gas_report_to_json |
| 537 | +{ |
| 538 | + cat - | "${REPO_ROOT}/scripts/externalTests/parse_eth_gas_report.py" | jq '{gas: .}' |
| 539 | +} |
| 540 | + |
| 541 | +function detect_hardhat_artifact_dir |
| 542 | +{ |
| 543 | + if [[ -e build/ && -e artifacts/ ]]; then |
| 544 | + fail "Cannot determine Hardhat artifact location. Both build/ and artifacts/ exist" |
| 545 | + elif [[ -e build/ ]]; then |
| 546 | + echo -n build/artifacts |
| 547 | + elif [[ -e artifacts/ ]]; then |
| 548 | + echo -n artifacts |
| 549 | + else |
| 550 | + fail "Hardhat build artifacts not found." |
| 551 | + fi |
| 552 | +} |
| 553 | + |
| 554 | +function bytecode_size_json_from_truffle_artifacts |
| 555 | +{ |
| 556 | + # NOTE: The output of this function is a series of concatenated JSON dicts rather than a list. |
| 557 | + |
| 558 | + for artifact in build/contracts/*.json; do |
| 559 | + if [[ $(jq '. | has("unlinked_binary")' "$artifact") == false ]]; then |
| 560 | + # Each artifact represents compilation output for a single contract. Some top-level keys contain |
| 561 | + # bits of Standard JSON output while others are generated by Truffle. Process it into a dict |
| 562 | + # of the form `{"<file>": {"<contract>": <size>}}`. |
| 563 | + # NOTE: The `bytecode` field starts with 0x, which is why we subtract 1 from size. |
| 564 | + jq '{ |
| 565 | + (.ast.absolutePath): { |
| 566 | + (.contractName): (.bytecode | length / 2 - 1) |
| 567 | + } |
| 568 | + }' "$artifact" |
| 569 | + fi |
| 570 | + done |
| 571 | +} |
| 572 | + |
| 573 | +function bytecode_size_json_from_hardhat_artifacts |
| 574 | +{ |
| 575 | + # NOTE: The output of this function is a series of concatenated JSON dicts rather than a list. |
| 576 | + |
| 577 | + for artifact in "$(detect_hardhat_artifact_dir)"/build-info/*.json; do |
| 578 | + # Each artifact contains Standard JSON output under the `output` key. |
| 579 | + # Process it into a dict of the form `{"<file>": {"<contract>": <size>}}`, |
| 580 | + # Note that one Hardhat artifact often represents multiple input files. |
| 581 | + jq '.output.contracts | to_entries[] | { |
| 582 | + "\(.key)": .value | to_entries[] | { |
| 583 | + "\(.key)": (.value.evm.bytecode.object | length / 2) |
| 584 | + } |
| 585 | + }' "$artifact" |
| 586 | + done |
| 587 | +} |
| 588 | + |
| 589 | +function combine_artifact_json |
| 590 | +{ |
| 591 | + # Combine all dicts into a list with `jq --slurp` and then use `reduce` to merge them into one |
| 592 | + # big dict with keys of the form `"<file>:<contract>"`. Then run jq again to filter out items |
| 593 | + # with zero size and put the rest under under a top-level `bytecode_size` key. Also add another |
| 594 | + # key with total bytecode size. |
| 595 | + # NOTE: The extra inner `bytecode_size` key is there only to make diffs more readable. |
| 596 | + cat - | |
| 597 | + jq --slurp 'reduce (.[] | to_entries[]) as {$key, $value} ({}; . + { |
| 598 | + ($key + ":" + ($value | to_entries[].key)): { |
| 599 | + bytecode_size: $value | to_entries[].value |
| 600 | + } |
| 601 | + })' | |
| 602 | + jq --indent 4 --sort-keys '{ |
| 603 | + bytecode_size: [. | to_entries[] | select(.value.bytecode_size > 0)] | from_entries, |
| 604 | + total_bytecode_size: (reduce (. | to_entries[]) as {$key, $value} (0; . + $value.bytecode_size)) |
| 605 | + }' |
| 606 | +} |
| 607 | + |
| 608 | +function project_info_json |
| 609 | +{ |
| 610 | + local project_url="$1" |
| 611 | + |
| 612 | + echo "{" |
| 613 | + echo " \"project\": {" |
| 614 | + # NOTE: Given that we clone with `--depth 1`, we'll only get useful output out of `git describe` |
| 615 | + # if we directly check out a tag. Still better than nothing. |
| 616 | + echo " \"version\": \"$(git describe --always)\"," |
| 617 | + echo " \"commit\": \"$(git rev-parse HEAD)\"," |
| 618 | + echo " \"url\": \"${project_url}\"" |
| 619 | + echo " }" |
| 620 | + echo "}" |
| 621 | +} |
| 622 | + |
| 623 | +function store_benchmark_report |
| 624 | +{ |
| 625 | + local framework="$1" |
| 626 | + local project_name="$2" |
| 627 | + local project_url="$3" |
| 628 | + local preset="$4" |
| 629 | + |
| 630 | + [[ $framework == truffle || $framework == hardhat ]] || assertFail |
| 631 | + [[ " ${AVAILABLE_PRESETS[*]} " == *" $preset "* ]] || assertFail |
| 632 | + |
| 633 | + local report_dir="${REPO_ROOT}/reports/externalTests" |
| 634 | + local output_file="${report_dir}/benchmark-${project_name}-${preset}.json" |
| 635 | + mkdir -p "$report_dir" |
| 636 | + |
| 637 | + { |
| 638 | + if [[ -e $(gas_report_path "$preset") ]]; then |
| 639 | + gas_report_to_json < "$(gas_report_path "$preset")" |
| 640 | + fi |
| 641 | + |
| 642 | + "bytecode_size_json_from_${framework}_artifacts" | combine_artifact_json |
| 643 | + project_info_json "$project_url" |
| 644 | + } | jq --slurp "{\"${project_name}\": {\"${preset}\": add}}" --indent 4 --sort-keys > "$output_file" |
| 645 | +} |
0 commit comments