From 565d767922d2327e190a816023838442af1c55dd Mon Sep 17 00:00:00 2001 From: 0xphaze <0xphaze@gmail.com> Date: Wed, 8 Mar 2023 13:25:14 +0100 Subject: [PATCH] Run `prettier **/*.md --write` --- CONTRIBUTING.md | 10 +- README.md | 22 +- SUMMARY.md | 203 ++-- development-guidelines/guidelines.md | 6 +- development-guidelines/incident_response.md | 12 +- development-guidelines/token_integration.md | 5 +- development-guidelines/workflow.md | 10 +- learn_evm/README.md | 8 +- learn_evm/beps_forks.md | 16 +- learn_evm/cips_forks.md | 46 +- learn_evm/eips_forks.md | 90 +- learn_evm/evm_opcodes.md | 917 ++++++++++++------ learn_evm/tips_upgrades.md | 132 ++- learn_evm/tracing.md | 12 +- learn_evm/yellow-paper.md | 45 +- not-so-smart-contracts/README.md | 2 +- not-so-smart-contracts/algorand/README.md | 32 +- .../algorand/access_controls/README.md | 2 +- .../algorand/denial_of_service/README.md | 4 +- .../algorand/rekeying/README.md | 2 + .../time_based_replay_attack/README.md | 2 +- .../unchecked_transaction_fee/README.md | 2 +- .../L1_to_L2_address_conversion/README.md | 8 +- not-so-smart-contracts/cairo/README.md | 32 +- .../cairo/access_controls/README.md | 3 +- .../cairo/arithmetic_overflow/README.md | 1 - .../consider_L1_to_L2_message_failure.md | 10 +- .../README.md | 5 +- .../cairo/incorrect_felt_comparison/README.md | 12 +- .../cairo/integer_division/README.md | 6 +- .../namespace_storage_var_collision/README.md | 5 +- .../cairo/replay_protection/README.md | 1 - .../cairo/view_state/README.md | 2 +- not-so-smart-contracts/cosmos/README.md | 33 +- .../cosmos/abci_fast/README.md | 5 +- .../cosmos/abci_panic/README.md | 10 +- .../cosmos/broken_bookkeeping/README.md | 10 +- .../cosmos/incorrect_getsigners/README.md | 6 +- .../cosmos/messages_priority/README.md | 4 +- .../cosmos/missing_error_handler/README.md | 7 +- .../cosmos/non_determinism/README.md | 19 +- .../cosmos/rounding_errors/README.md | 9 +- .../cosmos/unregistered_msg_handler/README.md | 3 +- not-so-smart-contracts/solana/README.md | 25 +- .../solana/arbitrary_cpi/README.md | 9 +- .../solana/improper_pda_validation/README.md | 4 +- .../solana/ownership_check/README.md | 7 +- .../solana/signer_check/README.md | 16 +- .../solana/sysvar_account_check/README.md | 17 +- not-so-smart-contracts/substrate/README.md | 28 +- .../substrate/arithmetic_overflow/README.md | 57 +- .../substrate/dont_panic/README.md | 9 +- .../substrate/origins/README.md | 8 +- .../substrate/randomness/README.md | 15 +- .../substrate/validate_unsigned/README.md | 10 +- .../substrate/verify_first/README.md | 11 +- .../substrate/weights_and_fees/README.md | 20 +- program-analysis/README.md | 35 +- program-analysis/echidna/README.md | 5 +- .../echidna/advanced/collecting-a-corpus.md | 97 +- .../echidna/advanced/end-to-end-testing.md | 34 +- ...-transactions-with-high-gas-consumption.md | 16 +- .../advanced/hevm-cheats-to-test-permit.md | 12 +- .../echidna/advanced/optimization_mode.md | 8 +- .../smart-contract-fuzzing-at-scale.md | 38 +- .../echidna/advanced/testing-bytecode.md | 18 +- .../echidna/advanced/using-multi-abi.md | 8 +- .../echidna/basic/assertion-checking.md | 24 +- .../basic/common-testing-approaches.md | 96 +- .../echidna/basic/filtering-functions.md | 21 +- .../echidna/basic/property-creation.md | 33 +- .../echidna/basic/testing-modes.md | 79 +- .../echidna/exercises/Exercise-1.md | 8 +- .../echidna/exercises/Exercise-2.md | 10 +- .../echidna/exercises/Exercise-3.md | 10 +- .../echidna/exercises/Exercise-4.md | 4 +- .../echidna/exercises/Exercise-5.md | 16 +- .../echidna/exercises/Exercise-6.md | 16 +- .../echidna/exercises/Exercise-7.md | 12 +- program-analysis/echidna/exercises/README.md | 2 +- .../echidna/frequently_asked_questions.md | 37 +- program-analysis/echidna/fuzzing_tips.md | 5 +- .../echidna/introduction/README.md | 2 +- .../introduction/fuzzing-introduction.md | 2 +- .../introduction/how-to-test-a-property.md | 13 +- .../echidna/introduction/installation.md | 4 +- program-analysis/manticore/README.md | 2 +- .../manticore/adding-constraints.md | 7 +- .../manticore/exercises/example.md | 1 + .../manticore/exercises/exercise1.md | 3 +- .../manticore/getting-throwing-paths.md | 6 +- .../manticore/running-under-manticore.md | 32 +- .../symbolic-execution-introduction.md | 16 +- program-analysis/slither/README.md | 5 +- program-analysis/slither/api.md | 2 +- program-analysis/slither/exercise1.md | 1 + program-analysis/slither/static_analysis.md | 7 +- resources/tob_blogposts.md | 154 ++- 98 files changed, 1630 insertions(+), 1278 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 1764ca45..1ffaa583 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,15 +1,19 @@ # Contributing to Building-secure-contracts + First, thanks for your interest in contributing to Building-secure-contracts! We welcome and appreciate all contributions, including bug reports, feature suggestions, tutorials/blog posts, and code improvements. If you're unsure where to start, we recommend our [`good first issue`](https://github.com/crytic/building-secure-contracts/issues?q=is%3Aissue+is%3Aopen+label%3A%22good+first+issue%22) and [`help wanted`](https://github.com/crytic/building-secure-contracts/issues?q=is%3Aissue+is%3Aopen+label%3A%22help+wanted%22) issue labels. ## Bug reports and feature suggestions + Bug reports and feature suggestions can be submitted to our issue tracker. For bug reports, attaching the contract that caused the bug will help us in debugging and resolving the issue quickly. If you find a security vulnerability, do not open an issue; email opensource@trailofbits.com instead. ## Questions + Questions can be submitted to the issue tracker, but you may get a faster response if you ask in our [chat room](https://empireslacking.herokuapp.com/) (in the #ethereum channel). ## Code + building-secure-contracts uses the pull request contribution model. Please make an account on Github, fork this repo, and submit code contributions via pull request. For more documentation, look [here](https://guides.github.com/activities/forking/). Some pull request guidelines: @@ -22,6 +26,7 @@ Some pull request guidelines: ## Directory Structure Below is a rough outline of building-secure-contracts's structure: + ```text . ├── development-guidelnes # High-level best-practices for all smart contracts @@ -34,9 +39,10 @@ Below is a rough outline of building-secure-contracts's structure: ## Linters -We run [markdown-link-check](https://github.com/tcort/markdown-link-check) to ensure all the markdown links are correct. +We run [markdown-link-check](https://github.com/tcort/markdown-link-check) to ensure all the markdown links are correct. To install `markdown-link-check`: + ```bash $ npm install -g markdown-link-check ``` @@ -52,10 +58,10 @@ $ find . -name \*.md -print0 | xargs -0 -n1 markdown-link-check We use `mdbook` to generate [secure-contracts.com](https://secure-contracts.com/). To run it locally: + ``` $ cargo install --git https://github.com/montyly/mdBook.git mdbook $ mdbook build ``` - Note: we use https://github.com/montyly/mdBook.git, which contains https://github.com/rust-lang/mdBook/pull/1584. diff --git a/README.md b/README.md index 3c5e8c29..4fcabb8d 100644 --- a/README.md +++ b/README.md @@ -18,15 +18,15 @@ We welcome contributions, and you can contribute by following our [contributing - [Transaction Tracing](./learn_evm/tracing.md): Helper scripts and guidance for generating and navigating transaction traces - [Yellow Paper Guidance](./learn_evm/yellow-paper.md): Symbol reference for more easily reading the Ethereum yellow paper - [Forks <> EIPs](./learn_evm/eips_forks.md): Summarize the EIPs included in each Ethereum fork - - [Forks <> CIPs](./learn_evm/cips_forks.md): Summarize the CIPs and EIPs included in each Celo fork *(EVM-compatible chain)* - - [Upgrades <> TIPs](./learn_evm/tips_upgrades.md): Summarize the TIPs included in each TRON upgrade *(EVM-compatible chain)* - - [Forks <> BEPs](./learn_evm/beps_forks.md): Summarize the BEPs included in each BSC fork *(EVM-compatible chain)* + - [Forks <> CIPs](./learn_evm/cips_forks.md): Summarize the CIPs and EIPs included in each Celo fork _(EVM-compatible chain)_ + - [Upgrades <> TIPs](./learn_evm/tips_upgrades.md): Summarize the TIPs included in each TRON upgrade _(EVM-compatible chain)_ + - [Forks <> BEPs](./learn_evm/beps_forks.md): Summarize the BEPs included in each BSC fork _(EVM-compatible chain)_ - [Not so smart contracts](./not-so-smart-contracts): Examples of smart contract common issues. Each issue contains a description, an example and recommendations - - [Algorand](./not-so-smart-contracts/algorand) - - [Cairo](./not-so-smart-contracts/cairo) - - [Cosmos](./not-so-smart-contracts/cosmos) - - [Substrate](./not-so-smart-contracts/substrate) - - [Solana](./not-so-smart-contracts/solana) + - [Algorand](./not-so-smart-contracts/algorand) + - [Cairo](./not-so-smart-contracts/cairo) + - [Cosmos](./not-so-smart-contracts/cosmos) + - [Substrate](./not-so-smart-contracts/substrate) + - [Solana](./not-so-smart-contracts/solana) - [Program analysis](./program-analysis): How to use automated tools to secure contracts - [Echidna](./program-analysis/echidna): a fuzzer that will check your contract's properties. - [Slither](./program-analysis/slither): a static analyzer available through a CLI and scriptable interface. @@ -35,8 +35,8 @@ We welcome contributions, and you can contribute by following our [contributing - a theoretical introduction, a walkthrough of its API, and a set of exercises. - exercises expected to require ~two hours to practically learn its operation. - [Resources](./resources): Various online resources - - [Trail of Bits blogposts](./resources/tob_blogposts.md): List of blockchain related blogposts made by Trail of Bits - + - [Trail of Bits blogposts](./resources/tob_blogposts.md): List of blockchain related blogposts made by Trail of Bits # License -secure-contracts and building-secure-contracts are licensed and distributed under the [AGPLv3 license](https://github.com/crytic/building-secure-contracts/blob/master/LICENSE). Contact us if you're looking for an exception to the terms. \ No newline at end of file + +secure-contracts and building-secure-contracts are licensed and distributed under the [AGPLv3 license](https://github.com/crytic/building-secure-contracts/blob/master/LICENSE). Contact us if you're looking for an exception to the terms. diff --git a/SUMMARY.md b/SUMMARY.md index 325304e5..3e0d5784 100644 --- a/SUMMARY.md +++ b/SUMMARY.md @@ -7,113 +7,102 @@ - [Token integration checklist](./development-guidelines/token_integration.md) - [Incident Response Recommendations](./development-guidelines/incident_response.md) - [Secure development workflow](./development-guidelines/workflow.md) - - [Learn EVM](./learn_evm/README.md) - - [EVM Opcode Reference](./learn_evm/evm_opcodes.md) - - [Transaction Tracing](./learn_evm/tracing.md) - - [Yellow Paper Guidance](./learn_evm/yellow-paper.md): - - [Forks <> EIPs](./learn_evm/eips_forks.md) - - [Forks <> CIPs](./learn_evm/cips_forks.md) - - [Upgrades <> TIPs](./learn_evm/tips_upgrades.md) - - [Forks <> BEPs](./learn_evm/beps_forks.md) + - [EVM Opcode Reference](./learn_evm/evm_opcodes.md) + - [Transaction Tracing](./learn_evm/tracing.md) + - [Yellow Paper Guidance](./learn_evm/yellow-paper.md): + - [Forks <> EIPs](./learn_evm/eips_forks.md) + - [Forks <> CIPs](./learn_evm/cips_forks.md) + - [Upgrades <> TIPs](./learn_evm/tips_upgrades.md) + - [Forks <> BEPs](./learn_evm/beps_forks.md) - [Not so smart contracts](./not-so-smart-contracts/README.md) - - [Algorand](./not-so-smart-contracts/algorand/README.md) - - [Rekeying](./not-so-smart-contracts/algorand/rekeying/README.md) - - [Unchecked Transaction Fees](./not-so-smart-contracts/algorand/unchecked_transaction_fee/README.md) - - [Closing Account](./not-so-smart-contracts/algorand/closing_account/README.md) - - [Closing Asset](./not-so-smart-contracts/algorand/closing_asset/README.md) - - [Group Size Check](./not-so-smart-contracts/algorand/group_size_check/README.md) - - [Time-based Replay Attack](./not-so-smart-contracts/algorand/time_based_replay_attack/README.md) - - [Access Controls](./not-so-smart-contracts/algorand/access_controls/README.md) - - [Asset Id Check](./not-so-smart-contracts/algorand/asset_id_check/README.md) - - [Denial of Service](./not-so-smart-contracts/algorand/denial_of_service/README.md) - - - [Cairo](./not-so-smart-contracts/cairo/README.md) - - [Improper access controls](./not-so-smart-contracts/cairo/access_controls/README.md) - - [Integer division errors](./not-so-smart-contracts/cairo/integer_division/README.md) - - [View state modifications](./not-so-smart-contracts/cairo/view_state/README.md) - - [Arithmetic overflow](./not-so-smart-contracts/cairo/arithmetic_overflow/README.md) - - [Signature replays](./not-so-smart-contracts/cairo/replay_protection/README.md) - - [L1 to L2 Address Conversion](./not-so-smart-contracts/cairo/L1_to_L2_address_conversion/README.md) - - [Incorrect Felt Comparison](./not-so-smart-contracts/cairo/incorrect_felt_comparison/README.md) - - [Namespace Storage Var Collision](./not-so-smart-contracts/cairo/namespace_storage_var_collision/README.md) - - [Dangerous Public Imports in Libraries](./not-so-smart-contracts/cairo/dangerous_public_imports_in_libraries/README.md) - - - [Cosmos](./not-so-smart-contracts/cosmos/README.md) - - [Incorrect signers](./not-so-smart-contracts/cosmos/incorrect_getsigners/README.md) - - [Non-determinism](./not-so-smart-contracts/cosmos/non_determinism/README.md) - - [Not prioritized messages](./not-so-smart-contracts/cosmos/messages_priority/README.md) - - [Slow ABCI methods](./not-so-smart-contracts/cosmos/abci_fast/README.md) - - [ABCI methods panic](./not-so-smart-contracts/cosmos/abci_panic/README.md) - - [Broken bookkeeping](./not-so-smart-contracts/cosmos/broken_bookkeeping/README.md) - - [Rounding errors](./not-so-smart-contracts/cosmos/rounding_errors/README.md) - - [Unregistered message handler](./not-so-smart-contracts/cosmos/unregistered_msg_handler/README.md) - - [Missing error handler](./not-so-smart-contracts/cosmos/missing_error_handler/README.md) - - - [Solana](./not-so-smart-contracts/solana/README.md) - - [Arbitrary CPI](./not-so-smart-contracts/solana/arbitrary_cpi/README.md) - - [Improper PDA Validation](./not-so-smart-contracts/solana/improper_pda_validation/README.md) - - [Ownership Check](./not-so-smart-contracts/solana/ownership_check/README.md) - - [Signer Check](./not-so-smart-contracts/solana/signer_check/README.md) - - [Sysvar Account Check](./not-so-smart-contracts/solana/sysvar_account_check/README.md) - - - [Substrate](./not-so-smart-contracts/substrate/README.md) - - [Arithmetic overflow](./not-so-smart-contracts/substrate/arithmetic_overflow/README.md) - - [Don't panic!](./not-so-smart-contracts/substrate/dont_panic/README.md) - - [Weights and fees](./not-so-smart-contracts/substrate/weights_and_fees/README.md) - - [Verify first](./not-so-smart-contracts/substrate/verify_first/README.md) - - [Unsigned transaction validation](./not-so-smart-contracts/substrate/validate_unsigned/README.md) - - [Bad randomness](./not-so-smart-contracts/substrate/randomness/README.md) - - [Bad origin](./not-so-smart-contracts/substrate/origins/README.md) - + - [Algorand](./not-so-smart-contracts/algorand/README.md) + - [Rekeying](./not-so-smart-contracts/algorand/rekeying/README.md) + - [Unchecked Transaction Fees](./not-so-smart-contracts/algorand/unchecked_transaction_fee/README.md) + - [Closing Account](./not-so-smart-contracts/algorand/closing_account/README.md) + - [Closing Asset](./not-so-smart-contracts/algorand/closing_asset/README.md) + - [Group Size Check](./not-so-smart-contracts/algorand/group_size_check/README.md) + - [Time-based Replay Attack](./not-so-smart-contracts/algorand/time_based_replay_attack/README.md) + - [Access Controls](./not-so-smart-contracts/algorand/access_controls/README.md) + - [Asset Id Check](./not-so-smart-contracts/algorand/asset_id_check/README.md) + - [Denial of Service](./not-so-smart-contracts/algorand/denial_of_service/README.md) + - [Cairo](./not-so-smart-contracts/cairo/README.md) + - [Improper access controls](./not-so-smart-contracts/cairo/access_controls/README.md) + - [Integer division errors](./not-so-smart-contracts/cairo/integer_division/README.md) + - [View state modifications](./not-so-smart-contracts/cairo/view_state/README.md) + - [Arithmetic overflow](./not-so-smart-contracts/cairo/arithmetic_overflow/README.md) + - [Signature replays](./not-so-smart-contracts/cairo/replay_protection/README.md) + - [L1 to L2 Address Conversion](./not-so-smart-contracts/cairo/L1_to_L2_address_conversion/README.md) + - [Incorrect Felt Comparison](./not-so-smart-contracts/cairo/incorrect_felt_comparison/README.md) + - [Namespace Storage Var Collision](./not-so-smart-contracts/cairo/namespace_storage_var_collision/README.md) + - [Dangerous Public Imports in Libraries](./not-so-smart-contracts/cairo/dangerous_public_imports_in_libraries/README.md) + - [Cosmos](./not-so-smart-contracts/cosmos/README.md) + - [Incorrect signers](./not-so-smart-contracts/cosmos/incorrect_getsigners/README.md) + - [Non-determinism](./not-so-smart-contracts/cosmos/non_determinism/README.md) + - [Not prioritized messages](./not-so-smart-contracts/cosmos/messages_priority/README.md) + - [Slow ABCI methods](./not-so-smart-contracts/cosmos/abci_fast/README.md) + - [ABCI methods panic](./not-so-smart-contracts/cosmos/abci_panic/README.md) + - [Broken bookkeeping](./not-so-smart-contracts/cosmos/broken_bookkeeping/README.md) + - [Rounding errors](./not-so-smart-contracts/cosmos/rounding_errors/README.md) + - [Unregistered message handler](./not-so-smart-contracts/cosmos/unregistered_msg_handler/README.md) + - [Missing error handler](./not-so-smart-contracts/cosmos/missing_error_handler/README.md) + - [Solana](./not-so-smart-contracts/solana/README.md) + - [Arbitrary CPI](./not-so-smart-contracts/solana/arbitrary_cpi/README.md) + - [Improper PDA Validation](./not-so-smart-contracts/solana/improper_pda_validation/README.md) + - [Ownership Check](./not-so-smart-contracts/solana/ownership_check/README.md) + - [Signer Check](./not-so-smart-contracts/solana/signer_check/README.md) + - [Sysvar Account Check](./not-so-smart-contracts/solana/sysvar_account_check/README.md) + - [Substrate](./not-so-smart-contracts/substrate/README.md) + - [Arithmetic overflow](./not-so-smart-contracts/substrate/arithmetic_overflow/README.md) + - [Don't panic!](./not-so-smart-contracts/substrate/dont_panic/README.md) + - [Weights and fees](./not-so-smart-contracts/substrate/weights_and_fees/README.md) + - [Verify first](./not-so-smart-contracts/substrate/verify_first/README.md) + - [Unsigned transaction validation](./not-so-smart-contracts/substrate/validate_unsigned/README.md) + - [Bad randomness](./not-so-smart-contracts/substrate/randomness/README.md) + - [Bad origin](./not-so-smart-contracts/substrate/origins/README.md) - [Program Analysis](./program-analysis/README.md) - - [Echidna](./program-analysis/echidna/README.md) - - [Introduction](./program-analysis/echidna/introduction/README.md) - - [Introduction to fuzzing](./program-analysis/echidna/introduction/fuzzing-introduction.md) - - [How to test a property](./program-analysis/echidna/introduction/how-to-test-a-property.md) - - [Basic](./program-analysis/echidna/basic/README.md) - - [How to select the most suitable testing mode](./program-analysis/echidna/basic/testing-modes.md) - - [How to select the best testing approach](./program-analysis/echidna/basic/common-testing-approaches.md) - - [How to filter functions](./program-analysis/echidna/basic/filtering-functions.md) - - [How to test assertions](./program-analysis/echidna/basic/assertion-checking.md) - - [How to write good properties step by step](./program-analysis/echidna/basic/property-creation.md) - - [Advanced](./program-analysis/echidna/advanced/README.md) - - [How to collect a corpus](./program-analysis/echidna/advanced/collecting-a-corpus.md) - - [How to use optimization mode](./program-analysis/echidna/advanced/optimization_mode.md) - - [How to detect high gas consumption](./program-analysis/echidna/advanced/finding-transactions-with-high-gas-consumption.md) - - [How to perform smart contract fuzzing at a large scale](./program-analysis/echidna/advanced/smart-contract-fuzzing-at-scale.md) - - - [How to test bytecode-only contracts](./program-analysis/echidna/advanced/testing-bytecode.md) - - [How to use hevm cheats to test permit](./program-analysis/echidna/advanced/hevm-cheats-to-test-permit.md) - - [How to seed Echidna with unit tests](./program-analysis/echidna/advanced/end-to-end-testing.md) - - [Understanding and using `multi-abi`](./program-analysis/echidna/advanced/using-multi-abi.md) - - [Fuzzing tips](./program-analysis/echidna/fuzzing_tips.md) - - [Frequently Asked Questions](./program-analysis/echidna/frequently_asked_questions.md) - - [Exercises](./program-analysis/echidna/exercises/README.md) - - [Exercise 1](./program-analysis/echidna/exercises/Exercise-1.md) - - [Exercise 2](./program-analysis/echidna/exercises/Exercise-2.md) - - [Exercise 3](./program-analysis/echidna/exercises/Exercise-3.md) - - [Exercise 4](./program-analysis/echidna/exercises/Exercise-4.md) - - [Exercise 5](./program-analysis/echidna/exercises/Exercise-5.md) - - [Exercise 6](./program-analysis/echidna/exercises/Exercise-6.md) - - [Exercise 7](./program-analysis/echidna/exercises/Exercise-7.md) - - [Exercise 8](./program-analysis/echidna/exercises/Exercise-8.md) - - - [Manticore](./program-analysis/manticore/README.md) - - [Introduction to symbolic execution](./program-analysis/manticore/symbolic-execution-introduction.md): - - [Running under Manticore](./program-analysis/manticore/running-under-manticore.md) - - [Getting throwing paths](./program-analysis/manticore/getting-throwing-paths.md) - - [Adding constraints](./program-analysis/manticore/adding-constraints.md) - - [Exercises](./program-analysis/manticore/exercises/README.md) - - [Example](./program-analysis/manticore/exercises/example.md) - - [Exercise 1](./program-analysis/manticore/exercises/exercise1.md) - - [Exercise 2](./program-analysis/manticore/exercises/exercise2.md) - - - [Slither](./program-analysis/slither/README.md) - - [Static Analysis](./program-analysis/slither/static_analysis.md) - - [API](./program-analysis/slither/api.md) - - [Exercise 1](./program-analysis/slither/exercise1.md) - - [Exercise 2](./program-analysis/slither/exercise2.md) - - -- [Resources](./resources/tob_blogposts.md) \ No newline at end of file + - [Echidna](./program-analysis/echidna/README.md) + - [Introduction](./program-analysis/echidna/introduction/README.md) + - [Introduction to fuzzing](./program-analysis/echidna/introduction/fuzzing-introduction.md) + - [How to test a property](./program-analysis/echidna/introduction/how-to-test-a-property.md) + - [Basic](./program-analysis/echidna/basic/README.md) + - [How to select the most suitable testing mode](./program-analysis/echidna/basic/testing-modes.md) + - [How to select the best testing approach](./program-analysis/echidna/basic/common-testing-approaches.md) + - [How to filter functions](./program-analysis/echidna/basic/filtering-functions.md) + - [How to test assertions](./program-analysis/echidna/basic/assertion-checking.md) + - [How to write good properties step by step](./program-analysis/echidna/basic/property-creation.md) + - [Advanced](./program-analysis/echidna/advanced/README.md) + - [How to collect a corpus](./program-analysis/echidna/advanced/collecting-a-corpus.md) + - [How to use optimization mode](./program-analysis/echidna/advanced/optimization_mode.md) + - [How to detect high gas consumption](./program-analysis/echidna/advanced/finding-transactions-with-high-gas-consumption.md) + - [How to perform smart contract fuzzing at a large scale](./program-analysis/echidna/advanced/smart-contract-fuzzing-at-scale.md) + - [How to test bytecode-only contracts](./program-analysis/echidna/advanced/testing-bytecode.md) + - [How to use hevm cheats to test permit](./program-analysis/echidna/advanced/hevm-cheats-to-test-permit.md) + - [How to seed Echidna with unit tests](./program-analysis/echidna/advanced/end-to-end-testing.md) + - [Understanding and using `multi-abi`](./program-analysis/echidna/advanced/using-multi-abi.md) + - [Fuzzing tips](./program-analysis/echidna/fuzzing_tips.md) + - [Frequently Asked Questions](./program-analysis/echidna/frequently_asked_questions.md) + - [Exercises](./program-analysis/echidna/exercises/README.md) + - [Exercise 1](./program-analysis/echidna/exercises/Exercise-1.md) + - [Exercise 2](./program-analysis/echidna/exercises/Exercise-2.md) + - [Exercise 3](./program-analysis/echidna/exercises/Exercise-3.md) + - [Exercise 4](./program-analysis/echidna/exercises/Exercise-4.md) + - [Exercise 5](./program-analysis/echidna/exercises/Exercise-5.md) + - [Exercise 6](./program-analysis/echidna/exercises/Exercise-6.md) + - [Exercise 7](./program-analysis/echidna/exercises/Exercise-7.md) + - [Exercise 8](./program-analysis/echidna/exercises/Exercise-8.md) + - [Manticore](./program-analysis/manticore/README.md) + - [Introduction to symbolic execution](./program-analysis/manticore/symbolic-execution-introduction.md): + - [Running under Manticore](./program-analysis/manticore/running-under-manticore.md) + - [Getting throwing paths](./program-analysis/manticore/getting-throwing-paths.md) + - [Adding constraints](./program-analysis/manticore/adding-constraints.md) + - [Exercises](./program-analysis/manticore/exercises/README.md) + - [Example](./program-analysis/manticore/exercises/example.md) + - [Exercise 1](./program-analysis/manticore/exercises/exercise1.md) + - [Exercise 2](./program-analysis/manticore/exercises/exercise2.md) + - [Slither](./program-analysis/slither/README.md) + - [Static Analysis](./program-analysis/slither/static_analysis.md) + - [API](./program-analysis/slither/api.md) + - [Exercise 1](./program-analysis/slither/exercise1.md) + - [Exercise 2](./program-analysis/slither/exercise2.md) +- [Resources](./resources/tob_blogposts.md) diff --git a/development-guidelines/guidelines.md b/development-guidelines/guidelines.md index 172b2950..64e00cb0 100644 --- a/development-guidelines/guidelines.md +++ b/development-guidelines/guidelines.md @@ -58,13 +58,13 @@ The delegatecall opcode is a very sharp tool that must be used carefully. Many h - **Contract Existence Checks**: All [low-level calls](https://docs.soliditylang.org/en/latest/control-structures.html?highlight=existence#error-handling-assert-require-revert-and-exceptions), not just delegatecall, will return true against an address with empty bytecode. This might cause callers to be misled to think that a call performed a meaningful operation when it did not or it might result in important safety checks being silently skipped. Be aware that while a contract’s constructor is running, its bytecode remains empty until the end of constructor execution. We recommend that you rigorously verify that all low-level calls are properly protected against nonexistent contracts, keeping in mind that most proxy libraries (such as the one written by Openzeppelin) do not perform contract existence checks automatically. For more information regarding delegatecall proxies in general, reference our blog posts and presentations: + - [Contract Upgradability Anti-Patterns](https://blog.trailofbits.com/2018/09/05/contract-upgrade-anti-patterns/): Describes the difference between a downstream data contract and delegatecall proxies which use an upstream data contract and how these patterns impact upgradability. - [How the Diamond standard falls short](https://blog.trailofbits.com/2020/10/30/good-idea-bad-design-how-the-diamond-standard-falls-short/): This post dives deep into delegatecall risks which apply to all contracts, not just those that follow the diamond standard. - [Breaking Aave Upgradeability](https://blog.trailofbits.com/2020/12/16/breaking-aave-upgradeability/): A write-up describing a subtle problem that we discovered in Aave `AToken` contracts that resulted from the interplay between delegatecall proxies, contact existence checks, and unsafe initialization. - [Contract Upgrade Risks and Recommendations](https://youtu.be/mebA5Qz9zeQ?t=353): A talk by Trail of Bits describing best-practices for developing upgradable delegatecall proxies. The section starting at 5:49 describes some general risks that also apply to non-upgradable proxies. - -## Implementation guidelines +## Implementation guidelines **Strive for simplicity.** Always use the simplest solution that fits your purpose. Any member of your team should be able to understand your solution. @@ -96,7 +96,7 @@ The architecture of your codebase should make your code easy to review. Avoid ar ### Testing and verification -- **Write thorough unit-tests.** An extensive test suite is crucial to build high-quality software. +- **Write thorough unit-tests.** An extensive test suite is crucial to build high-quality software. - **Write [Slither](https://github.com/crytic/slither) and [Echidna](https://github.com/crytic/echidna) custom checks and properties.** Automated tools will help ensure your contract is secure. Review the rest of this guide to learn how to write efficient checks and properties. ### Solidity diff --git a/development-guidelines/incident_response.md b/development-guidelines/incident_response.md index 89f66e70..c2b34b9c 100644 --- a/development-guidelines/incident_response.md +++ b/development-guidelines/incident_response.md @@ -1,6 +1,6 @@ -# Incident Response Recommendations +# Incident Response Recommendations -Here, we provide recommendations around the formulation of an incident response plan. +Here, we provide recommendations around the formulation of an incident response plan. - [ ] **Identify who (either specific people or roles) is responsible for carrying out the mitigations (deploying smart contracts, pausing contracts, upgrading the front end, etc.).** - Specifying these roles will strengthen the incident response plan and ease the execution of mitigating actions when necessary. @@ -13,18 +13,18 @@ Here, we provide recommendations around the formulation of an incident response - For each language and component, describe the noteworthy sources for vulnerability news. Subscribe to updates for each source. Consider creating a special private Discord/Slack channel with a bot that will post the latest vulnerability news; this will help the team keep track of updates all in one place. Also consider assigning specific team members to keep track of the vulnerability news of a specific component of the system. - [ ] **Consider scenarios involving issues that would indirectly affect the system.** - [ ] **Determine when and how the team would reach out to and onboard external parties (auditors, affected users, other protocol developers, etc.).** - - Some issues may require collaboration with external parties to efficiently remediate them. + - Some issues may require collaboration with external parties to efficiently remediate them. - [ ] **Define contract behavior that is considered abnormal for off-chain monitoring.** - Consider adding more resilient solutions for detection and mitigation, especially in terms of specific alternate endpoints and queries for different data as well as status pages and support contacts for affected services. - [ ] **Combine issues and determine whether new detection and mitigation scenarios are needed.** - [ ] **Perform periodic dry runs of specific scenarios in the incident response plan to find gaps and opportunities for improvement and to develop muscle memory.** - - Document the intervals at which the team should perform dry runs of the various scenarios. For scenarios that are more likely to happen, perform dry runs more regularly. Create a template to be filled in after a dry run to describe the improvements that need to be made to the incident response. + - Document the intervals at which the team should perform dry runs of the various scenarios. For scenarios that are more likely to happen, perform dry runs more regularly. Create a template to be filled in after a dry run to describe the improvements that need to be made to the incident response. -## Incident Response Plan Resources +## Incident Response Plan Resources - [How to Hack the Yield Protocol](https://docs.yieldprotocol.com/#/operations/how_to_hack) - [Emergency Steps – Yearn](https://github.com/yearn/yearn-devdocs/blob/master/docs/developers/v2/EMERGENCY.md) -## Well-handled IR Incidents +## Well-handled IR Incidents - [Yield Protocol](https://medium.com/yield-protocol/post-mortem-of-incident-on-august-5th-2022-7bb70dbb9ada) diff --git a/development-guidelines/token_integration.md b/development-guidelines/token_integration.md index 5939307d..569a89bb 100644 --- a/development-guidelines/token_integration.md +++ b/development-guidelines/token_integration.md @@ -39,7 +39,7 @@ To follow this checklist, use the below output from Slither for the token: - [ ] **The owner cannot blacklist the contract.** Malicious or compromised owners can trap contracts relying on tokens with a blacklist. Identify blacklisting features by hand. - [ ] **The team behind the token is known and can be held responsible for abuse.** Contracts with anonymous development teams or teams that reside in legal shelters require a higher standard of review. -## ERC20 tokens +## ERC20 tokens ### ERC20 conformity checks @@ -55,6 +55,7 @@ Slither includes a utility, [`slither-prop`](https://github.com/crytic/slither/w - [ ] **The contract passes all unit tests and security properties from `slither-prop`.** Run the generated unit tests and then check the properties with [Echidna](https://github.com/crytic/echidna) and [Manticore](https://manticore.readthedocs.io/en/latest/verifier.html). ### Risks of ERC20 Extensions + The behavior of certain contracts may differ from the original ERC specification. Conduct a manual review of the following conditions: - [ ] **The token is not an ERC777 token and has no external function call in `transfer` or `transferFrom`.** External calls in the transfer functions can lead to reentrancies. @@ -71,7 +72,7 @@ Reviews of token scarcity issues must be executed manually. Check for the follow - [ ] **Users understand the risks associated with a large amount of funds or flash loans.** Contracts relying on the token balance must account for attackers with a large amount of funds or attacks executed through flash loans. - [ ] **The token does not allow flash minting.** Flash minting can lead to substantial swings in the balance and the total supply, which necessitate strict and comprehensive overflow checks in the operation of the token. -## ERC721 tokens +## ERC721 tokens ### ERC721 Conformity Checks diff --git a/development-guidelines/workflow.md b/development-guidelines/workflow.md index ee23c7ec..a4dac4d0 100644 --- a/development-guidelines/workflow.md +++ b/development-guidelines/workflow.md @@ -11,7 +11,7 @@ Consider special features of your contract: - [ ] Are your contracts upgradeable? Review your upgradeability code for flaws with [`slither-check-upgradeability`](https://github.com/crytic/slither/wiki/Upgradeability-Checks) or [Crytic](https://blog.trailofbits.com/2020/06/12/upgradeable-contracts-made-safer-with-crytic/). We've documented 17 ways upgrades can go sideways. - [ ] Do your contracts purport to conform to ERCs? Check them with [`slither-check-erc`](https://github.com/crytic/slither/wiki/ERC-Conformance). This tool instantly identifies deviations from six common specs. - [ ] Do you have unit tests in Truffle? Enrich them with [`slither-prop`](https://github.com/crytic/slither/wiki/Property-generation). It automatically generates a robust suite of security properties for features of ERC20 based on your specific code. -- [ ] Do you integrate with 3rd party tokens? Review our [token integration checklist](./token_integration.md) before relying on external contracts. +- [ ] Do you integrate with 3rd party tokens? Review our [token integration checklist](./token_integration.md) before relying on external contracts. Visually inspect critical security features of your code: @@ -27,10 +27,10 @@ Document critical security properties and use automated test generators to evalu Finally, be mindful of issues that automated tools cannot easily find: -* Lack of privacy: everyone else can see your transactions while they're queued in the pool -* Front running transactions -* Cryptographic operations -* Risky interactions with external DeFi components +- Lack of privacy: everyone else can see your transactions while they're queued in the pool +- Front running transactions +- Cryptographic operations +- Risky interactions with external DeFi components ## Ask for help diff --git a/learn_evm/README.md b/learn_evm/README.md index 5f744984..694d4ffb 100644 --- a/learn_evm/README.md +++ b/learn_evm/README.md @@ -1,11 +1,11 @@ # Learn EVM -List of EVM technical knowledge +List of EVM technical knowledge - [EVM Opcode Reference](evm_opcodes.md): Reference and notes for each of the EVM opcodes - [Transaction Tracing](tracing.md): Helper scripts and guidance for generating and navigating transaction traces - [Yellow Paper Guidance](yellow-paper.md): Symbol reference for more easily reading the Ethereum yellow paper - [Forks <> EIPs](eips_forks.md): Summarize the EIPs included in each fork - - [Forks <> CIPs](cips_forks.md): Summarize the CIPs and EIPs included in each Celo fork *(EVM-compatible chain)* - - [Upgrades <> TIPs](tips_upgrades.md): Summarize the TIPs included in each TRON upgrade *(EVM-compatible chain)* - - [Forks <> BEPs](beps_forks.md): Summarize the BEPs included in each BSC fork *(EVM-compatible chain)* + - [Forks <> CIPs](cips_forks.md): Summarize the CIPs and EIPs included in each Celo fork _(EVM-compatible chain)_ + - [Upgrades <> TIPs](tips_upgrades.md): Summarize the TIPs included in each TRON upgrade _(EVM-compatible chain)_ + - [Forks <> BEPs](beps_forks.md): Summarize the BEPs included in each BSC fork _(EVM-compatible chain)_ diff --git a/learn_evm/beps_forks.md b/learn_evm/beps_forks.md index cb01098f..90c6e58d 100644 --- a/learn_evm/beps_forks.md +++ b/learn_evm/beps_forks.md @@ -1,10 +1,10 @@ The following lists every BEP associated to a Binance Smart Chain fork. -| Release | BEP | What it does -|---|---|---| - [v1.0.6](https://github.com/bnb-chain/bsc/releases/tag/v1.0.6) | [84](https://github.com/bnb-chain/BEPs/blob/master/BEP84.md) | Issue/bind BEP2 with existing BEP20 tokens - [v1.1.5](https://github.com/bnb-chain/bsc/releases/tag/v1.1.5) | [93](https://github.com/bnb-chain/BEPs/blob/master/BEP93.md) | Introduces new block syncing protocol - [v1.1.5](https://github.com/bnb-chain/bsc/releases/tag/v1.1.5) | [95](https://github.com/bnb-chain/BEPs/blob/master/BEP95.md) | Creates real-time burning mechanism - [v1.1.11](https://github.com/bnb-chain/bsc/releases/tag/v1.1.11) | [127](https://github.com/bnb-chain/BEPs/blob/master/BEP127.md) | Creates "Temporary Maintenance" mode for validators - [v1.1.11](https://github.com/bnb-chain/bsc/releases/tag/v1.1.11) | [131](https://github.com/bnb-chain/BEPs/blob/master/BEP131.md) | Increase validator set with "Candidate" validators - [v1.1.18](https://github.com/bnb-chain/bsc/releases/tag/v1.1.11) | [153](https://github.com/bnb-chain/BEPs/blob/master/BEP153.md) | Creates native staking protocol +| Release | BEP | What it does | +| ---------------------------------------------------------------- | -------------------------------------------------------------- | --------------------------------------------------- | +| [v1.0.6](https://github.com/bnb-chain/bsc/releases/tag/v1.0.6) | [84](https://github.com/bnb-chain/BEPs/blob/master/BEP84.md) | Issue/bind BEP2 with existing BEP20 tokens | +| [v1.1.5](https://github.com/bnb-chain/bsc/releases/tag/v1.1.5) | [93](https://github.com/bnb-chain/BEPs/blob/master/BEP93.md) | Introduces new block syncing protocol | +| [v1.1.5](https://github.com/bnb-chain/bsc/releases/tag/v1.1.5) | [95](https://github.com/bnb-chain/BEPs/blob/master/BEP95.md) | Creates real-time burning mechanism | +| [v1.1.11](https://github.com/bnb-chain/bsc/releases/tag/v1.1.11) | [127](https://github.com/bnb-chain/BEPs/blob/master/BEP127.md) | Creates "Temporary Maintenance" mode for validators | +| [v1.1.11](https://github.com/bnb-chain/bsc/releases/tag/v1.1.11) | [131](https://github.com/bnb-chain/BEPs/blob/master/BEP131.md) | Increase validator set with "Candidate" validators | +| [v1.1.18](https://github.com/bnb-chain/bsc/releases/tag/v1.1.11) | [153](https://github.com/bnb-chain/BEPs/blob/master/BEP153.md) | Creates native staking protocol | diff --git a/learn_evm/cips_forks.md b/learn_evm/cips_forks.md index 3a14dcdd..1cc8cdef 100644 --- a/learn_evm/cips_forks.md +++ b/learn_evm/cips_forks.md @@ -1,25 +1,25 @@ The following lists every CIP associated to a Celo fork. Celo is an EVM-compatible chain. -| Fork | CIP/EIP | What it does -|---|---|---| - [Churrito](https://github.com/celo-org/celo-proposals/blob/master/CIPs/cip-0024.md)| [EIP 211](https://eips.ethereum.org/EIPS/eip-211)| Create `RETURNDATASIZE` and `RETURNDATACOPY` opcodes - [Donut](https://github.com/celo-org/celo-proposals/blob/master/CIPs/cip-0027.md)| [CIP 25](https://github.com/celo-org/celo-proposals/blob/master/CIPs/cip-0025.md)| Add Ed25519 precompile - [Donut](https://github.com/celo-org/celo-proposals/blob/master/CIPs/cip-0027.md)| [CIP 31 - *copied from EIP-2539*](https://github.com/celo-org/celo-proposals/blob/master/CIPs/cip-0031.md) | Add precompile for BLS12-381 curve operations - [Donut](https://github.com/celo-org/celo-proposals/blob/master/CIPs/cip-0027.md)| [CIP 30 - *copied from EIP-2539*](https://github.com/celo-org/celo-proposals/blob/master/CIPs/cip-0030.md) | Add precompile for BLS12-377 curve operations - [Donut](https://github.com/celo-org/celo-proposals/blob/master/CIPs/cip-0027.md)| [CIP 20](https://github.com/celo-org/celo-proposals/blob/master/CIPs/cip-0020.md) | Add extensible hash function precompile - [Donut](https://github.com/celo-org/celo-proposals/blob/master/CIPs/cip-0027.md)| [CIP 21](https://github.com/celo-org/celo-proposals/blob/master/CIPs/cip-0021.md) | Add governable lookback window - [Donut](https://github.com/celo-org/celo-proposals/blob/master/CIPs/cip-0027.md)| [CIP 22](https://github.com/celo-org/celo-proposals/blob/master/CIPs/cip-0022.md) | Upgrade epoch SNARK data - [Donut](https://github.com/celo-org/celo-proposals/blob/master/CIPs/cip-0027.md)| [CIP 26](https://github.com/celo-org/celo-proposals/blob/master/CIPs/cip-0026.md) | Add precompile to return BLS pubkey of given validator - [Donut](https://github.com/celo-org/celo-proposals/blob/master/CIPs/cip-0027.md)| [CIP 28](https://github.com/celo-org/celo-proposals/blob/master/CIPs/cip-0028.md) | Split etherbase into separate addresses - [Donut](https://github.com/celo-org/celo-proposals/blob/master/CIPs/cip-0027.md)| [CIP 35](https://github.com/celo-org/celo-proposals/blob/master/CIPs/cip-0035.md) | Add support for Ethereum-compatible transactions - [Espresso](https://github.com/celo-org/celo-proposals/blob/master/CIPs/cip-0041.md)| [EIP 2565](https://eips.ethereum.org/EIPS/eip-2565) | Define gas cost of ModExp precompile - [Espresso](https://github.com/celo-org/celo-proposals/blob/master/CIPs/cip-0041.md)| [CIP 48 - *modified from EIP 2929*](https://github.com/celo-org/celo-proposals/blob/master/CIPs/cip-0048.md) | Gas repricing - [Espresso](https://github.com/celo-org/celo-proposals/blob/master/CIPs/cip-0041.md)| [EIP 2718](https://eips.ethereum.org/EIPS/eip-2718) | Introduce typed transaction envelope - [Espresso](https://github.com/celo-org/celo-proposals/blob/master/CIPs/cip-0041.md)| [EIP 2930](https://eips.ethereum.org/EIPS/eip-2930) | Introduce optional access lists - [Espresso](https://github.com/celo-org/celo-proposals/blob/master/CIPs/cip-0041.md)| [CIP 42 - *modified from EIP 1559*](https://github.com/celo-org/celo-proposals/blob/master/CIPs/cip-0042.md) | Fee market changes - [Espresso](https://github.com/celo-org/celo-proposals/blob/master/CIPs/cip-0041.md)| [EIP 3529](https://eips.ethereum.org/EIPS/eip-3529) | Reduction in gas refunds - [Espresso](https://github.com/celo-org/celo-proposals/blob/master/CIPs/cip-0041.md)| [EIP 3541](https://eips.ethereum.org/EIPS/eip-3541) | Reject deployment of contract code starting with the `0xEF` byte - [Espresso](https://github.com/celo-org/celo-proposals/blob/master/CIPs/cip-0041.md)| [CIP 43](https://github.com/celo-org/celo-proposals/blob/master/CIPs/cip-0043.md) | Block Context - [Espresso](https://github.com/celo-org/celo-proposals/blob/master/CIPs/cip-0041.md)| [CIP 47](https://github.com/celo-org/celo-proposals/blob/master/CIPs/cip-0047.md) | Modify round change timeout formula - [Espresso](https://github.com/celo-org/celo-proposals/blob/master/CIPs/cip-0041.md)| [CIP 45](https://github.com/celo-org/celo-proposals/blob/master/CIPs/cip-0045.md) | Modify transaction fee check - [Espresso](https://github.com/celo-org/celo-proposals/blob/master/CIPs/cip-0041.md)| [CIP 50](https://github.com/celo-org/celo-proposals/blob/master/CIPs/cip-0050.md) | Make replay protection optional +| Fork | CIP/EIP | What it does | +| ----------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------ | ---------------------------------------------------------------- | +| [Churrito](https://github.com/celo-org/celo-proposals/blob/master/CIPs/cip-0024.md) | [EIP 211](https://eips.ethereum.org/EIPS/eip-211) | Create `RETURNDATASIZE` and `RETURNDATACOPY` opcodes | +| [Donut](https://github.com/celo-org/celo-proposals/blob/master/CIPs/cip-0027.md) | [CIP 25](https://github.com/celo-org/celo-proposals/blob/master/CIPs/cip-0025.md) | Add Ed25519 precompile | +| [Donut](https://github.com/celo-org/celo-proposals/blob/master/CIPs/cip-0027.md) | [CIP 31 - _copied from EIP-2539_](https://github.com/celo-org/celo-proposals/blob/master/CIPs/cip-0031.md) | Add precompile for BLS12-381 curve operations | +| [Donut](https://github.com/celo-org/celo-proposals/blob/master/CIPs/cip-0027.md) | [CIP 30 - _copied from EIP-2539_](https://github.com/celo-org/celo-proposals/blob/master/CIPs/cip-0030.md) | Add precompile for BLS12-377 curve operations | +| [Donut](https://github.com/celo-org/celo-proposals/blob/master/CIPs/cip-0027.md) | [CIP 20](https://github.com/celo-org/celo-proposals/blob/master/CIPs/cip-0020.md) | Add extensible hash function precompile | +| [Donut](https://github.com/celo-org/celo-proposals/blob/master/CIPs/cip-0027.md) | [CIP 21](https://github.com/celo-org/celo-proposals/blob/master/CIPs/cip-0021.md) | Add governable lookback window | +| [Donut](https://github.com/celo-org/celo-proposals/blob/master/CIPs/cip-0027.md) | [CIP 22](https://github.com/celo-org/celo-proposals/blob/master/CIPs/cip-0022.md) | Upgrade epoch SNARK data | +| [Donut](https://github.com/celo-org/celo-proposals/blob/master/CIPs/cip-0027.md) | [CIP 26](https://github.com/celo-org/celo-proposals/blob/master/CIPs/cip-0026.md) | Add precompile to return BLS pubkey of given validator | +| [Donut](https://github.com/celo-org/celo-proposals/blob/master/CIPs/cip-0027.md) | [CIP 28](https://github.com/celo-org/celo-proposals/blob/master/CIPs/cip-0028.md) | Split etherbase into separate addresses | +| [Donut](https://github.com/celo-org/celo-proposals/blob/master/CIPs/cip-0027.md) | [CIP 35](https://github.com/celo-org/celo-proposals/blob/master/CIPs/cip-0035.md) | Add support for Ethereum-compatible transactions | +| [Espresso](https://github.com/celo-org/celo-proposals/blob/master/CIPs/cip-0041.md) | [EIP 2565](https://eips.ethereum.org/EIPS/eip-2565) | Define gas cost of ModExp precompile | +| [Espresso](https://github.com/celo-org/celo-proposals/blob/master/CIPs/cip-0041.md) | [CIP 48 - _modified from EIP 2929_](https://github.com/celo-org/celo-proposals/blob/master/CIPs/cip-0048.md) | Gas repricing | +| [Espresso](https://github.com/celo-org/celo-proposals/blob/master/CIPs/cip-0041.md) | [EIP 2718](https://eips.ethereum.org/EIPS/eip-2718) | Introduce typed transaction envelope | +| [Espresso](https://github.com/celo-org/celo-proposals/blob/master/CIPs/cip-0041.md) | [EIP 2930](https://eips.ethereum.org/EIPS/eip-2930) | Introduce optional access lists | +| [Espresso](https://github.com/celo-org/celo-proposals/blob/master/CIPs/cip-0041.md) | [CIP 42 - _modified from EIP 1559_](https://github.com/celo-org/celo-proposals/blob/master/CIPs/cip-0042.md) | Fee market changes | +| [Espresso](https://github.com/celo-org/celo-proposals/blob/master/CIPs/cip-0041.md) | [EIP 3529](https://eips.ethereum.org/EIPS/eip-3529) | Reduction in gas refunds | +| [Espresso](https://github.com/celo-org/celo-proposals/blob/master/CIPs/cip-0041.md) | [EIP 3541](https://eips.ethereum.org/EIPS/eip-3541) | Reject deployment of contract code starting with the `0xEF` byte | +| [Espresso](https://github.com/celo-org/celo-proposals/blob/master/CIPs/cip-0041.md) | [CIP 43](https://github.com/celo-org/celo-proposals/blob/master/CIPs/cip-0043.md) | Block Context | +| [Espresso](https://github.com/celo-org/celo-proposals/blob/master/CIPs/cip-0041.md) | [CIP 47](https://github.com/celo-org/celo-proposals/blob/master/CIPs/cip-0047.md) | Modify round change timeout formula | +| [Espresso](https://github.com/celo-org/celo-proposals/blob/master/CIPs/cip-0041.md) | [CIP 45](https://github.com/celo-org/celo-proposals/blob/master/CIPs/cip-0045.md) | Modify transaction fee check | +| [Espresso](https://github.com/celo-org/celo-proposals/blob/master/CIPs/cip-0041.md) | [CIP 50](https://github.com/celo-org/celo-proposals/blob/master/CIPs/cip-0050.md) | Make replay protection optional | diff --git a/learn_evm/eips_forks.md b/learn_evm/eips_forks.md index 3dee2a6a..6e784761 100644 --- a/learn_evm/eips_forks.md +++ b/learn_evm/eips_forks.md @@ -1,51 +1,51 @@ The following lists every EIP associated to an Ethereum fork. -| Fork | EIP | What it does | Opcode | Gas | Notes -|---|---|---|---|---|---| -| [Homestead (606)](https://eips.ethereum.org/EIPS/eip-606) | [2](https://eips.ethereum.org/EIPS/eip-2) | Homestead Hard-fork Changes | | X | | -| [Homestead (606)](https://eips.ethereum.org/EIPS/eip-606) | [7](https://eips.ethereum.org/EIPS/eip-7) | Delegatecall | X | | | -| [Homestead (606)](https://eips.ethereum.org/EIPS/eip-606) | [8](https://eips.ethereum.org/EIPS/eip-8) | Networking layer: devp2p Forward Compatibility Requirements for Homestead | | | | -| [DAO Fork (779)](https://eips.ethereum.org/EIPS/eip-779) | [779](https://eips.ethereum.org/EIPS/eip-779) | DAO Fork | | | -| [Tangerine Whistle (608)](https://eips.ethereum.org/EIPS/eip-608) | [150](https://eips.ethereum.org/EIPS/eip-150) | Gas cost changes for IO-heavy operations| | X | Define the *all but one 64th* rule | -| [Spurious Dragon (607)](https://eips.ethereum.org/EIPS/eip-607) | [155](https://eips.ethereum.org/EIPS/eip-155) | Simple replay attack protection | | | | -| [Spurious Dragon (607)](https://eips.ethereum.org/EIPS/eip-607) | [160](https://eips.ethereum.org/EIPS/eip-160) | EXP cost increase | | X | | | -| [Spurious Dragon (607)](https://eips.ethereum.org/EIPS/eip-607) | [161](https://eips.ethereum.org/EIPS/eip-161) | State trie clearing (invariant-preserving alternative) | | X | | -| [Spurious Dragon (607)](https://eips.ethereum.org/EIPS/eip-607) | [170](https://eips.ethereum.org/EIPS/eip-170) | Contract code size limit | | | Change the semantics of CREATE -| [Byzantium (609)](https://eips.ethereum.org/EIPS/eip-609) | [100](https://eips.ethereum.org/EIPS/eip-100) | Change difficulty adjustment to target mean block time including uncles | | | -| [Byzantium (609)](https://eips.ethereum.org/EIPS/eip-609) | [140](https://eips.ethereum.org/EIPS/eip-140) | REVERT instruction | X | | -| [Byzantium (609)](https://eips.ethereum.org/EIPS/eip-609) | [196](https://eips.ethereum.org/EIPS/eip-196) | Precompiled contracts for addition and scalar multiplication on the elliptic curve alt_bn128 | | | -| [Byzantium (609)](https://eips.ethereum.org/EIPS/eip-609) | [197](https://eips.ethereum.org/EIPS/eip-197) | Precompiled contracts for optimal ate pairing check on the elliptic curve alt_bn128 | | | -| [Byzantium (609)](https://eips.ethereum.org/EIPS/eip-609) | [198](https://eips.ethereum.org/EIPS/eip-198) | Precompiled contract for bigint modular exponentiation | | | -| [Byzantium (609)](https://eips.ethereum.org/EIPS/eip-609) | [211](https://eips.ethereum.org/EIPS/eip-211) | RETURNDATASIZE and RETURNDATACOPY | X | | -| [Byzantium (609)](https://eips.ethereum.org/EIPS/eip-609) | [214](https://eips.ethereum.org/EIPS/eip-214) | STATICCALL | X | | -| [Byzantium (609)](https://eips.ethereum.org/EIPS/eip-609) | [649](https://eips.ethereum.org/EIPS/eip-649) | Metropolis Difficulty Bomb Delay and Block Reward Reduction | | | -| [Byzantium (609)](https://eips.ethereum.org/EIPS/eip-609) | [658](https://eips.ethereum.org/EIPS/eip-658) | Embedding transaction status code in receipts | | | -| [Constantinople (1013)](https://eips.ethereum.org/EIPS/eip-1013) | [145](https://eips.ethereum.org/EIPS/eip-145) | Bitwise shifting instructions in EVM | X | | -| [Constantinople (1013)](https://eips.ethereum.org/EIPS/eip-1013) | [1014](https://eips.ethereum.org/EIPS/eip-1014) | Skinny CREATE2 | X | | -| [Constantinople (1013)](https://eips.ethereum.org/EIPS/eip-1234) | [1234](https://eips.ethereum.org/EIPS/eip-1234) | Constantinople Difficulty Bomb Delay and Block Reward Adjustment | | | -| [Constantinople (1013)](https://eips.ethereum.org/EIPS/eip-1234) | [1283](https://eips.ethereum.org/EIPS/eip-1283) | Net gas metering for SSTORE without dirty maps | | X | This EIP leads to reentrancies risks (see [EIP-1283 incident report](https://github.com/trailofbits/publications/blob/master/reviews/EIP-1283.pdf)) and was directly removed with [EIP-1716](https://eips.ethereum.org/EIPS/eip-1716) -| [Petersburg (1716)](https://eips.ethereum.org/EIPS/eip-1716) | [1716](https://eips.ethereum.org/EIPS/eip-1716) | Remove EIP-1283 | | X | See [EIP-1283 incident report](https://github.com/trailofbits/publications/blob/master/reviews/EIP-1283.pdf) -| [Istanbul (1679)](https://eips.ethereum.org/EIPS/eip-1679) | [152](https://eips.ethereum.org/EIPS/eip-152) | Precompiled contract for the BLAKE2 F compression function | | | -| [Istanbul (1679)](https://eips.ethereum.org/EIPS/eip-1679) | [1108](https://eips.ethereum.org/EIPS/eip-1108) | Reduce alt_bn128 precompile gas costs | | X | -| [Istanbul (1679)](https://eips.ethereum.org/EIPS/eip-1679) | [1344](https://eips.ethereum.org/EIPS/eip-1344) | ChainID opcode | X | | -| [Istanbul (1679)](https://eips.ethereum.org/EIPS/eip-1679) | [1884](https://eips.ethereum.org/EIPS/eip-1884) | Repricing for trie-size-dependent opcodes | X | X | The EIP changes the gas cost of multiple opcodes, and add SELFBALANCE -| [Istanbul (1679)](https://eips.ethereum.org/EIPS/eip-1679) | [2028](https://eips.ethereum.org/EIPS/eip-2028) | Transaction data gas cost reduction | | X | -| [Istanbul (1679)](https://eips.ethereum.org/EIPS/eip-1679) | [2200](https://eips.ethereum.org/EIPS/eip-2200) | Structured Definitions for Net Gas Metering | | X -| [Muir Glacier (2387)](https://eips.ethereum.org/EIPS/eip-2387) | [2384](https://eips.ethereum.org/EIPS/eip-2384) | Istanbul/Berlin Difficulty Bomb Delay | | -| [Berlin (2070)](https://github.com/ethereum/execution-specs/blob/a01c4c76e12fe9f0debf93bda7f67f002d77f8b4/network-upgrades/mainnet-upgrades/berlin.md) | [2565](https://eips.ethereum.org/EIPS/eip-2565) | ModExp Gas Cost | | X | -| [Berlin (2070)](https://github.com/ethereum/execution-specs/blob/a01c4c76e12fe9f0debf93bda7f67f002d77f8b4/network-upgrades/mainnet-upgrades/berlin.md) | [2929](https://eips.ethereum.org/EIPS/eip-2929) | Gas cost increases for state access opcodes | | X | -| [Berlin (2718)](https://github.com/ethereum/execution-specs/blob/a01c4c76e12fe9f0debf93bda7f67f002d77f8b4/network-upgrades/mainnet-upgrades/berlin.md) | [2718](https://eips.ethereum.org/EIPS/eip-2718) | Typed Transaction Envelope | | | -| [Berlin (2718)](https://github.com/ethereum/execution-specs/blob/a01c4c76e12fe9f0debf93bda7f67f002d77f8b4/network-upgrades/mainnet-upgrades/berlin.md) | [2930](https://eips.ethereum.org/EIPS/eip-2930) | Typed Transaction Envelope | | | -| [London](https://github.com/ethereum/execution-specs/blob/a01c4c76e12fe9f0debf93bda7f67f002d77f8b4/network-upgrades/mainnet-upgrades/london.md) | [1559](https://eips.ethereum.org/EIPS/eip-1559) | Fee market change for ETH 1.0 chain | | X | Significant modifications of Ethereum gas pricing -| [London](https://github.com/ethereum/execution-specs/blob/a01c4c76e12fe9f0debf93bda7f67f002d77f8b4/network-upgrades/mainnet-upgrades/london.md) | [3198](https://eips.ethereum.org/EIPS/eip-3198) | BASEFEE | X | | -| [London](https://github.com/ethereum/execution-specs/blob/a01c4c76e12fe9f0debf93bda7f67f002d77f8b4/network-upgrades/mainnet-upgrades/london.md) | [3529](https://eips.ethereum.org/EIPS/eip-3529) | Reduction in refunds | | X | Remove [gas tokens](https://gastoken.io/) benefits -| [London](https://github.com/ethereum/execution-specs/blob/a01c4c76e12fe9f0debf93bda7f67f002d77f8b4/network-upgrades/mainnet-upgrades/london.md) | [3554](https://eips.ethereum.org/EIPS/eip-3554) | Difficulty Bomb Delay to December 1st 2021 | | | -| [Arrow Glacier](https://github.com/ethereum/execution-specs/blob/bfe84c9a9b24695f160b4686d3b4640786ee9bac/network-upgrades/mainnet-upgrades/arrow-glacier.md) | [4345](https://eips.ethereum.org/EIPS/eip-4345) | Difficulty Bomb Delay to June 2022 | | | -| [Gray Glacier](https://github.com/ethereum/execution-specs/blob/bfe84c9a9b24695f160b4686d3b4640786ee9bac/network-upgrades/mainnet-upgrades/gray-glacier.md) | [5133](https://eips.ethereum.org/EIPS/eip-5133) | Difficulty Bomb Delay to mid-September 2022 | | | -| [Paris](https://github.com/ethereum/execution-specs/blob/0a18c44ab6e567d74f2700ab1a3208644e08276b/network-upgrades/mainnet-upgrades/paris.md) | [3675](https://eips.ethereum.org/EIPS/eip-3675) | Upgrade consensus to Proof-of-Stake | | | Changes to `DIFFICULTY` and `BLOCKHASH` -| [Paris](https://github.com/ethereum/execution-specs/blob/0a18c44ab6e567d74f2700ab1a3208644e08276b/network-upgrades/mainnet-upgrades/paris.md) | [4399](https://eips.ethereum.org/EIPS/eip-4399) | Supplant DIFFICULTY opcode with PREVRANDAO | X | | `DIFFICULTY` becomes `PREVRANDAO` - +| Fork | EIP | What it does | Opcode | Gas | Notes | +| ------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------- | -------------------------------------------------------------------------------------------- | ------ | --- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --- | +| [Homestead (606)](https://eips.ethereum.org/EIPS/eip-606) | [2](https://eips.ethereum.org/EIPS/eip-2) | Homestead Hard-fork Changes | | X | | +| [Homestead (606)](https://eips.ethereum.org/EIPS/eip-606) | [7](https://eips.ethereum.org/EIPS/eip-7) | Delegatecall | X | | | +| [Homestead (606)](https://eips.ethereum.org/EIPS/eip-606) | [8](https://eips.ethereum.org/EIPS/eip-8) | Networking layer: devp2p Forward Compatibility Requirements for Homestead | | | | +| [DAO Fork (779)](https://eips.ethereum.org/EIPS/eip-779) | [779](https://eips.ethereum.org/EIPS/eip-779) | DAO Fork | | | +| [Tangerine Whistle (608)](https://eips.ethereum.org/EIPS/eip-608) | [150](https://eips.ethereum.org/EIPS/eip-150) | Gas cost changes for IO-heavy operations | | X | Define the _all but one 64th_ rule | +| [Spurious Dragon (607)](https://eips.ethereum.org/EIPS/eip-607) | [155](https://eips.ethereum.org/EIPS/eip-155) | Simple replay attack protection | | | | +| [Spurious Dragon (607)](https://eips.ethereum.org/EIPS/eip-607) | [160](https://eips.ethereum.org/EIPS/eip-160) | EXP cost increase | | X | | | +| [Spurious Dragon (607)](https://eips.ethereum.org/EIPS/eip-607) | [161](https://eips.ethereum.org/EIPS/eip-161) | State trie clearing (invariant-preserving alternative) | | X | | +| [Spurious Dragon (607)](https://eips.ethereum.org/EIPS/eip-607) | [170](https://eips.ethereum.org/EIPS/eip-170) | Contract code size limit | | | Change the semantics of CREATE | +| [Byzantium (609)](https://eips.ethereum.org/EIPS/eip-609) | [100](https://eips.ethereum.org/EIPS/eip-100) | Change difficulty adjustment to target mean block time including uncles | | | +| [Byzantium (609)](https://eips.ethereum.org/EIPS/eip-609) | [140](https://eips.ethereum.org/EIPS/eip-140) | REVERT instruction | X | | +| [Byzantium (609)](https://eips.ethereum.org/EIPS/eip-609) | [196](https://eips.ethereum.org/EIPS/eip-196) | Precompiled contracts for addition and scalar multiplication on the elliptic curve alt_bn128 | | | +| [Byzantium (609)](https://eips.ethereum.org/EIPS/eip-609) | [197](https://eips.ethereum.org/EIPS/eip-197) | Precompiled contracts for optimal ate pairing check on the elliptic curve alt_bn128 | | | +| [Byzantium (609)](https://eips.ethereum.org/EIPS/eip-609) | [198](https://eips.ethereum.org/EIPS/eip-198) | Precompiled contract for bigint modular exponentiation | | | +| [Byzantium (609)](https://eips.ethereum.org/EIPS/eip-609) | [211](https://eips.ethereum.org/EIPS/eip-211) | RETURNDATASIZE and RETURNDATACOPY | X | | +| [Byzantium (609)](https://eips.ethereum.org/EIPS/eip-609) | [214](https://eips.ethereum.org/EIPS/eip-214) | STATICCALL | X | | +| [Byzantium (609)](https://eips.ethereum.org/EIPS/eip-609) | [649](https://eips.ethereum.org/EIPS/eip-649) | Metropolis Difficulty Bomb Delay and Block Reward Reduction | | | +| [Byzantium (609)](https://eips.ethereum.org/EIPS/eip-609) | [658](https://eips.ethereum.org/EIPS/eip-658) | Embedding transaction status code in receipts | | | +| [Constantinople (1013)](https://eips.ethereum.org/EIPS/eip-1013) | [145](https://eips.ethereum.org/EIPS/eip-145) | Bitwise shifting instructions in EVM | X | | +| [Constantinople (1013)](https://eips.ethereum.org/EIPS/eip-1013) | [1014](https://eips.ethereum.org/EIPS/eip-1014) | Skinny CREATE2 | X | | +| [Constantinople (1013)](https://eips.ethereum.org/EIPS/eip-1234) | [1234](https://eips.ethereum.org/EIPS/eip-1234) | Constantinople Difficulty Bomb Delay and Block Reward Adjustment | | | +| [Constantinople (1013)](https://eips.ethereum.org/EIPS/eip-1234) | [1283](https://eips.ethereum.org/EIPS/eip-1283) | Net gas metering for SSTORE without dirty maps | | X | This EIP leads to reentrancies risks (see [EIP-1283 incident report](https://github.com/trailofbits/publications/blob/master/reviews/EIP-1283.pdf)) and was directly removed with [EIP-1716](https://eips.ethereum.org/EIPS/eip-1716) | +| [Petersburg (1716)](https://eips.ethereum.org/EIPS/eip-1716) | [1716](https://eips.ethereum.org/EIPS/eip-1716) | Remove EIP-1283 | | X | See [EIP-1283 incident report](https://github.com/trailofbits/publications/blob/master/reviews/EIP-1283.pdf) | +| [Istanbul (1679)](https://eips.ethereum.org/EIPS/eip-1679) | [152](https://eips.ethereum.org/EIPS/eip-152) | Precompiled contract for the BLAKE2 F compression function | | | +| [Istanbul (1679)](https://eips.ethereum.org/EIPS/eip-1679) | [1108](https://eips.ethereum.org/EIPS/eip-1108) | Reduce alt_bn128 precompile gas costs | | X | +| [Istanbul (1679)](https://eips.ethereum.org/EIPS/eip-1679) | [1344](https://eips.ethereum.org/EIPS/eip-1344) | ChainID opcode | X | | +| [Istanbul (1679)](https://eips.ethereum.org/EIPS/eip-1679) | [1884](https://eips.ethereum.org/EIPS/eip-1884) | Repricing for trie-size-dependent opcodes | X | X | The EIP changes the gas cost of multiple opcodes, and add SELFBALANCE | +| [Istanbul (1679)](https://eips.ethereum.org/EIPS/eip-1679) | [2028](https://eips.ethereum.org/EIPS/eip-2028) | Transaction data gas cost reduction | | X | +| [Istanbul (1679)](https://eips.ethereum.org/EIPS/eip-1679) | [2200](https://eips.ethereum.org/EIPS/eip-2200) | Structured Definitions for Net Gas Metering | | X | +| [Muir Glacier (2387)](https://eips.ethereum.org/EIPS/eip-2387) | [2384](https://eips.ethereum.org/EIPS/eip-2384) | Istanbul/Berlin Difficulty Bomb Delay | | +| [Berlin (2070)](https://github.com/ethereum/execution-specs/blob/a01c4c76e12fe9f0debf93bda7f67f002d77f8b4/network-upgrades/mainnet-upgrades/berlin.md) | [2565](https://eips.ethereum.org/EIPS/eip-2565) | ModExp Gas Cost | | X | +| [Berlin (2070)](https://github.com/ethereum/execution-specs/blob/a01c4c76e12fe9f0debf93bda7f67f002d77f8b4/network-upgrades/mainnet-upgrades/berlin.md) | [2929](https://eips.ethereum.org/EIPS/eip-2929) | Gas cost increases for state access opcodes | | X | +| [Berlin (2718)](https://github.com/ethereum/execution-specs/blob/a01c4c76e12fe9f0debf93bda7f67f002d77f8b4/network-upgrades/mainnet-upgrades/berlin.md) | [2718](https://eips.ethereum.org/EIPS/eip-2718) | Typed Transaction Envelope | | | +| [Berlin (2718)](https://github.com/ethereum/execution-specs/blob/a01c4c76e12fe9f0debf93bda7f67f002d77f8b4/network-upgrades/mainnet-upgrades/berlin.md) | [2930](https://eips.ethereum.org/EIPS/eip-2930) | Typed Transaction Envelope | | | +| [London](https://github.com/ethereum/execution-specs/blob/a01c4c76e12fe9f0debf93bda7f67f002d77f8b4/network-upgrades/mainnet-upgrades/london.md) | [1559](https://eips.ethereum.org/EIPS/eip-1559) | Fee market change for ETH 1.0 chain | | X | Significant modifications of Ethereum gas pricing | +| [London](https://github.com/ethereum/execution-specs/blob/a01c4c76e12fe9f0debf93bda7f67f002d77f8b4/network-upgrades/mainnet-upgrades/london.md) | [3198](https://eips.ethereum.org/EIPS/eip-3198) | BASEFEE | X | | +| [London](https://github.com/ethereum/execution-specs/blob/a01c4c76e12fe9f0debf93bda7f67f002d77f8b4/network-upgrades/mainnet-upgrades/london.md) | [3529](https://eips.ethereum.org/EIPS/eip-3529) | Reduction in refunds | | X | Remove [gas tokens](https://gastoken.io/) benefits | +| [London](https://github.com/ethereum/execution-specs/blob/a01c4c76e12fe9f0debf93bda7f67f002d77f8b4/network-upgrades/mainnet-upgrades/london.md) | [3554](https://eips.ethereum.org/EIPS/eip-3554) | Difficulty Bomb Delay to December 1st 2021 | | | +| [Arrow Glacier](https://github.com/ethereum/execution-specs/blob/bfe84c9a9b24695f160b4686d3b4640786ee9bac/network-upgrades/mainnet-upgrades/arrow-glacier.md) | [4345](https://eips.ethereum.org/EIPS/eip-4345) | Difficulty Bomb Delay to June 2022 | | | +| [Gray Glacier](https://github.com/ethereum/execution-specs/blob/bfe84c9a9b24695f160b4686d3b4640786ee9bac/network-upgrades/mainnet-upgrades/gray-glacier.md) | [5133](https://eips.ethereum.org/EIPS/eip-5133) | Difficulty Bomb Delay to mid-September 2022 | | | +| [Paris](https://github.com/ethereum/execution-specs/blob/0a18c44ab6e567d74f2700ab1a3208644e08276b/network-upgrades/mainnet-upgrades/paris.md) | [3675](https://eips.ethereum.org/EIPS/eip-3675) | Upgrade consensus to Proof-of-Stake | | | Changes to `DIFFICULTY` and `BLOCKHASH` | +| [Paris](https://github.com/ethereum/execution-specs/blob/0a18c44ab6e567d74f2700ab1a3208644e08276b/network-upgrades/mainnet-upgrades/paris.md) | [4399](https://eips.ethereum.org/EIPS/eip-4399) | Supplant DIFFICULTY opcode with PREVRANDAO | X | | `DIFFICULTY` becomes `PREVRANDAO` | In this table: + - `Opcode`: the EIP adds or removes an opcode - `Gas`: the EIP changes the gas rules diff --git a/learn_evm/evm_opcodes.md b/learn_evm/evm_opcodes.md index f3c9e884..23aca53f 100644 --- a/learn_evm/evm_opcodes.md +++ b/learn_evm/evm_opcodes.md @@ -10,184 +10,188 @@ The gas information is a work in progress. If an asterisk is in the Gas column, ## Table -| Opcode | Name | Description | Extra Info | Gas | -| --- | --- | --- | --- | --- | -| [`0x00`](#stop) | STOP | Halts execution | - | 0 | -| [`0x01`](#add) | ADD | Addition operation | - | 3 | -| [`0x02`](#mul) | MUL | Multiplication operation | - | 5 | -| [`0x03`](#sub) | SUB | Subtraction operation | - | 3 | -| [`0x04`](#div) | DIV | Integer division operation | - | 5 | -| [`0x05`](#sdiv) | SDIV | Signed integer division operation (truncated) | - | 5 | -| [`0x06`](#mod) | MOD | Modulo remainder operation | - | 5 | -| [`0x07`](#smod) | SMOD | Signed modulo remainder operation | - | 5 | -| [`0x08`](#addmod) | ADDMOD | Modulo addition operation | - | 8 | -| [`0x09`](#mulmod) | MULMOD | Modulo multiplication operation | - | 8 | -| [`0x0a`](#exp) | EXP | Exponential operation | - | 10* | -| [`0x0b`](#signextend) | SIGNEXTEND | Extend length of two's complement signed integer | - | 5 | -| `0x0c` - `0x0f` | Unused | Unused | - | -| [`0x10`](#lt) | LT | Less-than comparison | - | 3 | -| [`0x11`](#gt) | GT | Greater-than comparison | - | 3 | -| [`0x12`](#slt) | SLT | Signed less-than comparison | - | 3 | -| [`0x13`](#sgt) | SGT | Signed greater-than comparison | - | 3 | -| [`0x14`](#eq) | EQ | Equality comparison | - | 3 | -| [`0x15`](#iszero) | ISZERO | Simple not operator | - | 3 | -| [`0x16`](#and) | AND | Bitwise AND operation | - | 3 | -| [`0x17`](#or) | OR | Bitwise OR operation | - | 3 | -| [`0x18`](#xor) | XOR | Bitwise XOR operation | - | 3 | -| [`0x19`](#not) | NOT | Bitwise NOT operation | - | 3 | -| [`0x1a`](#byte) | BYTE | Retrieve single byte from word | - | 3 | -| [`0x1b`](#shl) | SHL | Shift Left | [EIP145](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-145.md) | 3 | -| [`0x1c`](#shr) | SHR | Logical Shift Right | [EIP145](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-145.md) | 3 | -| [`0x1d`](#sar) | SAR | Arithmetic Shift Right | [EIP145](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-145.md) | 3 | -| [`0x20`](#keccak256) | KECCAK256 | Compute Keccak-256 hash | - | 30* | -| `0x21` - `0x2f`| Unused | Unused | -| [`0x30`](#address) | ADDRESS | Get address of currently executing account | - | 2 | -| [`0x31`](#balance) | BALANCE | Get balance of the given account | - | 700 | -| [`0x32`](#origin) | ORIGIN | Get execution origination address | - | 2 | -| [`0x33`](#caller) | CALLER | Get caller address | - | 2 | -| [`0x34`](#callvalue) | CALLVALUE | Get deposited value by the instruction/transaction responsible for this execution | - | 2 | -| [`0x35`](#calldataload) | CALLDATALOAD | Get input data of current environment | - | 3 | -| [`0x36`](#calldatasize) | CALLDATASIZE | Get size of input data in current environment | - | 2* | -| [`0x37`](#calldatacopy) | CALLDATACOPY | Copy input data in current environment to memory | - | 3 | -| [`0x38`](#codesize) | CODESIZE | Get size of code running in current environment | - | 2 | -| [`0x39`](#codecopy) | CODECOPY | Copy code running in current environment to memory | - | 3* | -| [`0x3a`](#gasprice) | GASPRICE | Get price of gas in current environment | - | 2 | -| [`0x3b`](#extcodesize) | EXTCODESIZE | Get size of an account's code | - | 700 | -| [`0x3c`](#extcodecopy) | EXTCODECOPY | Copy an account's code to memory | - | 700* | -| [`0x3d`](#returndatasize) | RETURNDATASIZE | Pushes the size of the return data buffer onto the stack | [EIP 211](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-211.md) | 2 | -| [`0x3e`](#returndatacopy) | RETURNDATACOPY | Copies data from the return data buffer to memory | [EIP 211](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-211.md) | 3 | -| [`0x3f`](#extcodehash) | EXTCODEHASH | Returns the keccak256 hash of a contract's code | [EIP 1052](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-1052.md) | 700 | -| [`0x40`](#blockhash) | BLOCKHASH | Get the hash of one of the 256 most recent complete blocks | - | 20 | -| [`0x41`](#coinbase) | COINBASE | Get the block's beneficiary address | - | 2 | -| [`0x42`](#timestamp) | TIMESTAMP | Get the block's timestamp | - | 2 | -| [`0x43`](#number) | NUMBER | Get the block's number | - | 2 | -| [`0x44`](#difficulty) | DIFFICULTY | Get the block's difficulty | - | 2 | -| [`0x45`](#gaslimit) | GASLIMIT | Get the block's gas limit | - | 2 | -| [`0x46`](#chainid) | CHAINID | Returns the current chain’s EIP-155 unique identifier | [EIP 1344](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-1344.md) | 2 | -| `0x47` - `0x4f` | Unused | - | -| [`0x48`](#basefee) | BASEFEE | Returns the value of the base fee of the current block it is executing in. | [EIP 3198](https://eips.ethereum.org/EIPS/eip-3198) | 2 | -| [`0x50`](#pop) | POP | Remove word from stack | - | 2 | -| [`0x51`](#mload) | MLOAD | Load word from memory | - | 3* | -| [`0x52`](#mstore) | MSTORE | Save word to memory | - | 3* | -| [`0x53`](#mstore8) | MSTORE8 | Save byte to memory | - | 3 | -| [`0x54`](#sload) | SLOAD | Load word from storage | - | 800 | -| [`0x55`](#sstore) | SSTORE | Save word to storage | - | 20000** | -| [`0x56`](#jump) | JUMP | Alter the program counter | - | 8 | -| [`0x57`](#jumpi) | JUMPI | Conditionally alter the program counter | - | 10 | -| [`0x58`](#pc) | PC | Get the value of the program counter prior to the increment | - | 2 | -| [`0x59`](#msize) | MSIZE | Get the size of active memory in bytes | - | 2 | -| [`0x5a`](#gas) | GAS | Get the amount of available gas, including the corresponding reduction for the cost of this instruction | - | 2 | -| [`0x5b`](#jumpdest) | JUMPDEST | Mark a valid destination for jumps | - | 1 | -| `0x5c` - `0x5f` | Unused | - | -| [`0x60`](#push1) | PUSH1 | Place 1 byte item on stack | - | 3 | -| [`0x61`](#push2) | PUSH2 | Place 2-byte item on stack | - | 3 | -| [`0x62`](#push3) | PUSH3 | Place 3-byte item on stack | - | 3 | -| [`0x63`](#push4) | PUSH4 | Place 4-byte item on stack | - | 3 | -| [`0x64`](#push5) | PUSH5 | Place 5-byte item on stack | - | 3 | -| [`0x65`](#push6) | PUSH6 | Place 6-byte item on stack | - | 3 | -| [`0x66`](#push7) | PUSH7 | Place 7-byte item on stack | - | 3 | -| [`0x67`](#push8) | PUSH8 | Place 8-byte item on stack | - | 3 | -| [`0x68`](#push9) | PUSH9 | Place 9-byte item on stack | - | 3 | -| [`0x69`](#push10) | PUSH10 | Place 10-byte item on stack | - | 3 | -| [`0x6a`](#push11) | PUSH11 | Place 11-byte item on stack | - | 3 | -| [`0x6b`](#push12) | PUSH12 | Place 12-byte item on stack | - | 3 | -| [`0x6c`](#push13) | PUSH13 | Place 13-byte item on stack | - | 3 | -| [`0x6d`](#push14) | PUSH14 | Place 14-byte item on stack | - | 3 | -| [`0x6e`](#push15) | PUSH15 | Place 15-byte item on stack | - | 3 | -| [`0x6f`](#push16) | PUSH16 | Place 16-byte item on stack | - | 3 | -| [`0x70`](#push17) | PUSH17 | Place 17-byte item on stack | - | 3 | -| [`0x71`](#push18) | PUSH18 | Place 18-byte item on stack | - | 3 | -| [`0x72`](#push19) | PUSH19 | Place 19-byte item on stack | - | 3 | -| [`0x73`](#push20) | PUSH20 | Place 20-byte item on stack | - | 3 | -| [`0x74`](#push21) | PUSH21 | Place 21-byte item on stack | - | 3 | -| [`0x75`](#push22) | PUSH22 | Place 22-byte item on stack | - | 3 | -| [`0x76`](#push23) | PUSH23 | Place 23-byte item on stack | - | 3 | -| [`0x77`](#push24) | PUSH24 | Place 24-byte item on stack | - | 3 | -| [`0x78`](#push25) | PUSH25 | Place 25-byte item on stack | - | 3 | -| [`0x79`](#push26) | PUSH26 | Place 26-byte item on stack | - | 3 | -| [`0x7a`](#push27) | PUSH27 | Place 27-byte item on stack | - | 3 | -| [`0x7b`](#push28) | PUSH28 | Place 28-byte item on stack | - | 3 | -| [`0x7c`](#push29) | PUSH29 | Place 29-byte item on stack | - | 3 | -| [`0x7d`](#push30) | PUSH30 | Place 30-byte item on stack | - | 3 | -| [`0x7e`](#push31) | PUSH31 | Place 31-byte item on stack | - | 3 | -| [`0x7f`](#push32) | PUSH32 | Place 32-byte (full word) item on stack | - | 3 | -| [`0x80`](#dup1) | DUP1 | Duplicate 1st stack item | - | 3 | -| [`0x81`](#dup2) | DUP2 | Duplicate 2nd stack item | - | 3 | -| [`0x82`](#dup3) | DUP3 | Duplicate 3rd stack item | - | 3 | -| [`0x83`](#dup4) | DUP4 | Duplicate 4th stack item | - | 3 | -| [`0x84`](#dup5) | DUP5 | Duplicate 5th stack item | - | 3 | -| [`0x85`](#dup6) | DUP6 | Duplicate 6th stack item | - | 3 | -| [`0x86`](#dup7) | DUP7 | Duplicate 7th stack item | - | 3 | -| [`0x87`](#dup8) | DUP8 | Duplicate 8th stack item | - | 3 | -| [`0x88`](#dup9) | DUP9 | Duplicate 9th stack item | - | 3 | -| [`0x89`](#dup10) | DUP10 | Duplicate 10th stack item | - | 3 | -| [`0x8a`](#dup11) | DUP11 | Duplicate 11th stack item | - | 3 | -| [`0x8b`](#dup12) | DUP12 | Duplicate 12th stack item | - | 3 | -| [`0x8c`](#dup13) | DUP13 | Duplicate 13th stack item | - | 3 | -| [`0x8d`](#dup14) | DUP14 | Duplicate 14th stack item | - | 3 | -| [`0x8e`](#dup15) | DUP15 | Duplicate 15th stack item | - | 3 | -| [`0x8f`](#dup16) | DUP16 | Duplicate 16th stack item | - | 3 | -| [`0x90`](#swap1) | SWAP1 | Exchange 1st and 2nd stack items | - | 3 | -| [`0x91`](#swap2) | SWAP2 | Exchange 1st and 3rd stack items | - | 3 | -| [`0x92`](#swap3) | SWAP3 | Exchange 1st and 4th stack items | - | 3 | -| [`0x93`](#swap4) | SWAP4 | Exchange 1st and 5th stack items | - | 3 | -| [`0x94`](#swap5) | SWAP5 | Exchange 1st and 6th stack items | - | 3 | -| [`0x95`](#swap6) | SWAP6 | Exchange 1st and 7th stack items | - | 3 | -| [`0x96`](#swap7) | SWAP7 | Exchange 1st and 8th stack items | - | 3 | -| [`0x97`](#swap8) | SWAP8 | Exchange 1st and 9th stack items | - | 3 | -| [`0x98`](#swap9) | SWAP9 | Exchange 1st and 10th stack items | - | 3 | -| [`0x99`](#swap10) | SWAP10 | Exchange 1st and 11th stack items | - | 3 | -| [`0x9a`](#swap11) | SWAP11 | Exchange 1st and 12th stack items | - | 3 | -| [`0x9b`](#swap12) | SWAP12 | Exchange 1st and 13th stack items | - | 3 | -| [`0x9c`](#swap13) | SWAP13 | Exchange 1st and 14th stack items | - | 3 | -| [`0x9d`](#swap14) | SWAP14 | Exchange 1st and 15th stack items | - | 3 | -| [`0x9e`](#swap15) | SWAP15 | Exchange 1st and 16th stack items | - | 3 | -| [`0x9f`](#swap16) | SWAP16 | Exchange 1st and 17th stack items | - | 3 | -| [`0xa0`](#log0) | LOG0 | Append log record with no topics | - | 375 | -| [`0xa1`](#log1) | LOG1 | Append log record with one topic | - | 750 | -| [`0xa2`](#log2) | LOG2 | Append log record with two topics | - | 1125 | -| [`0xa3`](#log3) | LOG3 | Append log record with three topics | - | 1500 | -| [`0xa4`](#log4) | LOG4 | Append log record with four topics | - | 1875 | -| `0xa5` - `0xaf` | Unused | - | -| `0xb0` | JUMPTO | Tentative [libevmasm has different numbers](https://github.com/ethereum/solidity/blob/c61610302aa2bfa029715b534719d25fe3949059/libevmasm/Instruction.h#L176)| [EIP 615](https://github.com/ethereum/EIPs/blob/606405b5ab7aa28d8191958504e8aad4649666c9/EIPS/eip-615.md) | -| `0xb1` | JUMPIF | Tentative | [EIP 615](https://github.com/ethereum/EIPs/blob/606405b5ab7aa28d8191958504e8aad4649666c9/EIPS/eip-615.md) | -| `0xb2` | JUMPSUB | Tentative | [EIP 615](https://github.com/ethereum/EIPs/blob/606405b5ab7aa28d8191958504e8aad4649666c9/EIPS/eip-615.md) | -| `0xb4` | JUMPSUBV | Tentative | [EIP 615](https://github.com/ethereum/EIPs/blob/606405b5ab7aa28d8191958504e8aad4649666c9/EIPS/eip-615.md) | -| `0xb5` | BEGINSUB | Tentative | [EIP 615](https://github.com/ethereum/EIPs/blob/606405b5ab7aa28d8191958504e8aad4649666c9/EIPS/eip-615.md) | -| `0xb6` | BEGINDATA | Tentative | [EIP 615](https://github.com/ethereum/EIPs/blob/606405b5ab7aa28d8191958504e8aad4649666c9/EIPS/eip-615.md) | -| `0xb8` | RETURNSUB | Tentative | [EIP 615](https://github.com/ethereum/EIPs/blob/606405b5ab7aa28d8191958504e8aad4649666c9/EIPS/eip-615.md) | -| `0xb9` | PUTLOCAL | Tentative | [EIP 615](https://github.com/ethereum/EIPs/blob/606405b5ab7aa28d8191958504e8aad4649666c9/EIPS/eip-615.md) | -| `0xba` | GETLOCAL | Tentative | [EIP 615](https://github.com/ethereum/EIPs/blob/606405b5ab7aa28d8191958504e8aad4649666c9/EIPS/eip-615.md) | -| `0xbb` - `0xe0` | Unused | - | -| `0xe1` | SLOADBYTES | Only referenced in pyethereum | - | - | -| `0xe2` | SSTOREBYTES | Only referenced in pyethereum | - | - | -| `0xe3` | SSIZE | Only referenced in pyethereum | - | - | -| `0xe4` - `0xef` | Unused | - | -| [`0xf0`](#create) | CREATE | Create a new account with associated code | - | 32000 | -| [`0xf1`](#call) | CALL | Message-call into an account | - | Complicated | -| [`0xf2`](#callcode) | CALLCODE | Message-call into this account with alternative account's code | - | Complicated | -| [`0xf3`](#return) | RETURN | Halt execution returning output data | - | 0 | -| [`0xf4`](#delegatecall) | DELEGATECALL | Message-call into this account with an alternative account's code, but persisting into this account with an alternative account's code | - | Complicated | -| [`0xf5`](#create2) | CREATE2 | Create a new account and set creation address to `sha3(sender + sha3(init code)) % 2**160` | - | -| `0xf6` - `0xf9` | Unused | - | - | -| [`0xfa`](#staticcall) | STATICCALL | Similar to CALL, but does not modify state | - | 40 | -| `0xfb` | Unused | - | - | -| [`0xfd`](#revert) | REVERT | Stop execution and revert state changes, without consuming all provided gas and providing a reason | - | 0 | -| `0xfe` | INVALID | Designated invalid instruction | - | 0 | -| [`0xff`](#selfdestruct) | SELFDESTRUCT | Halt execution and register account for later deletion | - | 5000* | +| Opcode | Name | Description | Extra Info | Gas | +| ------------------------- | -------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------ | --------------------------------------------------------------------------------------------------------- | ----------- | +| [`0x00`](#stop) | STOP | Halts execution | - | 0 | +| [`0x01`](#add) | ADD | Addition operation | - | 3 | +| [`0x02`](#mul) | MUL | Multiplication operation | - | 5 | +| [`0x03`](#sub) | SUB | Subtraction operation | - | 3 | +| [`0x04`](#div) | DIV | Integer division operation | - | 5 | +| [`0x05`](#sdiv) | SDIV | Signed integer division operation (truncated) | - | 5 | +| [`0x06`](#mod) | MOD | Modulo remainder operation | - | 5 | +| [`0x07`](#smod) | SMOD | Signed modulo remainder operation | - | 5 | +| [`0x08`](#addmod) | ADDMOD | Modulo addition operation | - | 8 | +| [`0x09`](#mulmod) | MULMOD | Modulo multiplication operation | - | 8 | +| [`0x0a`](#exp) | EXP | Exponential operation | - | 10\* | +| [`0x0b`](#signextend) | SIGNEXTEND | Extend length of two's complement signed integer | - | 5 | +| `0x0c` - `0x0f` | Unused | Unused | - | +| [`0x10`](#lt) | LT | Less-than comparison | - | 3 | +| [`0x11`](#gt) | GT | Greater-than comparison | - | 3 | +| [`0x12`](#slt) | SLT | Signed less-than comparison | - | 3 | +| [`0x13`](#sgt) | SGT | Signed greater-than comparison | - | 3 | +| [`0x14`](#eq) | EQ | Equality comparison | - | 3 | +| [`0x15`](#iszero) | ISZERO | Simple not operator | - | 3 | +| [`0x16`](#and) | AND | Bitwise AND operation | - | 3 | +| [`0x17`](#or) | OR | Bitwise OR operation | - | 3 | +| [`0x18`](#xor) | XOR | Bitwise XOR operation | - | 3 | +| [`0x19`](#not) | NOT | Bitwise NOT operation | - | 3 | +| [`0x1a`](#byte) | BYTE | Retrieve single byte from word | - | 3 | +| [`0x1b`](#shl) | SHL | Shift Left | [EIP145](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-145.md) | 3 | +| [`0x1c`](#shr) | SHR | Logical Shift Right | [EIP145](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-145.md) | 3 | +| [`0x1d`](#sar) | SAR | Arithmetic Shift Right | [EIP145](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-145.md) | 3 | +| [`0x20`](#keccak256) | KECCAK256 | Compute Keccak-256 hash | - | 30\* | +| `0x21` - `0x2f` | Unused | Unused | +| [`0x30`](#address) | ADDRESS | Get address of currently executing account | - | 2 | +| [`0x31`](#balance) | BALANCE | Get balance of the given account | - | 700 | +| [`0x32`](#origin) | ORIGIN | Get execution origination address | - | 2 | +| [`0x33`](#caller) | CALLER | Get caller address | - | 2 | +| [`0x34`](#callvalue) | CALLVALUE | Get deposited value by the instruction/transaction responsible for this execution | - | 2 | +| [`0x35`](#calldataload) | CALLDATALOAD | Get input data of current environment | - | 3 | +| [`0x36`](#calldatasize) | CALLDATASIZE | Get size of input data in current environment | - | 2\* | +| [`0x37`](#calldatacopy) | CALLDATACOPY | Copy input data in current environment to memory | - | 3 | +| [`0x38`](#codesize) | CODESIZE | Get size of code running in current environment | - | 2 | +| [`0x39`](#codecopy) | CODECOPY | Copy code running in current environment to memory | - | 3\* | +| [`0x3a`](#gasprice) | GASPRICE | Get price of gas in current environment | - | 2 | +| [`0x3b`](#extcodesize) | EXTCODESIZE | Get size of an account's code | - | 700 | +| [`0x3c`](#extcodecopy) | EXTCODECOPY | Copy an account's code to memory | - | 700\* | +| [`0x3d`](#returndatasize) | RETURNDATASIZE | Pushes the size of the return data buffer onto the stack | [EIP 211](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-211.md) | 2 | +| [`0x3e`](#returndatacopy) | RETURNDATACOPY | Copies data from the return data buffer to memory | [EIP 211](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-211.md) | 3 | +| [`0x3f`](#extcodehash) | EXTCODEHASH | Returns the keccak256 hash of a contract's code | [EIP 1052](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-1052.md) | 700 | +| [`0x40`](#blockhash) | BLOCKHASH | Get the hash of one of the 256 most recent complete blocks | - | 20 | +| [`0x41`](#coinbase) | COINBASE | Get the block's beneficiary address | - | 2 | +| [`0x42`](#timestamp) | TIMESTAMP | Get the block's timestamp | - | 2 | +| [`0x43`](#number) | NUMBER | Get the block's number | - | 2 | +| [`0x44`](#difficulty) | DIFFICULTY | Get the block's difficulty | - | 2 | +| [`0x45`](#gaslimit) | GASLIMIT | Get the block's gas limit | - | 2 | +| [`0x46`](#chainid) | CHAINID | Returns the current chain’s EIP-155 unique identifier | [EIP 1344](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-1344.md) | 2 | +| `0x47` - `0x4f` | Unused | - | +| [`0x48`](#basefee) | BASEFEE | Returns the value of the base fee of the current block it is executing in. | [EIP 3198](https://eips.ethereum.org/EIPS/eip-3198) | 2 | +| [`0x50`](#pop) | POP | Remove word from stack | - | 2 | +| [`0x51`](#mload) | MLOAD | Load word from memory | - | 3\* | +| [`0x52`](#mstore) | MSTORE | Save word to memory | - | 3\* | +| [`0x53`](#mstore8) | MSTORE8 | Save byte to memory | - | 3 | +| [`0x54`](#sload) | SLOAD | Load word from storage | - | 800 | +| [`0x55`](#sstore) | SSTORE | Save word to storage | - | 20000\*\* | +| [`0x56`](#jump) | JUMP | Alter the program counter | - | 8 | +| [`0x57`](#jumpi) | JUMPI | Conditionally alter the program counter | - | 10 | +| [`0x58`](#pc) | PC | Get the value of the program counter prior to the increment | - | 2 | +| [`0x59`](#msize) | MSIZE | Get the size of active memory in bytes | - | 2 | +| [`0x5a`](#gas) | GAS | Get the amount of available gas, including the corresponding reduction for the cost of this instruction | - | 2 | +| [`0x5b`](#jumpdest) | JUMPDEST | Mark a valid destination for jumps | - | 1 | +| `0x5c` - `0x5f` | Unused | - | +| [`0x60`](#push1) | PUSH1 | Place 1 byte item on stack | - | 3 | +| [`0x61`](#push2) | PUSH2 | Place 2-byte item on stack | - | 3 | +| [`0x62`](#push3) | PUSH3 | Place 3-byte item on stack | - | 3 | +| [`0x63`](#push4) | PUSH4 | Place 4-byte item on stack | - | 3 | +| [`0x64`](#push5) | PUSH5 | Place 5-byte item on stack | - | 3 | +| [`0x65`](#push6) | PUSH6 | Place 6-byte item on stack | - | 3 | +| [`0x66`](#push7) | PUSH7 | Place 7-byte item on stack | - | 3 | +| [`0x67`](#push8) | PUSH8 | Place 8-byte item on stack | - | 3 | +| [`0x68`](#push9) | PUSH9 | Place 9-byte item on stack | - | 3 | +| [`0x69`](#push10) | PUSH10 | Place 10-byte item on stack | - | 3 | +| [`0x6a`](#push11) | PUSH11 | Place 11-byte item on stack | - | 3 | +| [`0x6b`](#push12) | PUSH12 | Place 12-byte item on stack | - | 3 | +| [`0x6c`](#push13) | PUSH13 | Place 13-byte item on stack | - | 3 | +| [`0x6d`](#push14) | PUSH14 | Place 14-byte item on stack | - | 3 | +| [`0x6e`](#push15) | PUSH15 | Place 15-byte item on stack | - | 3 | +| [`0x6f`](#push16) | PUSH16 | Place 16-byte item on stack | - | 3 | +| [`0x70`](#push17) | PUSH17 | Place 17-byte item on stack | - | 3 | +| [`0x71`](#push18) | PUSH18 | Place 18-byte item on stack | - | 3 | +| [`0x72`](#push19) | PUSH19 | Place 19-byte item on stack | - | 3 | +| [`0x73`](#push20) | PUSH20 | Place 20-byte item on stack | - | 3 | +| [`0x74`](#push21) | PUSH21 | Place 21-byte item on stack | - | 3 | +| [`0x75`](#push22) | PUSH22 | Place 22-byte item on stack | - | 3 | +| [`0x76`](#push23) | PUSH23 | Place 23-byte item on stack | - | 3 | +| [`0x77`](#push24) | PUSH24 | Place 24-byte item on stack | - | 3 | +| [`0x78`](#push25) | PUSH25 | Place 25-byte item on stack | - | 3 | +| [`0x79`](#push26) | PUSH26 | Place 26-byte item on stack | - | 3 | +| [`0x7a`](#push27) | PUSH27 | Place 27-byte item on stack | - | 3 | +| [`0x7b`](#push28) | PUSH28 | Place 28-byte item on stack | - | 3 | +| [`0x7c`](#push29) | PUSH29 | Place 29-byte item on stack | - | 3 | +| [`0x7d`](#push30) | PUSH30 | Place 30-byte item on stack | - | 3 | +| [`0x7e`](#push31) | PUSH31 | Place 31-byte item on stack | - | 3 | +| [`0x7f`](#push32) | PUSH32 | Place 32-byte (full word) item on stack | - | 3 | +| [`0x80`](#dup1) | DUP1 | Duplicate 1st stack item | - | 3 | +| [`0x81`](#dup2) | DUP2 | Duplicate 2nd stack item | - | 3 | +| [`0x82`](#dup3) | DUP3 | Duplicate 3rd stack item | - | 3 | +| [`0x83`](#dup4) | DUP4 | Duplicate 4th stack item | - | 3 | +| [`0x84`](#dup5) | DUP5 | Duplicate 5th stack item | - | 3 | +| [`0x85`](#dup6) | DUP6 | Duplicate 6th stack item | - | 3 | +| [`0x86`](#dup7) | DUP7 | Duplicate 7th stack item | - | 3 | +| [`0x87`](#dup8) | DUP8 | Duplicate 8th stack item | - | 3 | +| [`0x88`](#dup9) | DUP9 | Duplicate 9th stack item | - | 3 | +| [`0x89`](#dup10) | DUP10 | Duplicate 10th stack item | - | 3 | +| [`0x8a`](#dup11) | DUP11 | Duplicate 11th stack item | - | 3 | +| [`0x8b`](#dup12) | DUP12 | Duplicate 12th stack item | - | 3 | +| [`0x8c`](#dup13) | DUP13 | Duplicate 13th stack item | - | 3 | +| [`0x8d`](#dup14) | DUP14 | Duplicate 14th stack item | - | 3 | +| [`0x8e`](#dup15) | DUP15 | Duplicate 15th stack item | - | 3 | +| [`0x8f`](#dup16) | DUP16 | Duplicate 16th stack item | - | 3 | +| [`0x90`](#swap1) | SWAP1 | Exchange 1st and 2nd stack items | - | 3 | +| [`0x91`](#swap2) | SWAP2 | Exchange 1st and 3rd stack items | - | 3 | +| [`0x92`](#swap3) | SWAP3 | Exchange 1st and 4th stack items | - | 3 | +| [`0x93`](#swap4) | SWAP4 | Exchange 1st and 5th stack items | - | 3 | +| [`0x94`](#swap5) | SWAP5 | Exchange 1st and 6th stack items | - | 3 | +| [`0x95`](#swap6) | SWAP6 | Exchange 1st and 7th stack items | - | 3 | +| [`0x96`](#swap7) | SWAP7 | Exchange 1st and 8th stack items | - | 3 | +| [`0x97`](#swap8) | SWAP8 | Exchange 1st and 9th stack items | - | 3 | +| [`0x98`](#swap9) | SWAP9 | Exchange 1st and 10th stack items | - | 3 | +| [`0x99`](#swap10) | SWAP10 | Exchange 1st and 11th stack items | - | 3 | +| [`0x9a`](#swap11) | SWAP11 | Exchange 1st and 12th stack items | - | 3 | +| [`0x9b`](#swap12) | SWAP12 | Exchange 1st and 13th stack items | - | 3 | +| [`0x9c`](#swap13) | SWAP13 | Exchange 1st and 14th stack items | - | 3 | +| [`0x9d`](#swap14) | SWAP14 | Exchange 1st and 15th stack items | - | 3 | +| [`0x9e`](#swap15) | SWAP15 | Exchange 1st and 16th stack items | - | 3 | +| [`0x9f`](#swap16) | SWAP16 | Exchange 1st and 17th stack items | - | 3 | +| [`0xa0`](#log0) | LOG0 | Append log record with no topics | - | 375 | +| [`0xa1`](#log1) | LOG1 | Append log record with one topic | - | 750 | +| [`0xa2`](#log2) | LOG2 | Append log record with two topics | - | 1125 | +| [`0xa3`](#log3) | LOG3 | Append log record with three topics | - | 1500 | +| [`0xa4`](#log4) | LOG4 | Append log record with four topics | - | 1875 | +| `0xa5` - `0xaf` | Unused | - | +| `0xb0` | JUMPTO | Tentative [libevmasm has different numbers](https://github.com/ethereum/solidity/blob/c61610302aa2bfa029715b534719d25fe3949059/libevmasm/Instruction.h#L176) | [EIP 615](https://github.com/ethereum/EIPs/blob/606405b5ab7aa28d8191958504e8aad4649666c9/EIPS/eip-615.md) | +| `0xb1` | JUMPIF | Tentative | [EIP 615](https://github.com/ethereum/EIPs/blob/606405b5ab7aa28d8191958504e8aad4649666c9/EIPS/eip-615.md) | +| `0xb2` | JUMPSUB | Tentative | [EIP 615](https://github.com/ethereum/EIPs/blob/606405b5ab7aa28d8191958504e8aad4649666c9/EIPS/eip-615.md) | +| `0xb4` | JUMPSUBV | Tentative | [EIP 615](https://github.com/ethereum/EIPs/blob/606405b5ab7aa28d8191958504e8aad4649666c9/EIPS/eip-615.md) | +| `0xb5` | BEGINSUB | Tentative | [EIP 615](https://github.com/ethereum/EIPs/blob/606405b5ab7aa28d8191958504e8aad4649666c9/EIPS/eip-615.md) | +| `0xb6` | BEGINDATA | Tentative | [EIP 615](https://github.com/ethereum/EIPs/blob/606405b5ab7aa28d8191958504e8aad4649666c9/EIPS/eip-615.md) | +| `0xb8` | RETURNSUB | Tentative | [EIP 615](https://github.com/ethereum/EIPs/blob/606405b5ab7aa28d8191958504e8aad4649666c9/EIPS/eip-615.md) | +| `0xb9` | PUTLOCAL | Tentative | [EIP 615](https://github.com/ethereum/EIPs/blob/606405b5ab7aa28d8191958504e8aad4649666c9/EIPS/eip-615.md) | +| `0xba` | GETLOCAL | Tentative | [EIP 615](https://github.com/ethereum/EIPs/blob/606405b5ab7aa28d8191958504e8aad4649666c9/EIPS/eip-615.md) | +| `0xbb` - `0xe0` | Unused | - | +| `0xe1` | SLOADBYTES | Only referenced in pyethereum | - | - | +| `0xe2` | SSTOREBYTES | Only referenced in pyethereum | - | - | +| `0xe3` | SSIZE | Only referenced in pyethereum | - | - | +| `0xe4` - `0xef` | Unused | - | +| [`0xf0`](#create) | CREATE | Create a new account with associated code | - | 32000 | +| [`0xf1`](#call) | CALL | Message-call into an account | - | Complicated | +| [`0xf2`](#callcode) | CALLCODE | Message-call into this account with alternative account's code | - | Complicated | +| [`0xf3`](#return) | RETURN | Halt execution returning output data | - | 0 | +| [`0xf4`](#delegatecall) | DELEGATECALL | Message-call into this account with an alternative account's code, but persisting into this account with an alternative account's code | - | Complicated | +| [`0xf5`](#create2) | CREATE2 | Create a new account and set creation address to `sha3(sender + sha3(init code)) % 2**160` | - | +| `0xf6` - `0xf9` | Unused | - | - | +| [`0xfa`](#staticcall) | STATICCALL | Similar to CALL, but does not modify state | - | 40 | +| `0xfb` | Unused | - | - | +| [`0xfd`](#revert) | REVERT | Stop execution and revert state changes, without consuming all provided gas and providing a reason | - | 0 | +| `0xfe` | INVALID | Designated invalid instruction | - | 0 | +| [`0xff`](#selfdestruct) | SELFDESTRUCT | Halt execution and register account for later deletion | - | 5000\* | ## Instruction Details ------ +--- + ### STOP + **0x00** () => () halts execution ------ +--- + ### ADD + **0x01** Takes two words from stack, adds them, then pushes the result onto the stack. @@ -196,90 +200,112 @@ Takes two words from stack, adds them, then pushes the result onto the stack. c = a + b ------ +--- + ### MUL + **0x02** (a, b) => (c) -c = a * b +c = a \* b + +--- ------ ### SUB + **0x03** (a, b) => (c) c = a - b ------ +--- + ### DIV + **0x04** (a, b) => (c) c = a / b ------ +--- + ### SDIV + **0x05** (a: int256, b: int256) => (c: int256) c = a / b ------ +--- + ### MOD + **0x06** (a, b) => (c) c = a % b ------ +--- + ### SMOD + **0x07** (a: int256, b: int256) => (c: int256) c = a % b ------ +--- + ### ADDMOD + **0x08** (a, b, m) => (c) c = (a + b) % m ------ +--- + ### MULMOD + **0x09** (a, b, m) => (c) -c = (a * b) % m +c = (a \* b) % m + +--- ------ ### EXP + **0x0a** (a, b, m) => (c) -c = (a * b) % m +c = (a \* b) % m + +--- ------ ### SIGNEXTEND + **0x0b** (b, x) => (y) y = SIGNEXTEND(x, b) -sign extends x from (b + 1) * 8 bits to 256 bits. +sign extends x from (b + 1) \* 8 bits to 256 bits. + +--- ------ ### LT + **0x10** (a, b) => (c) @@ -288,8 +314,10 @@ c = a < b all values interpreted as uint256 ------ +--- + ### GT + **0x11** (a, b) => (c) @@ -298,8 +326,10 @@ c = a > b all values interpreted as uint256 ------ +--- + ### SLT + **0x12** (a, b) => (c) @@ -308,8 +338,10 @@ c = a < b all values interpreted as int256 ------ +--- + ### SGT + **0x13** (a, b) => (c) @@ -318,8 +350,10 @@ c = a > b all values interpreted as int256 ------ +--- + ### EQ + **0x14** Pops 2 elements off the stack and pushes the value 1 to the stack in case they're equal, otherwise the value 0. @@ -328,76 +362,94 @@ Pops 2 elements off the stack and pushes the value 1 to the stack in case they'r c = a == b ------ +--- + ### ISZERO + **0x15** (a) => (c) c = a == 0 ------ +--- + ### AND + **0x16** (a, b) => (c) c = a & b ------ +--- + ### OR + **0x17** (a, b) => (c) c = a | b ------ +--- + ### XOR + **0x18** (a, b) => (c) c = a ^ b ------ +--- + ### NOT + **0x19** (a) => (c) c = ~a ------ +--- + ### BYTE + **0x1a** (i, x) => (y) -y = (x >> (248 - i * 8) & 0xff +y = (x >> (248 - i \* 8) & 0xff + +--- ------ ### SHL + **0x1b** -Pops 2 elements from the stack and pushes the second element onto the stack shifted left by the shift amount (first element). +Pops 2 elements from the stack and pushes the second element onto the stack shifted left by the shift amount (first element). (shift, value) => (res) res = value << shift ------ +--- + ### SHR + **0x1c** -Pops 2 elements from the stack and pushes the second element onto the stack shifted right by the shift amount (first element). +Pops 2 elements from the stack and pushes the second element onto the stack shifted right by the shift amount (first element). (shift, value) => (res) res = value >> shift ------ +--- + ### SAR + **0x1d** (shift, value) => (res) @@ -406,100 +458,130 @@ res = value >> shift value: int256 ------ +--- + ### KECCAK256 + **0x20** (offset, len) => (hash) hash = keccak256(memory[offset:offset+len]) ------ +--- + ### ADDRESS + **0x30** () => (address(this)) ------ +--- + ### BALANCE + **0x31** () => (address(this).balance) ------ +--- + ### ORIGIN + **0x32** () => (tx.origin) ------ +--- + ### CALLER + **0x33** () => (msg.sender) ------ +--- + ### CALLVALUE + **0x34** () => (msg.value) ------ +--- + ### CALLDATALOAD + **0x35** (index) => (msg.data[index:index+32]) ------ +--- + ### CALLDATASIZE + **0x36** () => (msg.data.size) ------ +--- + ### CALLDATACOPY + **0x37** (memOffset, offset, length) => () memory[memOffset:memOffset+len] = msg.data[offset:offset+len] ------ +--- + ### CODESIZE + **0x38** () => (address(this).code.size) ------ +--- + ### CODECOPY + **0x39** (memOffset, codeOffset, len) => () memory[memOffset:memOffset+len] = address(this).code[codeOffset:codeOffset+len] ------ +--- + ### GASPRICE + **0x3a** () => (tx.gasprice) ------ +--- + ### EXTCODESIZE + **0x3b** (addr) => (address(addr).code.size) ------ +--- + ### EXTCODECOPY + **0x3c** (addr, memOffset, offset, length) => () memory[memOffset:memOffset+len] = address(addr).code[codeOffset:codeOffset+len] ------ +--- + ### RETURNDATASIZE + **0x3d** () => (size) @@ -508,8 +590,10 @@ size = RETURNDATASIZE() The number of bytes that were returned from the last ext call ------ +--- + ### RETURNDATACOPY + **0x3e** (memOffset, offset, length) => () @@ -518,138 +602,174 @@ memory[memOffset:memOffset+len] = RETURNDATA[codeOffset:codeOffset+len] RETURNDATA is the data returned from the last external call ------ +--- + ### EXTCODEHASH + **0x3f** (addr) => (hash) hash = address(addr).exists ? keccak256(address(addr).code) : 0 ------ +--- + ### BLOCKHASH + **0x40** (number) => (hash) hash = block.blockHash(number) ------ +--- + ### COINBASE + **0x41** () => (block.coinbase) ------ +--- + ### TIMESTAMP + **0x42** () => (block.timestamp) ------ +--- + ### NUMBER + **0x43** () => (block.number) ------ +--- + ### DIFFICULTY + **0x44** () => (block.difficulty) ------ +--- + ### GASLIMIT + **0x45** () => (block.gaslimit) ------ +--- + ### CHAINID + **0x46** () => (chainid) where chainid = 1 for mainnet & some other value for other networks ------ +--- + ### SELFBALANCE + **0x47** () => (address(this).balance) ------ +--- + ### BASEFEE + **0x48** () => (block.basefee) current block's base fee (related to EIP1559) ------ +--- + ### POP + **0x50** (a) => () discards the top stack item ------ +--- + ### MLOAD + **0x51** (offset) => (value) value = memory[offset:offset+32] ------ +--- + ### MSTORE + **0x52** -Saves a word to the EVM memory. Pops 2 elements from stack - the first element being the word memory address where the saved value (second element popped from stack) will be stored. +Saves a word to the EVM memory. Pops 2 elements from stack - the first element being the word memory address where the saved value (second element popped from stack) will be stored. (offset, value) => () memory[offset:offset+32] = value ------ +--- + ### MSTORE8 + **0x53** (offset, value) => () memory[offset:offset+32] = value & 0xff ------ +--- + ### SLOAD + **0x54** -Pops 1 element off the stack, that being the key which is the storage slot and returns the read value stored there. +Pops 1 element off the stack, that being the key which is the storage slot and returns the read value stored there. (key) => (value) value = storage[key] ------ +--- + ### SSTORE + **0x55** -Pops 2 elements off the stack, the first element being the key and the second being the value which is then stored at the storage slot represented from the first element (key). +Pops 2 elements off the stack, the first element being the key and the second being the value which is then stored at the storage slot represented from the first element (key). (key, value) => () storage[key] = value ------ +--- + ### JUMP + **0x56** (dest) => () pc = dest ------ +--- + ### JUMPI + **0x57** Conditional - Pops 2 elements from the stack, the first element being the jump location and the second being the value 0 (false) or 1 (true). If the value’s 1 the PC will be altered and the jump executed. Otherwise, the value will be 0 and the PC will remain the same and execution unaltered. @@ -658,462 +778,610 @@ Conditional - Pops 2 elements from the stack, the first element being the jump l pc = cond ? dest : pc + 1 ------ +--- + ### PC + **0x58** () => (pc) ------ +--- + ### MSIZE + **0x59** () => (memory.size) ------ +--- + ### GAS + **0x5a** () => (gasRemaining) not including the gas required for this opcode ------ +--- + ### JUMPDEST + **0x5b** () => () noop, marks a valid jump destination ------ +--- + ### PUSH1 + **0x60** The following byte is read from PC, placed into a word, then this word is pushed onto the stack. () => (address(this).code[pc+1:pc+2]) ------ +--- + ### PUSH2 + **0x61** () => (address(this).code[pc+2:pc+3]) ------ +--- + ### PUSH3 + **0x62** () => (address(this).code[pc+3:pc+4]) ------ +--- + ### PUSH4 + **0x63** () => (address(this).code[pc+4:pc+5]) ------ +--- + ### PUSH5 + **0x64** () => (address(this).code[pc+5:pc+6]) ------ +--- + ### PUSH6 + **0x65** () => (address(this).code[pc+6:pc+7]) ------ +--- + ### PUSH7 + **0x66** () => (address(this).code[pc+7:pc+8]) ------ +--- + ### PUSH8 + **0x67** () => (address(this).code[pc+8:pc+9]) ------ +--- + ### PUSH9 + **0x68** () => (address(this).code[pc+9:pc+10]) ------ +--- + ### PUSH10 + **0x69** () => (address(this).code[pc+10:pc+11]) ------ +--- + ### PUSH11 + **0x6a** () => (address(this).code[pc+11:pc+12]) ------ +--- + ### PUSH12 + **0x6b** () => (address(this).code[pc+12:pc+13]) ------ +--- + ### PUSH13 + **0x6c** () => (address(this).code[pc+13:pc+14]) ------ +--- + ### PUSH14 + **0x6d** () => (address(this).code[pc+14:pc+15]) ------ +--- + ### PUSH15 + **0x6e** () => (address(this).code[pc+15:pc+16]) ------ +--- + ### PUSH16 + **0x6f** () => (address(this).code[pc+16:pc+17]) ------ +--- + ### PUSH17 + **0x70** () => (address(this).code[pc+17:pc+18]) ------ +--- + ### PUSH18 + **0x71** () => (address(this).code[pc+18:pc+19]) ------ +--- + ### PUSH19 + **0x72** () => (address(this).code[pc+19:pc+20]) ------ +--- + ### PUSH20 + **0x73** () => (address(this).code[pc+20:pc+21]) ------ +--- + ### PUSH21 + **0x74** () => (address(this).code[pc+21:pc+22]) ------ +--- + ### PUSH22 + **0x75** () => (address(this).code[pc+22:pc+23]) ------ +--- + ### PUSH23 + **0x76** () => (address(this).code[pc+23:pc+24]) ------ +--- + ### PUSH24 + **0x77** () => (address(this).code[pc+24:pc+25]) ------ +--- + ### PUSH25 + **0x78** () => (address(this).code[pc+25:pc+26]) ------ +--- + ### PUSH26 + **0x79** () => (address(this).code[pc+26:pc+27]) ------ +--- + ### PUSH27 + **0x7a** () => (address(this).code[pc+27:pc+28]) ------ +--- + ### PUSH28 + **0x7b** () => (address(this).code[pc+28:pc+29]) ------ +--- + ### PUSH29 + **0x7c** () => (address(this).code[pc+29:pc+30]) ------ +--- + ### PUSH30 + **0x7d** () => (address(this).code[pc+30:pc+31]) ------ +--- + ### PUSH31 + **0x7e** () => (address(this).code[pc+31:pc+32]) ------ +--- + ### PUSH32 + **0x7f** () => (address(this).code[pc+32:pc+33]) ------ +--- + ### DUP1 + **0x80** (1) => (1, 1) ------ +--- + ### DUP2 + **0x81** (1, 2) => (2, 1, 2) ------ +--- + ### DUP3 + **0x82** (1, 2, 3) => (3, 1, 2, 3) ------ +--- + ### DUP4 + **0x83** (1, ..., 4) => (4, 1, ..., 4) ------ +--- + ### DUP5 + **0x84** (1, ..., 5) => (5, 1, ..., 5) ------ +--- + ### DUP6 + **0x85** (1, ..., 6) => (6, 1, ..., 6) ------ +--- + ### DUP7 + **0x86** (1, ..., 7) => (7, 1, ..., 7) ------ +--- + ### DUP8 + **0x87** (1, ..., 8) => (8, 1, ..., 8) ------ +--- + ### DUP9 + **0x88** (1, ..., 9) => (9, 1, ..., 9) ------ +--- + ### DUP10 + **0x89** (1, ..., 10) => (10, 1, ..., 10) ------ +--- + ### DUP11 + **0x8a** (1, ..., 11) => (11, 1, ..., 11) ------ +--- + ### DUP12 + **0x8b** (1, ..., 12) => (12, 1, ..., 12) ------ +--- + ### DUP13 + **0x8c** (1, ..., 13) => (13, 1, ..., 13) ------ +--- + ### DUP14 + **0x8d** (1, ..., 14) => (14, 1, ..., 14) ------ +--- + ### DUP15 + **0x8e** (1, ..., 15) => (15, 1, ..., 15) ------ +--- + ### DUP16 + **0x8f** (1, ..., 16) => (16, 1, ..., 16) ------ +--- + ### SWAP1 + **0x90** (1, 2) => (2, 1) ------ +--- + ### SWAP2 + **0x91** (1, 2, 3) => (3, 2, 1) ------ +--- + ### SWAP3 + **0x92** (1, ..., 4) => (4, ..., 1) ------ +--- + ### SWAP4 + **0x93** (1, ..., 5) => (5, ..., 1) ------ +--- + ### SWAP5 + **0x94** (1, ..., 6) => (6, ..., 1) ------ +--- + ### SWAP6 + **0x95** (1, ..., 7) => (7, ..., 1) ------ +--- + ### SWAP7 + **0x96** (1, ..., 8) => (8, ..., 1) ------ +--- + ### SWAP8 + **0x97** (1, ..., 9) => (9, ..., 1) ------ +--- + ### SWAP9 + **0x98** (1, ..., 10) => (10, ..., 1) ------ +--- + ### SWAP10 + **0x99** (1, ..., 11) => (11, ..., 1) ------ +--- + ### SWAP11 + **0x9a** (1, ..., 12) => (12, ..., 1) ------ +--- + ### SWAP12 + **0x9b** (1, ..., 13) => (13, ..., 1) ------ +--- + ### SWAP13 + **0x9c** (1, ..., 14) => (14, ..., 1) ------ +--- + ### SWAP14 + **0x9d** (1, ..., 15) => (15, ..., 1) ------ +--- + ### SWAP15 + **0x9e** (1, ..., 16) => (16, ..., 1) ------ +--- + ### SWAP16 + **0x9f** (1, ..., 17) => (17, ..., 1) ------ +--- + ### LOG0 + **0xa0** (offset, length) => () emit(memory[offset:offset+length]) ------ +--- + ### LOG1 + **0xa1** (offset, length, topic0) => () emit(memory[offset:offset+length], topic0) ------ +--- + ### LOG2 + **0xa2** (offset, length, topic0, topic1) => () emit(memory[offset:offset+length], topic0, topic1) ------ +--- + ### LOG3 + **0xa3** (offset, length, topic0, topic1, topic2) => () emit(memory[offset:offset+length], topic0, topic1, topic2) ------ +--- + ### LOG4 + **0xa4** (offset, length, topic0, topic1, topic2, topic3) => () emit(memory[offset:offset+length], topic0, topic1, topic2, topic3) ------ +--- + ### CREATE + **0xf0** (value, offset, length) => (addr) @@ -1124,8 +1392,10 @@ addr.balance += value this.balance -= value this.nonce += 1 ------ +--- + ### CALL + **0xf1** (gas, addr, value, argsOffset, argsLength, retOffset, retLength) => (success) @@ -1133,8 +1403,10 @@ this.nonce += 1 memory[retOffset:retOffset+retLength] = address(addr).callcode.gas(gas).value(value)(memory[argsOffset:argsOffset+argsLength]) success = true (unless the prev call reverted) ------ +--- + ### CALLCODE + **0xf2** (gas, addr, value, argsOffset, argsLength, retOffset, retLength) => (success) @@ -1144,16 +1416,20 @@ success = true (unless the prev call reverted) TODO: what's the difference between this & CALL? ------ +--- + ### RETURN + **0xf3** (offset, length) => () return memory[offset:offset+length] ------ +--- + ### DELEGATECALL + **0xf4** (gas, addr, argsOffset, argsLength, retOffset, retLength) => (success) @@ -1161,8 +1437,10 @@ return memory[offset:offset+length] memory[retOffset:retOffset+retLength] = address(addr).delegatecall.gas(gas)(memory[argsOffset:argsOffset+argsLength]) success = true (unless the prev call reverted) ------ +--- + ### CREATE2 + **0xf5** (value, offset, length, salt) => (addr) @@ -1171,9 +1449,10 @@ initCode = memory[offset:offset+length] addr = keccak256(0xff ++ address(this) ++ salt ++ keccak256(initCode))[12:] address(addr).code = exec(initCode) +--- ------ ### STATICCALL + **0xfa** (gas, addr, argsOffset, argsLength, retOffset, retLength) => (success) @@ -1183,16 +1462,20 @@ success = true (unless the prev call reverted) TODO: what's the difference between this & DELEGATECALL? ------ +--- + ### REVERT + **0xfd** (offset, length) => () revert(memory[offset:offset+length]) ------ +--- + ### SELFDESTRUCT + **0xff** (addr) => () diff --git a/learn_evm/tips_upgrades.md b/learn_evm/tips_upgrades.md index cf845249..87cb2498 100644 --- a/learn_evm/tips_upgrades.md +++ b/learn_evm/tips_upgrades.md @@ -1,70 +1,68 @@ The following lists every TIP associated to a TRON upgrade. TRON is an EVM-compatible chain. -|Upgrade | TIP | What it does -|---|---|---| - [Odyssey-v3.5](https://github.com/tronprotocol/java-tron/releases/tag/Odyssey-v3.5)| [12](https://github.com/tronprotocol/TIPs/blob/master/tip-12.md)| Event subscription model - [Odyssey-v3.5](https://github.com/tronprotocol/java-tron/releases/tag/Odyssey-v3.5) | [16](https://github.com/tronprotocol/TIPs/blob/master/tip-16.md) | Account multi-signature/different permissions support - [Odyssey-v3.5](https://github.com/tronprotocol/java-tron/releases/tag/Odyssey-v3.5) | [17](https://github.com/tronprotocol/TIPs/blob/master/tip-17.md) | Adapative energy upper limit - [Odyssey-v3.5.1](https://github.com/tronprotocol/java-tron/releases/tag/Odyssey-v3.5.1) | [24](https://github.com/tronprotocol/TIPs/blob/master/tip-24.md) | RocksDB offered as storage engine - [Odyssey-v3.6.0](https://github.com/tronprotocol/java-tron/releases/tag/Odyssey-v3.6.0) | [26](https://github.com/tronprotocol/TIPs/blob/master/tip-26.md) |Add `create2` instruction to TVM - [Odyssey-v3.6.0](https://github.com/tronprotocol/java-tron/releases/tag/Odyssey-v3.6.0) | [28](https://github.com/tronprotocol/TIPs/blob/master/tip-28.md) | Built-in Message Queue in Event Subscription Model - [Odyssey-v3.6.0](https://github.com/tronprotocol/java-tron/releases/tag/Odyssey-v3.6.0) | [29](https://github.com/tronprotocol/TIPs/blob/master/tip-29.md) | Add bitwise shifting instructions to TVM - [Odyssey-v3.6.0](https://github.com/tronprotocol/java-tron/releases/tag/Odyssey-v3.6.0) | [30](https://github.com/tronprotocol/TIPs/blob/master/tip-30.md) | Add `extcodehash` instruction to TVM to return keccak256 hash of a contract's code - [Odyssey-v3.6.0](https://github.com/tronprotocol/java-tron/releases/tag/Odyssey-v3.6.0) | [31](https://github.com/tronprotocol/TIPs/blob/master/tip-31.md) | Add `triggerConstantContract` API to support contracts without ABI - [Odyssey-v3.6.0](https://github.com/tronprotocol/java-tron/releases/tag/Odyssey-v3.6.0) | [32](https://github.com/tronprotocol/TIPs/blob/master/tip-32.md) | Add `clearContractABI` API to clear existing ABI of contract - [Odyssey-v3.6.1](https://github.com/tronprotocol/java-tron/releases/tag/Odyssey-v3.6.1) | [41](https://github.com/tronprotocol/TIPs/blob/master/tip-41.md) | Optimize transactionHistoryStore occupancy space - [Odyssey-v3.6.5](https://github.com/tronprotocol/java-tron/releases/tag/Odyssey-v3.6.5) | [37](https://github.com/tronprotocol/TIPs/blob/master/tip-37.md) | Prohibit TransferContract & TransferAssetContract use for contract account - [Odyssey-v3.6.5](https://github.com/tronprotocol/java-tron/releases/tag/Odyssey-v3.6.5) | [43](https://github.com/tronprotocol/TIPs/blob/master/tip-43.md) | Add precompiled contract function `batchvalidatesign` to TVM that supports parallel signature verification - [Odyssey-v3.6.5](https://github.com/tronprotocol/java-tron/releases/tag/Odyssey-v3.6.5) | [44](https://github.com/tronprotocol/TIPs/blob/master/tip-44.md) | Add `ISCONTRACT` opcode - [Odyssey-v3.6.5](https://github.com/tronprotocol/java-tron/releases/tag/Odyssey-v3.6.5) | [53](https://github.com/tronprotocol/TIPs/blob/master/tip-53.md) | Optimize current TRON delegation mechanism - [Odyssey-v3.6.5](https://github.com/tronprotocol/java-tron/releases/tag/Odyssey-v3.6.5) | [54](https://github.com/tronprotocol/TIPs/blob/master/tip-54.md) | Automatic account activation when transferring TRX/TRC10 tokens in contracts - [Odyssey-v3.6.5](https://github.com/tronprotocol/java-tron/releases/tag/Odyssey-v3.6.5) | [60](https://github.com/tronprotocol/TIPs/blob/master/tip-60.md) | Add `validatemultisign` instruction to TVM to support multi-signature verification - [GreatVoyage-v4.0.0](https://github.com/tronprotocol/java-tron/releases/tag/GreatVoyage-v4.0.0) | [135](https://github.com/tronprotocol/TIPs/blob/master/tip-135.md) | Introduce shielded TRC-20 contract standards - [GreatVoyage-v4.0.0](https://github.com/tronprotocol/java-tron/releases/tag/GreatVoyage-v4.0.0) | [137](https://github.com/tronprotocol/TIPs/blob/master/tip-137.md) | Add ZKP verification functions to shielded TRC-20 contract - `verifyMintProof`, `verifyTransferProof`, and `verifyBurnProof` - [GreatVoyage-v4.0.0](https://github.com/tronprotocol/java-tron/releases/tag/GreatVoyage-v4.0.0) | [138](https://github.com/tronprotocol/TIPs/blob/master/tip-138.md) | Add Pedersen hash computation `pedersenHash` function to shielded TRC-20 contract - [GreatVoyage-v4.1.0](https://github.com/tronprotocol/java-tron/releases/tag/GreatVoyage-v4.1.0) | [127](https://github.com/tronprotocol/TIPs/blob/master/tip-127.md) | Add new system contracts to support token exchange (including TRX and TRC-10) - [GreatVoyage-v4.1.0](https://github.com/tronprotocol/java-tron/releases/tag/GreatVoyage-v4.1.0) | [128](https://github.com/tronprotocol/TIPs/blob/master/tip-128.md) | Add new node type: Lite Fullnode - [GreatVoyage-v4.1.0](https://github.com/tronprotocol/java-tron/releases/tag/GreatVoyage-v4.1.0) | [174](https://github.com/tronprotocol/TIPs/blob/master/tip-174.md) | Add `CHAINID` instruction to TVM - [GreatVoyage-v4.1.0](https://github.com/tronprotocol/java-tron/releases/tag/GreatVoyage-v4.1.0) | [175](https://github.com/tronprotocol/TIPs/blob/master/tip-175.md) | Add `SELFBALANCE` instruction to TVM - [GreatVoyage-v4.1.0](https://github.com/tronprotocol/java-tron/releases/tag/GreatVoyage-v4.1.0) | [176](https://github.com/tronprotocol/TIPs/blob/master/tip-176.md) | `altbn128`-related operation energy reduction in TVM - [GreatVoyage-v4.1.2](https://github.com/tronprotocol/java-tron/releases/tag/GreatVoyage-v4.1.2) | [196](https://github.com/tronprotocol/TIPs/blob/master/tip-196.md) | Reward SRs with tx fees - [GreatVoyage-v4.1.2](https://github.com/tronprotocol/java-tron/releases/tag/GreatVoyage-v4.1.2) | [204](https://github.com/tronprotocol/TIPs/blob/master/tip-204.md) | `MAX_FEE_LIMIT` is configurable - [GreatVoyage-v4.1.2](https://github.com/tronprotocol/java-tron/releases/tag/GreatVoyage-v4.1.2) | [209](https://github.com/tronprotocol/TIPs/blob/master/tip-209.md) | Adapt Solidity compilers to Solidity 0.6.0 - [GreatVoyage-v4.2.0(Plato)](https://github.com/tronprotocol/java-tron/releases/tag/GreatVoyage-v4.2.0) | [157](https://github.com/tronprotocol/TIPs/blob/master/tip-157.md) | Add freeze instructions to TVM - `FREEZE`, `UNFREEZE`, and `FREEZEEXPIRETIME` - [GreatVoyage-v4.2.0(Plato)](https://github.com/tronprotocol/java-tron/releases/tag/GreatVoyage-v4.2.0) | [207](https://github.com/tronprotocol/TIPs/blob/master/tip-207.md) | Optimize TRX freezing resource utilization - [GreatVoyage-v4.2.2(Lucretius)](https://github.com/tronprotocol/java-tron/releases/tag/GreatVoyage-v4.2.2) | [268](https://github.com/tronprotocol/TIPs/blob/master/tip-268.md) | ABI optimization - Move ABI out of SmartContract and store it in a new ABI store to reduce execution speeds of certain opcodes - [GreatVoyage-v4.2.2(Lucretius)](https://github.com/tronprotocol/java-tron/releases/tag/GreatVoyage-v4.2.2) | [269](https://github.com/tronprotocol/TIPs/blob/master/tip-269.md) | Optimize block processing speed - [GreatVoyage-v4.2.2(Lucretius)](https://github.com/tronprotocol/java-tron/releases/tag/GreatVoyage-v4.2.2) | [281](https://github.com/tronprotocol/TIPs/blob/master/tip-281.md) | Optimize database query performance - [GreatVoyage-v4.3.0(Bacon)](https://github.com/tronprotocol/java-tron/releases/tag/GreatVoyage-v4.3.0) | [271](https://github.com/tronprotocol/TIPs/blob/master/tip-271.md) | Add vote instructions and precompile contracts to TVM - [GreatVoyage-v4.3.0(Bacon)](https://github.com/tronprotocol/java-tron/releases/tag/GreatVoyage-v4.3.0) | [276](https://github.com/tronprotocol/TIPs/blob/master/tip-276.md) | Optimize block verification logic - [GreatVoyage-v4.3.0(Bacon)](https://github.com/tronprotocol/java-tron/releases/tag/GreatVoyage-v4.3.0) | [285](https://github.com/tronprotocol/TIPs/blob/master/tip-285.md) | Optimize node startup - [GreatVoyage-v4.3.0(Bacon)](https://github.com/tronprotocol/java-tron/releases/tag/GreatVoyage-v4.3.0) | [292](https://github.com/tronprotocol/TIPs/blob/master/tip-292.md) | Adjust account free net limit - [GreatVoyage-v4.3.0(Bacon)](https://github.com/tronprotocol/java-tron/releases/tag/GreatVoyage-v4.3.0) | [293](https://github.com/tronprotocol/TIPs/blob/master/tip-293.md) | Adjust total net limit - [GreatVoyage-v4.3.0(Bacon)](https://github.com/tronprotocol/java-tron/releases/tag/GreatVoyage-v4.3.0) | [295](https://github.com/tronprotocol/TIPs/blob/master/tip-295.md) | Optimize account data structure - [GreatVoyage-v4.3.0(Bacon)](https://github.com/tronprotocol/java-tron/releases/tag/GreatVoyage-v4.3.0) | [298](https://github.com/tronprotocol/TIPs/blob/master/tip-298.md) | Add new plugin to optimize levelDB performance startup - [GreatVoyage-v4.3.0(Bacon)](https://github.com/tronprotocol/java-tron/releases/tag/GreatVoyage-v4.3.0) | [306](https://github.com/tronprotocol/TIPs/blob/master/tip-306.md) | Add `Error` type in smart contract ABI - [GreatVoyage-v4.4.0(Rousseau)](https://github.com/tronprotocol/java-tron/releases/tag/GreatVoyage-v4.4.0) | [289](https://github.com/tronprotocol/TIPs/blob/master/tip-289.md) | Block broadcasting optimization - [GreatVoyage-v4.4.0(Rousseau)](https://github.com/tronprotocol/java-tron/releases/tag/GreatVoyage-v4.4.0) | [290](https://github.com/tronprotocol/TIPs/blob/master/tip-290.md) | Optimize dynamic database query performance - [GreatVoyage-v4.4.0(Rousseau)](https://github.com/tronprotocol/java-tron/releases/tag/GreatVoyage-v4.4.0) | [272](https://github.com/tronprotocol/TIPs/blob/master/tip-272.md) | TVM compatibility with EVM - [GreatVoyage-v4.4.0(Rousseau)](https://github.com/tronprotocol/java-tron/releases/tag/GreatVoyage-v4.4.0) | [318](https://github.com/tronprotocol/TIPs/blob/master/tip-318.md) | Adapt to Ethereum London Upgrade - [GreatVoyage-v4.4.2(Augustinus)](https://github.com/tronprotocol/java-tron/releases/tag/GreatVoyage-v4.4.2) | [343](https://github.com/tronprotocol/TIPs/blob/master/tip-343.md) | Optimize levelDB read performance - [GreatVoyage-v4.4.2(Augustinus)](https://github.com/tronprotocol/java-tron/releases/tag/GreatVoyage-v4.4.2) | [343](https://github.com/tronprotocol/TIPs/blob/master/tip-344.md) | Optimize TVM instruction execution - [GreatVoyage-v4.4.4(Plotinus)](https://github.com/tronprotocol/java-tron/releases/tag/GreatVoyage-v4.4.4) | [362](https://github.com/tronprotocol/TIPs/blob/master/tip-362.md) | Optimize node broadcast data caching - [GreatVoyage-v4.4.4(Plotinus)](https://github.com/tronprotocol/java-tron/releases/tag/GreatVoyage-v4.4.4) | [366](https://github.com/tronprotocol/TIPs/blob/master/tip-366.md) | Optimize node startup process - [GreatVoyage-v4.5.1(Tertullian)](https://github.com/tronprotocol/java-tron/releases/tag/GreatVoyage-v4.5.1) | [369](https://github.com/tronprotocol/TIPs/blob/master/tip-369.md) | Support prometheus (metrics interface) - [GreatVoyage-v4.5.1(Tertullian)](https://github.com/tronprotocol/java-tron/releases/tag/GreatVoyage-v4.5.1) | [370](https://github.com/tronprotocol/TIPs/blob/master/tip-370.md) | Support node conditionalized stop - [GreatVoyage-v4.5.1(Tertullian)](https://github.com/tronprotocol/java-tron/releases/tag/GreatVoyage-v4.5.1) | [382](https://github.com/tronprotocol/TIPs/blob/master/tip-382.md) | Optimize account assets data structure - [GreatVoyage-v4.5.1(Tertullian)](https://github.com/tronprotocol/java-tron/releases/tag/GreatVoyage-v4.5.1) | [383](https://github.com/tronprotocol/TIPs/blob/master/tip-383.md) | Optimize transaction cache loading - [GreatVoyage-v4.5.1(Tertullian)](https://github.com/tronprotocol/java-tron/releases/tag/GreatVoyage-v4.5.1) | [388](https://github.com/tronprotocol/TIPs/blob/master/tip-388.md) | Optimize light node synchronization logic - [GreatVoyage-v4.5.1(Tertullian)](https://github.com/tronprotocol/java-tron/releases/tag/GreatVoyage-v4.5.1) | [391](https://github.com/tronprotocol/TIPs/blob/master/tip-391.md) | Optimize block process and broadcasting logic - [GreatVoyage-v4.5.1(Tertullian)](https://github.com/tronprotocol/java-tron/releases/tag/GreatVoyage-v4.5.1) | [397](https://github.com/tronprotocol/TIPs/blob/master/tip-397.md) | Raise limit of the 13th network parameter - [GreatVoyage-v4.5.2(Aurelius)](https://github.com/tronprotocol/java-tron/releases/tag/GreatVoyage-v4.5.2) | [425](https://github.com/tronprotocol/TIPs/blob/master/tip-425.md) | Speed up TCP connection establishment. - [GreatVoyage-v4.5.2(Aurelius)](https://github.com/tronprotocol/java-tron/releases/tag/GreatVoyage-v4.5.2) | [440](https://github.com/tronprotocol/TIPs/blob/master/tip-440.md) | Optimize transaction cache - [GreatVoyage-v4.5.2(Aurelius)](https://github.com/tronprotocol/java-tron/releases/tag/GreatVoyage-v4.5.2) | [428](https://github.com/tronprotocol/TIPs/blob/master/tip-428.md) | Optimize lock competition in block processing - [GreatVoyage-v4.6.0(Socrates)](https://github.com/tronprotocol/java-tron/releases/tag/GreatVoyage-v4.6.0) | [461](https://github.com/tronprotocol/TIPs/blob/master/tip-461.md) | Upgrade checkpoint mechanism to V2 in database module - [GreatVoyage-v4.6.0(Socrates)](https://github.com/tronprotocol/java-tron/releases/tag/GreatVoyage-v4.6.0) | [476](https://github.com/tronprotocol/TIPs/blob/master/tip-476.md) | Optimize delegate data structure - [GreatVoyage-v4.6.0(Socrates)](https://github.com/tronprotocol/java-tron/releases/tag/GreatVoyage-v4.6.0) | [387](https://github.com/tronprotocol/TIPs/blob/master/tip-387.md) | Add transaction memo fee - [GreatVoyage-v4.6.0(Socrates)](https://github.com/tronprotocol/java-tron/releases/tag/GreatVoyage-v4.6.0) | [465](https://github.com/tronprotocol/TIPs/blob/master/tip-465.md) | Optimize reward calculation algorithm - - +| Upgrade | TIP | What it does | +| ----------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------ | +| [Odyssey-v3.5](https://github.com/tronprotocol/java-tron/releases/tag/Odyssey-v3.5) | [12](https://github.com/tronprotocol/TIPs/blob/master/tip-12.md) | Event subscription model | +| [Odyssey-v3.5](https://github.com/tronprotocol/java-tron/releases/tag/Odyssey-v3.5) | [16](https://github.com/tronprotocol/TIPs/blob/master/tip-16.md) | Account multi-signature/different permissions support | +| [Odyssey-v3.5](https://github.com/tronprotocol/java-tron/releases/tag/Odyssey-v3.5) | [17](https://github.com/tronprotocol/TIPs/blob/master/tip-17.md) | Adapative energy upper limit | +| [Odyssey-v3.5.1](https://github.com/tronprotocol/java-tron/releases/tag/Odyssey-v3.5.1) | [24](https://github.com/tronprotocol/TIPs/blob/master/tip-24.md) | RocksDB offered as storage engine | +| [Odyssey-v3.6.0](https://github.com/tronprotocol/java-tron/releases/tag/Odyssey-v3.6.0) | [26](https://github.com/tronprotocol/TIPs/blob/master/tip-26.md) | Add `create2` instruction to TVM | +| [Odyssey-v3.6.0](https://github.com/tronprotocol/java-tron/releases/tag/Odyssey-v3.6.0) | [28](https://github.com/tronprotocol/TIPs/blob/master/tip-28.md) | Built-in Message Queue in Event Subscription Model | +| [Odyssey-v3.6.0](https://github.com/tronprotocol/java-tron/releases/tag/Odyssey-v3.6.0) | [29](https://github.com/tronprotocol/TIPs/blob/master/tip-29.md) | Add bitwise shifting instructions to TVM | +| [Odyssey-v3.6.0](https://github.com/tronprotocol/java-tron/releases/tag/Odyssey-v3.6.0) | [30](https://github.com/tronprotocol/TIPs/blob/master/tip-30.md) | Add `extcodehash` instruction to TVM to return keccak256 hash of a contract's code | +| [Odyssey-v3.6.0](https://github.com/tronprotocol/java-tron/releases/tag/Odyssey-v3.6.0) | [31](https://github.com/tronprotocol/TIPs/blob/master/tip-31.md) | Add `triggerConstantContract` API to support contracts without ABI | +| [Odyssey-v3.6.0](https://github.com/tronprotocol/java-tron/releases/tag/Odyssey-v3.6.0) | [32](https://github.com/tronprotocol/TIPs/blob/master/tip-32.md) | Add `clearContractABI` API to clear existing ABI of contract | +| [Odyssey-v3.6.1](https://github.com/tronprotocol/java-tron/releases/tag/Odyssey-v3.6.1) | [41](https://github.com/tronprotocol/TIPs/blob/master/tip-41.md) | Optimize transactionHistoryStore occupancy space | +| [Odyssey-v3.6.5](https://github.com/tronprotocol/java-tron/releases/tag/Odyssey-v3.6.5) | [37](https://github.com/tronprotocol/TIPs/blob/master/tip-37.md) | Prohibit TransferContract & TransferAssetContract use for contract account | +| [Odyssey-v3.6.5](https://github.com/tronprotocol/java-tron/releases/tag/Odyssey-v3.6.5) | [43](https://github.com/tronprotocol/TIPs/blob/master/tip-43.md) | Add precompiled contract function `batchvalidatesign` to TVM that supports parallel signature verification | +| [Odyssey-v3.6.5](https://github.com/tronprotocol/java-tron/releases/tag/Odyssey-v3.6.5) | [44](https://github.com/tronprotocol/TIPs/blob/master/tip-44.md) | Add `ISCONTRACT` opcode | +| [Odyssey-v3.6.5](https://github.com/tronprotocol/java-tron/releases/tag/Odyssey-v3.6.5) | [53](https://github.com/tronprotocol/TIPs/blob/master/tip-53.md) | Optimize current TRON delegation mechanism | +| [Odyssey-v3.6.5](https://github.com/tronprotocol/java-tron/releases/tag/Odyssey-v3.6.5) | [54](https://github.com/tronprotocol/TIPs/blob/master/tip-54.md) | Automatic account activation when transferring TRX/TRC10 tokens in contracts | +| [Odyssey-v3.6.5](https://github.com/tronprotocol/java-tron/releases/tag/Odyssey-v3.6.5) | [60](https://github.com/tronprotocol/TIPs/blob/master/tip-60.md) | Add `validatemultisign` instruction to TVM to support multi-signature verification | +| [GreatVoyage-v4.0.0](https://github.com/tronprotocol/java-tron/releases/tag/GreatVoyage-v4.0.0) | [135](https://github.com/tronprotocol/TIPs/blob/master/tip-135.md) | Introduce shielded TRC-20 contract standards | +| [GreatVoyage-v4.0.0](https://github.com/tronprotocol/java-tron/releases/tag/GreatVoyage-v4.0.0) | [137](https://github.com/tronprotocol/TIPs/blob/master/tip-137.md) | Add ZKP verification functions to shielded TRC-20 contract - `verifyMintProof`, `verifyTransferProof`, and `verifyBurnProof` | +| [GreatVoyage-v4.0.0](https://github.com/tronprotocol/java-tron/releases/tag/GreatVoyage-v4.0.0) | [138](https://github.com/tronprotocol/TIPs/blob/master/tip-138.md) | Add Pedersen hash computation `pedersenHash` function to shielded TRC-20 contract | +| [GreatVoyage-v4.1.0](https://github.com/tronprotocol/java-tron/releases/tag/GreatVoyage-v4.1.0) | [127](https://github.com/tronprotocol/TIPs/blob/master/tip-127.md) | Add new system contracts to support token exchange (including TRX and TRC-10) | +| [GreatVoyage-v4.1.0](https://github.com/tronprotocol/java-tron/releases/tag/GreatVoyage-v4.1.0) | [128](https://github.com/tronprotocol/TIPs/blob/master/tip-128.md) | Add new node type: Lite Fullnode | +| [GreatVoyage-v4.1.0](https://github.com/tronprotocol/java-tron/releases/tag/GreatVoyage-v4.1.0) | [174](https://github.com/tronprotocol/TIPs/blob/master/tip-174.md) | Add `CHAINID` instruction to TVM | +| [GreatVoyage-v4.1.0](https://github.com/tronprotocol/java-tron/releases/tag/GreatVoyage-v4.1.0) | [175](https://github.com/tronprotocol/TIPs/blob/master/tip-175.md) | Add `SELFBALANCE` instruction to TVM | +| [GreatVoyage-v4.1.0](https://github.com/tronprotocol/java-tron/releases/tag/GreatVoyage-v4.1.0) | [176](https://github.com/tronprotocol/TIPs/blob/master/tip-176.md) | `altbn128`-related operation energy reduction in TVM | +| [GreatVoyage-v4.1.2](https://github.com/tronprotocol/java-tron/releases/tag/GreatVoyage-v4.1.2) | [196](https://github.com/tronprotocol/TIPs/blob/master/tip-196.md) | Reward SRs with tx fees | +| [GreatVoyage-v4.1.2](https://github.com/tronprotocol/java-tron/releases/tag/GreatVoyage-v4.1.2) | [204](https://github.com/tronprotocol/TIPs/blob/master/tip-204.md) | `MAX_FEE_LIMIT` is configurable | +| [GreatVoyage-v4.1.2](https://github.com/tronprotocol/java-tron/releases/tag/GreatVoyage-v4.1.2) | [209](https://github.com/tronprotocol/TIPs/blob/master/tip-209.md) | Adapt Solidity compilers to Solidity 0.6.0 | +| [GreatVoyage-v4.2.0(Plato)](https://github.com/tronprotocol/java-tron/releases/tag/GreatVoyage-v4.2.0) | [157](https://github.com/tronprotocol/TIPs/blob/master/tip-157.md) | Add freeze instructions to TVM - `FREEZE`, `UNFREEZE`, and `FREEZEEXPIRETIME` | +| [GreatVoyage-v4.2.0(Plato)](https://github.com/tronprotocol/java-tron/releases/tag/GreatVoyage-v4.2.0) | [207](https://github.com/tronprotocol/TIPs/blob/master/tip-207.md) | Optimize TRX freezing resource utilization | +| [GreatVoyage-v4.2.2(Lucretius)](https://github.com/tronprotocol/java-tron/releases/tag/GreatVoyage-v4.2.2) | [268](https://github.com/tronprotocol/TIPs/blob/master/tip-268.md) | ABI optimization - Move ABI out of SmartContract and store it in a new ABI store to reduce execution speeds of certain opcodes | +| [GreatVoyage-v4.2.2(Lucretius)](https://github.com/tronprotocol/java-tron/releases/tag/GreatVoyage-v4.2.2) | [269](https://github.com/tronprotocol/TIPs/blob/master/tip-269.md) | Optimize block processing speed | +| [GreatVoyage-v4.2.2(Lucretius)](https://github.com/tronprotocol/java-tron/releases/tag/GreatVoyage-v4.2.2) | [281](https://github.com/tronprotocol/TIPs/blob/master/tip-281.md) | Optimize database query performance | +| [GreatVoyage-v4.3.0(Bacon)](https://github.com/tronprotocol/java-tron/releases/tag/GreatVoyage-v4.3.0) | [271](https://github.com/tronprotocol/TIPs/blob/master/tip-271.md) | Add vote instructions and precompile contracts to TVM | +| [GreatVoyage-v4.3.0(Bacon)](https://github.com/tronprotocol/java-tron/releases/tag/GreatVoyage-v4.3.0) | [276](https://github.com/tronprotocol/TIPs/blob/master/tip-276.md) | Optimize block verification logic | +| [GreatVoyage-v4.3.0(Bacon)](https://github.com/tronprotocol/java-tron/releases/tag/GreatVoyage-v4.3.0) | [285](https://github.com/tronprotocol/TIPs/blob/master/tip-285.md) | Optimize node startup | +| [GreatVoyage-v4.3.0(Bacon)](https://github.com/tronprotocol/java-tron/releases/tag/GreatVoyage-v4.3.0) | [292](https://github.com/tronprotocol/TIPs/blob/master/tip-292.md) | Adjust account free net limit | +| [GreatVoyage-v4.3.0(Bacon)](https://github.com/tronprotocol/java-tron/releases/tag/GreatVoyage-v4.3.0) | [293](https://github.com/tronprotocol/TIPs/blob/master/tip-293.md) | Adjust total net limit | +| [GreatVoyage-v4.3.0(Bacon)](https://github.com/tronprotocol/java-tron/releases/tag/GreatVoyage-v4.3.0) | [295](https://github.com/tronprotocol/TIPs/blob/master/tip-295.md) | Optimize account data structure | +| [GreatVoyage-v4.3.0(Bacon)](https://github.com/tronprotocol/java-tron/releases/tag/GreatVoyage-v4.3.0) | [298](https://github.com/tronprotocol/TIPs/blob/master/tip-298.md) | Add new plugin to optimize levelDB performance startup | +| [GreatVoyage-v4.3.0(Bacon)](https://github.com/tronprotocol/java-tron/releases/tag/GreatVoyage-v4.3.0) | [306](https://github.com/tronprotocol/TIPs/blob/master/tip-306.md) | Add `Error` type in smart contract ABI | +| [GreatVoyage-v4.4.0(Rousseau)](https://github.com/tronprotocol/java-tron/releases/tag/GreatVoyage-v4.4.0) | [289](https://github.com/tronprotocol/TIPs/blob/master/tip-289.md) | Block broadcasting optimization | +| [GreatVoyage-v4.4.0(Rousseau)](https://github.com/tronprotocol/java-tron/releases/tag/GreatVoyage-v4.4.0) | [290](https://github.com/tronprotocol/TIPs/blob/master/tip-290.md) | Optimize dynamic database query performance | +| [GreatVoyage-v4.4.0(Rousseau)](https://github.com/tronprotocol/java-tron/releases/tag/GreatVoyage-v4.4.0) | [272](https://github.com/tronprotocol/TIPs/blob/master/tip-272.md) | TVM compatibility with EVM | +| [GreatVoyage-v4.4.0(Rousseau)](https://github.com/tronprotocol/java-tron/releases/tag/GreatVoyage-v4.4.0) | [318](https://github.com/tronprotocol/TIPs/blob/master/tip-318.md) | Adapt to Ethereum London Upgrade | +| [GreatVoyage-v4.4.2(Augustinus)](https://github.com/tronprotocol/java-tron/releases/tag/GreatVoyage-v4.4.2) | [343](https://github.com/tronprotocol/TIPs/blob/master/tip-343.md) | Optimize levelDB read performance | +| [GreatVoyage-v4.4.2(Augustinus)](https://github.com/tronprotocol/java-tron/releases/tag/GreatVoyage-v4.4.2) | [343](https://github.com/tronprotocol/TIPs/blob/master/tip-344.md) | Optimize TVM instruction execution | +| [GreatVoyage-v4.4.4(Plotinus)](https://github.com/tronprotocol/java-tron/releases/tag/GreatVoyage-v4.4.4) | [362](https://github.com/tronprotocol/TIPs/blob/master/tip-362.md) | Optimize node broadcast data caching | +| [GreatVoyage-v4.4.4(Plotinus)](https://github.com/tronprotocol/java-tron/releases/tag/GreatVoyage-v4.4.4) | [366](https://github.com/tronprotocol/TIPs/blob/master/tip-366.md) | Optimize node startup process | +| [GreatVoyage-v4.5.1(Tertullian)](https://github.com/tronprotocol/java-tron/releases/tag/GreatVoyage-v4.5.1) | [369](https://github.com/tronprotocol/TIPs/blob/master/tip-369.md) | Support prometheus (metrics interface) | +| [GreatVoyage-v4.5.1(Tertullian)](https://github.com/tronprotocol/java-tron/releases/tag/GreatVoyage-v4.5.1) | [370](https://github.com/tronprotocol/TIPs/blob/master/tip-370.md) | Support node conditionalized stop | +| [GreatVoyage-v4.5.1(Tertullian)](https://github.com/tronprotocol/java-tron/releases/tag/GreatVoyage-v4.5.1) | [382](https://github.com/tronprotocol/TIPs/blob/master/tip-382.md) | Optimize account assets data structure | +| [GreatVoyage-v4.5.1(Tertullian)](https://github.com/tronprotocol/java-tron/releases/tag/GreatVoyage-v4.5.1) | [383](https://github.com/tronprotocol/TIPs/blob/master/tip-383.md) | Optimize transaction cache loading | +| [GreatVoyage-v4.5.1(Tertullian)](https://github.com/tronprotocol/java-tron/releases/tag/GreatVoyage-v4.5.1) | [388](https://github.com/tronprotocol/TIPs/blob/master/tip-388.md) | Optimize light node synchronization logic | +| [GreatVoyage-v4.5.1(Tertullian)](https://github.com/tronprotocol/java-tron/releases/tag/GreatVoyage-v4.5.1) | [391](https://github.com/tronprotocol/TIPs/blob/master/tip-391.md) | Optimize block process and broadcasting logic | +| [GreatVoyage-v4.5.1(Tertullian)](https://github.com/tronprotocol/java-tron/releases/tag/GreatVoyage-v4.5.1) | [397](https://github.com/tronprotocol/TIPs/blob/master/tip-397.md) | Raise limit of the 13th network parameter | +| [GreatVoyage-v4.5.2(Aurelius)](https://github.com/tronprotocol/java-tron/releases/tag/GreatVoyage-v4.5.2) | [425](https://github.com/tronprotocol/TIPs/blob/master/tip-425.md) | Speed up TCP connection establishment. | +| [GreatVoyage-v4.5.2(Aurelius)](https://github.com/tronprotocol/java-tron/releases/tag/GreatVoyage-v4.5.2) | [440](https://github.com/tronprotocol/TIPs/blob/master/tip-440.md) | Optimize transaction cache | +| [GreatVoyage-v4.5.2(Aurelius)](https://github.com/tronprotocol/java-tron/releases/tag/GreatVoyage-v4.5.2) | [428](https://github.com/tronprotocol/TIPs/blob/master/tip-428.md) | Optimize lock competition in block processing | +| [GreatVoyage-v4.6.0(Socrates)](https://github.com/tronprotocol/java-tron/releases/tag/GreatVoyage-v4.6.0) | [461](https://github.com/tronprotocol/TIPs/blob/master/tip-461.md) | Upgrade checkpoint mechanism to V2 in database module | +| [GreatVoyage-v4.6.0(Socrates)](https://github.com/tronprotocol/java-tron/releases/tag/GreatVoyage-v4.6.0) | [476](https://github.com/tronprotocol/TIPs/blob/master/tip-476.md) | Optimize delegate data structure | +| [GreatVoyage-v4.6.0(Socrates)](https://github.com/tronprotocol/java-tron/releases/tag/GreatVoyage-v4.6.0) | [387](https://github.com/tronprotocol/TIPs/blob/master/tip-387.md) | Add transaction memo fee | +| [GreatVoyage-v4.6.0(Socrates)](https://github.com/tronprotocol/java-tron/releases/tag/GreatVoyage-v4.6.0) | [465](https://github.com/tronprotocol/TIPs/blob/master/tip-465.md) | Optimize reward calculation algorithm | diff --git a/learn_evm/tracing.md b/learn_evm/tracing.md index c97ad41a..0044884c 100644 --- a/learn_evm/tracing.md +++ b/learn_evm/tracing.md @@ -1,4 +1,3 @@ - # Tracing Utils ## Transaction Tracing @@ -43,7 +42,7 @@ The output of the above features a list of opcode executions, a snippet of which ``` { "structLogs": [ - ..., + ..., { "index": 191, "pc": 3645, @@ -75,7 +74,7 @@ The output of the above features a list of opcode executions, a snippet of which "7d7d4dc7c32ad4c905ab39fc25c4323c4a85e4b1b17a396514e6b88ee8b814e8": "00000000000000000000000000000000000000000000014af3e50252dfc40000" } }, - ..., + ..., ], "gas": 34718, "failed": false, @@ -84,14 +83,15 @@ The output of the above features a list of opcode executions, a snippet of which ``` An overview of the fields for opcode execution trace: + - `index`: The index we added, indicates that the above opcode was the 191st one executed. Helpful for staying oriented as you jump around the trace. - `pc`: program counter eg this opcode exists at index `3645` of the contract bytecode. You'll notice that `pc` increments by one for many common opcodes, by more than one for PUSH opcodes, and is reset entirely by JUMP/JUMP opcodes. - `op`: name of the opcode, because most of the actual data is hex-encoded, using grep or ctrl-f to search through the trace for opcode names is an effective strategy. -- `gas`: remaining gas *before* the opcode is executed +- `gas`: remaining gas _before_ the opcode is executed - `gasCost`: cost of this operation, for CALL & similar opcodes, this cost takes into account all gas spent by the child execution frame. - `depth`: each call creates a new child execution frame & this variable tracks how many sub-frames exist. Generally, CALL opcodes increase the depth and RETURN opcodes decrease it. -- `stack`: a snapshot of the entire stack *before* the opcode executes -- `memory`: a snapshot of the entire memory *before* the opcode executes +- `stack`: a snapshot of the entire stack _before_ the opcode executes +- `memory`: a snapshot of the entire memory _before_ the opcode executes - `storage`: an accumulation of all state changes made during the execution of the transaction being traced One big challenge of navigating such a transaction trace is matching opcode executions to higher-level solidity code. An effective first step is to identify uncommon opcodes which correspond to easily identified logic of the source code. Generally, expensive operations are relatively uncommon so SLOAD and SSTORE are good ones to scan for first and match against places where state variables are being read or written in solidity. Alternatively, CALL and related opcodes are relatively uncommon and can be matched with calls to other contracts in the source code. diff --git a/learn_evm/yellow-paper.md b/learn_evm/yellow-paper.md index 07287875..13a3db08 100644 --- a/learn_evm/yellow-paper.md +++ b/learn_evm/yellow-paper.md @@ -1,9 +1,8 @@ - # Ethereum Yellow Paper So, you want to read the yellow paper. Before we dive in, keep in mind that the yellow paper is out of date and some in the community might refer to it as being depreciated. Check out the [BRANCHES.md](https://github.com/ethereum/yellowpaper/blob/master/BRANCHES.md) file of the [`yellowpaper` repository on github](https://github.com/ethereum/yellowpaper) to stay up-to-date on how closely this document tracks the latest version of the Ethereum protocol. At the time of writing, the yellow paper is up to date with the Berlin hardfork which occurred in April 2021. For an overview of all Ethereum forks and which EIPs are included in each of them, see the [EIPs Forks](./eips_forks.md) page. -For a more up-to-date reference, check out the [Ethereum Specification](https://ethereum.github.io/execution-specs/autoapi/ethereum/) which features a detailed description of each opcode *for each hardfork* in addition to reference implementations written in python. +For a more up-to-date reference, check out the [Ethereum Specification](https://ethereum.github.io/execution-specs/autoapi/ethereum/) which features a detailed description of each opcode _for each hardfork_ in addition to reference implementations written in python. That said, the yellow paper is still a rich resource for ramping up on the fundamentals of the Ethereum protocol. This document aims to provide some guidance and assistance in deciphering Ethereum's flagship specification. @@ -11,35 +10,35 @@ That said, the yellow paper is still a rich resource for ramping up on the funda One challenging part of the yellow paper, for those of us who are not so well trained in formal mathematics, is comprehending the mathematical symbols. A cheat-sheet of some of these symbols is provided below - - `∃`: there exists - - `∀`: for all - - `∧`: and - - `∨`: or +- `∃`: there exists +- `∀`: for all +- `∧`: and +- `∨`: or And some more Ethereum-specific symbols: - - `N_{H}`: 1,150,000 aka block number at which the protocol was upgraded from homestead to frontier. - - `T`: a transaction eg `T = { n: nonce, p: gasPrice, g: gasLimit, t: to, v: value, i: initBytecode, d: data }` - - `S()`: returns the sender of a transaction eg `S(T) = T.from` - - `Λ`: (lambda) account creation function - - `KEC`: Keccak SHA-3 hash function - - `RLP`: Recursive Length Prefix encoding +- `N_{H}`: 1,150,000 aka block number at which the protocol was upgraded from homestead to frontier. +- `T`: a transaction eg `T = { n: nonce, p: gasPrice, g: gasLimit, t: to, v: value, i: initBytecode, d: data }` +- `S()`: returns the sender of a transaction eg `S(T) = T.from` +- `Λ`: (lambda) account creation function +- `KEC`: Keccak SHA-3 hash function +- `RLP`: Recursive Length Prefix encoding ## High-level glossary The following are symbols and function representations that provide a high-level description of ethereum. Many of these symbols represent a data structure, the details of which are described in subsequent sections. - - `σ`: ethereum world state - - `B`: block - - `μ`: EVM state - - `A`: accumulated transaction sub-state - - `I`: execution environment - - `o`: output of `H(μ,I)` ie null if we're good to go or a set of data if execution should halt - - `Υ(σ,T) => σ'`: the transaction-level state transition function - - `Π(σ,B) => σ'`: the block-level state transition function, processes all transactions then finalizes with Ω - - `Ω(B,σ) => σ`: block-finalisation state transition function - - `O(σ,μ,A,I)`: one iteration of the execution cycle - - `H(μ,I) => o`: outputs null while execution should continue or a series if execution should halt. +- `σ`: ethereum world state +- `B`: block +- `μ`: EVM state +- `A`: accumulated transaction sub-state +- `I`: execution environment +- `o`: output of `H(μ,I)` ie null if we're good to go or a set of data if execution should halt +- `Υ(σ,T) => σ'`: the transaction-level state transition function +- `Π(σ,B) => σ'`: the block-level state transition function, processes all transactions then finalizes with Ω +- `Ω(B,σ) => σ`: block-finalisation state transition function +- `O(σ,μ,A,I)`: one iteration of the execution cycle +- `H(μ,I) => o`: outputs null while execution should continue or a series if execution should halt. ## Ethereum World-State: σ diff --git a/not-so-smart-contracts/README.md b/not-so-smart-contracts/README.md index 6ee372d0..c70b6c16 100644 --- a/not-so-smart-contracts/README.md +++ b/not-so-smart-contracts/README.md @@ -6,4 +6,4 @@ This repository contains examples of common smart contract vulnerabilities, incl - [Cairo](./cairo/README.md) - [Cosmos](./cosmos/README.md) - [Solana](./solana/README.md) -- [Substrate](./substrate/README.md) \ No newline at end of file +- [Substrate](./substrate/README.md) diff --git a/not-so-smart-contracts/algorand/README.md b/not-so-smart-contracts/algorand/README.md index ac99e298..19219b06 100644 --- a/not-so-smart-contracts/algorand/README.md +++ b/not-so-smart-contracts/algorand/README.md @@ -6,25 +6,25 @@ This repository contains examples of common Algorand smart contract vulnerabilit Each _Not So Smart Contract_ includes a standard set of information: -* Description of the vulnerability type -* Attack scenarios to exploit the vulnerability -* Recommendations to eliminate or mitigate the vulnerability -* Real-world contracts that exhibit the flaw -* References to third-party resources with more information +- Description of the vulnerability type +- Attack scenarios to exploit the vulnerability +- Recommendations to eliminate or mitigate the vulnerability +- Real-world contracts that exhibit the flaw +- References to third-party resources with more information ## Vulnerabilities -| Not So Smart Contract | Description | Applicable to smart signatures | Applicable to smart contracts | -| --- | --- | --- | --- | -| [Rekeying](rekeying) | Attacker rekeys an account | yes | yes | -| [Unchecked Transaction Fees](unchecked_transaction_fee) | Attacker sets excessive fees for smart signature transactions | yes | no | -| [Closing Account](closing_account) | Attacker closes smart signature accounts | yes | no | -| [Closing Asset](closing_asset) | Attacker transfers entire asset balance of a smart signature | yes | no | -| [Group Size Check](group_size_check) | Contract does not check transaction group size | yes | yes | -| [Time-based Replay Attack](time_based_replay_attack) | Contract does not use lease for periodic payments | yes | no | -| [Access Controls](access_controls) | Contract does not enfore access controls for updating and deleting application | no | yes | -| [Asset Id Check](asset_id_check) | Contract does not check asset id for asset transfer operations | yes | yes | -| [Denial of Service](denial_of_service) | Attacker stalls contract execution by opting out of a asset | yes | yes | +| Not So Smart Contract | Description | Applicable to smart signatures | Applicable to smart contracts | +| ------------------------------------------------------- | ------------------------------------------------------------------------------ | ------------------------------ | ----------------------------- | +| [Rekeying](rekeying) | Attacker rekeys an account | yes | yes | +| [Unchecked Transaction Fees](unchecked_transaction_fee) | Attacker sets excessive fees for smart signature transactions | yes | no | +| [Closing Account](closing_account) | Attacker closes smart signature accounts | yes | no | +| [Closing Asset](closing_asset) | Attacker transfers entire asset balance of a smart signature | yes | no | +| [Group Size Check](group_size_check) | Contract does not check transaction group size | yes | yes | +| [Time-based Replay Attack](time_based_replay_attack) | Contract does not use lease for periodic payments | yes | no | +| [Access Controls](access_controls) | Contract does not enfore access controls for updating and deleting application | no | yes | +| [Asset Id Check](asset_id_check) | Contract does not check asset id for asset transfer operations | yes | yes | +| [Denial of Service](denial_of_service) | Attacker stalls contract execution by opting out of a asset | yes | yes | ## Credits diff --git a/not-so-smart-contracts/algorand/access_controls/README.md b/not-so-smart-contracts/algorand/access_controls/README.md index ec5de682..f743d0aa 100644 --- a/not-so-smart-contracts/algorand/access_controls/README.md +++ b/not-so-smart-contracts/algorand/access_controls/README.md @@ -4,7 +4,7 @@ Lack of appropriate checks for application calls of type UpdateApplication and D ## Description -When an application call is successful, additional operations are executed based on the OnComplete field. If the OnComplete field is set to UpdateApplication the approval and clear programs of the application are replaced with the programs specified in the transaction. Similarly, if the OnComplete field is set to DeleteApplication, application parameters are deleted. +When an application call is successful, additional operations are executed based on the OnComplete field. If the OnComplete field is set to UpdateApplication the approval and clear programs of the application are replaced with the programs specified in the transaction. Similarly, if the OnComplete field is set to DeleteApplication, application parameters are deleted. This allows attackers to update or delete the application if proper access controls are not enforced in the application. ## Exploit Scenarios diff --git a/not-so-smart-contracts/algorand/denial_of_service/README.md b/not-so-smart-contracts/algorand/denial_of_service/README.md index cb8e2737..c1456e2c 100644 --- a/not-so-smart-contracts/algorand/denial_of_service/README.md +++ b/not-so-smart-contracts/algorand/denial_of_service/README.md @@ -1,10 +1,10 @@ # Denial of Service -When a contract does not verify whether an account has opted in to an asset and attempts to transfer that asset, an attacker can DoS other users if the contract's operation is to transfer asset to multiple accounts. +When a contract does not verify whether an account has opted in to an asset and attempts to transfer that asset, an attacker can DoS other users if the contract's operation is to transfer asset to multiple accounts. ## Description -A user must explicitly opt-in to receive any particular Algorand Standard Asset(ASAs). A user may also opt out of an ASA. A transaction will fail if it attempts to transfer tokens to an account that didn’t opt in to that asset. This could be leveraged by attackers to DOS a contract if the contract’s operation depends on successful transfer of an asset to the attacker owned address. +A user must explicitly opt-in to receive any particular Algorand Standard Asset(ASAs). A user may also opt out of an ASA. A transaction will fail if it attempts to transfer tokens to an account that didn’t opt in to that asset. This could be leveraged by attackers to DOS a contract if the contract’s operation depends on successful transfer of an asset to the attacker owned address. ## Exploit Scenarios diff --git a/not-so-smart-contracts/algorand/rekeying/README.md b/not-so-smart-contracts/algorand/rekeying/README.md index bead6296..d1da6d93 100644 --- a/not-so-smart-contracts/algorand/rekeying/README.md +++ b/not-so-smart-contracts/algorand/rekeying/README.md @@ -14,6 +14,7 @@ Contract accounts are accounts which are derived from the Teal code that is in c Similar issue affects the accounts that created a delegate signature by signing a Teal program. Delegator is only needed to sign the contract and any user with access to delegate signature can construct and submit transactions. Because of this, a malicious user can rekey the sender’s account if the Teal logic accepts a transaction with the rekey-to field set to the user controlled address. Note: From Teal v6, Applications can also be rekeyed by executing an inner transaction with "RekeyTo" field set to a non-zero address. Rekeying an application allows to bypass the application logic and directly transfer Algos and assets of the application account. + ## Exploit Scenarios A user creates a delegate signature for recurring payments. Attacker rekeys the sender’s account by specifying the rekey-to field in a valid payment transaction. @@ -41,6 +42,7 @@ def withdraw( ``` ## Recommendations + - For the Teal programs written in Teal version 2 or greater, either used as delegate signature or contract account, include a check in the program that verifies rekey-to field to be equal to ZeroAddress or any intended address. Teal contracts written in Teal version 1 are not affected by this issue. Rekeying feature is introduced in version 2 and Algorand rejects transactions that use features introduced in the versions later than the executed Teal program version. - Use [Tealer](https://github.com/crytic/tealer) to detect this issue. diff --git a/not-so-smart-contracts/algorand/time_based_replay_attack/README.md b/not-so-smart-contracts/algorand/time_based_replay_attack/README.md index 97796870..3c19b693 100644 --- a/not-so-smart-contracts/algorand/time_based_replay_attack/README.md +++ b/not-so-smart-contracts/algorand/time_based_replay_attack/README.md @@ -1,6 +1,6 @@ # Time-based Replay Attack -Lack of check for lease field in smart signatures that intend to approve a single transaction in the particular period allows attackers to submit multiple valid transactions in that period. +Lack of check for lease field in smart signatures that intend to approve a single transaction in the particular period allows attackers to submit multiple valid transactions in that period. ## Description diff --git a/not-so-smart-contracts/algorand/unchecked_transaction_fee/README.md b/not-so-smart-contracts/algorand/unchecked_transaction_fee/README.md index bbb4de85..c3d3b7dc 100644 --- a/not-so-smart-contracts/algorand/unchecked_transaction_fee/README.md +++ b/not-so-smart-contracts/algorand/unchecked_transaction_fee/README.md @@ -36,4 +36,4 @@ def withdraw( ## Recommendations -- Force the transaction fee to be `0` and use fee pooling. If the users should be able to call the smart signature outside of a group, force the transaction fee to be minimum transaction fee: `global MinTxnFee`. +- Force the transaction fee to be `0` and use fee pooling. If the users should be able to call the smart signature outside of a group, force the transaction fee to be minimum transaction fee: `global MinTxnFee`. diff --git a/not-so-smart-contracts/cairo/L1_to_L2_address_conversion/README.md b/not-so-smart-contracts/cairo/L1_to_L2_address_conversion/README.md index bbc467df..4af26af6 100644 --- a/not-so-smart-contracts/cairo/L1_to_L2_address_conversion/README.md +++ b/not-so-smart-contracts/cairo/L1_to_L2_address_conversion/README.md @@ -6,8 +6,8 @@ In Starknet, addresses are of type `felt` while on L1 addresses are of type `uin Suppose that the following code to initiate L2 deposits from L1. The first example has no checks on the `to` parameter and thus depending on the users' address, it is possible to transfer tokens to an unexpected address on L2. The second example, however, verifies to make sure this check cannot happen. Note that the code is just a simplification of how messages are sent on L1 and processed on L2. For a more thorough overview, see here: https://www.cairo-lang.org/docs/hello_starknet/l1l2.html. -```solidity -uint256 public constant STARKNET_FIELD_PRIME; // the prime order P of the elliptic curve used +```solidity +uint256 public constant STARKNET_FIELD_PRIME; // the prime order P of the elliptic curve used IERC20 public constant token; //some token to deposit on L2 event Deposited(uint256 sender, uint256 amount); @@ -18,7 +18,7 @@ function badDepositToL2(uint256 to, uint256 amount) public returns (bool) { } function betterDepositToL2(uint256 to, uint256 amount) public returns (bool) { - require(to !=0 && to < STARKNET_FIELD_PRIME, "invalid address"); //verifies 0 < to < P + require(to !=0 && to < STARKNET_FIELD_PRIME, "invalid address"); //verifies 0 < to < P token.transferFrom(to, address(this),amount); emit Deposited(to,amount); // this message gets processed on L2 return true; @@ -27,4 +27,4 @@ function betterDepositToL2(uint256 to, uint256 amount) public returns (bool) { # Mitigations -When sending a message from L1 to L2, remember to verify parameters, especially user supplied params. Remember that the type and range of Cairo's default `felt` type is less than the `uint256` type used by Solidity. \ No newline at end of file +When sending a message from L1 to L2, remember to verify parameters, especially user supplied params. Remember that the type and range of Cairo's default `felt` type is less than the `uint256` type used by Solidity. diff --git a/not-so-smart-contracts/cairo/README.md b/not-so-smart-contracts/cairo/README.md index f253abcf..c0cd5627 100644 --- a/not-so-smart-contracts/cairo/README.md +++ b/not-so-smart-contracts/cairo/README.md @@ -6,25 +6,25 @@ This repository contains examples of common Cairo smart contract vulnerabilities Each _Not So Smart Contract_ includes a standard set of information: -* Description of the vulnerability type -* Attack scenarios to exploit the vulnerability -* Recommendations to eliminate or mitigate the vulnerability -* Real-world contracts that exhibit the flaw -* References to third-party resources with more information +- Description of the vulnerability type +- Attack scenarios to exploit the vulnerability +- Recommendations to eliminate or mitigate the vulnerability +- Real-world contracts that exhibit the flaw +- References to third-party resources with more information ## Vulnerabilities -| Not So Smart Contract | Description | -| --- | --- | -| [Improper access controls](access_controls) | Broken access controls due to StarkNet account abstraction | -| [Integer division errors](integer_division) | Unexpected results due to division in a finite field | -| [View state modifications](view_state) | View functions don't prevent state modifications | -| [Arithmetic overflow](arithmetic_overflow) | Arithmetic in Cairo is not safe by default | -| [Signature replays](replay_protection) | Account abstraction requires robust reuse protections | -| [L1 to L2 Address Conversion](L1_to_L2_address_conversion) | L1 to L2 messaging requires L2 address checks | -| [Incorrect Felt Comparison](incorrect_felt_comparison) | Unexpected results can occur during felt comparison | -| [Namespace Storage Var Collision](namespace_storage_var_collision) | Storage variables are not scoped by namespaces | -| [Dangerous Public Imports in Libraries](dangerous_public_imports_in_libraries) | Nonimported external functions can still be called | +| Not So Smart Contract | Description | +| ------------------------------------------------------------------------------ | ---------------------------------------------------------- | +| [Improper access controls](access_controls) | Broken access controls due to StarkNet account abstraction | +| [Integer division errors](integer_division) | Unexpected results due to division in a finite field | +| [View state modifications](view_state) | View functions don't prevent state modifications | +| [Arithmetic overflow](arithmetic_overflow) | Arithmetic in Cairo is not safe by default | +| [Signature replays](replay_protection) | Account abstraction requires robust reuse protections | +| [L1 to L2 Address Conversion](L1_to_L2_address_conversion) | L1 to L2 messaging requires L2 address checks | +| [Incorrect Felt Comparison](incorrect_felt_comparison) | Unexpected results can occur during felt comparison | +| [Namespace Storage Var Collision](namespace_storage_var_collision) | Storage variables are not scoped by namespaces | +| [Dangerous Public Imports in Libraries](dangerous_public_imports_in_libraries) | Nonimported external functions can still be called | ## Credits diff --git a/not-so-smart-contracts/cairo/access_controls/README.md b/not-so-smart-contracts/cairo/access_controls/README.md index 2ed04956..ffa092f9 100644 --- a/not-so-smart-contracts/cairo/access_controls/README.md +++ b/not-so-smart-contracts/cairo/access_controls/README.md @@ -1,4 +1,5 @@ # Access controls & account abstraction + NOTE: The following was possible before StarkNet OS enforced the use of an account contract. The account abstraction model used by StarkNet has some important differences from what Solidity developers might be used to. There are no EOA addresses in StarkNet, only contract addresses. Rather than interact with contracts directly, users will usually deploy a contract that authenticates them and makes further calls on the user's behalf. At its simplest, this contract checks that the transaction is signed by the expected key, but it could also represent a multisig or DAO, or have more complex logic for what kinds of transactions it will allow (e.g. deposits and withdrawals could be handled by separate contracts or it could prevent unprofitable trades). @@ -38,4 +39,4 @@ end ## External Examples -- An [issue](https://github.com/OpenZeppelin/cairo-contracts/issues/148) in the ERC721 implementation included in a pre-0.1.0 version of OpenZeppelin's Cairo contract library would have allowed unapproved users to transfer tokens. \ No newline at end of file +- An [issue](https://github.com/OpenZeppelin/cairo-contracts/issues/148) in the ERC721 implementation included in a pre-0.1.0 version of OpenZeppelin's Cairo contract library would have allowed unapproved users to transfer tokens. diff --git a/not-so-smart-contracts/cairo/arithmetic_overflow/README.md b/not-so-smart-contracts/cairo/arithmetic_overflow/README.md index be8b740d..71cfa23b 100644 --- a/not-so-smart-contracts/cairo/arithmetic_overflow/README.md +++ b/not-so-smart-contracts/cairo/arithmetic_overflow/README.md @@ -6,7 +6,6 @@ StarkNet also provides the Uint256 module which offers a more typical 256-bit in ## Attack Scenarios - ## Mitigations - Always add checks for overflow when working with felts or Uint256s directly. diff --git a/not-so-smart-contracts/cairo/consider_L1_to_L2_message_failure.md b/not-so-smart-contracts/cairo/consider_L1_to_L2_message_failure.md index d7b1f38c..47c228da 100644 --- a/not-so-smart-contracts/cairo/consider_L1_to_L2_message_failure.md +++ b/not-so-smart-contracts/cairo/consider_L1_to_L2_message_failure.md @@ -1,14 +1,14 @@ # Consider L1 to L2 message failure -In Starknet, [Ethereum contracts can send messages from L1 to L2, using a bridge](https://docs.starknet.io/documentation/architecture_and_concepts/L1-L2_Communication/messaging-mechanism/). However, it is not guaranteed that the message will be processed by the sequencer. -For instance, a message can fail to be processed if there is a sudden spike in the gas price and the value provided is too low. For that reason, Starknet developers provided a +In Starknet, [Ethereum contracts can send messages from L1 to L2, using a bridge](https://docs.starknet.io/documentation/architecture_and_concepts/L1-L2_Communication/messaging-mechanism/). However, it is not guaranteed that the message will be processed by the sequencer. +For instance, a message can fail to be processed if there is a sudden spike in the gas price and the value provided is too low. For that reason, Starknet developers provided a [API to cancel on-going messages](https://docs.starknet.io/documentation/architecture_and_concepts/L1-L2_Communication/messaging-mechanism/#l2-l1_message_cancellation) # Example Suppose that the following code to initiate L2 deposits from L1, taking the tokens from the user: -```solidity +```solidity IERC20 public constant token; //some token to deposit on L2 function depositToL2(uint256 to, uint256 amount) public returns (bool) { @@ -21,8 +21,8 @@ function depositToL2(uint256 to, uint256 amount) public returns (bool) { If a L1 message is never processed by the sequencer, users will never receive their tokens either in L1 or L2, so they need a way to cancel it. -As a more real example, a recent [AAVE audit](https://github.com/aave-starknet-project/aave-starknet-bridge/pull/106#issue-1336925381) highlighed this issue and required to add code to cancel messages. +As a more real example, a recent [AAVE audit](https://github.com/aave-starknet-project/aave-starknet-bridge/pull/106#issue-1336925381) highlighed this issue and required to add code to cancel messages. # Mitigations -When sending a message from L1 to L2, consider the case where a message is never processed by the sequencer. This can block either the contract to reach certain state or users to retrieve their funds. Allow to use `startL1ToL2MessageCancellation` and `cancelL1ToL2Message` to cancel ongoing messages, if needed. +When sending a message from L1 to L2, consider the case where a message is never processed by the sequencer. This can block either the contract to reach certain state or users to retrieve their funds. Allow to use `startL1ToL2MessageCancellation` and `cancelL1ToL2Message` to cancel ongoing messages, if needed. diff --git a/not-so-smart-contracts/cairo/dangerous_public_imports_in_libraries/README.md b/not-so-smart-contracts/cairo/dangerous_public_imports_in_libraries/README.md index c7923fbb..32f8a012 100644 --- a/not-so-smart-contracts/cairo/dangerous_public_imports_in_libraries/README.md +++ b/not-so-smart-contracts/cairo/dangerous_public_imports_in_libraries/README.md @@ -1,4 +1,5 @@ # Dangerous Public Imports in Libraries + NOTE: The following was possible until cairo-lang 0.10.0. When a library is imported in Cairo, all functions can be called even if some of them are not declared in the import statement. As a result, it is possible to call functions that a developer may think is unexposed, leading to unexpected behavior. @@ -53,6 +54,4 @@ end # Mitigations -Make sure to exercise caution when declaring external functions in a library. Recognize the possible state changes that can be made through the function and verify it is acceptable for anyone to call it. In addition, [Amarna](https://github.com/crytic/amarna) has a detector to uncover this issue. - - +Make sure to exercise caution when declaring external functions in a library. Recognize the possible state changes that can be made through the function and verify it is acceptable for anyone to call it. In addition, [Amarna](https://github.com/crytic/amarna) has a detector to uncover this issue. diff --git a/not-so-smart-contracts/cairo/incorrect_felt_comparison/README.md b/not-so-smart-contracts/cairo/incorrect_felt_comparison/README.md index b6824c78..202919cc 100644 --- a/not-so-smart-contracts/cairo/incorrect_felt_comparison/README.md +++ b/not-so-smart-contracts/cairo/incorrect_felt_comparison/README.md @@ -1,8 +1,9 @@ # Incorrect Felt Comparison In Cairo, there are two methods for the less than or equal to comparison operator: `assert_le` and `assert_nn_le`: + - `assert_le` asserts that a number `a` is less than or equal to `b`, regardless of the size of `a` -- `assert_nn_le` additionally asserts that `a` is [non-negative](https://github.com/starkware-libs/cairo-lang/blob/9889fbd522edc5eff603356e1912e20642ae20af/src/starkware/cairo/common/math.cairo#L71), i.e. not greater than or equal to the `RANGE_CHECK_BOUND` value of `2^128`. +- `assert_nn_le` additionally asserts that `a` is [non-negative](https://github.com/starkware-libs/cairo-lang/blob/9889fbd522edc5eff603356e1912e20642ae20af/src/starkware/cairo/common/math.cairo#L71), i.e. not greater than or equal to the `RANGE_CHECK_BOUND` value of `2^128`. `assert_nn_le` works to compare unsigned integers but with a value less than `2^128` (e.g. an [Uint256](https://github.com/starkware-libs/cairo-lang/blob/9889fbd522edc5eff603356e1912e20642ae20af/src/starkware/cairo/common/uint256.cairo#L9-L14) field). To compare felts as unsigned integer over the entire range (0, P], `assert_le_felt` should be used. Note these functions exist also with the `is_` prefix where they return 1 (TRUE) or 0 (FALSE). @@ -36,13 +37,12 @@ func better_comparison{syscall_ptr : felt*, pedersen_ptr : HashBuiltin*, range_c return (); - + } ``` - - # Mitigations -- Review all felt comparisons closely. -- Determine what sort of behavior the comparison should have, and if `assert_nn_le` or `assert_le_felt` is more appropriate. + +- Review all felt comparisons closely. +- Determine what sort of behavior the comparison should have, and if `assert_nn_le` or `assert_le_felt` is more appropriate. - Use `assert_le` if you explicitly want to make comparison between signed integers - otherwise explicitely document why it is used over `assert_nn_le` diff --git a/not-so-smart-contracts/cairo/integer_division/README.md b/not-so-smart-contracts/cairo/integer_division/README.md index 143b94c9..cb0b8834 100644 --- a/not-so-smart-contracts/cairo/integer_division/README.md +++ b/not-so-smart-contracts/cairo/integer_division/README.md @@ -1,10 +1,10 @@ # Integer Division -Math in Cairo is done in a finite field, which is why the numeric type is called `felt`, for field elements. In most cases addition, subtraction and multiplication will behave as they would in standard integer operations when writing Cairo code. However, developers need to pay a little bit extra attention when performing division. Unlike in Solidity, where division is carried out as if the values were real numbers and anything after the decimal place is truncated, in Cairo it's more intuitive to think of division as the inverse of multiplication. When a number divides a whole number of times into another number, the result is what we would expect, for example 30/6=5. But if we try to divide numbers that don't quite match up so perfectly, like 30/9, the result can be a bit surprising, in this case 1206167596222043737899107594365023368541035738443865566657697352045290673497. That's because 120...97 * 9 = 30 (modulo the [252-bit prime used by StarkNet](https://docs.starkware.co/starkex-v4/crypto/stark-curve)) +Math in Cairo is done in a finite field, which is why the numeric type is called `felt`, for field elements. In most cases addition, subtraction and multiplication will behave as they would in standard integer operations when writing Cairo code. However, developers need to pay a little bit extra attention when performing division. Unlike in Solidity, where division is carried out as if the values were real numbers and anything after the decimal place is truncated, in Cairo it's more intuitive to think of division as the inverse of multiplication. When a number divides a whole number of times into another number, the result is what we would expect, for example 30/6=5. But if we try to divide numbers that don't quite match up so perfectly, like 30/9, the result can be a bit surprising, in this case 1206167596222043737899107594365023368541035738443865566657697352045290673497. That's because 120...97 \* 9 = 30 (modulo the [252-bit prime used by StarkNet](https://docs.starkware.co/starkex-v4/crypto/stark-curve)) ## Example -Consider the following functions that normalize a user's token balance to a human readable value for a token with 10^18 decimals. In the first function, it will only provide meaningful values if a user has a whole number of tokens and return non-sense values in every other case. The better version stores these values as Uint256s and uses more traditional integer division. +Consider the following functions that normalize a user's token balance to a human readable value for a token with 10^18 decimals. In the first function, it will only provide meaningful values if a user has a whole number of tokens and return non-sense values in every other case. The better version stores these values as Uint256s and uses more traditional integer division. ```cairo @external @@ -36,4 +36,4 @@ func better_normalize_tokens{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, ran - Review which numeric type is most appropriate for your use case. Especially if your programs rely on division, consider using [the uint256 module](https://github.com/starkware-libs/cairo-lang/blob/master/src/starkware/cairo/common/uint256.cairo) instead of the felt primitive type. -## External Examples \ No newline at end of file +## External Examples diff --git a/not-so-smart-contracts/cairo/namespace_storage_var_collision/README.md b/not-so-smart-contracts/cairo/namespace_storage_var_collision/README.md index 382d5a85..736d6ee7 100644 --- a/not-so-smart-contracts/cairo/namespace_storage_var_collision/README.md +++ b/not-so-smart-contracts/cairo/namespace_storage_var_collision/README.md @@ -1,11 +1,12 @@ # Namespace Storage Variable Collsion + NOTE: The following was possible until cairo-lang 0.10.0. In Cairo, it is possible to use namespaces to scope functions under an identifier. However, storage variables are not scoped by these namespaces. If a developer accidentally uses the same variable name in two different namespaces, it could lead to a storage collision. -# Example +# Example -The following example has been copied from [here](https://gist.github.com/koloz193/18cb491167e844e9a28ac69825f68975). Suppose we have two different namespaces `A` and `B`, both with the same `balance` storage variable. In addition, both namespaces have respective functions `increase_balance()` and `get_balance()` to increment the storage variable and retrieve it respectively. When either `increase_balance_a` or `increase_balance_b()` is called, the expected behavior would be to have two seperate storage variables have their balance increased respectively. However, because storage variables are not scoped by namespaces, there will be one `balance` variable updated twice: +The following example has been copied from [here](https://gist.github.com/koloz193/18cb491167e844e9a28ac69825f68975). Suppose we have two different namespaces `A` and `B`, both with the same `balance` storage variable. In addition, both namespaces have respective functions `increase_balance()` and `get_balance()` to increment the storage variable and retrieve it respectively. When either `increase_balance_a` or `increase_balance_b()` is called, the expected behavior would be to have two seperate storage variables have their balance increased respectively. However, because storage variables are not scoped by namespaces, there will be one `balance` variable updated twice: ```cairo %lang starknet diff --git a/not-so-smart-contracts/cairo/replay_protection/README.md b/not-so-smart-contracts/cairo/replay_protection/README.md index dd6f6b52..b050bae2 100644 --- a/not-so-smart-contracts/cairo/replay_protection/README.md +++ b/not-so-smart-contracts/cairo/replay_protection/README.md @@ -15,4 +15,3 @@ Consider the following function that validates a signature for EIP712-style perm - Consider using the [OpenZeppelin Contracts for Cairo Account contract](https://github.com/OpenZeppelin/cairo-contracts/blob/main/docs/modules/ROOT/pages/accounts.adoc) or another existing account contract implementation. ## External Examples - diff --git a/not-so-smart-contracts/cairo/view_state/README.md b/not-so-smart-contracts/cairo/view_state/README.md index 75236787..3b1c15ed 100644 --- a/not-so-smart-contracts/cairo/view_state/README.md +++ b/not-so-smart-contracts/cairo/view_state/README.md @@ -4,7 +4,7 @@ StarkNet provides the @view decorator to signal that a function should not make ## Example -Consider the following function that's declared as a `@view`. It may have originally been intended as an actual view function but was later repurposed to fetch a nonce _and also increment it in the process_ to ensure a nonce is never repeated when building a signature. +Consider the following function that's declared as a `@view`. It may have originally been intended as an actual view function but was later repurposed to fetch a nonce _and also increment it in the process_ to ensure a nonce is never repeated when building a signature. ```cairo @view diff --git a/not-so-smart-contracts/cosmos/README.md b/not-so-smart-contracts/cosmos/README.md index 2f8e0392..1f8cad44 100644 --- a/not-so-smart-contracts/cosmos/README.md +++ b/not-so-smart-contracts/cosmos/README.md @@ -6,25 +6,26 @@ This repository contains examples of common Cosmos applications vulnerabilities, Each _Not So Smart Cosmos_ includes a standard set of information: -* Description of the vulnerability type -* Attack scenarios to exploit the vulnerability -* Recommendations to eliminate or mitigate the vulnerability -* Real-world contracts that exhibit the flaw -* References to third-party resources with more information +- Description of the vulnerability type +- Attack scenarios to exploit the vulnerability +- Recommendations to eliminate or mitigate the vulnerability +- Real-world contracts that exhibit the flaw +- References to third-party resources with more information ## Vulnerabilities -| Not So Smart Contract | Description | -| --- | --- | -| [Incorrect signers](incorrect_getsigners) | Broken access controls due to incorrect signers validation | -| [Non-determinism](non_determinism) | Consensus failure because of non-determinism | -| [Not prioritized messages](messages_priority) | Risks arising from usage of not prioritized message types | -| [Slow ABCI methods](abci_fast) | Consensus failure because of slow ABCI methods | -| [ABCI methods panic](abci_panic) | Chain halt due to panics in ABCI methods | -| [Broken bookkeeping](broken_bookkeeping) | Exploit mismatch between different modules' views on balances | -| [Rounding errors](rounding_errors) | Bugs related to imprecision of finite precision arithmetic | -| [Unregistered message handler](unregistered_msg_handler) | Broken functionality because of unregistered msg handler | -| [Missing error handler](missing_error_handler) | Missing error handling leads to successful execution of a transaction that should have failed | +| Not So Smart Contract | Description | +| -------------------------------------------------------- | --------------------------------------------------------------------------------------------- | +| [Incorrect signers](incorrect_getsigners) | Broken access controls due to incorrect signers validation | +| [Non-determinism](non_determinism) | Consensus failure because of non-determinism | +| [Not prioritized messages](messages_priority) | Risks arising from usage of not prioritized message types | +| [Slow ABCI methods](abci_fast) | Consensus failure because of slow ABCI methods | +| [ABCI methods panic](abci_panic) | Chain halt due to panics in ABCI methods | +| [Broken bookkeeping](broken_bookkeeping) | Exploit mismatch between different modules' views on balances | +| [Rounding errors](rounding_errors) | Bugs related to imprecision of finite precision arithmetic | +| [Unregistered message handler](unregistered_msg_handler) | Broken functionality because of unregistered msg handler | +| [Missing error handler](missing_error_handler) | Missing error handling leads to successful execution of a transaction that should have failed | + ## Credits These examples are developed and maintained by [Trail of Bits](https://www.trailofbits.com/). diff --git a/not-so-smart-contracts/cosmos/abci_fast/README.md b/not-so-smart-contracts/cosmos/abci_fast/README.md index c9ec7265..da11a4e6 100644 --- a/not-so-smart-contracts/cosmos/abci_fast/README.md +++ b/not-so-smart-contracts/cosmos/abci_fast/README.md @@ -2,7 +2,7 @@ ABCI methods (like `EndBlocker`) [are not constrained by `gas`](https://docs.cosmos.network/v0.45/basics/app-anatomy.html#beginblocker-and-endblocker). Therefore, it is essential to ensure that they always will finish in a reasonable time. Otherwise, the chain will halt. -## Example +## Example Below you can find part of a tokens lending application. Before a block is executed, the `BeginBlocker` method charges an interest for each borrower. @@ -38,4 +38,5 @@ users can take a lot of small loans to slow down computation to a point where th - [Ensure that minimal fees are enforced on all messages](https://docs.cosmos.network/v0.46/basics/gas-fees.html#introduction-to-gas-and-fees) to prevent spam ## External examples -- [Gravity Bridge's `slashing` method was executed in the `EndBlocker` and contained a computationally expensive, nested loop](https://github.com/althea-net/cosmos-gravity-bridge/issues/347). \ No newline at end of file + +- [Gravity Bridge's `slashing` method was executed in the `EndBlocker` and contained a computationally expensive, nested loop](https://github.com/althea-net/cosmos-gravity-bridge/issues/347). diff --git a/not-so-smart-contracts/cosmos/abci_panic/README.md b/not-so-smart-contracts/cosmos/abci_panic/README.md index fefd9504..0e9757f3 100644 --- a/not-so-smart-contracts/cosmos/abci_panic/README.md +++ b/not-so-smart-contracts/cosmos/abci_panic/README.md @@ -3,11 +3,12 @@ A `panic` inside an ABCI method (e.g., `EndBlocker`) will stop the chain. There should be no unanticipated `panic`s in these methods. Some less expected `panic` sources are: -* [`Coins`, `DecCoins`, `Dec`, `Int`, and `UInt` types panics a lot](https://github.com/cosmos/cosmos-sdk/blob/afbb0bd1941f7ad36e086913153af02eb6a68f5a/types/coin.go#L68), [for example on overflows](https://github.com/cosmos/cosmos-sdk/blob/afbb0bd1941f7ad36e086913153af02eb6a68f5a/types/dec_coin.go#L105) and [rounding errors](https://github.com/cosmos/cosmos-sdk/blob/afbb0bd1941f7ad36e086913153af02eb6a68f5a/types/decimal.go#L648) -* [`new Dec` panics](https://pkg.go.dev/github.com/cosmos/cosmos-sdk/types@v0.45.5#Dec) -* [`x/params`'s `SetParamSet` panics if arguments are invalid](https://github.com/cosmos/cosmos-sdk/blob/1b1dbf8ab722e4689e14a5a2a1fc433b69bc155e/x/params/doc.go#L107-L108) -## Example +- [`Coins`, `DecCoins`, `Dec`, `Int`, and `UInt` types panics a lot](https://github.com/cosmos/cosmos-sdk/blob/afbb0bd1941f7ad36e086913153af02eb6a68f5a/types/coin.go#L68), [for example on overflows](https://github.com/cosmos/cosmos-sdk/blob/afbb0bd1941f7ad36e086913153af02eb6a68f5a/types/dec_coin.go#L105) and [rounding errors](https://github.com/cosmos/cosmos-sdk/blob/afbb0bd1941f7ad36e086913153af02eb6a68f5a/types/decimal.go#L648) +- [`new Dec` panics](https://pkg.go.dev/github.com/cosmos/cosmos-sdk/types@v0.45.5#Dec) +- [`x/params`'s `SetParamSet` panics if arguments are invalid](https://github.com/cosmos/cosmos-sdk/blob/1b1dbf8ab722e4689e14a5a2a1fc433b69bc155e/x/params/doc.go#L107-L108) + +## Example The application below enforces limits on how much coins can be borrowed globally. If the `loan.Borrowed` array of Coins can be forced to be not-sorted (by coins' denominations), the `Add` method will `panic`. @@ -41,6 +42,7 @@ func validateTotalBorrows(ctx sdk.Context, k keeper.Keeper) { - Review the code against unexpected `panic`s ## External examples + - [Gravity Bridge can `panic` in multiple locations in the `EndBlocker` method](https://giters.com/althea-net/cosmos-gravity-bridge/issues/348) - [Agoric `panic`s purposefully if the `PushAction` method returns an error](https://github.com/Agoric/agoric-sdk/blob/9116ede69169ebb252faf069d90022e8e05c6a4e/golang/cosmos/x/vbank/module.go#L166) - [Setting invalid parameters in `x/distribution` module causes `panic` in `BeginBlocker`](https://github.com/cosmos/cosmos-sdk/issues/5808). Valid parameters are [described in the documentation](https://docs.cosmos.network/v0.45/modules/distribution/07_params.html). diff --git a/not-so-smart-contracts/cosmos/broken_bookkeeping/README.md b/not-so-smart-contracts/cosmos/broken_bookkeeping/README.md index 08765c79..7907e6c9 100644 --- a/not-so-smart-contracts/cosmos/broken_bookkeeping/README.md +++ b/not-so-smart-contracts/cosmos/broken_bookkeeping/README.md @@ -29,11 +29,11 @@ A spiteful user can simply transfer a tiny amount of BTC tokens directly to the Because an invariant's failure stops the chain, the bug constitutes a simple Denial-of-Service attack vector. -## Example 2 +## Example 2 An example application implements a lending platform. It allows users to deposit Tokens in exchange for xTokens - similarly to the [Compound's cTokens](https://compound.finance/docs/ctokens#exchange-rate). Token:xToken exchange rate is calculated as `(amount of Tokens borrowed + amount of Tokens held by the module account) / (amount of uTokens in circulation)`. -Implementation of the `GetExchangeRate` method computing an exchange rate is presented below. +Implementation of the `GetExchangeRate` method computing an exchange rate is presented below. ```go func (k Keeper) GetExchangeRate(tokenDenom string) sdk.Coin { @@ -50,14 +50,13 @@ func (k Keeper) GetExchangeRate(tokenDenom string) sdk.Coin { A malicious user can screw an exchange rate in two ways: -* by force-sending Tokens to the module, changing the `tokensHeld` value -* by transferring uTokens to another chain via IBC, chaning `uTokensInCirculation` value +- by force-sending Tokens to the module, changing the `tokensHeld` value +- by transferring uTokens to another chain via IBC, chaning `uTokensInCirculation` value The first "attack" could be pulled of by sending [`MsgSend`](https://docs.cosmos.network/main/modules/bank#msgsend) message. However, it would be not profitable (probably), as executing it would irreversibly decrease an attacker's resources. The second one works because the IBC module [burns transferred coins in the source chain](https://github.com/cosmos/ibc-go/blob/48a6ae512b4ea42c29fdf6c6f5363f50645591a2/modules/apps/transfer/keeper/relay.go#L135-L136) and mints corresponding tokens in the destination chain. Therefore, it will decrease the supply reported by the `x/bank` module, increasing the exchange rate. After the attack the malicious user can just transfer back uTokens. - ## Mitigations - Use [`Blocklist` to prevent unexpected token transfers](https://docs.cosmos.network/v0.45/modules/bank/02_keepers.html#blocklisting-addresses) to specific addresses @@ -68,4 +67,3 @@ The second one works because the IBC module [burns transferred coins in the sour - [Umee was vulnerable to the token:uToken exchange rate manipulation](https://github.com/trailofbits/publications/blob/master/reviews/Umee.pdf) (search for finding TOB-UMEE-21). - [Desmos incorrectly blocklisted addresses](https://github.com/desmos-labs/desmos/blob/e3c89e2f9ddd5dfde5d11c3ad5319e3c249cacb3/CHANGELOG.md#version-0154) (check app.go file in [the commits diff](https://github.com/desmos-labs/desmos/compare/v0.15.3...v0.15.4)) - diff --git a/not-so-smart-contracts/cosmos/incorrect_getsigners/README.md b/not-so-smart-contracts/cosmos/incorrect_getsigners/README.md index c4d6227f..9660059f 100644 --- a/not-so-smart-contracts/cosmos/incorrect_getsigners/README.md +++ b/not-so-smart-contracts/cosmos/incorrect_getsigners/README.md @@ -5,12 +5,12 @@ where locations of the keys [are specified in `GetSigners` methods](https://docs In the simplest case there is just one signer required, and its address is simple to use correctly. However, in more complex scenarios like when multiple signatures are required or a delegation schema is implemented, -it is possible to make mistakes about what addresses in the transaction (the message) are actually authenticated. +it is possible to make mistakes about what addresses in the transaction (the message) are actually authenticated. Fortunately, mistakes in `GetSigners` should make part of application's intended functionality not working, -making it easy to spot the bug. +making it easy to spot the bug. -## Example +## Example The example application allows an author to create posts. A post can be created with a `MsgCreatePost` message, which has `signer` and `author` fields. diff --git a/not-so-smart-contracts/cosmos/messages_priority/README.md b/not-so-smart-contracts/cosmos/messages_priority/README.md index 867cd990..ef7c0fa6 100644 --- a/not-so-smart-contracts/cosmos/messages_priority/README.md +++ b/not-so-smart-contracts/cosmos/messages_priority/README.md @@ -48,8 +48,7 @@ service Msg { There is the `Pause` message, which allows privileged users to stop the pool. -Once a bug in pool's implementation is discovered, attackers and the pool's operators will compete for whose message is first executed (`Swap` vs `Pause`). Prioritizing `Pause` messages will help pool's operators to prevent exploitation, but in this case it won't stop the attackers completely. They can outrun the `Pause` message by order of magnitude - so the priority will not matter - or even cooperate with a malicious validator node - who can order his mempool in an arbitrary way. - +Once a bug in pool's implementation is discovered, attackers and the pool's operators will compete for whose message is first executed (`Swap` vs `Pause`). Prioritizing `Pause` messages will help pool's operators to prevent exploitation, but in this case it won't stop the attackers completely. They can outrun the `Pause` message by order of magnitude - so the priority will not matter - or even cooperate with a malicious validator node - who can order his mempool in an arbitrary way. ## Mitigations @@ -58,5 +57,6 @@ Once a bug in pool's implementation is discovered, attackers and the pool's oper - Alternatively, charge a high fee for prioritized transactions to disincentivize attackers. ## External examples + - [Terra Money's oracle messages were not prioritized](https://cryptorisks.substack.com/p/ust-december-2021) (search for "priority"). It was [fixed with modifications to Tendermint](https://github.com/terra-money/tendermint/commit/6805b4866bdbd6933000eb0e761acbf15edd8ed6). - [Umee oracle and orchestrator messages were not prioritized](https://github.com/trailofbits/publications/blob/master/reviews/Umee.pdf) (search for finding TOB-UMEE-20 and TOB-UMEE-31). diff --git a/not-so-smart-contracts/cosmos/missing_error_handler/README.md b/not-so-smart-contracts/cosmos/missing_error_handler/README.md index 2d787ec8..72a4e93f 100644 --- a/not-so-smart-contracts/cosmos/missing_error_handler/README.md +++ b/not-so-smart-contracts/cosmos/missing_error_handler/README.md @@ -2,9 +2,10 @@ The idiomatic way of handling errors in `Go` is to compare the returned error to nil. This way of checking for errors gives the programmer a lot of control. However, when error handling is ignored it can also lead to numerous problems. The impact of this is most obvious in method calls in the `bankKeeper` module, which even causes some accounts with insufficient balances to perform `SendCoin` operations normally without triggering a transaction failure. +## Example -## Example In the following code, `k.bankKeeper.SendCoins(ctx, sender, receiver, amount)` does not have any return values being used, including `err`. This results in `SendCoin` not being able to prevent the transaction from executing even if there is an `error` due to insufficient balance in `SendCoin`. + ```golang func (k msgServer) Transfer(goCtx context.Context, msg *types.MsgTransfer) (*types.MsgTransferResponse, error) { ... @@ -13,12 +14,14 @@ func (k msgServer) Transfer(goCtx context.Context, msg *types.MsgTransfer) (*typ return &types.MsgTransferResponse{}, nil } ``` + ## Mitigations - Implement the error handling process instead of missing it ## External examples -- [ignite's tutorials](https://github.com/ignite/cli/issues/2828). + +- [ignite's tutorials](https://github.com/ignite/cli/issues/2828). - [Fadeev's Loan Project](https://github.com/fadeev/loan/blob/master/x/loan/keeper/msg_server_approve_loan.go) - [JackalLabs](https://github.com/JackalLabs/canine-chain/issues/8). - [OllO](https://github.com/OllO-Station/ollo/issues/20) diff --git a/not-so-smart-contracts/cosmos/non_determinism/README.md b/not-so-smart-contracts/cosmos/non_determinism/README.md index 5056da47..ab44be24 100644 --- a/not-so-smart-contracts/cosmos/non_determinism/README.md +++ b/not-so-smart-contracts/cosmos/non_determinism/README.md @@ -3,16 +3,16 @@ Non-determinism in conensus-relevant code will cause the blockchain to halt. There are quite a few sources of non-determinism, some of which are specific to the Go language: -* [`range` iterations over an unordered map or other operations involving unordered structures](https://lev.pm/posts/2020-04-18-golang-map-randomness/) -* [Implementation (platform) dependent types like `int`](https://go.dev/ref/spec#Numeric_types) or `filepath.Ext` -* [goroutines and `select` statement](https://github.com/golang/go/issues/33702) -* [Memory addresses](https://github.com/cosmos/cosmos-sdk/issues/11726#issuecomment-1108427164) -* [Floating point arithmetic operations](https://en.wikipedia.org/wiki/Floating-point_arithmetic#Accuracy_problems) -* Randomness ([may be problematic even with a constant seed](https://github.com/golang/go/issues/42701)) -* Local time and timezones -* Packages like `unsafe`, `reflect`, and `runtime` +- [`range` iterations over an unordered map or other operations involving unordered structures](https://lev.pm/posts/2020-04-18-golang-map-randomness/) +- [Implementation (platform) dependent types like `int`](https://go.dev/ref/spec#Numeric_types) or `filepath.Ext` +- [goroutines and `select` statement](https://github.com/golang/go/issues/33702) +- [Memory addresses](https://github.com/cosmos/cosmos-sdk/issues/11726#issuecomment-1108427164) +- [Floating point arithmetic operations](https://en.wikipedia.org/wiki/Floating-point_arithmetic#Accuracy_problems) +- Randomness ([may be problematic even with a constant seed](https://github.com/golang/go/issues/42701)) +- Local time and timezones +- Packages like `unsafe`, `reflect`, and `runtime` -## Example +## Example Below we can see an iteration over a `amounts` `map`. If `k.GetPool` fails for more than one `asset`, then different nodes will fail with different errors, causing the chain to halt. @@ -51,5 +51,6 @@ Even if we fix the `map` problem, it is still possible that the `total` overflow - Prepare and test procedures for recovering from a blockchain split ## External examples + - [ThorChain halt due to "iteration over a map error-ing at different indexes"](https://gitlab.com/thorchain/thornode/-/issues/1169) - [Cyber's had problems with `float64` type](https://github.com/cybercongress/go-cyber/issues/66) diff --git a/not-so-smart-contracts/cosmos/rounding_errors/README.md b/not-so-smart-contracts/cosmos/rounding_errors/README.md index 41d5aa9d..dd9e908a 100644 --- a/not-so-smart-contracts/cosmos/rounding_errors/README.md +++ b/not-so-smart-contracts/cosmos/rounding_errors/README.md @@ -3,10 +3,11 @@ Application developers must take care of correct rounding of numbers, especially if the rounding impacts tokens amounts. Cosmos-sdk offers two custom types for dealing with numbers: -* `sdk.Int` (`sdk.UInt`) type for integral numbers -* `sdk.Dec` type for decimal arithmetic -The `sdk.Dec` type [has problems with precision and does not guarantee associativity](https://github.com/cosmos/cosmos-sdk/issues/7773), so it must be used carefully. But even if a more robust library for decimal numbers is deployed in the cosmos-sdk, rounding may be unavoidable. +- `sdk.Int` (`sdk.UInt`) type for integral numbers +- `sdk.Dec` type for decimal arithmetic + +The `sdk.Dec` type [has problems with precision and does not guarantee associativity](https://github.com/cosmos/cosmos-sdk/issues/7773), so it must be used carefully. But even if a more robust library for decimal numbers is deployed in the cosmos-sdk, rounding may be unavoidable. ## Example @@ -36,4 +37,4 @@ func TestDec() { ## External examples -- [Umee had vulnerability caused by incorrect rounding direction](https://github.com/umee-network/umee/issues/545) \ No newline at end of file +- [Umee had vulnerability caused by incorrect rounding direction](https://github.com/umee-network/umee/issues/545) diff --git a/not-so-smart-contracts/cosmos/unregistered_msg_handler/README.md b/not-so-smart-contracts/cosmos/unregistered_msg_handler/README.md index 592274c2..5184400f 100644 --- a/not-so-smart-contracts/cosmos/unregistered_msg_handler/README.md +++ b/not-so-smart-contracts/cosmos/unregistered_msg_handler/README.md @@ -4,7 +4,7 @@ In the legacy version of the `Msg Service`, all messages have to be registered i In [the recent Cosmos version manual registration is no longer needed](https://docs.cosmos.network/v0.47/building-modules/msg-services). -## Example +## Example There is one message handler missing. @@ -178,4 +178,5 @@ And it is the `CancelCall` msg. - Deploy static-analysis tests in CI pipeline for all manually maintained code that must be repeated in multiple files/methods ## External examples + - The bug occured in the [Gravity Bridge](https://github.com/code-423n4/2021-08-gravitybridge-findings/issues/64). It was impossible to send evidence of malicious behavior, which impacted Gravity Bridge's security model. diff --git a/not-so-smart-contracts/solana/README.md b/not-so-smart-contracts/solana/README.md index 715393b2..aeb367be 100644 --- a/not-so-smart-contracts/solana/README.md +++ b/not-so-smart-contracts/solana/README.md @@ -6,20 +6,21 @@ This repository contains examples of common Solana smart contract vulnerabilitie Each _Not So Smart Contract_ includes a standard set of information: -* Description of the vulnerability type -* Attack scenarios to exploit the vulnerability -* Recommendations to eliminate or mitigate the vulnerability -* Real-world contracts that exhibit the flaw -* References to third-party resources with more information +- Description of the vulnerability type +- Attack scenarios to exploit the vulnerability +- Recommendations to eliminate or mitigate the vulnerability +- Real-world contracts that exhibit the flaw +- References to third-party resources with more information ## Vulnerabilities -| Not So Smart Contract | Description | -| --- | --- | -| [Arbitrary CPI](arbitrary_cpi) | Arbitrary program account passed in upon invocation | -| [Improper PDA Validation](improper_pda_validation) | PDAs are vulnerable to being spoofed via bump seeds | -| [Ownership Check](ownership_check) | Broken access control due to missing ownership validation | -| [Signer Check](signer_check) | Broken access control due to missing signer validation | -| [Sysvar Account Check](sysvar_account_check) | Sysvar accounts are vulnerable to being spoofed | + +| Not So Smart Contract | Description | +| -------------------------------------------------- | --------------------------------------------------------- | +| [Arbitrary CPI](arbitrary_cpi) | Arbitrary program account passed in upon invocation | +| [Improper PDA Validation](improper_pda_validation) | PDAs are vulnerable to being spoofed via bump seeds | +| [Ownership Check](ownership_check) | Broken access control due to missing ownership validation | +| [Signer Check](signer_check) | Broken access control due to missing signer validation | +| [Sysvar Account Check](sysvar_account_check) | Sysvar accounts are vulnerable to being spoofed | ## Credits diff --git a/not-so-smart-contracts/solana/arbitrary_cpi/README.md b/not-so-smart-contracts/solana/arbitrary_cpi/README.md index e78917b0..61657f73 100644 --- a/not-so-smart-contracts/solana/arbitrary_cpi/README.md +++ b/not-so-smart-contracts/solana/arbitrary_cpi/README.md @@ -1,11 +1,15 @@ # Arbitrary CPI + Solana allows programs to call one another through cross-program invocation (CPI). This can be done via `invoke`, which is responsible for routing the passed in instruction to the program. Whenever an external contract is invoked via CPI, the program must check and verify the program ID. If the program ID isn't verified, then the contract can call an attacker-controlled program instead of the intended one. View ToB's lint implementation for the arbitrary CPI issue [here](https://github.com/crytic/solana-lints/tree/master/lints/arbitrary_cpi). ## Exploit Scenario + Consider the following `withdraw` function. Tokens are able to be withdrawn from the pool to a user account. The program invoked here is user-controlled and there's no check that the program passed in is the intended `token_program`. This allows a malicious user to pass in their own program with functionality to their discretion - such as draining the pool of the inputted `amount` tokens. + ### Example Contract + ```rust pub fn withdraw(accounts: &[AccountInfo], amount: u64) -> ProgramResult { let account_info_iter = &mut accounts.iter(); @@ -30,8 +34,11 @@ Consider the following `withdraw` function. Tokens are able to be withdrawn from ) } ``` -*Inspired by [Sealevel](https://github.com/coral-xyz/sealevel-attacks/)* + +_Inspired by [Sealevel](https://github.com/coral-xyz/sealevel-attacks/)_ + ## Mitigation + ```rust if INPUTTED_PROGRAM.key != &INTENDED_PROGRAM::id() { return Err(ProgramError::InvalidProgramId); diff --git a/not-so-smart-contracts/solana/improper_pda_validation/README.md b/not-so-smart-contracts/solana/improper_pda_validation/README.md index e78cd15b..901a4b7b 100644 --- a/not-so-smart-contracts/solana/improper_pda_validation/README.md +++ b/not-so-smart-contracts/solana/improper_pda_validation/README.md @@ -1,4 +1,3 @@ - # Improper PDA bump seed validation PDAs (Program Derived Addresses) are, by definition, [program-controlled](https://docs.solana.com/terminology#program-derived-account-pda) accounts and therefore can be used to sign without the need to provide a private key. PDAs are generated through a set of seeds and a program id, which are then collectively hashed to verify that the point doesn't lie on the ed25519 curve (the curve used by Solana to sign transactions). @@ -12,12 +11,15 @@ View ToB's lint implementation for the bump seed canonicalization issue [here](h ## Exploit Scenario In Solana, the `create_program_address` function creates a 32-byte address based off the set of seeds and program address. On its own, the point may lie on the ed25519 curve. Consider the following without any other validation being referenced within a sensitive function, such as one that handles transfers. That PDA could be spoofed by a passed in user-controlled PDA. + ### Example Contract + ```rust let program_address = Pubkey::create_program_address(&[key.to_le_bytes().as_ref(), &[reserve_bump]], program_id)?; ... ``` + ## Mitigation The `find_program_address` function finds the largest bump seeds for which there exists a corresponding PDA (i.e., a point not on the ed25519 curve), and returns both the address and the bump seed. The function panics in the case that no PDA address can be found. diff --git a/not-so-smart-contracts/solana/ownership_check/README.md b/not-so-smart-contracts/solana/ownership_check/README.md index 34121390..ee300d98 100644 --- a/not-so-smart-contracts/solana/ownership_check/README.md +++ b/not-so-smart-contracts/solana/ownership_check/README.md @@ -1,13 +1,16 @@ # Missing Ownership Check + Accounts in Solana include metadata of an owner. These owners are identified by their own program ID. Without sufficient checks that the expected program ID matches that of the passed in account, an attacker can fabricate an account with spoofed data to pass any other preconditions. This malicious account will inherently have a different program ID as owner, but considering there’s no check that the program ID is the same, as long as the other preconditions are passed, the attacker can trick the program into thinking their malicious account is the expected account. ## Exploit Scenario + The following contract allows funds to be dispersed from an escrow account vault, provided the escrow account's state is `Complete`. Unfortunately, there is no check that the `State` account is owned by the program. Therefore, a malicious actor can pass in their own fabricated `State` account with spoofed data, allowing the attacker to send the vault's funds to themselves. ### Example Contract + ```rust fn pay_escrow(_program_id: &Pubkey, accounts: &[AccountInfo], _instruction_data: &[u8]) -> ProgramResult { let account_info_iter = &mut accounts.iter(); @@ -25,7 +28,8 @@ fn pay_escrow(_program_id: &Pubkey, accounts: &[AccountInfo], _instruction_data: Ok(()) } ``` -*Inspired by [SPL Lending Program](https://github.com/solana-labs/solana-program-library/tree/master/token-lending/program)* + +_Inspired by [SPL Lending Program](https://github.com/solana-labs/solana-program-library/tree/master/token-lending/program)_ ## Mitigation @@ -34,4 +38,5 @@ fn pay_escrow(_program_id: &Pubkey, accounts: &[AccountInfo], _instruction_data: return Err(ProgramError::IncorrectProgramId); } ``` + For further reading on different forms of account verification in Solana and implementation refer to the [Solana Cookbook](https://solanacookbook.com/references/programs.html#how-to-verify-accounts). diff --git a/not-so-smart-contracts/solana/signer_check/README.md b/not-so-smart-contracts/solana/signer_check/README.md index 4b761670..20a9f947 100644 --- a/not-so-smart-contracts/solana/signer_check/README.md +++ b/not-so-smart-contracts/solana/signer_check/README.md @@ -1,13 +1,16 @@ # Missing Signer Check + In Solana, each public key has an associated private key that can be used to generate signatures. A [transaction](https://docs.solana.com/developing/programming-model/transactions) lists each account public key whose private key was used to generate a signature for the transaction. These signatures are verified using the inputted public keys prior to transaction execution. In case certain permissions are required to perform a sensitive function of the contract, a missing signer check becomes an issue. Without this check, an attacker would be able to call the respective access controlled functions permissionlessly. ## Exploit Scenario + The following contract sets an escrow account's state to `Complete`. Unfortunately, the contract does not check whether the `State` account's `authority` has signed the transaction. Therefore, a malicious actor can set the state to `Complete`, without needing access to the `authority`’s private key. ### Example Contract + ```rust fn complete_escrow(_program_id: &Pubkey, accounts: &[AccountInfo], _instruction_data: &[u8]) -> ProgramResult { let account_info_iter = &mut accounts.iter(); @@ -15,24 +18,27 @@ fn complete_escrow(_program_id: &Pubkey, accounts: &[AccountInfo], _instruction_ let authority = next_account_info(account_info_iter)?; let mut state = State::deserialize(&mut &**state_info.data.borrow())?; - + if state.authority != *authority.key { return Err(ProgramError::IncorrectAuthority); } - + state.escrow_state = EscrowState::Complete; state.serialize(&mut &mut **state_info.data.borrow_mut())?; - + Ok(()) - + } ``` -*Inspired by [SPL Lending Program](https://github.com/solana-labs/solana-program-library/tree/master/token-lending/program)* + +_Inspired by [SPL Lending Program](https://github.com/solana-labs/solana-program-library/tree/master/token-lending/program)_ ## Mitigation + ```rust if !EXPECTED_ACCOUNT.is_signer { return Err(ProgramError::MissingRequiredSignature); } ``` + For further reading on different forms of account verification in Solana and implementation refer to the [Solana Cookbook](https://solanacookbook.com/references/programs.html#how-to-verify-accounts). diff --git a/not-so-smart-contracts/solana/sysvar_account_check/README.md b/not-so-smart-contracts/solana/sysvar_account_check/README.md index bce5ed28..05ba3274 100644 --- a/not-so-smart-contracts/solana/sysvar_account_check/README.md +++ b/not-so-smart-contracts/solana/sysvar_account_check/README.md @@ -1,4 +1,5 @@ # Missing Sysvar Account Check + The sysvar (system account) account is often used while validating access control for restricted functions by confirming that the inputted sysvar account by the user matches up with the expected sysvar account. Without this check in place, any user is capable of passing in their own spoofed sysvar account and in turn bypassing any further authentication associated with it, causing potentially disastrous effects. ## Exploit Scenario @@ -8,6 +9,7 @@ secp256k1 is an elliptic curve used by a number of blockchains for signatures. V Here, `load_current_index` and `load_instruction_at` are functions that don't verify that the inputted sysvar account is authorized, therefore allowing serialized maliciously fabricated data to sucessfully spoof as an authorized secp256k1 signature. ### Example Contract + ```rust pub fn verify_signatures(account_info: &AccountInfo) -> ProgramResult { let index = solana_program::sysvar::instructions::load_current_index( @@ -24,9 +26,11 @@ pub fn verify_signatures(account_info: &AccountInfo) -> ProgramResult { ... } ``` + Refer to [Mitigation](https://github.com/crytic/building-secure-contracts/tree/master/not-so-smart-contracts/solana/sysvar_account_check#Mitigation) to understand what's wrong with these functions and how sysvar account checks were added. ## Mitigation + - Solana libraries should be running on version 1.8.1 and up - Use `load_instruction_at_checked` and `load_current_index_checked` @@ -34,11 +38,14 @@ Utilizing the latest Solana version and referencing checked functions, especiall Leaving the system exposed to any point of failure compromises the entire system's integrity, especially while the contracts are being constantly updated. Here is the code showing the sysvar account checks added between unchecked and checked functions: + - [load_instruction_at](https://docs.rs/solana-program/1.13.5/src/solana_program/sysvar/instructions.rs.html#186-188) vs [load_instruction_at_checked](https://docs.rs/solana-program/1.13.5/src/solana_program/sysvar/instructions.rs.html#192-205) - [load_current_index](https://docs.rs/solana-program/1.13.5/src/solana_program/sysvar/instructions.rs.html#107-112) vs [load_current_index_checked](https://docs.rs/solana-program/1.13.5/src/solana_program/sysvar/instructions.rs.html#116-128) --- + ## Example: Wormhole Exploit (February 2022) + ### Funds lost: ~326,000,000 USD **Note: The following analysis is condensed down to be present this attack vector as clearly as possible, and certain details might’ve been left out for the sake of simplification** @@ -46,14 +53,14 @@ Here is the code showing the sysvar account checks added between unchecked and c The Wormhole hack serves to be one of the most memorable exploits in terms of impact DeFi has ever seen. This exploit also happens to incorporate a missing sysvar account check that allowed the attacker to: + 1. Spoof Guardian signatures as valid 2. Use them to create a Validator Action Approval (VAA) 3. Mint 120,000 ETH via calling complete_wrapped function (These actions are all chronologically dependent on one another based on permissions and conditions - this analysis will only dive into “Step 1”) -The SignatureSet was able to be faked because the `verify_signatures` function failed to appropriately [verify](https://github.com/wormhole-foundation/wormhole/blob/ca509f2d73c0780e8516ffdfcaf90b38ab6db203/solana/bridge/program/src/api/verify_signature.rs#L101 -) the sysvar account passed in: +The SignatureSet was able to be faked because the `verify_signatures` function failed to appropriately [verify](https://github.com/wormhole-foundation/wormhole/blob/ca509f2d73c0780e8516ffdfcaf90b38ab6db203/solana/bridge/program/src/api/verify_signature.rs#L101) the sysvar account passed in: ```rust let secp_ix = solana_program::sysvar::instructions::load_instruction_at( @@ -61,11 +68,11 @@ let secp_ix = solana_program::sysvar::instructions::load_instruction_at( &accs.instruction_acc.try_borrow_mut_data()?, ) ``` + `load_instruction_at` doesn't verify that the inputted data came from the authorized sysvar account. -The fix for this was to upgrade the Solana version and get rid of these unsafe deprecated functions (see [Mitigation](https://github.com/crytic/building-secure-contracts/tree/master/not-so-smart-contracts/solana/sysvar_account_check#Mitigation)). Wormhole had [caught](https://github.com/wormhole-foundation/wormhole/commit/7edbbd3677ee6ca681be8722a607bc576a3912c8#diff-0d27d8889edd071b86d3f3299276882d97613ad6ab3b0b6412ae4ebf3ccd6370R92-R103) this issue but didn't update their deployed contracts in time before the exploiter had already managed to drain funds. +The fix for this was to upgrade the Solana version and get rid of these unsafe deprecated functions (see [Mitigation](https://github.com/crytic/building-secure-contracts/tree/master/not-so-smart-contracts/solana/sysvar_account_check#Mitigation)). Wormhole had [caught](https://github.com/wormhole-foundation/wormhole/commit/7edbbd3677ee6ca681be8722a607bc576a3912c8#diff-0d27d8889edd071b86d3f3299276882d97613ad6ab3b0b6412ae4ebf3ccd6370R92-R103) this issue but didn't update their deployed contracts in time before the exploiter had already managed to drain funds. ## Resources: -[samczsun's Wormhole exploit breakdown thread](https://twitter.com/samczsun/status/1489044939732406275) - +[samczsun's Wormhole exploit breakdown thread](https://twitter.com/samczsun/status/1489044939732406275) diff --git a/not-so-smart-contracts/substrate/README.md b/not-so-smart-contracts/substrate/README.md index 19bd2dee..2ccd84c3 100644 --- a/not-so-smart-contracts/substrate/README.md +++ b/not-so-smart-contracts/substrate/README.md @@ -6,23 +6,23 @@ This repository contains examples of common Substrate pallet vulnerabilities. Us Each _Not So Smart Pallet_ includes a standard set of information: -* Description of the vulnerability type -* Attack scenarios to exploit the vulnerability -* Recommendations to eliminate or mitigate the vulnerability -* A mock pallet that exhibits the flaw -* References to third-party resources with more information +- Description of the vulnerability type +- Attack scenarios to exploit the vulnerability +- Recommendations to eliminate or mitigate the vulnerability +- A mock pallet that exhibits the flaw +- References to third-party resources with more information ## Vulnerabilities -| Not So Smart Pallet | Description | -| --- | --- | -| [Arithmetic overflow](arithmetic_overflow) | Integer overflow due to incorrect use of arithmetic operators | -| [Don't panic!](dont_panic) | System panics create a potential DoS attack vector | -| [Weights and fees](weights_and_fees) | Incorrect weight calculations can create a potential DoS attack vector | -| [Verify first](verify_first) | Verify first, write last | -| [Unsigned transaction validation](validate_unsigned) | Insufficient validation of unsigned transactions | -| [Bad randomness](randomness) | Unsafe sources of randomness in Substrate | -| [Bad origin](origins) | Incorrect use of call origin can lead to bypassing access controls | +| Not So Smart Pallet | Description | +| ---------------------------------------------------- | ---------------------------------------------------------------------- | +| [Arithmetic overflow](arithmetic_overflow) | Integer overflow due to incorrect use of arithmetic operators | +| [Don't panic!](dont_panic) | System panics create a potential DoS attack vector | +| [Weights and fees](weights_and_fees) | Incorrect weight calculations can create a potential DoS attack vector | +| [Verify first](verify_first) | Verify first, write last | +| [Unsigned transaction validation](validate_unsigned) | Insufficient validation of unsigned transactions | +| [Bad randomness](randomness) | Unsafe sources of randomness in Substrate | +| [Bad origin](origins) | Incorrect use of call origin can lead to bypassing access controls | ## Credits diff --git a/not-so-smart-contracts/substrate/arithmetic_overflow/README.md b/not-so-smart-contracts/substrate/arithmetic_overflow/README.md index 1d7adfb9..68d19910 100644 --- a/not-so-smart-contracts/substrate/arithmetic_overflow/README.md +++ b/not-so-smart-contracts/substrate/arithmetic_overflow/README.md @@ -3,42 +3,45 @@ Arithmetic overflow in Substrate occurs when arithmetic operations are performed using primitive operations instead of specialized functions that check for overflow. When a Substrate node is compiled in `debug` mode, integer overflows will cause the program to panic. However, when the node is compiled in `release` mode (e.g. `cargo build --release`), Substrate will perform two's complement wrapping. A production-ready node will be compiled in `release` mode, which makes it vulnerable to arithmetic overflow. # Example + In the [`pallet-overflow`](./pallet-overflow.rs) pallet, notice that the `transfer` function sets `update_sender` and `update_to` using primitive arithmetic operations. - - ```rust - /// Allow minting account to transfer a given balance to another account. - /// - /// Parameters: - /// - `to`: The account to receive the transfer. - /// - `amount`: The amount of balance to transfer. - /// - /// Emits `Transferred` event when successful. - #[pallet::weight(10_000)] - pub fn transfer( - origin: OriginFor, - to: T::AccountId, - amount: u64, - ) -> DispatchResultWithPostInfo { - let sender = ensure_signed(origin)?; - let sender_balance = Self::get_balance(&sender); - let receiver_balance = Self::get_balance(&to); - - // Calculate new balances. - let update_sender = sender_balance - amount; - let update_to = receiver_balance + amount; - [...] - } + +```rust + /// Allow minting account to transfer a given balance to another account. + /// + /// Parameters: + /// - `to`: The account to receive the transfer. + /// - `amount`: The amount of balance to transfer. + /// + /// Emits `Transferred` event when successful. + #[pallet::weight(10_000)] + pub fn transfer( + origin: OriginFor, + to: T::AccountId, + amount: u64, + ) -> DispatchResultWithPostInfo { + let sender = ensure_signed(origin)?; + let sender_balance = Self::get_balance(&sender); + let receiver_balance = Self::get_balance(&to); + + // Calculate new balances. + let update_sender = sender_balance - amount; + let update_to = receiver_balance + amount; + [...] + } ``` -The sender of the extrinsic can exploit this vulnerability by causing `update_sender` to underflow, which artificially inflates their balance. +The sender of the extrinsic can exploit this vulnerability by causing `update_sender` to underflow, which artificially inflates their balance. **Note**: Aside from the stronger mitigations mentioned below, a check to make sure that `sender` has at least `amount` balance would have also prevented an underflow. # Mitigations + - Use `checked` or `saturating` functions for arithmetic operations. - - [`CheckedAdd` trait](https://docs.rs/num/0.4.0/num/traits/trait.CheckedAdd.html) - - [`Saturating` trait](https://docs.rs/num/0.4.0/num/traits/trait.Saturating.html) + - [`CheckedAdd` trait](https://docs.rs/num/0.4.0/num/traits/trait.CheckedAdd.html) + - [`Saturating` trait](https://docs.rs/num/0.4.0/num/traits/trait.Saturating.html) # References + - https://doc.rust-lang.org/book/ch03-02-data-types.html#integer-overflow - https://docs.substrate.io/reference/how-to-guides/basics/use-helper-functions/ diff --git a/not-so-smart-contracts/substrate/dont_panic/README.md b/not-so-smart-contracts/substrate/dont_panic/README.md index 45a36467..79e21f9e 100644 --- a/not-so-smart-contracts/substrate/dont_panic/README.md +++ b/not-so-smart-contracts/substrate/dont_panic/README.md @@ -3,7 +3,8 @@ Panics occur when the node enters a state that it cannot handle and stops the program / process instead of trying to proceed. Panics can occur for a large variety of reasons such as out-of-bounds array access, incorrect data validation, type conversions, and much more. A well-designed Substrate node must NEVER panic! If a node panics, it opens up the possibility for a denial-of-service (DoS) attack. # Example -In the [`pallet-dont-panic`](./pallet-dont-panic.rs) pallet, the `find_important_value` dispatchable checks to see if `useful_amounts[0]` is greater than `1_000`. If so, it sets the `ImportantVal` `StorageValue` to the value held in `useful_amounts[0]`. + +In the [`pallet-dont-panic`](./pallet-dont-panic.rs) pallet, the `find_important_value` dispatchable checks to see if `useful_amounts[0]` is greater than `1_000`. If so, it sets the `ImportantVal` `StorageValue` to the value held in `useful_amounts[0]`. ```rust /// Do some work @@ -20,20 +21,22 @@ In the [`pallet-dont-panic`](./pallet-dont-panic.rs) pallet, the `find_important let sender = ensure_signed(origin)?; ensure!(useful_amounts[0] > 1_000, >::NoImportantValueFound); - + // Found the important value ImportantValue::::put(&useful_amounts[0]); [...] } ``` -However, notice that there is no check before the array indexing to see whether the length of `useful_amounts` is greater than zero. Thus, if `useful_amounts` is empty, the indexing will cause an array out-of-bounds error which will make the node panic. Since the `find_important_value` function is callable by anyone, an attacker can set `useful_amounts` to an empty array and spam the network with malicious transactions to launch a DoS attack. +However, notice that there is no check before the array indexing to see whether the length of `useful_amounts` is greater than zero. Thus, if `useful_amounts` is empty, the indexing will cause an array out-of-bounds error which will make the node panic. Since the `find_important_value` function is callable by anyone, an attacker can set `useful_amounts` to an empty array and spam the network with malicious transactions to launch a DoS attack. # Mitigations + - Write non-throwing Rust code (e.g. prefer returning [`Result`](https://paritytech.github.io/substrate/master/frame_support/dispatch/result/enum.Result.html) types, use [`ensure!`](https://paritytech.github.io/substrate/master/frame_support/macro.ensure.html), etc.). - Proper data validation of all input parameters is crucial to ensure that an unexpected panic does not occur. - A thorough suite of unit tests should be implemented. - Fuzz testing (e.g. using [`test-fuzz`](https://github.com/trailofbits/test-fuzz)) can aid in exploring more of the input space. # References + - https://docs.substrate.io/main-docs/build/events-errors/#errors diff --git a/not-so-smart-contracts/substrate/origins/README.md b/not-so-smart-contracts/substrate/origins/README.md index 111177d8..5c6e1d88 100644 --- a/not-so-smart-contracts/substrate/origins/README.md +++ b/not-so-smart-contracts/substrate/origins/README.md @@ -1,6 +1,6 @@ # Origins -The origin of a call tells a dispatchable function where the call has come from. Origins are a way to implement access controls in the system. +The origin of a call tells a dispatchable function where the call has come from. Origins are a way to implement access controls in the system. There are three types of origins that can used in the runtime: @@ -12,11 +12,12 @@ pub enum RawOrigin { } ``` -Outside of the out-of-box origins, custom origins can also be created that are catered to a specific runtime. The primary use case for custom origins is to configure privileged access to dispatch calls in the runtime, outside of `RawOrigin::Root`. +Outside of the out-of-box origins, custom origins can also be created that are catered to a specific runtime. The primary use case for custom origins is to configure privileged access to dispatch calls in the runtime, outside of `RawOrigin::Root`. Using privileged origins, like `RawOrigin::Root` or custom origins, can lead to access control violations if not used correctly. It is a common error to use `ensure_signed` in place of `ensure_root` which would allow any user to bypass the access control placed by using `ensure_root`. # Example + In the [`pallet-bad-origin`](./pallet-bad-origin.rs) pallet, there is a `set_important_val` function that should be only callable by the `ForceOrigin` _custom_ origin type. This custom origin allows the pallet to specify that only a specific account can call `set_important_val`. ```rust @@ -40,6 +41,7 @@ impl Pallet { } } ``` + However, the `set_important_val` is using `ensure_signed`; this allows any account to set `ImportantVal`. To allow only the `ForceOrigin` to call `set_important_val` the following change can be made: ```rust @@ -48,11 +50,13 @@ let sender = ensure_signed(origin)?; ``` # Mitigations + - Ensure that the correct access controls are placed on privileged functions. - Develop user documentation on all risks associated with the system, including those associated with privileged users. - A thorough suite of unit tests that validates access controls is crucial. # References + - https://docs.substrate.io/main-docs/build/origins/ - https://docs.substrate.io/tutorials/work-with-pallets/specify-the-origin-for-a-call/ - https://paritytech.github.io/substrate/master/pallet_sudo/index.html# diff --git a/not-so-smart-contracts/substrate/randomness/README.md b/not-so-smart-contracts/substrate/randomness/README.md index e573c3e3..af32784a 100644 --- a/not-so-smart-contracts/substrate/randomness/README.md +++ b/not-so-smart-contracts/substrate/randomness/README.md @@ -1,15 +1,17 @@ # Bad Randomness To use randomness in a Substrate pallet, all you need to do is require a source of randomness in the `Config` trait of a pallet. This source of Randomness must implement the [`Randomness`](https://paritytech.github.io/substrate/master/frame_support/traits/trait.Randomness.html) trait. The trait provides two methods for obtaining randomness. + 1. `random_seed`: This function takes no arguments and returns back a random value. Calling this value multiple times in a block will result in the same value. -2. `random`: Takes in a byte-array (a.k.a "context-identifier") and returns a value that is as independent as possible from other contexts. +2. `random`: Takes in a byte-array (a.k.a "context-identifier") and returns a value that is as independent as possible from other contexts. Substrate provides the [Randomness Collective Flip Pallet](https://docs.rs/pallet-randomness-collective-flip/latest/pallet_randomness_collective_flip/) and a Verifiable Random Function implementation in the [BABE pallet](https://paritytech.github.io/substrate/master/pallet_babe/index.html). Developers can also choose to build their own source of randomness. -A bad source of randomness can lead to a variety of exploits such as the theft of funds or undefined system behavior. +A bad source of randomness can lead to a variety of exploits such as the theft of funds or undefined system behavior. # Example -The [`pallet-bad-lottery`](./pallet-bad-lottery.rs) pallet is a simplified "lottery" system that requires one to guess the next random number. If they guess correctly, they are the winner of the lottery. + +The [`pallet-bad-lottery`](./pallet-bad-lottery.rs) pallet is a simplified "lottery" system that requires one to guess the next random number. If they guess correctly, they are the winner of the lottery. ```rust #[pallet::call] @@ -45,17 +47,18 @@ pub fn get_and_increment_nonce() -> Vec { } ``` -Note that the quality of randomness provided to the `pallet-bad-lottery` pallet is related to the randomness source. If the randomness source is the "Randomness Collective Flip Pallet", this lottery system is insecure. This is because the collective flip pallet implements "low-influence randomness". This makes it vulnerable to a collusion attack where a small minority of participants can give the same random number contribution making it highly likely to have the seed be this random number (click [here](https://ethresear.ch/t/rng-exploitability-analysis-assuming-pure-randao-based-main-chain/1825/7) to learn more). Additionally, as mentioned in the Substrate documentation, "low-influence randomness can be useful when defending against relatively weak adversaries. Using this pallet as a randomness source is advisable primarily in low-security situations like testing." +Note that the quality of randomness provided to the `pallet-bad-lottery` pallet is related to the randomness source. If the randomness source is the "Randomness Collective Flip Pallet", this lottery system is insecure. This is because the collective flip pallet implements "low-influence randomness". This makes it vulnerable to a collusion attack where a small minority of participants can give the same random number contribution making it highly likely to have the seed be this random number (click [here](https://ethresear.ch/t/rng-exploitability-analysis-assuming-pure-randao-based-main-chain/1825/7) to learn more). Additionally, as mentioned in the Substrate documentation, "low-influence randomness can be useful when defending against relatively weak adversaries. Using this pallet as a randomness source is advisable primarily in low-security situations like testing." # Mitigations + - Use the randomness implementation provided by the [BABE pallet](https://paritytech.github.io/substrate/master/pallet_babe/index.html). This pallet provides "production-grade randomness, and is used in Polkadot. **Selecting this randomness source dictates that your blockchain use Babe consensus.**" - Defer from creating a custom source of randomness unless specifically necessary for the runtime being developed. - Do not use `random_seed` as the method of choice for randomness unless specifically necessary for the runtime being developed. - # References + - https://docs.substrate.io/main-docs/build/randomness/ - https://docs.substrate.io/reference/how-to-guides/pallet-design/incorporate-randomness/ - https://ethresear.ch/t/rng-exploitability-analysis-assuming-pure-randao-based-main-chain/1825/7 - https://ethresear.ch/t/collective-coin-flipping-csprng/3252/21 -- https://github.com/paritytech/ink/issues/57#issuecomment-486998848 \ No newline at end of file +- https://github.com/paritytech/ink/issues/57#issuecomment-486998848 diff --git a/not-so-smart-contracts/substrate/validate_unsigned/README.md b/not-so-smart-contracts/substrate/validate_unsigned/README.md index 30586c6f..840379ed 100644 --- a/not-so-smart-contracts/substrate/validate_unsigned/README.md +++ b/not-so-smart-contracts/substrate/validate_unsigned/README.md @@ -1,12 +1,13 @@ # Unsigned Transaction Validation -There are three types of transactions allowed in a Substrate runtime: signed, unsigned, and inherent. An unsigned transaction does not require a signature and does not include information about who sent the transaction. This is naturally problematic because there is no by-default deterrent to spam or replay attacks. Because of this, Substrate allows users to create custom functions to validate unsigned transaction. However, incorrect or improper validation of an unsigned transaction can allow _anyone_ to perform potentially malicious actions. Usually, unsigned transactions are allowed only for select parties (e.g., off-chain workers (OCW)). But, if improper data validation of an unsigned transaction allows a malicious actor to spoof data as if it came from an OCW, this can lead to unexpected behavior. Additionally, improper validation opens up the possibility to replay attacks where the same transaction can be sent to the transaction pool again and again to perform some malicious action repeatedly. +There are three types of transactions allowed in a Substrate runtime: signed, unsigned, and inherent. An unsigned transaction does not require a signature and does not include information about who sent the transaction. This is naturally problematic because there is no by-default deterrent to spam or replay attacks. Because of this, Substrate allows users to create custom functions to validate unsigned transaction. However, incorrect or improper validation of an unsigned transaction can allow _anyone_ to perform potentially malicious actions. Usually, unsigned transactions are allowed only for select parties (e.g., off-chain workers (OCW)). But, if improper data validation of an unsigned transaction allows a malicious actor to spoof data as if it came from an OCW, this can lead to unexpected behavior. Additionally, improper validation opens up the possibility to replay attacks where the same transaction can be sent to the transaction pool again and again to perform some malicious action repeatedly. The validation of an unsigned transaction must be provided by the pallet that chooses to accept them. To allow unsigned transactions, a pallet must implement the [`frame_support::unsigned::ValidateUnsigned`](https://paritytech.github.io/substrate/master/frame_support/attr.pallet.html#validate-unsigned-palletvalidate_unsigned-optional) trait. The `validate_unsigned` function, which must be implemented as part of the `ValidateUnsigned` trait, will provide the logic necessary to ensure that the transaction is valid. An off chain worker (OCW) can be implemented directly in a pallet using the `offchain_worker` [hook](https://paritytech.github.io/substrate/master/frame_support/attr.pallet.html#hooks-pallethooks-optional). The OCW can send an unsigned transaction by calling [`SubmitTransaction::submit_unsigned_transaction`](https://paritytech.github.io/substrate/master/frame_system/offchain/struct.SubmitTransaction.html). Upon submission, the `validate_unsigned` function will ensure that the transaction is valid and then pass the transaction on towards towards the final dispatchable function. # Example -The [`pallet-bad-unsigned`](./pallet-bad-unsigned.rs) pallet is an example that showcases improper unsigned transaction validation. The pallet tracks the average, rolling price of some "asset"; this price data is being retrieved by an OCW. The `fetch_price` function, which is called by the OCW, naively returns 100 as the current price (note that an [HTTP request](https://github.com/paritytech/substrate/blob/e8a7d161f39db70cb27fdad6c6e215cf493ebc3b/frame/examples/offchain-worker/src/lib.rs#L572-L625) can be made here for true price data). The `validate_unsigned` function (see below) simply validates that the `Call` is being made to `submit_price_unsigned` and nothing else. +The [`pallet-bad-unsigned`](./pallet-bad-unsigned.rs) pallet is an example that showcases improper unsigned transaction validation. The pallet tracks the average, rolling price of some "asset"; this price data is being retrieved by an OCW. The `fetch_price` function, which is called by the OCW, naively returns 100 as the current price (note that an [HTTP request](https://github.com/paritytech/substrate/blob/e8a7d161f39db70cb27fdad6c6e215cf493ebc3b/frame/examples/offchain-worker/src/lib.rs#L572-L625) can be made here for true price data). The `validate_unsigned` function (see below) simply validates that the `Call` is being made to `submit_price_unsigned` and nothing else. + ```rust /// By default unsigned transactions are disallowed, but implementing the validator /// here we make sure that some particular calls (the ones produced by offchain worker) @@ -39,9 +40,12 @@ However, notice that there is nothing preventing an attacker from sending malici Note that the simplest solution would be to sign the offchain submissions so that the runtime can validate that a known OCW is sending the price submission transactions. # Mitigations + - Consider whether unsigned transactions is a requirement for the runtime that is being built. OCWs can also submit signed transactions or transactions with signed payloads. -- Ensure that each parameter provided to `validate_unsigned` is validated to prevent the runtime from entering a state that is vulnerable or undefined. +- Ensure that each parameter provided to `validate_unsigned` is validated to prevent the runtime from entering a state that is vulnerable or undefined. + # References + - https://docs.substrate.io/main-docs/fundamentals/transaction-types/#unsigned-transactions - https://docs.substrate.io/main-docs/fundamentals/offchain-operations/ - https://github.com/paritytech/substrate/blob/polkadot-v0.9.26/frame/examples/offchain-worker/src/lib.rs diff --git a/not-so-smart-contracts/substrate/verify_first/README.md b/not-so-smart-contracts/substrate/verify_first/README.md index c8e373da..d45be9e8 100644 --- a/not-so-smart-contracts/substrate/verify_first/README.md +++ b/not-so-smart-contracts/substrate/verify_first/README.md @@ -13,7 +13,9 @@ Substrate does not cache state prior to extrinsic dispatch. Instead, state chang // all event emissions & storage writes go here } ``` + # Example + In the [`pallet-verify-first`](./pallet-verify-first.rs) pallet, the `init` dispatchable is used to set up the `TotalSupply` of the token and transfer them to the `sender`. `init` should be only called once. Thus, the `Init` boolean is set to `true` when it is called initially. If `init` is called more than once, the transaction will throw an error because `Init` is already `true`. ```rust @@ -26,7 +28,7 @@ pub fn init( supply: u64 ) -> DispatchResultWithPostInfo { let sender = ensure_signed(origin)?; - + if supply > 0 { >::put(&supply); } @@ -38,7 +40,7 @@ pub fn init( // Set Init StorageValue to `true` Init::::put(true); - + // Emit event Self::deposit_event(Event::Initialized(sender)); @@ -49,6 +51,9 @@ pub fn init( However, notice that the setting of `TotalSupply` and the transfer of funds happens before the check on `Init`. This violates the "Verify First, Write Last" practice. In an older version of Substrate, this would allow a malicious `sender` to call `init` multiple times and change the value of `TotalSupply` and their balance of the token. # Mitigations + - Follow the "Verify First, Write Last" practice by doing all the necessary data validation before performing state changes and emitting events. + # References -- https://docs.substrate.io/main-docs/build/runtime-storage/#best-practices \ No newline at end of file + +- https://docs.substrate.io/main-docs/build/runtime-storage/#best-practices diff --git a/not-so-smart-contracts/substrate/weights_and_fees/README.md b/not-so-smart-contracts/substrate/weights_and_fees/README.md index 41741fd4..576a602c 100644 --- a/not-so-smart-contracts/substrate/weights_and_fees/README.md +++ b/not-so-smart-contracts/substrate/weights_and_fees/README.md @@ -1,13 +1,14 @@ # Weights and Fees -Weights and transaction fees are the two main ways to regulate the consumption of blockchain resources. The overuse of blockchain resources can allow a malicious actor to spam the network to cause a denial-of-service (DoS). Weights are used to manage the time it takes to validate the block. The larger the weight, the more "resources" / time the computation takes. Transaction fees provide an economic incentive to limit the number of resources used to perform operations; the fee for a given transaction is a function of the weight required by the transaction. +Weights and transaction fees are the two main ways to regulate the consumption of blockchain resources. The overuse of blockchain resources can allow a malicious actor to spam the network to cause a denial-of-service (DoS). Weights are used to manage the time it takes to validate the block. The larger the weight, the more "resources" / time the computation takes. Transaction fees provide an economic incentive to limit the number of resources used to perform operations; the fee for a given transaction is a function of the weight required by the transaction. Weights can be fixed or a custom "weight annotation / function" can be implemented. A weight function can calculate the weight, for example, based on the number of database read / writes and the size of the input paramaters (e.g. a long `Vec<>`). To optimize the weight such that users do not pay too little or too much for a transaction, benchmarking can be used to empirically determine the correct weight in worst case scenarios. -Specifying the correct weight function and benchmarking it is crucial to protect the Substrate node from denial-of-service (DoS) attacks. Since fees are a function of weight, a bad weight function implies incorrect fees. For example, if some function performs heavy computation (which takes a lot of time) but specifies a very small weight, it is cheap to call that function. In this way an attacker can perform a low-cost attack while still stealing a large amount of block execution time. This will prevent regular transactions from being fit into those blocks. +Specifying the correct weight function and benchmarking it is crucial to protect the Substrate node from denial-of-service (DoS) attacks. Since fees are a function of weight, a bad weight function implies incorrect fees. For example, if some function performs heavy computation (which takes a lot of time) but specifies a very small weight, it is cheap to call that function. In this way an attacker can perform a low-cost attack while still stealing a large amount of block execution time. This will prevent regular transactions from being fit into those blocks. # Example -In the [`pallet-bad-weights`](./pallet-bad-weights.rs) pallet, a custom weight function, `MyWeightFunction`, is used to calculate the weight for a call to `do_work`. The weight required for a call to `do_work` is `10_000_000` times the length of the `useful_amounts` vector. + +In the [`pallet-bad-weights`](./pallet-bad-weights.rs) pallet, a custom weight function, `MyWeightFunction`, is used to calculate the weight for a call to `do_work`. The weight required for a call to `do_work` is `10_000_000` times the length of the `useful_amounts` vector. ```rust impl WeighData<(&Vec,)> for MyWeightFunction { @@ -31,19 +32,22 @@ impl WeighData<(&Vec,)> for MyWeightFunction { } ``` -In the example above, if the length of `amounts` (i.e. `useful_amounts`) is zero, then the function will return `self.0` (i.e. `10_000_000`). +In the example above, if the length of `amounts` (i.e. `useful_amounts`) is zero, then the function will return `self.0` (i.e. `10_000_000`). -On the other hand, if an attacker sends a `useful_amounts` vector that is incredibly large, the returned `Weight` can become large enough such that the dispatchable takes up a large amount block execution time and prevents other transactions from being fit into the block. A fix for this would be to bound the maximum allowable length for `useful_amounts`. +On the other hand, if an attacker sends a `useful_amounts` vector that is incredibly large, the returned `Weight` can become large enough such that the dispatchable takes up a large amount block execution time and prevents other transactions from being fit into the block. A fix for this would be to bound the maximum allowable length for `useful_amounts`. **Note**: Custom _fee_ functions can also be created. These functions should also be carefully evaluated and tested to ensure that the risk of DoS attacks is mitigated. + # Mitigations -- Use [benchmarking](https://docs.substrate.io/main-docs/test/benchmark/) to empirically test the computational resources utilized by various dispatchable functions. Additionally, use benchmarking to define a lower and upper weight bound for each dispatchable. + +- Use [benchmarking](https://docs.substrate.io/main-docs/test/benchmark/) to empirically test the computational resources utilized by various dispatchable functions. Additionally, use benchmarking to define a lower and upper weight bound for each dispatchable. - Create bounds for input arguments to prevent a transaction from taking up too many computational resources. For example, if a `Vec<>` is being taken as an input argument to a function, prevent the length of the `Vec<>` from being too large. -- Be wary of fixed weight dispatchables (e.g. `#[pallet::weight(1_000_000)]`). A weight that is completely agnostic to database read / writes or input parameters may open up avenues for DoS attacks. +- Be wary of fixed weight dispatchables (e.g. `#[pallet::weight(1_000_000)]`). A weight that is completely agnostic to database read / writes or input parameters may open up avenues for DoS attacks. # References + - https://docs.substrate.io/main-docs/build/tx-weights-fees/ - https://docs.substrate.io/reference/how-to-guides/weights/add-benchmarks/ - https://docs.substrate.io/reference/how-to-guides/weights/use-custom-weights/ - https://docs.substrate.io/reference/how-to-guides/weights/use-conditional-weights/ -- https://www.shawntabrizi.com/substrate/substrate-weight-and-fees/ \ No newline at end of file +- https://www.shawntabrizi.com/substrate/substrate-weight-and-fees/ diff --git a/program-analysis/README.md b/program-analysis/README.md index 3e351c30..5ef2a1d4 100644 --- a/program-analysis/README.md +++ b/program-analysis/README.md @@ -8,11 +8,11 @@ We are going use three distinctive testing and program analysis techniques: Each technique has advantages and pitfalls, and will be useful in [specific cases](#determining-security-properties): -Technique | Tool | Usage | Speed | Bugs missed | False Alarms ---- | --- | --- | --- | --- | --- -Static Analysis | Slither | CLI & scripts | seconds | moderate | low -Fuzzing | Echidna | Solidity properties | minutes | low | none -Symbolic Execution | Manticore | Solidity properties & scripts | hours | none\* | none +| Technique | Tool | Usage | Speed | Bugs missed | False Alarms | +| ------------------ | --------- | ----------------------------- | ------- | ----------- | ------------ | +| Static Analysis | Slither | CLI & scripts | seconds | moderate | low | +| Fuzzing | Echidna | Solidity properties | minutes | low | none | +| Symbolic Execution | Manticore | Solidity properties & scripts | hours | none\* | none | \* if all the paths are explored without timeout @@ -40,7 +40,7 @@ To effectively test and verify your code, you must identify the areas that need - [Rapid Risk Assessments](https://infosec.mozilla.org/guidelines/risk/rapid_risk_assessment.html) (our preferred approach when time is short) - [Guide to Data-Centric System Threat Modeling](https://csrc.nist.gov/publications/detail/sp/800-154/draft) (aka NIST 800-154) - [Shostack thread modeling](https://www.amazon.com/Threat-Modeling-Designing-Adam-Shostack/dp/1118809998) -- [STRIDE](https://en.wikipedia.org/wiki/STRIDE_(security)) / [DREAD](https://en.wikipedia.org/wiki/DREAD_(risk_assessment_model)) +- [STRIDE]() / [DREAD]() - [PASTA](https://en.wikipedia.org/wiki/Threat_model#P.A.S.T.A.) - [Use of Assertions](https://blog.regehr.org/archives/1091) @@ -51,33 +51,38 @@ Knowing what you want to check will also help you to select the right tool. The broad areas that are frequently relevant for smart contracts include: - **State machine.** Most contracts can be represented as a state machine. Consider checking that (1) No invalid state can be reached, (2) if a state is valid that it can be reached, and (3) no state traps the contract. + - Echidna and Manticore are the tools to favor to test state-machine specifications. - **Access controls.** If you system has privileged users (e.g. an owner, controllers, ...) you must ensure that (1) each user can only perform the authorized actions and (2) no user can block actions from a more priviledged user. + - Slither, Echidna and Manticore can check for correct access controls. For example, Slither can check that only whitelisted functions lack the onlyOwner modifier. Echidna and Manticore are useful for more complex access control, such as a permission given only if the contract reaches a given state. - **Arithmetic operations.** Checking the soundness of the arithmetic operations is critical. Using `SafeMath` everywhere is a good step to prevent overflow/underflow, however, you must still consider other arithmetic flaws, including rounding issues and flaws that trap the contract. + - Manticore is the best choice here. Echidna can be used if the arithmetic is out-of-scope of the SMT solver. - **Inheritance correctness.** Solidity contracts rely heavily on multiple inheritance. Mistakes such as a shadowing function missing a `super` call and misinterpreted c3 linearization order can easily be introduced. + - Slither is the tool to ensure detection of these issues. - **External interactions.** Contracts interact with each other, and some external contracts should not be trusted. For example, if your contract relies on external oracles, will it remain secure if half the available oracles are compromised? + - Manticore and Echidna are the best choice for testing external interactions with your contracts. Manticore has an built-in mechanism to stub external contracts. - **Standard conformance.** Ethereum standards (e.g. ERC20) have a history of flaws in their design. Be aware of the limitations of the standard you are building on. - - Slither, Echidna, and Manticore will help you to detect deviations from a given standard. + - Slither, Echidna, and Manticore will help you to detect deviations from a given standard. ### Tool selection cheatsheet -Component | Tools | Examples ---- | --- | --- | -State machine | Echidna, Manticore | -Access control | Slither, Echidna, Manticore | [Slither exercise 2](./slither/exercise2.md), [Echidna exercise 2](./echidna/exercises/Exercise-2.md) -Arithmetic operations | Manticore, Echidna | [Echidna exercise 1](./echidna/exercises/Exercise-1.md), [Manticore exercises 1 - 3](./manticore/exercises) -Inheritance correctness | Slither | [Slither exercise 1](./slither/exercise1.md) -External interactions | Manticore, Echidna | -Standard conformance | Slither, Echidna, Manticore | [`slither-erc`](https://github.com/crytic/slither/wiki/ERC-Conformance) +| Component | Tools | Examples | +| ----------------------- | --------------------------- | ----------------------------------------------------------------------------------------------------------- | +| State machine | Echidna, Manticore | +| Access control | Slither, Echidna, Manticore | [Slither exercise 2](./slither/exercise2.md), [Echidna exercise 2](./echidna/exercises/Exercise-2.md) | +| Arithmetic operations | Manticore, Echidna | [Echidna exercise 1](./echidna/exercises/Exercise-1.md), [Manticore exercises 1 - 3](./manticore/exercises) | +| Inheritance correctness | Slither | [Slither exercise 1](./slither/exercise1.md) | +| External interactions | Manticore, Echidna | +| Standard conformance | Slither, Echidna, Manticore | [`slither-erc`](https://github.com/crytic/slither/wiki/ERC-Conformance) | Other areas will need to be checked depending on your goals, but these coarse-grained areas of focus are a good start for any smart contract system. diff --git a/program-analysis/echidna/README.md b/program-analysis/echidna/README.md index a03f4241..a489644f 100644 --- a/program-analysis/echidna/README.md +++ b/program-analysis/echidna/README.md @@ -1,6 +1,6 @@ # Echidna Tutorial -The aim of this tutorial is to show how to use Echidna to automatically test smart contracts. +The aim of this tutorial is to show how to use Echidna to automatically test smart contracts. Watch our [Fuzzing workshop](https://www.youtube.com/watch?v=QofNQxW_K08&list=PLciHOL_J7Iwqdja9UH4ZzE8dP1IxtsBXI) to learn through live coding sessions. @@ -11,7 +11,6 @@ Watch our [Fuzzing workshop](https://www.youtube.com/watch?v=QofNQxW_K08&list=PL - [Advanced](advanced): Learn advanced features of Echidna - [Fuzzing tips](./fuzzing_tips.md): General fuzzing tips - [Frequently Asked Questions](./frequently_asked_questions.md): Answers to common questions about Echidna -- [Exercises](exercises): Exercises +- [Exercises](exercises): Exercises Join the team on Slack at: https://empireslacking.herokuapp.com/ #ethereum - diff --git a/program-analysis/echidna/advanced/collecting-a-corpus.md b/program-analysis/echidna/advanced/collecting-a-corpus.md index d91a7bba..0d5eb19c 100644 --- a/program-analysis/echidna/advanced/collecting-a-corpus.md +++ b/program-analysis/echidna/advanced/collecting-a-corpus.md @@ -9,7 +9,7 @@ ## Introduction -We will see how to collect and use a corpus of transactions with Echidna. The target is the following smart contract (*[../example/magic.sol](../example/magic.sol)*): +We will see how to collect and use a corpus of transactions with Echidna. The target is the following smart contract (_[../example/magic.sol](../example/magic.sol)_): ```Solidity contract C { @@ -34,7 +34,7 @@ This small example forces Echidna to find certain values to change a state varia We can run Echidna to verify this: ``` -$ echidna-test magic.sol +$ echidna-test magic.sol ... echidna_magic_values: passed! 🎉 @@ -61,7 +61,7 @@ corpusDir: "corpus-magic" Now we can run our tool and check the collected corpus: ``` -$ echidna-test magic.sol --config config.yaml +$ echidna-test magic.sol --config config.yaml ``` Echidna still cannot find the correct magic value. We can verify where it gets stuck reviewing the `corpus-magic/covered.*.txt` file: @@ -84,60 +84,51 @@ r | require(magic_3 == magic_4+333); } ``` -The label `r` on the left of each line shows that Echidna is able to reach these lines but it ends in a revert. +The label `r` on the left of each line shows that Echidna is able to reach these lines but it ends in a revert. As you can see, the fuzzer gets stuck at the last `require`. To find a workaround, let's take a look at the corpus it collected. For instance, one of these files was: ```json [ - { - "_gas'" : "0xffffffff", - "_delay" : [ - "0x13647", - "0xccf6" - ], - "_src" : "00a329c0648769a73afac7f9381e08fb43dbea70", - "_dst" : "00a329c0648769a73afac7f9381e08fb43dbea72", - "_value" : "0x0", - "_call" : { - "tag" : "SolCall", - "contents" : [ - "magic", - [ - { - "contents" : [ - 256, - "93723985220345906694500679277863898678726808528711107336895287282192244575836" - ], - "tag" : "AbiUInt" - }, - { - "contents" : [ - 256, - "334" - ], - "tag" : "AbiUInt" - }, - { - "contents" : [ - 256, - "68093943901352437066264791224433559271778087297543421781073458233697135179558" - ], - "tag" : "AbiUInt" - }, - { - "tag" : "AbiUInt", - "contents" : [ - 256, - "332" - ] - } - ] - ] - }, - "_gasprice'" : "0xa904461f1" - } + { + "_gas'": "0xffffffff", + "_delay": ["0x13647", "0xccf6"], + "_src": "00a329c0648769a73afac7f9381e08fb43dbea70", + "_dst": "00a329c0648769a73afac7f9381e08fb43dbea72", + "_value": "0x0", + "_call": { + "tag": "SolCall", + "contents": [ + "magic", + [ + { + "contents": [ + 256, + "93723985220345906694500679277863898678726808528711107336895287282192244575836" + ], + "tag": "AbiUInt" + }, + { + "contents": [256, "334"], + "tag": "AbiUInt" + }, + { + "contents": [ + 256, + "68093943901352437066264791224433559271778087297543421781073458233697135179558" + ], + "tag": "AbiUInt" + }, + { + "tag": "AbiUInt", + "contents": [256, "332"] + } + ] + ] + }, + "_gasprice'": "0xa904461f1" + } ] ``` @@ -155,9 +146,9 @@ $ cp corpus-magic/coverage/2712688662897926208.txt corpus-magic/coverage/new.txt We will modify `new.txt` to call `magic(42,129,333,0)`. Now, we can re-run Echidna: ``` -$ echidna-test magic.sol --config config.yaml +$ echidna-test magic.sol --config config.yaml ... -echidna_magic_values: failed!💥 +echidna_magic_values: failed!💥 Call sequence: magic(42,129,333,0) diff --git a/program-analysis/echidna/advanced/end-to-end-testing.md b/program-analysis/echidna/advanced/end-to-end-testing.md index b8bd103f..7149240a 100644 --- a/program-analysis/echidna/advanced/end-to-end-testing.md +++ b/program-analysis/echidna/advanced/end-to-end-testing.md @@ -6,11 +6,11 @@ When smart contracts require a complex initialization and the time to do it is s This approach needs a smart contract project, with the following constraints: -* It should use Solidity: Vyper is not supported, since Slither/Echidna is not very effective at running these (e.g. no AST is included). -* It should have tests or at least, a complete deployment script. -* It should work with Slither. If it fails, [please report the issue](https://github.com/crytic/slither). +- It should use Solidity: Vyper is not supported, since Slither/Echidna is not very effective at running these (e.g. no AST is included). +- It should have tests or at least, a complete deployment script. +- It should work with Slither. If it fails, [please report the issue](https://github.com/crytic/slither). -For this tutorial, [we used the drizzle-box example](https://github.com/truffle-box/drizzle-box). +For this tutorial, [we used the drizzle-box example](https://github.com/truffle-box/drizzle-box). ## Getting started: @@ -24,7 +24,7 @@ $ cd drizzle-box $ npm i truffle ``` -If `ganache` is not installed, add it manually. In our example, we will run: +If `ganache` is not installed, add it manually. In our example, we will run: ``` $ npm -g i ganache @@ -38,7 +38,7 @@ $ yarn global add ganache Ensure that `$ ganache --version` outputs `ganache v7.3.2` or greater. -It is also important to select *one* test script from the available tests. Ideally, this test will deploy all (or most) contracts, including mock/test ones. For this example, we are going to take a look to the `SimpleStorage` contract: +It is also important to select _one_ test script from the available tests. Ideally, this test will deploy all (or most) contracts, including mock/test ones. For this example, we are going to take a look to the `SimpleStorage` contract: ```solidity contract SimpleStorage { @@ -59,7 +59,7 @@ This small contract allows to set the `storedData` state variable. As expected, ```js const SimpleStorage = artifacts.require("SimpleStorage"); -contract("SimpleStorage", accounts => { +contract("SimpleStorage", (accounts) => { it("...should store the value 89.", async () => { const simpleStorageInstance = await SimpleStorage.deployed(); @@ -78,13 +78,14 @@ contract("SimpleStorage", accounts => { Before starting to write interesting properties, it is necessary to to collect an Etheno trace to replay it inside Echidna: -First, start Etheno: +First, start Etheno: ```bash $ etheno --ganache --ganache-args="--miner.blockGasLimit 10000000" -x init.json ``` By default the following Ganache arguments are set via Etheno: + - `-d`: Ganache will use a pre-defined, deterministic seed to create all accounts. - `--chain.allowUnlimitedContractSize`: Allows unlimited contract sizes while debugging. This is set so that there is no size limitations on the contracts that are going to be deployed - `-p `: The `port_num` will be set to (1) the value of `--ganache-port` or (2) Etheno will choose the smallest port number higher than the port number on which Etheno’s JSON RPC server is running. @@ -96,17 +97,16 @@ $ docker run -it -p 8545:8545 -v ~/etheno:/home/etheno/ trailofbits/etheno (you will now be working within the Docker instance) $ etheno --ganache --ganache-args="--miner.blockGasLimit 10000000" -x init.json ``` + - The `-p` in the _first command_ publishes (i.e. exposes) port 8545 from inside the Docker container out to port 8545 on the host. - The `-v` in the _first command_ maps a directory from inside the Docker container to one outside the Docker container. After Etheno exits, the `init.json` file will now be in the `~/etheno` folder on the host. - - Note that if the deployment fails to complete successfully due to a `ProviderError: exceeds block gas limit` exception, increasing the `--miner.blockGasLimit` value can help. -This is especially helpful for large contract deployments. Learn more about the various Ganache command-line arguments that can be set by clicking [here](https://www.npmjs.com/package/ganache). +This is especially helpful for large contract deployments. Learn more about the various Ganache command-line arguments that can be set by clicking [here](https://www.npmjs.com/package/ganache). Additionally, if Etheno fails to produce any output, then it failed to execute `ganache` under-the-hood. Check if `ganache` (with the associated command-line arguments) can be executed correctly from your terminal without the use of Etheno. -Meanwhile, in another terminal, run *one* test or the deployment process. How to run it depends on how the project was developed. For instance, for truffle, use: +Meanwhile, in another terminal, run _one_ test or the deployment process. How to run it depends on how the project was developed. For instance, for truffle, use: ``` $ truffle test test/test.js @@ -149,15 +149,15 @@ This simple property checks if the stored data remains constant. To run it you w prefix: crytic_ initialize: init.json multi-abi: true -cryticArgs: ['--truffle-build-directory', 'app/src/contracts/'] # needed by drizzle +cryticArgs: ["--truffle-build-directory", "app/src/contracts/"] # needed by drizzle ``` -Then, running Echidna shows the results immediately: +Then, running Echidna shows the results immediately: ``` $ echidna-test . --contract E2E --config echidna.yaml ... -crytic_const_storage: failed!💥 +crytic_const_storage: failed!💥 Call sequence: (0x871dd7c2b4b25e1aa18728e9d5f2af4c4e431f5c).set(0) from: 0x0000000000000000000000000000000000010000 ``` @@ -165,8 +165,10 @@ crytic_const_storage: failed!💥 For this last step, make sure you are using `.` as a target for `echidna-test`. If you use the path to the `E2E.sol` file instead, then Echidna will not be able get information from all the deployed contracts to call the `set(uint256)` function and the property will never fail. ## Key considerations: + When using Etheno with Echidna, note that there are two edge cases that may cause unexpected behavior: + 1. Function calls that use ether: The accounts that are created and used for testing in Ganache are not the same as the accounts that are used to send transactions in Echidna. Thus, the account balances of the Ganache accounts do not carry over to the accounts used by Echidna. So, if there is a function call logged by Etheno that requires the transfer of some ether from an account that exists in Ganache, this call will fail in Echidna. -2. Fuzz tests that rely on `block.timestamp`: The concept of time is different between Ganache and Echidna. Echidna always starts with a fixed timestamp while Etheno will use Ganache's concept of time. This means that assertions or requirements in a fuzz test that rely on timestamp comparisons / evaluations may fail in Echidna. +2. Fuzz tests that rely on `block.timestamp`: The concept of time is different between Ganache and Echidna. Echidna always starts with a fixed timestamp while Etheno will use Ganache's concept of time. This means that assertions or requirements in a fuzz test that rely on timestamp comparisons / evaluations may fail in Echidna. In the next part of this tutorial, we will explore how to easily find where contracts are deployed with a specific tool based on Slither. This will be useful if the deployment process is complex and we need to test an specific contract. diff --git a/program-analysis/echidna/advanced/finding-transactions-with-high-gas-consumption.md b/program-analysis/echidna/advanced/finding-transactions-with-high-gas-consumption.md index 1e716170..c5b773c0 100644 --- a/program-analysis/echidna/advanced/finding-transactions-with-high-gas-consumption.md +++ b/program-analysis/echidna/advanced/finding-transactions-with-high-gas-consumption.md @@ -11,7 +11,7 @@ ## Introduction -We will see how to find the transactions with high gas consumption with Echidna. The target is the following smart contract (*[../example/gas.sol](../example/gas.sol)*): +We will see how to find the transactions with high gas consumption with Echidna. The target is the following smart contract (_[../example/gas.sol](../example/gas.sol)_): ```solidity contract C { @@ -35,7 +35,8 @@ contract C { } ``` -Here `expensive` can have a large gas consumption. + +Here `expensive` can have a large gas consumption. Currently, Echidna always needs a property to test: here `echidna_test` always returns `true`. We can run Echidna to verify this: @@ -56,7 +57,7 @@ To enable Echidna's gas consumption feature, create a configuration file [`../ex estimateGas: true ``` -In this example, we will also reduce the size of the transaction sequence to make the results easier to understand: +In this example, we will also reduce the size of the transaction sequence to make the results easier to understand: ```yaml seqLen: 2 @@ -68,7 +69,7 @@ estimateGas: true Once we have the configuration file created, we can run Echidna like this: ``` -$ echidna-test gas.sol --config config.yaml +$ echidna-test gas.sol --config config.yaml ... echidna_test: passed! 🎉 @@ -89,7 +90,7 @@ Seed: -325611019680165325 The tutorial on [filtering functions to call during a fuzzing campaign](../basic/filtering-functions.md) shows how to remove some functions during testing. This can be critical for getting an accurate gas estimate. -Consider the following example (*[example/pushpop.sol](../example/pushpop.sol)*): +Consider the following example (_[example/pushpop.sol](../example/pushpop.sol)_): ```solidity contract C { @@ -114,6 +115,7 @@ contract C { } } ``` + If Echidna uses this [`config.yaml`](../example/pushpop.yaml), it can call all functions and won't easily find transactions with high gas cost: ``` @@ -129,7 +131,7 @@ push used a maximum of 40839 gas ``` That's because the cost depends on the size of `addrs` and random calls tend to leave the array almost empty. -Blacklisting `pop` and `clear`, however, gives us much better results (*[../example/blacklistpushpop.yaml](../example/blacklistpushpop.yaml)*): +Blacklisting `pop` and `clear`, however, gives us much better results (_[../example/blacklistpushpop.yaml](../example/blacklistpushpop.yaml)_): ```yaml estimateGas: true @@ -154,7 +156,7 @@ estimateGas: true ``` ```bash -$ echidna-test contract.sol --config config.yaml +$ echidna-test contract.sol --config config.yaml ... ``` diff --git a/program-analysis/echidna/advanced/hevm-cheats-to-test-permit.md b/program-analysis/echidna/advanced/hevm-cheats-to-test-permit.md index bb6674d9..18043590 100644 --- a/program-analysis/echidna/advanced/hevm-cheats-to-test-permit.md +++ b/program-analysis/echidna/advanced/hevm-cheats-to-test-permit.md @@ -1,18 +1,18 @@ # Using HEVM Cheats To Test Permit -## Introduction +## Introduction [EIP 2612](https://eips.ethereum.org/EIPS/eip-2612) introduces the function `permit(address owner, address spender, uint value, uint deadline, uint8 v, bytes32 r, bytes32 s)` to the ERC20 abi. This function essentially takes in signature parameters generated through ECDSA combined with the [EIP 712](https://eips.ethereum.org/EIPS/eip-712) standard for typed data hashing, and recovers the author of the signature through `ecrecover()`. It then sets `allowances[owner][spender]` to `value`. -## Uses +## Uses This is a new way of allocating allowances, as signatures can be computed offchain and passed to a contract. This allows a relayer to pay the entire gas fee of the permit transaction in exchange for a fee and thus allows completely gasless transactions for a user. Furthermore this removes the typical `approve() -> transferFrom()` pattern that forces users to send two transactions instead of just one via this new method. Do note that for the permit function to work, a valid signature is needed. This example will show how we can use [`hevm`'s `sign` cheatcode](https://github.com/dapphub/dapptools/blob/master/src/hevm/README.md#cheat-codes) to sign data with a private key. More generally, you can use this cheatcode to test anything that requires valid signatures. -## Example +## Example -We use solmate’s implementation of the ERC20 standard that includes the permit function. Notice that there are also values for the `PERMIT_TYPEHASH` and a `mapping(address -> uint256) public nonces` , the former is a part of the EIP712 standard and the latter is used to prevent signature replay attacks. +We use solmate’s implementation of the ERC20 standard that includes the permit function. Notice that there are also values for the `PERMIT_TYPEHASH` and a `mapping(address -> uint256) public nonces` , the former is a part of the EIP712 standard and the latter is used to prevent signature replay attacks. In our `TestDepositWithPermit` contract, we need to have the signature signed by an owner for validation. To do this, we can use `hevm`’s `sign` cheatcode, which takes in a message and a private key and creates a valid signature. For this example, we use the private key `0x02` and the following signed message, which essentially represents the permit signature following EIP 712: @@ -37,9 +37,9 @@ In our `TestDepositWithPermit` contract, we need to have the signature signed by ); ``` -The helper function `getSignature(address owner, address spender, uint256 assetAmount)` returns a valid signature generated via the `sign` cheatcode. Note that the sign cheatcode leaks the private key and thus it is best to use dummy keys when testing. Our keypair data was taken from [this site](https://privatekeys.pw/keys/ethereum/1). Now to test out the signature, we will mint a random amount to the `OWNER` address, the address corresponding to private key `0x02`, which was the signer of the permit signature. We then see if we can use that signature to transfer the owner’s tokens to ourselves. +The helper function `getSignature(address owner, address spender, uint256 assetAmount)` returns a valid signature generated via the `sign` cheatcode. Note that the sign cheatcode leaks the private key and thus it is best to use dummy keys when testing. Our keypair data was taken from [this site](https://privatekeys.pw/keys/ethereum/1). Now to test out the signature, we will mint a random amount to the `OWNER` address, the address corresponding to private key `0x02`, which was the signer of the permit signature. We then see if we can use that signature to transfer the owner’s tokens to ourselves. -First we will call `permit()` on our Mock ERC20 token with the signature generated in `getSignature()`, and then call `transferFrom()`. If our permit request and transfer was successful, our balance of the mock ERC20 should be increased by the amount permitted and `OWNER`'s balance should decrease as well. For simplicity, we'll transfer all the minted tokens so that `OWNER`'s balance should be `0`, and our balance should be `amount`. +First we will call `permit()` on our Mock ERC20 token with the signature generated in `getSignature()`, and then call `transferFrom()`. If our permit request and transfer was successful, our balance of the mock ERC20 should be increased by the amount permitted and `OWNER`'s balance should decrease as well. For simplicity, we'll transfer all the minted tokens so that `OWNER`'s balance should be `0`, and our balance should be `amount`. ## Code diff --git a/program-analysis/echidna/advanced/optimization_mode.md b/program-analysis/echidna/advanced/optimization_mode.md index 47080f35..c440999b 100644 --- a/program-analysis/echidna/advanced/optimization_mode.md +++ b/program-analysis/echidna/advanced/optimization_mode.md @@ -8,10 +8,10 @@ ## Introduction -We will see how to perform function optimization using Echidna. This tutorial will require Echidna 2.0.5 or greater, +We will see how to perform function optimization using Echidna. This tutorial will require Echidna 2.0.5 or greater, so make sure you have update it before starting. -Optimization mode is a experimental feature that allows to define a special function which takes no arguments +Optimization mode is a experimental feature that allows to define a special function which takes no arguments and returns a `int256`. Echidna will try find a sequence of transactions to maximize the value returned: ```solidity @@ -23,7 +23,7 @@ and returns a `int256`. Echidna will try find a sequence of transactions to maxi ## Optimizing with Echidna -In this example, the target is the following smart contract (*[../example/opt.sol](../example/opt.sol)*): +In this example, the target is the following smart contract (_[../example/opt.sol](../example/opt.sol)_): ```solidity contract TestDutchAuctionOptimization { @@ -77,7 +77,7 @@ echidna_opt_price_difference: max value: 1076841 The resulting max value is not unique, running in longer campaign will likely result in a larger value. -Regarding the command line, the optimization mode is enabled using `--test-mode optimization`. additionally, we included the following tweaks: +Regarding the command line, the optimization mode is enabled using `--test-mode optimization`. additionally, we included the following tweaks: 1. Use only one transaction (we know that the function is stateless) 2. Use a large shrink limit in order to obtain a better value during the minimization of the complexity of the input. diff --git a/program-analysis/echidna/advanced/smart-contract-fuzzing-at-scale.md b/program-analysis/echidna/advanced/smart-contract-fuzzing-at-scale.md index c229ec6a..bb3c2e30 100644 --- a/program-analysis/echidna/advanced/smart-contract-fuzzing-at-scale.md +++ b/program-analysis/echidna/advanced/smart-contract-fuzzing-at-scale.md @@ -8,12 +8,12 @@ In this tutorial we will review how we can create a dedicated server for fuzzing 2. Start a short fuzzing campaign 3. Start a continuous fuzzing campaign 4. Add properties, check coverage and modify the code if necessary -5. Ending the campaign +5. Ending the campaign ## 1. Install and setup a dedicated server -First, obtain a dedicated server with at least 32 GB of RAM and as many cores as possible. Start by creating a user for the fuzzing campaign. -**Only use the root acount to create an unprivileged user**: +First, obtain a dedicated server with at least 32 GB of RAM and as many cores as possible. Start by creating a user for the fuzzing campaign. +**Only use the root acount to create an unprivileged user**: ``` # adduser echidna @@ -54,15 +54,15 @@ Before starting this campaign, modify your echidna config to define a corpus dir corpusDir: "corpus-exploration" ``` -This directory will be automatically created but since we are starting a new campaign, **please remove the corpus directory if it was created by a previous echidna campaign**. +This directory will be automatically created but since we are starting a new campaign, **please remove the corpus directory if it was created by a previous echidna campaign**. If you don't have any properties to test, you can use: ``` testMode: exploration ``` -to allow Echidna to run without any properties. - +to allow Echidna to run without any properties. + We will start a very short Echidna run (5 minutes), to check that everything looks fine. To do that, use the following config: ``` @@ -72,7 +72,6 @@ timeout: 300 # 5 minutes After it runs, check the coverage file, located in `corpus-exploration/covered.*.txt`. If the initialization is wrong, **clean the `corpus-exploration` directory** and restart the campaign. - ## 3. Starting a continuous fuzzing campaign When you are satisfied with the first iteration of the initialization, we can start a "continuous campaign" for exploration and testing using [echidna-parade](https://github.com/agroce/echidna-parade). Before starting, double check your config file. For instance, if you added properties, do not forget to remove `benchmarkMode`. @@ -80,16 +79,17 @@ When you are satisfied with the first iteration of the initialization, we can st `echidna-parade` is a tool is used to launch multiple Echidna instances at the same time, keeping track of the corpora of each one. Each instance will be configured to run for a certain amount of time, with different parameters, in order to maximize the chance to reach new code. We will show it with an example, where: -* the initial corpus is empty -* the base config file will be `exploration.yaml` -* the time to run the initial instance will be 3600 seconds (1 hour) -* the time to run each "generation" will be 1800 seconds (30 minutes) -* the campaign will run in continuous mode (if timeout is -1, it means run forever) -* the number of Echidna instances per generation will be 8. This should be adjusted according to the number of available cores, but avoid using all your cores if you don't want to kill your server -* the target contract is named `C` -* the file that contains the contract is `test.sol` -Finally, we will log the stdout and stderr in `parade.log` and `parade.err` and fork the process to let it run forever. +- the initial corpus is empty +- the base config file will be `exploration.yaml` +- the time to run the initial instance will be 3600 seconds (1 hour) +- the time to run each "generation" will be 1800 seconds (30 minutes) +- the campaign will run in continuous mode (if timeout is -1, it means run forever) +- the number of Echidna instances per generation will be 8. This should be adjusted according to the number of available cores, but avoid using all your cores if you don't want to kill your server +- the target contract is named `C` +- the file that contains the contract is `test.sol` + +Finally, we will log the stdout and stderr in `parade.log` and `parade.err` and fork the process to let it run forever. ``` $ echidna-parade test.sol --config exploration.yaml --initial_time 3600 --gen_time 1800 --timeout -1 --ncores 8 --contract C > parade.log 2> parade.err & @@ -99,8 +99,8 @@ $ echidna-parade test.sol --config exploration.yaml --initial_time 3600 --gen_ti ## 4. Add more properties, check coverage and modify the code if necessary -In this step, we can add more properties while Echidna is exploring the contracts. Keep in mind that you should avoid changing the ABI of the contracts -(otherwise the quality of the corpus will degrade). +In this step, we can add more properties while Echidna is exploring the contracts. Keep in mind that you should avoid changing the ABI of the contracts +(otherwise the quality of the corpus will degrade). Also, we can tweak the code to improve coverage, but before starting that, we need to know how to monitor our fuzzing campaign. We can use this command: @@ -119,7 +119,7 @@ COLLECTING NEW COVERAGE: parade.181140/gen.37.7/corpus/coverage/3230611262129031 COLLECTING NEW COVERAGE: parade.181140/gen.37.6/corpus/coverage/6733481703877290093.txt ``` -you can verify the corresponding covered file, such as `parade.181140/gen.37.6/corpus/covered.1615497368.txt`. +you can verify the corresponding covered file, such as `parade.181140/gen.37.6/corpus/covered.1615497368.txt`. For examples on how to help Echidna to improve its coverage, please review the [improving coverage tutorial](./collecting-a-corpus.md). diff --git a/program-analysis/echidna/advanced/testing-bytecode.md b/program-analysis/echidna/advanced/testing-bytecode.md index eda3c858..147e9e73 100644 --- a/program-analysis/echidna/advanced/testing-bytecode.md +++ b/program-analysis/echidna/advanced/testing-bytecode.md @@ -1,6 +1,7 @@ # How to test bytecode only contracts **Table of contents:** + - [How to test bytecode only contracts](#how-to-test-bytecode-only-contracts) - [Introduction](#introduction) - [Proxy pattern](#proxy-pattern) @@ -12,15 +13,17 @@ ## Introduction -We will see how to fuzz a contract without any provided source code. +We will see how to fuzz a contract without any provided source code. The technique can also be used to perform differential fuzzing (i.e. compare multiple implementations) between a Solidity contract and a Vyper contract. Consider the following bytecode: + ``` 608060405234801561001057600080fd5b506103e86000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055506103e86001819055506101fa8061006e6000396000f3fe608060405234801561001057600080fd5b50600436106100415760003560e01c806318160ddd1461004657806370a0823114610064578063a9059cbb146100bc575b600080fd5b61004e61010a565b6040518082815260200191505060405180910390f35b6100a66004803603602081101561007a57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610110565b6040518082815260200191505060405180910390f35b610108600480360360408110156100d257600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050610128565b005b60015481565b60006020528060005260406000206000915090505481565b806000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008282540392505081905550806000808473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008282540192505081905550505056fe ``` For which we only know the ABI: + ```solidity interface Target{ function totalSupply() external returns(uint); @@ -31,8 +34,8 @@ interface Target{ We want to test if it is possible to have more tokens than the total supply. - ## Proxy pattern + Because we don't have the source code, we cannot directly add the property in the contract. Instead we will use a proxy contract: @@ -70,6 +73,7 @@ contract TestBytecodeOnly{ ``` The proxy: + - Deploys the bytecode in its constructor - Has one function that will call the target's `transfer` function - Has one Echidna property `t.balanceOf(address(this)) <= t.totalSupply()` @@ -78,16 +82,17 @@ The proxy: ```bash $ echidna-test bytecode_only.sol --contract TestBytecodeOnly -echidna_test_balance: failed!💥 +echidna_test_balance: failed!💥 Call sequence: transfer(0x0,1002) ``` -Here Echidna found that by calling `transfer(0, 1002)` anyone can mint tokens. +Here Echidna found that by calling `transfer(0, 1002)` anyone can mint tokens. ### Target source code The actual source code of the target is: + ```solidity contract C{ mapping(address => uint) public balanceOf; @@ -110,6 +115,7 @@ Echidna correctly found the bug: lack of overflow checks in `transfer`. ## Differential fuzzing Consider the following Vyper and Solidity contracts: + ```vyper @view @external @@ -160,13 +166,16 @@ contract SolidityVersion{ ``` Here we run Echidna with the [assertion mode](../basic/assertion-checking.md): + ``` $ echidna-test vyper.sol --config config.yaml --contract SolidityVersion --test-mode assertion assertion in test: passed! 🎉 ``` ## Generic Proxy code + Adapt the following code to your needs: + ```solidity interface Target{ // public/external functions @@ -196,7 +205,6 @@ contract TestBytecodeOnly{ } ``` - ## Summary: Testing contracts without source code Echidna can fuzz contracts without source code using a proxy contract. This technique can be also used to compare implementations written in Solidity and Vyper. diff --git a/program-analysis/echidna/advanced/using-multi-abi.md b/program-analysis/echidna/advanced/using-multi-abi.md index 41b13cb5..1d599946 100644 --- a/program-analysis/echidna/advanced/using-multi-abi.md +++ b/program-analysis/echidna/advanced/using-multi-abi.md @@ -54,7 +54,7 @@ contract Flag { } ``` -The test harness will instantiate a new `Flag`, and the invariant under test will be that `f.get()` (that is, the boolean value of the flag) is always false. +The test harness will instantiate a new `Flag`, and the invariant under test will be that `f.get()` (that is, the boolean value of the flag) is always false. ```solidity contract EchidnaTest { @@ -84,7 +84,7 @@ To run the Echidna tests, run `echidna-test multiabi.sol --contract EchidnaTest ### Example run with `multi-abi` set to `false` ``` -$ echidna-test multiabi.sol --contract EchidnaTest --config multiabi.yaml +$ echidna-test multiabi.sol --contract EchidnaTest --config multiabi.yaml Analyzing contract: building-secure-contracts/program-analysis/echidna/example/multiabi.sol:EchidnaTest test_flag_is_false(): passed! 🎉 AssertionFailed(..): passed! 🎉 @@ -98,9 +98,9 @@ Seed: -8252538430849362039 ### Example run with `multi-abi` set to `true` ``` -$ echidna-test multiabi.sol --contract EchidnaTest --config multiabi.yaml +$ echidna-test multiabi.sol --contract EchidnaTest --config multiabi.yaml Analyzing contract: building-secure-contracts/program-analysis/echidna/example/multiabi.sol:EchidnaTest -test_flag_is_false(): failed!💥 +test_flag_is_false(): failed!💥 Call sequence: flip() flip() diff --git a/program-analysis/echidna/basic/assertion-checking.md b/program-analysis/echidna/basic/assertion-checking.md index 0020d4cc..41442341 100644 --- a/program-analysis/echidna/basic/assertion-checking.md +++ b/program-analysis/echidna/basic/assertion-checking.md @@ -15,7 +15,7 @@ In this short tutorial, we will show you how to use Echidna to check assertions ## Write an assertion -Let's suppose we have a contract like this one: +Let's suppose we have a contract like this one: ```solidity contract Incrementor { @@ -30,7 +30,7 @@ contract Incrementor { } ``` -We want to make sure that `tmp` is less than or equal to `counter` after returning its difference. We could write an Echidna property, but we will need to store the `tmp` value somewhere. Instead, we could use an assertion like this one (*[../example/assert.sol](../example/assert.sol)*): +We want to make sure that `tmp` is less than or equal to `counter` after returning its difference. We could write an Echidna property, but we will need to store the `tmp` value somewhere. Instead, we could use an assertion like this one (_[../example/assert.sol](../example/assert.sol)_): ```solidity contract Incrementor { @@ -64,7 +64,7 @@ contract Incrementor { ## Run Echidna -To enable the assertion failure testing in Echidna, you can use `--test-mode assertion` directly from the command line. +To enable the assertion failure testing in Echidna, you can use `--test-mode assertion` directly from the command line. Otherwise, you can create an [Echidna configuration file](https://github.com/crytic/echidna/wiki/Config), `config.yaml`, with `testMode` set for assertion checking: @@ -77,7 +77,7 @@ When we run this contract with Echidna, we obtain the expected results: ``` $ echidna-test assert.sol --test-mode assertion Analyzing contract: assert.sol:Incrementor -assertion in inc: failed!💥 +assertion in inc: failed!💥 Call sequence, shrinking (2596/5000): inc(21711016731996786641919559689128982722488122124807605757398297001483711807488) inc(7237005577332262213973186563042994240829374041602535252466099000494570602496) @@ -90,7 +90,7 @@ As you can see, Echidna reports an assertion failure in the `inc` function. Addi ## When and how to use assertions -Assertions can be used as alternatives to explicit properties if the conditions to check are directly related to the correct use of some operation `f`. Adding assertions after some code will enforce that the check happens immediately after it was executed: +Assertions can be used as alternatives to explicit properties if the conditions to check are directly related to the correct use of some operation `f`. Adding assertions after some code will enforce that the check happens immediately after it was executed: ```solidity function f(..) public { @@ -105,16 +105,16 @@ On the contrary, using an explicit boolean property will randomly execute transa ```solidity function echidna_assert_after_f() public returns (bool) { - f(..); + f(..); return(condition); } ``` However, there are some issues: -* It does not compile if `f` is declared as `internal` or `external` -* It is unclear which arguments should be used to call `f` -* The property will fail if `f` reverts, +- It does not compile if `f` is declared as `internal` or `external` +- It is unclear which arguments should be used to call `f` +- The property will fail if `f` reverts, Assertions can help to overcome this possible issues. For instance, they can be easily detected when calling internal or public functions: @@ -140,8 +140,8 @@ function f(..) public { In general, we recommend following [John Regehr's advice](https://blog.regehr.org/archives/1091) on using assertions: -* Do not force any side effects during the assertion checking. For instance: `assert(ChangeStateAndReturn() == 1)` -* Do not assert obvious statements. For instance `assert(var >= 0)` where `var` is declared as `uint`. +- Do not force any side effects during the assertion checking. For instance: `assert(ChangeStateAndReturn() == 1)` +- Do not assert obvious statements. For instance `assert(var >= 0)` where `var` is declared as `uint`. Finally, please **do not use** `require` instead of `assert`, since Echidna will not be able to detect it (but the contract will revert anyway). @@ -165,7 +165,7 @@ contract Incrementor { ```bash $ echidna-test assert.sol --test-mode assertion Analyzing contract: assert.sol:Incrementor -assertion in inc: failed!💥 +assertion in inc: failed!💥 Call sequence, shrinking (2596/5000): inc(21711016731996786641919559689128982722488122124807605757398297001483711807488) inc(7237005577332262213973186563042994240829374041602535252466099000494570602496) diff --git a/program-analysis/echidna/basic/common-testing-approaches.md b/program-analysis/echidna/basic/common-testing-approaches.md index 470f0e2f..05f3bc48 100644 --- a/program-analysis/echidna/basic/common-testing-approaches.md +++ b/program-analysis/echidna/basic/common-testing-approaches.md @@ -1,34 +1,37 @@ # Common testing approaches -Testing of smart contracts is not as straightforward as testing normal binaries that you run in your local computer. -This is caused by the existence of multiple accounts interacting with one or many entry points. -While a fuzzer can simulate the Ethereum Virtual Machine and can potentially use any account with any feature (e.g. a an unlimited amount of ETH), -we take care to avoid breaking some important underlying assumptions of transactions that are impossible in Ethereum (e.g. for instance using msg.sender as the zero address). -That is why it is important to have a clear view of the system to test, and how transactions are going to be simulated. There are a few classifications for the testing approach. +Testing of smart contracts is not as straightforward as testing normal binaries that you run in your local computer. +This is caused by the existence of multiple accounts interacting with one or many entry points. +While a fuzzer can simulate the Ethereum Virtual Machine and can potentially use any account with any feature (e.g. a an unlimited amount of ETH), +we take care to avoid breaking some important underlying assumptions of transactions that are impossible in Ethereum (e.g. for instance using msg.sender as the zero address). +That is why it is important to have a clear view of the system to test, and how transactions are going to be simulated. There are a few classifications for the testing approach. We will start with two of them, internal and external: **Table of contents:** + - [Common testing approaches](#common-testing-approaches) - [Internal testing](#internal-testing) - [External testing](#external-testing) - [Partial testing](#partial-testing) ## Internal testing + In this testing approach, properties are defined inside the contract to test, with complete access to the internal state of the system. ```solidity -Contract InternalTest is System { +Contract InternalTest is System { function echidna_state_greater_than_X() public returns (bool) { return stateVar > X; } } ``` -In this approach, Echidna will generate transactions from a simulated account to the target contract. This testing approach is particularly useful for simpler contracts that do not require a complex initialization and have a single entrypoint. +In this approach, Echidna will generate transactions from a simulated account to the target contract. This testing approach is particularly useful for simpler contracts that do not require a complex initialization and have a single entrypoint. Additionally, properties can be easier to write, since properties can access the system's internal state. - + ## External testing -In the external testing approach, properties are tested using external calls from a different contract. Properties are only allowed to access external/public variables or functions. + +In the external testing approach, properties are tested using external calls from a different contract. Properties are only allowed to access external/public variables or functions. ```solidity contract ExternalTest { @@ -41,12 +44,12 @@ contract ExternalTest { } ``` -This testing approach is useful for dealing with contracts that require external initialization (e.g. using Etheno), however, it should handle correctly how Echidna runs the transactions, -since the contract with the properties is no longer the same as the one we want to test. -Since `ExternalTest` defines no additional methods, running Echidna directly on this will not allow any code to be executed from the contract to test (there are no functions in `ExternalTest` to call besides the actual properties). +This testing approach is useful for dealing with contracts that require external initialization (e.g. using Etheno), however, it should handle correctly how Echidna runs the transactions, +since the contract with the properties is no longer the same as the one we want to test. +Since `ExternalTest` defines no additional methods, running Echidna directly on this will not allow any code to be executed from the contract to test (there are no functions in `ExternalTest` to call besides the actual properties). In this case, there are several alternatives: -**Contract wrapper**: define specific operations to "wrap" the system to test. For every operation that we want Echidna to execute in the system to test, +**Contract wrapper**: define specific operations to "wrap" the system to test. For every operation that we want Echidna to execute in the system to test, we add one or more functions that performs external call to it. ```solidity @@ -66,61 +69,62 @@ contract ExternalTest { ``` There are two important points to consider in this approach: -* The sender of each transaction will be the `ExternalTest` contract, instead of the simulated Echidna senders (e.g `0x10000`, ..). This means that the real address interacting with the system will be the `External` contract one, instead of one of the Echidna senders. Please take particular care, if you need to provide ETH or tokens into this contract. -* This approach is manual and can be time consuming if there a lot of functions operations, -but it can be useful when Echidna needs some help calculating some value which cannot be randomly sampled: - +- The sender of each transaction will be the `ExternalTest` contract, instead of the simulated Echidna senders (e.g `0x10000`, ..). This means that the real address interacting with the system will be the `External` contract one, instead of one of the Echidna senders. Please take particular care, if you need to provide ETH or tokens into this contract. + +- This approach is manual and can be time consuming if there a lot of functions operations, + but it can be useful when Echidna needs some help calculating some value which cannot be randomly sampled: + ```solidity contract ExternalTest { ... function methodUsingF(..., uint256 x) public returns (...) { return System(addr).method(.., f(x)); } - ... + ... } ``` -**Multi ABI**: Echidna is capable of performing direct calls to every contract, if the `multi-abi` mode is enabled. -This means that using it wil not require wrapped calls, however since every contract deployed can be called, there could be unintended effects. +**Multi ABI**: Echidna is capable of performing direct calls to every contract, if the `multi-abi` mode is enabled. +This means that using it wil not require wrapped calls, however since every contract deployed can be called, there could be unintended effects. For instance, if we have a property to ensure that the amount of tokens is limited: ```solidity contract ExternalTest { constructor() public { addr = ..; - MockERC20(..).mint(..); + MockERC20(..).mint(..); } function echidna_limited_supply() public returns (bool) { return System(addr).balanceOf(...) <= X; } - ... + ... } -``` +``` -If we used "mock" contracts for tokens (e.g. MockERC20) could be an issue, because Echidna could call functions that are public but are only supposed to be used during the initialization such as `mint`. This can be easily solved using a blacklist of functions to ignore: +If we used "mock" contracts for tokens (e.g. MockERC20) could be an issue, because Echidna could call functions that are public but are only supposed to be used during the initialization such as `mint`. This can be easily solved using a blacklist of functions to ignore: ```yaml filterBlacklist: true -filterFunctions: [“MockERC20.mint(uint256,address)”] +filterFunctions: [“MockERC20.mint(uint256, address)”] ``` -Finally, there is another benefit for using this approach: it will force the developer or auditor to write properties using public data. +Finally, there is another benefit for using this approach: it will force the developer or auditor to write properties using public data. If an important property cannot be defined using public data, it could be an indication that users or other contracts will NOT be able to easily interact with the system to either perform some operation or verify that the system is in a valid state. ## Partial testing -Ideally, testing a smart contract system uses the complete deployed system, with the same parameters that the developers intend to use. -Testing with the real code, it is always preferred, even if it is slower than doing something else (but perhaps not in the case that it is extremely slow). -However, there are many cases where even if the complete system is deployed, it cannot be simulated because it depends on off-chain -components (e.g. a token bridge). In such cases, we are forced to implement alternative solutions. +Ideally, testing a smart contract system uses the complete deployed system, with the same parameters that the developers intend to use. +Testing with the real code, it is always preferred, even if it is slower than doing something else (but perhaps not in the case that it is extremely slow). +However, there are many cases where even if the complete system is deployed, it cannot be simulated because it depends on off-chain +components (e.g. a token bridge). In such cases, we are forced to implement alternative solutions. -In this case, we will do testing of some of the components, ignoring or abstracting uninteresting parts such as standard ERC20 tokens or oracles. -There are a few ways to do this. +In this case, we will do testing of some of the components, ignoring or abstracting uninteresting parts such as standard ERC20 tokens or oracles. +There are a few ways to do this. -**Isolated testing**: If a component is properly abstracted from the rest of the system, testing it can be easy. -This is particularly useful for testing stateless properties that you can find in components that compute mathematical operations, such as +**Isolated testing**: If a component is properly abstracted from the rest of the system, testing it can be easy. +This is particularly useful for testing stateless properties that you can find in components that compute mathematical operations, such as mathematical libraries. **Function override**: Solidity allows to override functions, in order to change the functionality of a piece of code, without affecting the rest of the code base. We can use this to disable certain functions in our tests, in order to allow testing using Echidna: @@ -131,7 +135,7 @@ Contract InternalTestOverridingSignatures is System { function verifySignature(..) public returns (bool) override { return true; // signatures are always valid } - + function echidna_state_greater_than_X() public returns (bool) { executeSomethingWithSignature(..) return stateVar > X; @@ -139,24 +143,24 @@ Contract InternalTestOverridingSignatures is System { } ``` -**Model testing**: if the system is not modular enough, then we will need a different approach. +**Model testing**: if the system is not modular enough, then we will need a different approach. Instead of using the code as it is, we will create a “model” of the system in Solidity, using mostly the original code. While there is no defined list of steps to build a model, we can show a generic example. Let’s assume we have a complex system that include this piece of code: ```solidity Contract System { - … + … function calculateSomething() public returns (uint256) { if (booleanState) { stateSomething = (uint256State1 * uint256State2) / 2**128; return stateSomething / uint128State; - } + } … } } ``` -Where `boolState`, `uint256State1`, `uint256State2` and `stateSomething` are state variables of our system to test. -We are going to create a model (e.g. copy, paste and modify the original code in a new contract), where each state variable is +Where `boolState`, `uint256State1`, `uint256State2` and `stateSomething` are state variables of our system to test. +We are going to create a model (e.g. copy, paste and modify the original code in a new contract), where each state variable is transformed into a parameter: ```solidity @@ -166,21 +170,21 @@ Contract SystemModel { if (boolState) { stateSomething = (uint256State1 * uint256State2) / 2**128; return stateSomething / uint128State; - } + } … } } ``` -At this point, we should be able to compile our model without any dependency from the original codebase (everything necessary should be included in +At this point, we should be able to compile our model without any dependency from the original codebase (everything necessary should be included in the model). Then, we can insert assertions to detect when the returned value exceeds a certain threshold. While developers or auditors can be tempted to quickly create tests using this technique there are certain disadvantages when creating models: -* The code tested can be very different from the one we want to test: this can either introduce issues that are not real (false positives) or -hide real issues from the original code (false negatives). In the example, it is unclear if the state variable can take arbitrary values. +- The code tested can be very different from the one we want to test: this can either introduce issues that are not real (false positives) or + hide real issues from the original code (false negatives). In the example, it is unclear if the state variable can take arbitrary values. -* The model will have a limited value if the code is changed since any modification in the original model will force a rebuild of the model, -and this should be manually performed. +- The model will have a limited value if the code is changed since any modification in the original model will force a rebuild of the model, + and this should be manually performed. In any case, developers should be warned that their code is difficult to test and it should be refactored to avoid this issue in the future. diff --git a/program-analysis/echidna/basic/filtering-functions.md b/program-analysis/echidna/basic/filtering-functions.md index f5130747..e8417054 100644 --- a/program-analysis/echidna/basic/filtering-functions.md +++ b/program-analysis/echidna/basic/filtering-functions.md @@ -11,7 +11,7 @@ ## Introduction We will see how to filter the functions to be fuzzed. -The target is the following smart contract (*[../example/multi.sol](../example/multi.sol)*): +The target is the following smart contract (_[../example/multi.sol](../example/multi.sol)_): ```solidity contract C { @@ -63,12 +63,12 @@ contract C { } ``` -This small example forces Echidna to find a certain sequence of transactions to change a state variable. +This small example forces Echidna to find a certain sequence of transactions to change a state variable. This is hard for a fuzzer (it is recommended to use a symbolic execution tool like [Manticore](https://github.com/trailofbits/manticore)). We can run Echidna to verify this: ``` -$ echidna-test multi.sol +$ echidna-test multi.sol ... echidna_state4: passed! 🎉 Seed: -3684648582249875403 @@ -76,9 +76,9 @@ Seed: -3684648582249875403 ## Filtering functions -Echidna has trouble finding the correct sequence to test this contract because the two reset functions (`reset1` and `reset2`) will set all the state variables to `false`. -However, we can use a special Echidna feature to either blacklist the `reset` functions or to whitelist only the `f`, `g`, -`h` and `i` functions. +Echidna has trouble finding the correct sequence to test this contract because the two reset functions (`reset1` and `reset2`) will set all the state variables to `false`. +However, we can use a special Echidna feature to either blacklist the `reset` functions or to whitelist only the `f`, `g`, +`h` and `i` functions. To blacklist functions, we can use this configuration file: @@ -102,9 +102,9 @@ filterFunctions: ["C.f(uint256)", "C.g(uint256)", "C.h(uint256)", "C.i()"] To run Echidna with a configuration file `blacklist.yaml`: ``` -$ echidna-test multi.sol --config blacklist.yaml +$ echidna-test multi.sol --config blacklist.yaml ... -echidna_state4: failed!💥 +echidna_state4: failed!💥 Call sequence: f(12) g(8) @@ -112,8 +112,7 @@ echidna_state4: failed!💥 i() ``` -Echidna will find the sequence of transactions to falsify the property almost immediately. - +Echidna will find the sequence of transactions to falsify the property almost immediately. ## Summary: Filtering functions @@ -125,7 +124,7 @@ filterFunctions: ["C.f1()", "C.f2()", "C.f3()"] ``` ```bash -$ echidna-test contract.sol --config config.yaml +$ echidna-test contract.sol --config config.yaml ... ``` diff --git a/program-analysis/echidna/basic/property-creation.md b/program-analysis/echidna/basic/property-creation.md index 27ede2b5..583c1ca6 100644 --- a/program-analysis/echidna/basic/property-creation.md +++ b/program-analysis/echidna/basic/property-creation.md @@ -16,7 +16,7 @@ In this short tutorial, we will detail some ideas to write interesting or useful One of the simplest properties to write using Echidna is to throw an assertion when some function is expected to revert/return. -Let's suppose we have a contract interface like the one below: +Let's suppose we have a contract interface like the one below: ```solidity interface DeFi { @@ -40,7 +40,7 @@ contract Test { c = DeFi(..); token.mint(address(this), ...); } - + function getShares_never_reverts() public { (bool b,) = c.call(abi.encodeWithSignature("getShares(address)", address(this))); assert(b); @@ -52,39 +52,38 @@ contract Test { assert(b); } } - + function withdrawShares_never_reverts(uint256 val) public { if (c.getShares(address(this)) >= val) { (bool b,) = c.call(abi.encodeWithSignature("withdrawShares(uint256)", val)); assert(b); } } - + function depositShares_can_revert(uint256 val) public { if (token.balanceOf(address(this)) < val) { (bool b,) = c.call(abi.encodeWithSignature("depositShares(uint256)", val)); assert(!b); } } - + function withdrawShares_can_revert(uint256 val) public { if (c.getShares(address(this)) < val) { (bool b,) = c.call(abi.encodeWithSignature("withdrawShares(uint256)", val)); assert(!b); } } - + } ``` -After you have writen your first version of properties, run Echidna to make sure they work as expected. During this tutorial, we will improve them step by step. It is strongly recommended to run the fuzzer at each step to increase the probability of detecting any potential issues. +After you have writen your first version of properties, run Echidna to make sure they work as expected. During this tutorial, we will improve them step by step. It is strongly recommended to run the fuzzer at each step to increase the probability of detecting any potential issues. Perhaps you think these properties are too low level to be useful, particularly if the code has a good coverage in terms of unit tests. But you will be surprised how often an unexpected revert/return uncovers a complex and severe issue. Moreover, we will see how these properties can be improved to cover more complex post-conditions. Before we continue, we will improve these properties using [try/catch](https://docs.soliditylang.org/en/v0.6.0/control-structures.html#try-catch). The use of a low-level call forces us to manually encode the data, which can be error prone (an error will always cause calls to revert). Note, this will only work if the codebase is using solc 0.6.0 or later: - ```solidity ... function depositShares_never_reverts(uint256 val) public { @@ -92,20 +91,20 @@ Before we continue, we will improve these properties using [try/catch](https://d try c.depositShares(val) { /* not reverted */ } catch { assert(false); } } } - + function depositShares_can_revert(uint256 val) public { if (token.balanceOf(address(this)) < val) { try c.depositShares(val) { assert(false); } catch { /* reverted */ } } } ... - + } ``` ## Enhacing postcondition checks -If the previous properties are passing, this means that the pre-conditions are good enough, however the post-conditions are not very precise. +If the previous properties are passing, this means that the pre-conditions are good enough, however the post-conditions are not very precise. Avoiding reverts doesn't mean that the contract is in a valid state. Let's add some basic preconditions: ```solidity @@ -116,7 +115,7 @@ Avoiding reverts doesn't mean that the contract is in a valid state. Let's add s assert(c.getShares(address(this)) > 0); } } - + function withdrawShares_never_reverts(uint256 val) public { if (c.getShares(address(this)) >= val) { try c.withdrawShares(val) { /* not reverted */ } catch { assert(false); } @@ -124,7 +123,7 @@ Avoiding reverts doesn't mean that the contract is in a valid state. Let's add s } } ... - + } ``` @@ -132,12 +131,12 @@ Uhm, it looks like it is not that easy to specify the value of shares/tokens obt ## Combining properties -In this generic example, it is unclear if there is a way to calculate how many shares or tokens we should receive after executing the deposit/withdraw operations. Of course, if we have that information, we should use it. In any case, what we can do here is to combine these two properties into a single one to be able check more precisely it's preconditions. +In this generic example, it is unclear if there is a way to calculate how many shares or tokens we should receive after executing the deposit/withdraw operations. Of course, if we have that information, we should use it. In any case, what we can do here is to combine these two properties into a single one to be able check more precisely it's preconditions. ```solidity ... function deposit_withdraw_shares_never_reverts(uint256 val) public { - uint256 original_balance = token.balanceOf(address(this)); + uint256 original_balance = token.balanceOf(address(this)); if (original_balance >= val) { try c.depositShares(val) { /* not reverted */ } catch { assert(false); } uint256 shares = c.getShares(address(this); @@ -147,7 +146,7 @@ In this generic example, it is unclear if there is a way to calculate how many s } } ... - + } ``` @@ -175,4 +174,4 @@ Additionally, combining properties does not mean that we will have to remove sim ## Summary: How to write good properties -It is usually a good idea to start writing simple properties first and then improving them to make them more precise and easier to read. At each step you should run a short fuzzing campaign to make sure they work as expected and try to catch issues early during the development of your smart contracts. +It is usually a good idea to start writing simple properties first and then improving them to make them more precise and easier to read. At each step you should run a short fuzzing campaign to make sure they work as expected and try to catch issues early during the development of your smart contracts. diff --git a/program-analysis/echidna/basic/testing-modes.md b/program-analysis/echidna/basic/testing-modes.md index f3212a75..2ff7be8f 100644 --- a/program-analysis/echidna/basic/testing-modes.md +++ b/program-analysis/echidna/basic/testing-modes.md @@ -1,8 +1,9 @@ # How to select the most suitable testing mode -Since Echidna offers several ways to write properties, often developers or auditors are wondering which testing mode should use. We will review how each mode works, as well as their advantages or disadvantages. +Since Echidna offers several ways to write properties, often developers or auditors are wondering which testing mode should use. We will review how each mode works, as well as their advantages or disadvantages. **Table of contents:** + - [Boolean properties](#boolean-properties) - [Assertions](#assertions) - [Dapptest](#dapptest) @@ -11,15 +12,16 @@ Since Echidna offers several ways to write properties, often developers or audit ## Boolean properties By default, the "property" testing mode is used, which reports failures using a special functions called properties: -* Testing functions should be named with a specific prefix (e.g. `echidna_`). -* Testing functions take no parameters, and always return a boolean value. -* Any side effect will be reverted at the end of the execution of the property. -* Properties pass if they return true, and fail if they return false or revert. As an alternative, properties that starts with "echidna_revert_" will fail if they return any value (true or false), and pass if they revert. This pseudo-code summarizes how properties work: + +- Testing functions should be named with a specific prefix (e.g. `echidna_`). +- Testing functions take no parameters, and always return a boolean value. +- Any side effect will be reverted at the end of the execution of the property. +- Properties pass if they return true, and fail if they return false or revert. As an alternative, properties that starts with "echidna*revert*" will fail if they return any value (true or false), and pass if they revert. This pseudo-code summarizes how properties work: ```solidity function echidna_property() public returns (bool) { // No arguments are required - // The following statements can trigger a failure if they revert + // The following statements can trigger a failure if they revert publicFunction(..); internalFunction(..); contract.function(..); @@ -42,30 +44,31 @@ function echidna_revert_property() public returns (bool) { // No arguments is re ### Advantages: -* Properties can be easier to write and understand compared to other approaches for testing. -* No need to worry about side-effects, since these are reverted at the end of the property execution. +- Properties can be easier to write and understand compared to other approaches for testing. +- No need to worry about side-effects, since these are reverted at the end of the property execution. -### Disadvantages: -* Since the properties take no parameters, any additional input should be added using a state variable. -* Any revert will be interpreted as a failure, which is not always expected. -* No coverage is collected during its execution so these properties should be used with simple code. For anything complex (e.g. with a non-trivial amount of branches), other types of tests should be used. +### Disadvantages: + +- Since the properties take no parameters, any additional input should be added using a state variable. +- Any revert will be interpreted as a failure, which is not always expected. +- No coverage is collected during its execution so these properties should be used with simple code. For anything complex (e.g. with a non-trivial amount of branches), other types of tests should be used. ### Recommendations This mode can be used when a property can be easily computed from the use of state variables (either internal or public), and there is no need to use extra parameters. -## Assertions +## Assertions Using the "assertion" testing mode, Echidna will report an assert violation if: -* The execution reverts during a call to `assert`. Technically speaking, Echidna will detect an assertion failure if it executes an `assert` call that fails in the first call frame of the target contract (so this excludes any internal transactions in most of the cases). -* An `AssertionFailed` event (with any number of parameters) is emitted by any contract. This pseudo-code summarizes how assertions work: +- The execution reverts during a call to `assert`. Technically speaking, Echidna will detect an assertion failure if it executes an `assert` call that fails in the first call frame of the target contract (so this excludes any internal transactions in most of the cases). +- An `AssertionFailed` event (with any number of parameters) is emitted by any contract. This pseudo-code summarizes how assertions work: ```solidity function checkInvariant(..) public { // Any number of arguments is supported // The following statements can trigger a failure using `assert` - assert(..); + assert(..); publicFunction(..); internalFunction(..); @@ -75,7 +78,7 @@ function checkInvariant(..) public { // Any number of arguments is supported // The following statement will *only* trigger a failure using `assert` if using solc 0.8.x or newer // To make sure it works in older versions, use the AssertionFailed(..) event anotherContract.function(..); - + } // side effects are preserved ``` @@ -83,20 +86,21 @@ Functions checking assertions do not require any particular name and are execute ### Advantages -* Easy to implement, in particular, if there are any number of parameters required to compute the invariant. -* Coverage is collected during the execution of these tests, so it can help to reach new failures. -* If the code base already contains assertions for checking invariants, they can be reused. +- Easy to implement, in particular, if there are any number of parameters required to compute the invariant. +- Coverage is collected during the execution of these tests, so it can help to reach new failures. +- If the code base already contains assertions for checking invariants, they can be reused. ### Disadvantages -* If the code to test is already using assertions for data validation, it will not work as expected. For example: +- If the code to test is already using assertions for data validation, it will not work as expected. For example: + ```solidity function deposit(uint256 tokens) public { assert(tokens > 0); // should be strictly positive .. ``` -Developers *should* avoid doing that and use `require` instead, but if that is not possible because you are calling some contract that is outside your control, you can use the `AssertionFailure` event. +Developers _should_ avoid doing that and use `require` instead, but if that is not possible because you are calling some contract that is outside your control, you can use the `AssertionFailure` event. ### Recommendation @@ -105,7 +109,7 @@ You should use assertions if your invariant is more natural to be expressed usin ```solidity function testStake(uint256 toStake) public { uint256 balance = balanceOf(msg.sender); - toStake = toStake % (balance + 1); + toStake = toStake % (balance + 1); if (toStake < MINSTAKE) // Pre: minimal stake is required return; stake(msg.sender, toStake); // Action: token staking @@ -114,12 +118,13 @@ function testStake(uint256 toStake) public { } ``` -`testStake` checks some invariants on staking, but also ensures that the state of the contract is properly updated (e.g only allowing a user to stake at least `MINSTAKE`). +`testStake` checks some invariants on staking, but also ensures that the state of the contract is properly updated (e.g only allowing a user to stake at least `MINSTAKE`). ## Dapptest Using the "dapptest" testing mode, Echidna will report violations using certain functions following how dapptool and foundry work: -* This mode uses any function name with one or more arguments, which will trigger a failure if they revert, except in one special case. This is, if the execution reverts with the special reason “FOUNDRY::ASSUME”, then the test will pass (this emulates how [the `assume` foundry cheat code works](https://github.com/gakonst/foundry/commit/7dcce93a38345f261d92297abf11fafd6a9e7a35#diff-47207bb2f6cf3c4ac054647e851a98a57286fb9bb37321200f91637262d3eabfR90-R96)). This pseudo-code summarizes how dapptests work: + +- This mode uses any function name with one or more arguments, which will trigger a failure if they revert, except in one special case. This is, if the execution reverts with the special reason “FOUNDRY::ASSUME”, then the test will pass (this emulates how [the `assume` foundry cheat code works](https://github.com/gakonst/foundry/commit/7dcce93a38345f261d92297abf11fafd6a9e7a35#diff-47207bb2f6cf3c4ac054647e851a98a57286fb9bb37321200f91637262d3eabfR90-R96)). This pseudo-code summarizes how dapptests work: ```solidity function checkDappTest(..) public { // One or more arguments are required @@ -132,15 +137,17 @@ function checkDappTest(..) public { // One or more arguments are required } ``` -* Functions implementing these tests do not require any particular name and are executed like any other function, and therefore, their side effects are kept if they do not revert (but usually, this mode is used only in stateless testing). -* The function should NOT be payable (but this can change in the future) +- Functions implementing these tests do not require any particular name and are executed like any other function, and therefore, their side effects are kept if they do not revert (but usually, this mode is used only in stateless testing). +- The function should NOT be payable (but this can change in the future) ### Advantages: -* Easy to implement, in particular, for stateless mode. -* Coverage is collected during the execution of these tests, so it can help to reach new failures. -### Disadvantages: -* Almost any revert will be interpreted as a failure, which is not always expected. To avoid this, you should use reverts with `FOUNDRY::ASSUME` or use try/catch. +- Easy to implement, in particular, for stateless mode. +- Coverage is collected during the execution of these tests, so it can help to reach new failures. + +### Disadvantages: + +- Almost any revert will be interpreted as a failure, which is not always expected. To avoid this, you should use reverts with `FOUNDRY::ASSUME` or use try/catch. ### Recommendation @@ -148,12 +155,12 @@ Use dapptest mode if you are testing stateless invariants and the code will neve ## Stateless vs Stateful -Any of these testing modes can be used, in either stateful (by default) or stateless mode (using `--seqLen 1`). In stateful mode, Echidna will keep the state between each function call and will try to break the invariants. In stateless, Echidna will discard the state changes during the fuzzing. There are notable differences in these two modes. +Any of these testing modes can be used, in either stateful (by default) or stateless mode (using `--seqLen 1`). In stateful mode, Echidna will keep the state between each function call and will try to break the invariants. In stateless, Echidna will discard the state changes during the fuzzing. There are notable differences in these two modes. -* Stateful is more powerful, and can allow breaking invariants that exist only if the contract reaches a specific state. -* Stateless tests can be easier to use than stateful and benefits from simpler input generation. -* Stateless tests can hide issues, since some of them can depend on a sequence of operations that is not reachable in a single transaction. -* Stateless mode forces resetting the EVM after each transaction or test, which is usually slower than resetting the state once every certain amount of transactions (by default, every 100 transactions). +- Stateful is more powerful, and can allow breaking invariants that exist only if the contract reaches a specific state. +- Stateless tests can be easier to use than stateful and benefits from simpler input generation. +- Stateless tests can hide issues, since some of them can depend on a sequence of operations that is not reachable in a single transaction. +- Stateless mode forces resetting the EVM after each transaction or test, which is usually slower than resetting the state once every certain amount of transactions (by default, every 100 transactions). ### Recommendations diff --git a/program-analysis/echidna/exercises/Exercise-1.md b/program-analysis/echidna/exercises/Exercise-1.md index 8960eb78..53b9286a 100644 --- a/program-analysis/echidna/exercises/Exercise-1.md +++ b/program-analysis/echidna/exercises/Exercise-1.md @@ -9,8 +9,8 @@ Join the team on Slack at: https://empireslacking.herokuapp.com/ #ethereum ## Targeted contract - -We will test the following contract *[./exercise1/token.sol](./exercise1/token.sol)*: + +We will test the following contract _[./exercise1/token.sol](./exercise1/token.sol)_: ```Solidity contract Ownership{ @@ -57,7 +57,7 @@ We will test the following contract *[./exercise1/token.sol](./exercise1/token.s - Add a property to check that `echidna_caller` cannot have more than an initial balance of 10000. - Once Echidna finds the bug, fix the issue, and re-check your property with Echidna. -The skeleton for this exercise is (*[./exercise1/template.sol](./exercise1/template.sol)*): +The skeleton for this exercise is (_[./exercise1/template.sol](./exercise1/template.sol)_): ```Solidity import "token.sol"; @@ -70,7 +70,7 @@ The skeleton for this exercise is (*[./exercise1/template.sol](./exercise1/templ // add the property function echidna_test_balance() public view returns (bool) {} } - ``` +``` ## Solution diff --git a/program-analysis/echidna/exercises/Exercise-2.md b/program-analysis/echidna/exercises/Exercise-2.md index 1a5f950e..32f44507 100644 --- a/program-analysis/echidna/exercises/Exercise-2.md +++ b/program-analysis/echidna/exercises/Exercise-2.md @@ -11,8 +11,8 @@ This exercise requires to finish the [exercise 1](Exercise-1.md). Join the team on Slack at: https://empireslacking.herokuapp.com/ #ethereum ## Targeted contract - -We will test the following contract *[./exercise2/token.sol](./exercise2/token.sol)*: + +We will test the following contract _[./exercise2/token.sol](./exercise2/token.sol)_: ```Solidity contract Ownership{ @@ -51,7 +51,7 @@ We will test the following contract *[./exercise2/token.sol](./exercise2/token.s } ``` - + ## Testing access control ### Goals @@ -60,7 +60,7 @@ We will test the following contract *[./exercise2/token.sol](./exercise2/token.s - Add a property to check that the contract cannot be unpaused. - Once Echidna finds the bug, fix the issue, and re-try your property with Echidna. -The skeleton for this exercise is (*[./exercise2/template.sol](./exercise2/template.sol)*): +The skeleton for this exercise is (_[./exercise2/template.sol](./exercise2/template.sol)_): ```Solidity import "token.sol"; @@ -77,4 +77,4 @@ The skeleton for this exercise is (*[./exercise2/template.sol](./exercise2/templ ## Solution - This solution can be found in [./exercise2/solution.sol](./exercise2/solution.sol) +This solution can be found in [./exercise2/solution.sol](./exercise2/solution.sol) diff --git a/program-analysis/echidna/exercises/Exercise-3.md b/program-analysis/echidna/exercises/Exercise-3.md index 6dcfaeaf..1aab063a 100644 --- a/program-analysis/echidna/exercises/Exercise-3.md +++ b/program-analysis/echidna/exercises/Exercise-3.md @@ -11,8 +11,8 @@ This exercise requires to finish [exercise 1](./Exercise-1.md) and [exercise 2]( Join the team on Slack at: https://empireslacking.herokuapp.com/ #ethereum ## Targeted contract - -We will test the following contract *[./exercise3/token.sol](./exercise3/token.sol)*: + +We will test the following contract _[./exercise3/token.sol](./exercise3/token.sol)_: ```Solidity contract Ownership{ @@ -55,7 +55,7 @@ We will test the following contract *[./exercise3/token.sol](./exercise3/token.s ## Testing with custom initialization -Consider the following extension of the token (*[./exercise3/mintable.sol](./exercise3/mintable.sol)*): +Consider the following extension of the token (_[./exercise3/mintable.sol](./exercise3/mintable.sol)_): ```Solidity import "token.sol"; @@ -83,7 +83,7 @@ The [version of token.sol](./exercise3/token.sol#L1) contains the fixes of the p - Add a property to check if `echidna_caller` can mint more than 10,000 tokens. - Once Echidna finds the bug, fix the issue, and re-try your property with Echidna. -The skeleton for this exercise is (*[./exercise3/template.sol](./exercise3/template.sol)*): +The skeleton for this exercise is (_[./exercise3/template.sol](./exercise3/template.sol)_): ```Solidity import "mintable.sol"; @@ -100,4 +100,4 @@ The skeleton for this exercise is (*[./exercise3/template.sol](./exercise3/templ ## Solution - This solution can be found in [./exercise3/solution.sol](./exercise3/solution.sol) +This solution can be found in [./exercise3/solution.sol](./exercise3/solution.sol) diff --git a/program-analysis/echidna/exercises/Exercise-4.md b/program-analysis/echidna/exercises/Exercise-4.md index 10ce3855..9f093539 100644 --- a/program-analysis/echidna/exercises/Exercise-4.md +++ b/program-analysis/echidna/exercises/Exercise-4.md @@ -14,7 +14,7 @@ Join the team on Slack at: https://empireslacking.herokuapp.com/ #ethereum ## Targeted contract -We will test the following contract *[./exercise4/token.sol](./exercise4/token.sol)*: +We will test the following contract _[./exercise4/token.sol](./exercise4/token.sol)_: ```Solidity contract Ownership{ @@ -66,7 +66,7 @@ Add asserts to ensure that after calling `transfer`: Once Echidna finds the bug, fix the issue, and re-try your assertion with Echidna. This exercise is similar to the [first one](Exercise-1.md), but using assertions instead of explicit properties. -However, in this exercise, it is easier to modify the original token contract (*[./exercise4/token.sol](./exercise4/token.sol)*). +However, in this exercise, it is easier to modify the original token contract (_[./exercise4/token.sol](./exercise4/token.sol)_). ## Solution diff --git a/program-analysis/echidna/exercises/Exercise-5.md b/program-analysis/echidna/exercises/Exercise-5.md index de0343af..f710ced1 100644 --- a/program-analysis/echidna/exercises/Exercise-5.md +++ b/program-analysis/echidna/exercises/Exercise-5.md @@ -12,6 +12,7 @@ Join the team on Slack at: https://empireslacking.herokuapp.com/ #ethereum ## Setup + 1. Clone the repo: `git clone https://github.com/crytic/damn-vulnerable-defi-echidna` 2. install the dependencies via `yarn install`. @@ -19,7 +20,6 @@ Join the team on Slack at: https://empireslacking.herokuapp.com/ #ethereum The challenge is described here: https://www.damnvulnerabledefi.xyz/challenges/2.html, we assume that the reader is familiar with it. - ## Goals - Setup the testing environment with the right contracts and necessary balances. @@ -29,25 +29,24 @@ The challenge is described here: https://www.damnvulnerabledefi.xyz/challenges/2 - Once Echidna finds the bug, fix the issue, and re-try your property with Echidna. Only the following contracts are relevant: - - `contracts/naive-receiver/FlashLoanReceiver.sol` - - `contracts/naive-receiver/NaiveReceiverLenderPool.sol` + +- `contracts/naive-receiver/FlashLoanReceiver.sol` +- `contracts/naive-receiver/NaiveReceiverLenderPool.sol` ## Hints We recommend to first try without reading the following hints. The hints are in the [`hints` branch](https://github.com/crytic/damn-vulnerable-defi-echidna/tree/hints). - Remember that sometimes you have to supply the test contract with Ether. Read more in [the Echidna wiki](https://github.com/crytic/echidna/wiki/Config) and look at [the default config setup](https://github.com/crytic/echidna/blob/master/tests/solidity/basic/default.yaml). -- The invariant that we are looking for is "the balance of the receiver contract can not decrease" +- The invariant that we are looking for is "the balance of the receiver contract can not decrease" - Read what is the [multi abi option](../basic/common-testing-approaches.md#external-testing) - A template is provided in [contracts/naive-receiver/NaiveReceiverEchidna.sol](https://github.com/crytic/damn-vulnerable-defi-echidna/blob/hints/contracts/naive-receiver/NaiveReceiverEchidna.sol) - A config file is provided in [naivereceiver.yaml](https://github.com/crytic/damn-vulnerable-defi-echidna/blob/hints/naivereceiver.yaml) - ## Solution This solution can be found in [`solutions` branch](https://github.com/crytic/damn-vulnerable-defi-echidna/blob/solutions/contracts/naive-receiver/NaiveReceiverEchidna.sol). - [ctf]: https://www.damnvulnerabledefi.xyz/
@@ -64,12 +63,11 @@ See example output below from Echidna: $ echidna-test . --contract NaiveReceiverEchidna --config naivereceiver.yaml ... -echidna_test_contract_balance: failed!💥 +echidna_test_contract_balance: failed!💥 Call sequence: flashLoan(0x62d69f6867a0a084c6d313943dc22023bc263691,353073667) ... ``` -
- + diff --git a/program-analysis/echidna/exercises/Exercise-6.md b/program-analysis/echidna/exercises/Exercise-6.md index c1f7b463..5ba0ad75 100644 --- a/program-analysis/echidna/exercises/Exercise-6.md +++ b/program-analysis/echidna/exercises/Exercise-6.md @@ -12,6 +12,7 @@ Join the team on Slack at: https://empireslacking.herokuapp.com/ #ethereum ## Setup + 1. Clone the repo: `git clone https://github.com/crytic/damn-vulnerable-defi-echidna` 2. install the dependencies via `yarn install`. @@ -28,9 +29,10 @@ The challenge is described here: https://www.damnvulnerabledefi.xyz/challenges/1 - Once Echidna finds the bug, fix the issue, and re-try your property with Echidna. Only the following contracts are relevant: - - `contracts/DamnValuableToken.sol` - - `contracts/unstoppable/UnstoppableLender.sol` - - `contracts/unstoppable/ReceiverUnstoppable.sol` + +- `contracts/DamnValuableToken.sol` +- `contracts/unstoppable/UnstoppableLender.sol` +- `contracts/unstoppable/ReceiverUnstoppable.sol` ## Hints @@ -42,8 +44,6 @@ We recommend to first try without reading the following hints. The hints are in - A template is provided in [contracts/unstoppable/UnstoppableEchidna.sol](https://github.com/crytic/damn-vulnerable-defi-echidna/blob/hints/contracts/unstoppable/UnstoppableEchidna.sol) - A config file is provided in [unstoppable.yaml](https://github.com/crytic/damn-vulnerable-defi-echidna/blob/hints/unstoppable.yaml) - - ## Solution This solution can be found in the [`solutions` branch](https://github.com/crytic/damn-vulnerable-defi-echidna/blob/solutions/contracts/unstoppable/UnstoppableEchidna.sol). @@ -53,8 +53,7 @@ This solution can be found in the [`solutions` branch](https://github.com/crytic
Solution Explained (spoilers ahead) - -Note: Please make sure that you have placed `solution.sol` (or `UnstoppableEchidna.sol`) in `contracts/unstoppable`. +Note: Please make sure that you have placed `solution.sol` (or `UnstoppableEchidna.sol`) in `contracts/unstoppable`. The goal of the unstoppable challenge is to realize that `UnstoppableLender` has two modes of tracking its balance: `poolBalance` and `damnValuableToken.balanceOf(address(this))`. @@ -73,10 +72,11 @@ $ echidna-test . --contract UnstoppableEchidna --config unstoppable.yaml ... -echidna_testFlashLoan: failed!💥 +echidna_testFlashLoan: failed!💥 Call sequence: transfer(0x62d69f6867a0a084c6d313943dc22023bc263691,1296000) ... ``` +
diff --git a/program-analysis/echidna/exercises/Exercise-7.md b/program-analysis/echidna/exercises/Exercise-7.md index 44341c0b..422b0d0e 100644 --- a/program-analysis/echidna/exercises/Exercise-7.md +++ b/program-analysis/echidna/exercises/Exercise-7.md @@ -12,6 +12,7 @@ Join the team on Slack at: https://empireslacking.herokuapp.com/ #ethereum ## Setup ## Setup + 1. Clone the repo: `git clone https://github.com/crytic/damn-vulnerable-defi-echidna` 2. install the dependencies via `yarn install`. 3. Analyze the `before` function in `test/side-entrance/side-entrance.challenge.js` to identify what initial setup needs to be done. @@ -27,6 +28,7 @@ No skeleton will be provided for this exercise. - Once Echidna finds the bug, fix the issue, and re-try your property with Echidna. Hint: It might help to start with doing a manual flashloan to get familiar with the workings of the target contract. + ## Solution This solution can be found in [./exercise7/solution.sol](./exercise7/solution.sol) @@ -38,19 +40,20 @@ This solution can be found in [./exercise7/solution.sol](./exercise7/solution.so The goal of the side entrance challenge is to realize that the contract's accounting of its ETH balance is misconfigured. `balanceBefore` is used to track the balance of the contract before the flash loan BUT `address(this).balance` is used to track the balance of the contract after the flash loan. Thus, you can use the deposit function to repay your flash loan while still maintaining that the contract's total balance of ETH has not changed (i.e. `address(this).balance >= balanceBefore`). Since the ETH that was deposited is now owned by you, you can now also withdraw it and drain all the funds from the contract. -In order for Echidna to be able to interact with the `SideEntranceLenderPool`, it has to be deployed first. However, deploying and funding it from the contract to be used by Echidna won't work, as the funding transaction's `msg.sender` is the contract itself. This means that the owner of the funds is the Echidna contract and therefore it can remove the funds by calling `withdraw()`, without the need for the exploit. +In order for Echidna to be able to interact with the `SideEntranceLenderPool`, it has to be deployed first. However, deploying and funding it from the contract to be used by Echidna won't work, as the funding transaction's `msg.sender` is the contract itself. This means that the owner of the funds is the Echidna contract and therefore it can remove the funds by calling `withdraw()`, without the need for the exploit. To prevent that issue, a simple factory contract has to be created to deploy the pool without setting the Echidna property testing contract as the owner of the funds. This factory has a public function that deploys a `SideEntranceLenderPool`, funds it with the given amount, and return its address. Now, since the Echidna testing contract is not the owner of the funds, it cannot call `withdraw()` to empty the pool. Now that the challenge is set up as intended, we proceed to solve it by instructing Echidna to do a flashloan. Using the `setEnableWithdraw` and `setEnableDeposit` Echidna will search for function(s) to call inside the flashloan callback to try and break the `testPoolBalance` property. - + At some point Echidna will identify that if (1) `deposit` is used to pay back the flash loan and (2) `withdraw` is called right after, the `testPoolBalance` property breaks. Example Echidna output: + ``` $ echidna-test . --contract EchidnaSideEntranceLenderPool --config config.yaml ... -testPoolBalance(): failed!💥 +testPoolBalance(): failed!💥 Call sequence: execute() Value: 0x103 setEnableDeposit(true,256) @@ -61,6 +64,5 @@ testPoolBalance(): failed!💥 testPoolBalance() ... ``` - - + diff --git a/program-analysis/echidna/exercises/README.md b/program-analysis/echidna/exercises/README.md index 7d776a09..383575f2 100644 --- a/program-analysis/echidna/exercises/README.md +++ b/program-analysis/echidna/exercises/README.md @@ -7,4 +7,4 @@ - [Exercise 5](./Exercise-5.md): Solving Damn Vulnerable DeFi - Naive Receiver - [Exercise 6](./Exercise-6.md): Solving Damn Vulnerable DeFi - Unstoppable - [Exercise 7](./Exercise-7.md): Solving Damn Vulnerable DeFi - Side Entrance -- [Exercise 8](./Exercise-8.md): Solving Damn Vulnerable DeFi - The Rewarder \ No newline at end of file +- [Exercise 8](./Exercise-8.md): Solving Damn Vulnerable DeFi - The Rewarder diff --git a/program-analysis/echidna/frequently_asked_questions.md b/program-analysis/echidna/frequently_asked_questions.md index 92899f1e..bc51f398 100644 --- a/program-analysis/echidna/frequently_asked_questions.md +++ b/program-analysis/echidna/frequently_asked_questions.md @@ -1,6 +1,6 @@ # Frequently asked questions about Echidna -This list contains answers to frequent questions related with the usage of Echidna. If this looks too difficult to understand for you, you need to make sure you already reviewed [all the other Echidna documentation](./README.md). +This list contains answers to frequent questions related with the usage of Echidna. If this looks too difficult to understand for you, you need to make sure you already reviewed [all the other Echidna documentation](./README.md). ## Echidna fails to start or compile my contract, what should I do? @@ -14,18 +14,18 @@ If `crytic-compile` works fine, test `slither` to see if there is any issues wit `slither . --print echidna` -If that command works correctly, it should print a json file with some information from your contracts, otherwise, report any error [in the slither issue tracker](https://github.com/crytic/slither/issues). +If that command works correctly, it should print a json file with some information from your contracts, otherwise, report any error [in the slither issue tracker](https://github.com/crytic/slither/issues). If everything here works, but Echidna still fails, please open an issue in our issue tracker or ask in the #ethereum channel of the EmpireHacking slack. ## How long should I run Echidna? -Echidna uses fuzzing testing which runs for a fixed amount of transactions (or a global timeout). -Users should specify a suitable number of transactions or a timeout (in seconds), depending on the amount of resources available for a fuzzing campaign -and the complexity of the code. Determining the best amount of time to run a fuzzer is still an [open research question](https://blog.trailofbits.com/2021/03/23/a-year-in-the-life-of-a-compiler-fuzzing-campaign/), however, [monitoring the code coverage of your smart contracts](./advanced/collecting-a-corpus.md) can be a good way to determinate if the fuzzing campaign should be extended. +Echidna uses fuzzing testing which runs for a fixed amount of transactions (or a global timeout). +Users should specify a suitable number of transactions or a timeout (in seconds), depending on the amount of resources available for a fuzzing campaign +and the complexity of the code. Determining the best amount of time to run a fuzzer is still an [open research question](https://blog.trailofbits.com/2021/03/23/a-year-in-the-life-of-a-compiler-fuzzing-campaign/), however, [monitoring the code coverage of your smart contracts](./advanced/collecting-a-corpus.md) can be a good way to determinate if the fuzzing campaign should be extended. ## Why has Echidna not implemented fuzzing of smart contract constructors with parameters? -Echidna is focused on security testing during audits. When we perform testing, we adjust the fuzzing campaign to test with a limited number of possible constructor parameters (normally, the ones that are going to be used for the real deployment). We are not focused on issues that depend on alternative deployments that should not happen. On top of that, redeploying contracts during the fuzzing campaign has a performance impact and the sequences of transactions that we collect in the corpus could be more difficult (or even impossible) to reuse and mutate in different contexts. +Echidna is focused on security testing during audits. When we perform testing, we adjust the fuzzing campaign to test with a limited number of possible constructor parameters (normally, the ones that are going to be used for the real deployment). We are not focused on issues that depend on alternative deployments that should not happen. On top of that, redeploying contracts during the fuzzing campaign has a performance impact and the sequences of transactions that we collect in the corpus could be more difficult (or even impossible) to reuse and mutate in different contexts. ## How does Echidna know which sequence of transactions should be added into the corpus? @@ -38,11 +38,12 @@ Coverage information is used to determine if a sequence of transactions has reac ## What is coverage information exactly? Coverage is a combination of the following information: -* Echidna reached a certain program counter in a given contract. -* The execution ended, either with stop, revert or a variety of errors (e.g. assertion failed, out of gas, not enough ether balance, etc) -* The number of EVM frames when the execution ended (in other words, how deep ends the execution in terms of internal transactions) -## How is the corpus used? +- Echidna reached a certain program counter in a given contract. +- The execution ended, either with stop, revert or a variety of errors (e.g. assertion failed, out of gas, not enough ether balance, etc) +- The number of EVM frames when the execution ended (in other words, how deep ends the execution in terms of internal transactions) + +## How is the corpus used? The corpus is used as the primary source of transactions to replay and mutate during a fuzzing campaign. The probability of using a sequence of transactions to replay and mutate is directly proportional to the number of transactions needed to add it into the corpus. In other words, more rare sequences are replayed and mutated more often during a fuzzing campaign. @@ -62,15 +63,15 @@ Check the [tutorial on selecting the right test mode](./basic/testing-modes.md) Before starting a fuzzing campaign, Echidna tests the properties with no transactions at all to check if they fail. In that case, a property can be detected to fail in the initial state (after the contract is deployed). You should check that the property is correct to know why it fails without any transactions. -## How can I know how a property or assertion failed? +## How can I know how a property or assertion failed? Echidna indicates the cause of a failed test in the UI. For instance, if a boolean property X fails because of a revert, Echidna will show “property X FAILED! with ErrorRevert”, otherwise, it should show “property X FAILED! with ErrorReturnFalse”. Assertion can only fail because with “ErrorUnrecognizedOpcode”, which is how Solidity implements assertions in EVM. ## How can I know exactly where and how property or assertion failed? -Events are an easy way to output values from the EVM. You can use them to get information in the code that has the failed property or assertion. Only the events of transaction triggering the failure will be shown (this will be improved in the near future). Also, events are collected and displayed, even if the transaction reverted (despite the Yellow Paper states that the event log should be cleaned). +Events are an easy way to output values from the EVM. You can use them to get information in the code that has the failed property or assertion. Only the events of transaction triggering the failure will be shown (this will be improved in the near future). Also, events are collected and displayed, even if the transaction reverted (despite the Yellow Paper states that the event log should be cleaned). -Another way to see where an assertion failed is using the coverage information. This requires to enable the corpus collection (e.g. `--corpus-dir X`) and check the coverage.\*.txt file to see something like this: +Another way to see where an assertion failed is using the coverage information. This requires to enable the corpus collection (e.g. `--corpus-dir X`) and check the coverage.\*.txt file to see something like this: ``` *e | function test(int x, address y, address z) public { @@ -81,22 +82,22 @@ Another way to see where an assertion failed is using the coverage information. | } ``` -The `e` marker indicates that Echidna collected a trace that ends with an assertion failure. As we can see, +The `e` marker indicates that Echidna collected a trace that ends with an assertion failure. As we can see, the path ends in the assert, so it should fail there. ## Why coverage information seems incorrect or incomplete? -Coverage mappings can be imprecesie, however, if it fails completely, it could be that you are using the [`viaIR` optimization option](https://docs.soliditylang.org/en/v0.8.14/ir-breaking-changes.html?highlight=viaIR#solidity-ir-based-codegen-changes), which seems to have some unexpected impact on the solc maps that we are still investigating. As a workaround, disable `viaIR`. +Coverage mappings can be imprecesie, however, if it fails completely, it could be that you are using the [`viaIR` optimization option](https://docs.soliditylang.org/en/v0.8.14/ir-breaking-changes.html?highlight=viaIR#solidity-ir-based-codegen-changes), which seems to have some unexpected impact on the solc maps that we are still investigating. As a workaround, disable `viaIR`. ## Echidna crashes showing ` NonEmpty.fromList: empty list` Echidna relies on the Solidity metadata to detect where each contract is deployed. Please do not disable it. If this is not the case, please [open an issue](https://github.com/crytic/echidna/issues) in our issue tracker. -## Echidna stopped working for some reason. How can I debug it? +## Echidna stopped working for some reason. How can I debug it? Use `--format text` and open an issue with the error you see in your console or ask in the #ethereum channel at the EmpireHacking slack. -## I am not getting expected results from Echidna tests. What can I do? +## I am not getting expected results from Echidna tests. What can I do? Sometimes it is useful to create small properties or assertions to test that the tool executed them correctly. For instance, for property mode: @@ -110,7 +111,7 @@ And for assertion mode: ```solidity function test_assert_false() public { - assert(false); + assert(false); } ``` diff --git a/program-analysis/echidna/fuzzing_tips.md b/program-analysis/echidna/fuzzing_tips.md index 5511ba61..49b30a7b 100644 --- a/program-analysis/echidna/fuzzing_tips.md +++ b/program-analysis/echidna/fuzzing_tips.md @@ -16,11 +16,10 @@ function operation(uint index, ...) public{ } ``` -If `require(index <= 10**18)` is used instead, many transactions generated will revert, slowing the fuzzer. +If `require(index <= 10**18)` is used instead, many transactions generated will revert, slowing the fuzzer. This can also be generalized define a min and max range, for example: - ```solidity function operation(uint balance, ...) public{ balance = MIN_BALANCE + balance % (MAX_BALANCE - MIN_BALANCE); @@ -76,4 +75,4 @@ This will work well to test arrays with a small amount of elements; however, it filterFunctions: ["C.pop()"] ``` -This is enough for small scale testing. A more general solution is available using a specific testing technique called [*swarm testing*](https://www.cs.utah.edu/~regehr/papers/swarm12.pdf). This allows to run a long testing campaign with some tool but randomly shuffling the configuration of it. In case of Echidna, swarm testing runs with different config files, where it blacklists some number of random functions from the contract before testing. We offer swarm testing and scalability with [echidna-parade](https://github.com/crytic/echidna-parade), our dedicated tool for fuzzing smart contracts. A specific tutorial in the use of echidna-parade is available [here](./advanced/smart-contract-fuzzing-at-scale.md). +This is enough for small scale testing. A more general solution is available using a specific testing technique called [_swarm testing_](https://www.cs.utah.edu/~regehr/papers/swarm12.pdf). This allows to run a long testing campaign with some tool but randomly shuffling the configuration of it. In case of Echidna, swarm testing runs with different config files, where it blacklists some number of random functions from the contract before testing. We offer swarm testing and scalability with [echidna-parade](https://github.com/crytic/echidna-parade), our dedicated tool for fuzzing smart contracts. A specific tutorial in the use of echidna-parade is available [here](./advanced/smart-contract-fuzzing-at-scale.md). diff --git a/program-analysis/echidna/introduction/README.md b/program-analysis/echidna/introduction/README.md index 3d554df9..93396720 100644 --- a/program-analysis/echidna/introduction/README.md +++ b/program-analysis/echidna/introduction/README.md @@ -4,4 +4,4 @@ Introductory material to fuzzing and Echidna - [Installation](./installation.md) - [Introduction to fuzzing](./fuzzing-introduction.md): Brief introduction to fuzzing -- [How to test a property](./how-to-test-a-property.md): How to test a property with Echidna \ No newline at end of file +- [How to test a property](./how-to-test-a-property.md): How to test a property with Echidna diff --git a/program-analysis/echidna/introduction/fuzzing-introduction.md b/program-analysis/echidna/introduction/fuzzing-introduction.md index f2f9f197..c3c0f32a 100644 --- a/program-analysis/echidna/introduction/fuzzing-introduction.md +++ b/program-analysis/echidna/introduction/fuzzing-introduction.md @@ -10,7 +10,7 @@ Beyond the purely random generation of inputs, there are many techniques and str - **Obtain feedback from each execution and guide generation using it**. For example, if a newly generated input leads to the discovery of a new path, it makes sense to generate new inputs closest to it. - **Generate input with respect to a structural constraint**. For example, if your input contains a header with a checksum, it makes sense to let the fuzzer generate input validating the checksum. -- **Use known inputs to generate new inputs**. If you have access to a large dataset of valid input, your fuzzer can generate new inputs from them, rather than starting from scratch for each generation. These are usually called *seeds*. +- **Use known inputs to generate new inputs**. If you have access to a large dataset of valid input, your fuzzer can generate new inputs from them, rather than starting from scratch for each generation. These are usually called _seeds_. ## Property-based fuzzing diff --git a/program-analysis/echidna/introduction/how-to-test-a-property.md b/program-analysis/echidna/introduction/how-to-test-a-property.md index a2bd447b..c0cc2dae 100644 --- a/program-analysis/echidna/introduction/how-to-test-a-property.md +++ b/program-analysis/echidna/introduction/how-to-test-a-property.md @@ -9,10 +9,9 @@ - [Run Echidna](#run-echidna) - [Summary: Testing a property](#summary-testing-a-property) - ## Introduction -We will see how to test a smart contract with Echidna. The target is the following smart contract (*[../example/token.sol](../example/token.sol)*): +We will see how to test a smart contract with Echidna. The target is the following smart contract (_[../example/token.sol](../example/token.sol)_): ```Solidity contract Token{ @@ -28,7 +27,7 @@ We will see how to test a smart contract with Echidna. The target is the followi balances[msg.sender] += 1; } } - + ``` We will make the assumption that this token has the following properties: @@ -40,13 +39,15 @@ We will make the assumption that this token has the following properties: ## Write a property Echidna properties are Solidity functions. A property must: + - Have no argument - Return true if it is successful - Have its name starting with `echidna` Echidna will: + - Automatically generate arbitrary transactions to test the property. -- Report any transactions leading a property to return false or throw an error. +- Report any transactions leading a property to return false or throw an error. - Discard side-effects when calling a property (i.e. if the property changes a state variable, it is discarded after the test) The following property checks that the caller can have no more than 1000 tokens: @@ -67,7 +68,7 @@ Use inheritance to separate your contract from your properties: } ``` -*[../example/testtoken.sol](../example/testtoken.sol)* implements the property and inherits from the token. +_[../example/testtoken.sol](../example/testtoken.sol)_ implements the property and inherits from the token. ## Initiate a contract @@ -113,7 +114,7 @@ The following summarizes the run of Echidna on our example: $ echidna-test testtoken.sol --contract TestToken ... -echidna_balance_under_1000: failed!💥 +echidna_balance_under_1000: failed!💥 Call sequence, shrinking (1205/5000): airdrop() backdoor() diff --git a/program-analysis/echidna/introduction/installation.md b/program-analysis/echidna/introduction/installation.md index 5d0f372d..7d03fd45 100644 --- a/program-analysis/echidna/introduction/installation.md +++ b/program-analysis/echidna/introduction/installation.md @@ -4,7 +4,7 @@ Echidna can be installed through docker or using the pre-compiled binary. ## MacOS -You can install Echidna with `brew install echidna`. +You can install Echidna with `brew install echidna`. ## Echidna through docker @@ -13,7 +13,7 @@ docker pull trailofbits/eth-security-toolbox docker run -it -v "$PWD":/home/training trailofbits/eth-security-toolbox ``` -*The last command runs eth-security-toolbox in a docker container that has access to your current directory. You can change the files from your host and run the tools on the files through the container* +_The last command runs eth-security-toolbox in a docker container that has access to your current directory. You can change the files from your host and run the tools on the files through the container_ Inside docker, run : diff --git a/program-analysis/manticore/README.md b/program-analysis/manticore/README.md index bfdcf5b1..deff4ee1 100644 --- a/program-analysis/manticore/README.md +++ b/program-analysis/manticore/README.md @@ -27,7 +27,7 @@ docker pull trailofbits/eth-security-toolbox docker run -it -v "$PWD":/home/training trailofbits/eth-security-toolbox ``` -*The last command runs eth-security-toolbox in a docker that has access to your current directory. You can change the files from your host, and run the tools on the files from the docker* +_The last command runs eth-security-toolbox in a docker that has access to your current directory. You can change the files from your host, and run the tools on the files from the docker_ Inside docker, run: diff --git a/program-analysis/manticore/adding-constraints.md b/program-analysis/manticore/adding-constraints.md index 8327aa3f..8fb3ff26 100644 --- a/program-analysis/manticore/adding-constraints.md +++ b/program-analysis/manticore/adding-constraints.md @@ -14,7 +14,7 @@ ## Introduction We will see how to constrain the exploration. We will make the assumption that the -documentation of `f()` states that the function is never called with `a == 65`, so any bug with `a == 65` is not a real bug. The target is still the following smart contract (*[examples/example.sol](./examples/example.sol)*): +documentation of `f()` states that the function is never called with `a == 65`, so any bug with `a == 65` is not a real bug. The target is still the following smart contract (_[examples/example.sol](./examples/example.sol)_): ```Solidity pragma solidity >=0.4.24 <0.6.0; @@ -50,7 +50,6 @@ from manticore.core.smtlib import Operators last_return = Operators.CONCAT(256, *last_return) ``` - ## Constraints You can use constraints globally or for a specific state. @@ -76,8 +75,8 @@ It can be used to constrain the state after its exploration to check some proper ## Checking Constraint -Use `solver.check(state.constraints)` to know if a constraint is still feasible. -For example, the following will constraint symbolic_value to be different from 65 and check if the state is still feasible: +Use `solver.check(state.constraints)` to know if a constraint is still feasible. +For example, the following will constraint symbolic_value to be different from 65 and check if the state is still feasible: ```python3 state.constrain(symbolic_var != 65) diff --git a/program-analysis/manticore/exercises/example.md b/program-analysis/manticore/exercises/example.md index 5d118e7c..7b73be8d 100644 --- a/program-analysis/manticore/exercises/example.md +++ b/program-analysis/manticore/exercises/example.md @@ -1,4 +1,5 @@ # Example: Arithmetic overflow + This scenario is given as an example. You can follow its structure to solve the exercises. [`my_token.py`](example/my_token.py) uses manticore to find for an attacker to generate tokens during a transfer on Token ([my_token.sol](example/my_token.sol)). diff --git a/program-analysis/manticore/exercises/exercise1.md b/program-analysis/manticore/exercises/exercise1.md index 786c6ab6..ec391fbd 100644 --- a/program-analysis/manticore/exercises/exercise1.md +++ b/program-analysis/manticore/exercises/exercise1.md @@ -1,4 +1,3 @@ - # Exercice 1 : Arithmetic Use Manticore to find an input allowing an attacker to generate free tokens in [exercise1/token.sol](./exercise1/token.sol). @@ -29,4 +28,4 @@ Follow the pattern initilization, exploration and property for the script. ### Solution -[exercise1/solution.py](./exercise1/solution.py) \ No newline at end of file +[exercise1/solution.py](./exercise1/solution.py) diff --git a/program-analysis/manticore/getting-throwing-paths.md b/program-analysis/manticore/getting-throwing-paths.md index 021c0cad..2d92e0ed 100644 --- a/program-analysis/manticore/getting-throwing-paths.md +++ b/program-analysis/manticore/getting-throwing-paths.md @@ -9,10 +9,9 @@ - [Summary](#summary) - [Summary: Getting Throwing Path](#summary-getting-throwing-path) - ## Introduction -We will now improve [the previous example](running-under-manticore.md) and generate specific inputs for the paths raising an exception in `f()`. The target is still the following smart contract (*[examples/example.sol](./examples/example.sol)*): +We will now improve [the previous example](running-under-manticore.md) and generate specific inputs for the paths raising an exception in `f()`. The target is still the following smart contract (_[examples/example.sol](./examples/example.sol)_): ```Solidity pragma solidity >=0.4.24 <0.6.0; @@ -95,5 +94,4 @@ All the code above you can find into the [examples/example_throw.py](./examples/ The next step is to [add constraints](./adding-constraints.md) to the state. -*Note we could have generated a much simpler script, as all the states returned by terminated_state have REVERT or INVALID in their result: this example was only meant to demonstrate how to manipulate the API.* - +_Note we could have generated a much simpler script, as all the states returned by terminated_state have REVERT or INVALID in their result: this example was only meant to demonstrate how to manipulate the API._ diff --git a/program-analysis/manticore/running-under-manticore.md b/program-analysis/manticore/running-under-manticore.md index 40a7d49b..4d471c77 100644 --- a/program-analysis/manticore/running-under-manticore.md +++ b/program-analysis/manticore/running-under-manticore.md @@ -7,10 +7,9 @@ - [Manipulate a smart contract through the API](#manipulate-a-smart-contract-through-the-api) - [Summary: Running under Manticore](#summary-running-under-manticore) - ## Introduction -We will see how to explore a smart contract with the Manticore API. The target is the following smart contract (*[examples/example.sol](./examples/example.sol)*): +We will see how to explore a smart contract with the Manticore API. The target is the following smart contract (_[examples/example.sol](./examples/example.sol)_): ```Solidity pragma solidity >=0.4.24 <0.6.0; @@ -31,7 +30,6 @@ You can run Manticore directly on the smart contract by the following command (` $ manticore project ``` - You will get the output of testcases like this one (the order may change): ``` @@ -52,21 +50,21 @@ transactions until it does not explore new paths on the contract. Manticore does Manticore will output the information in a `mcore_*` directory. Among other, you will find in this directory: - - `global.summary`: coverage and compiler warnings - - `test_XXXXX.summary`: coverage, last instruction, account balances per test case - - `test_XXXXX.tx`: detailed list of transactions per test case +- `global.summary`: coverage and compiler warnings +- `test_XXXXX.summary`: coverage, last instruction, account balances per test case +- `test_XXXXX.tx`: detailed list of transactions per test case Here Manticore founds 7 test cases, which correspond to (the filename order may change): -| | Transaction 0 | Transaction 1 | Transaction 2 | Result | -|:----------------:|:------------------:|:-----------------:|-------------------|:------:| -| **test_00000000.tx** | Contract creation | f(!=65) | f(!=65) | STOP | -| **test_00000001.tx** | Contract creation | fallback function | | REVERT | -| **test_00000002.tx** | Contract creation | | | RETURN | -| **test_00000003.tx** | Contract creation | f(65) | | REVERT | -| **test_00000004.tx** | Contract creation | f(!=65) | | STOP | -| **test_00000005.tx** | Contract creation | f(!=65) | f(65) | REVERT | -| **test_00000006.tx** | Contract creation | f(!=65) | fallback function | REVERT | +| | Transaction 0 | Transaction 1 | Transaction 2 | Result | +| :------------------: | :---------------: | :---------------: | ----------------- | :----: | +| **test_00000000.tx** | Contract creation | f(!=65) | f(!=65) | STOP | +| **test_00000001.tx** | Contract creation | fallback function | | REVERT | +| **test_00000002.tx** | Contract creation | | | RETURN | +| **test_00000003.tx** | Contract creation | f(65) | | REVERT | +| **test_00000004.tx** | Contract creation | f(!=65) | | STOP | +| **test_00000005.tx** | Contract creation | f(!=65) | f(65) | REVERT | +| **test_00000006.tx** | Contract creation | f(!=65) | fallback function | REVERT | _Exploration summary f(!=65) denotes f called with any value different than 65._ @@ -74,10 +72,9 @@ As you can notice, Manticore generates an unique test case for every successful Use the `--quick-mode` flag if you want fast code exploration (it disable bug detectors, gas computation, ...) - ## Manipulate a smart contract through the API -This section describes details how to manipulate a smart contract through the Manticore Python API. You can create new file with python extension ```*.py``` and write the necessary code by adding the API commands (basics of which will be described below) into this file and then run it with the command ```$ python3 *.py```. Also you can execute the commands below directly into the python console, to run the console use the command ```$ python3```. +This section describes details how to manipulate a smart contract through the Manticore Python API. You can create new file with python extension `*.py` and write the necessary code by adding the API commands (basics of which will be described below) into this file and then run it with the command `$ python3 *.py`. Also you can execute the commands below directly into the python console, to run the console use the command `$ python3`. ### Creating Accounts @@ -170,7 +167,6 @@ If `value` of the transaction is not specified, it is 0 by default. - A raw transaction will explore all the functions - Function can be called by their name - ### Workspace `m.workspace` is the directory used as output directory for all the files generated: diff --git a/program-analysis/manticore/symbolic-execution-introduction.md b/program-analysis/manticore/symbolic-execution-introduction.md index 50a88f0e..7f559f00 100644 --- a/program-analysis/manticore/symbolic-execution-introduction.md +++ b/program-analysis/manticore/symbolic-execution-introduction.md @@ -4,33 +4,36 @@ ## Dynamic Symbolic Execution in a Nutshell -Dynamic symbolic execution (DSE) is a program analysis technique that explores a state space with a high degree of semantic awareness. This technique is based on the discovery of "program paths", represented as mathematical formulas called `path predicates`. Conceptually, this technique operates on path predicates in two steps: +Dynamic symbolic execution (DSE) is a program analysis technique that explores a state space with a high degree of semantic awareness. This technique is based on the discovery of "program paths", represented as mathematical formulas called `path predicates`. Conceptually, this technique operates on path predicates in two steps: -1. They are constructed using constraints on the program's input. +1. They are constructed using constraints on the program's input. 2. They are used to generate program inputs that will cause the associated paths to execute. This approach produces no false positives in the sense that all identified program states can be triggered during concrete execution. For example, if the analysis finds an integer overflow, it is guaranteed to be reproducible. ### Path Predicate Example + To get an insigh of how DSE works, consider the following example: ```solidity function f(uint a){ - + if (a == 65) { // A bug is present } - + } ``` As `f()` contains two paths, a DSE will construct two differents path predicates: + - Path 1: `a == 65` - Path 2: `Not (a == 65)` Each path predicate is a mathematical formula that can be given to a so-called `SMT solver`, which will try to solve the equation. For `Path 1`, the solver will say that the path can be explored with `a = 65`. For `Path 2`, the solver can give `a` any value other than 65, for example `a = 0`. ### Verifying properties + Manticore allows a full control over all the execution of each path. As a result, it allows to add arbirtray contraints to almost anything. This control allows for the creation of properties on the contract. Consider the following example: @@ -43,9 +46,11 @@ function unsafe_add(uint a, uint b) returns(uint c){ ``` Here there is only one path to explore in the function: + - Path 1: `c = a + b` Using Manticore, you can check for overflow, and add constraitns to the path predicate: + - `c = a + b AND (c < a OR c < b)` If it is possible to find a valuation of `a` and `b` for which the path predicate above is feasible, it means that you have found an overflow. For example the solver can generate the input `a = 10 , b = MAXUINT256`. @@ -54,7 +59,7 @@ If you consider a fixed version: ```solidity function safe_add(uint a, uint b) returns(uint c){ - c = a + b; + c = a + b; require(c>=a); require(c>=b); return c; @@ -62,6 +67,7 @@ function safe_add(uint a, uint b) returns(uint c){ ``` The associated formula with overflow check would be: + - `c = a + b AND (c >= a) AND (c=>b) AND (c < a OR c < b)` This formula cannot be solved; in other words this is a **proof** that in `safe_add`, `c` will always increase. diff --git a/program-analysis/slither/README.md b/program-analysis/slither/README.md index fd2c5c2b..cf34b80a 100644 --- a/program-analysis/slither/README.md +++ b/program-analysis/slither/README.md @@ -25,6 +25,7 @@ pip3 install --user slither-analyzer ``` ### Docker + Slither through docker: ```bash @@ -32,7 +33,7 @@ docker pull trailofbits/eth-security-toolbox docker run -it -v "$PWD":/home/trufflecon trailofbits/eth-security-toolbox ``` -*The last command runs eth-security-toolbox in a docker that has access to your current directory. You can change the files from your host, and run the tools on the files from the docker* +_The last command runs eth-security-toolbox in a docker that has access to your current directory. You can change the files from your host, and run the tools on the files from the docker_ Inside docker, run: @@ -45,7 +46,7 @@ cd /home/trufflecon/ **Command line versus user-defined scripts.** Slither comes with a set of predefined detectors that find many common bugs. Calling Slither from the command line will run all the detectors, no detailed knowledge of static analysis needed: -```bash +```bash slither project_paths ``` diff --git a/program-analysis/slither/api.md b/program-analysis/slither/api.md index 365618bd..75569f98 100644 --- a/program-analysis/slither/api.md +++ b/program-analysis/slither/api.md @@ -42,4 +42,4 @@ A `Function` or a `Modifier` object has: ### Example: Print Basic Information -[print_basic_information.py](./examples/print_basic_information.py) shows how to print basic information about a project. \ No newline at end of file +[print_basic_information.py](./examples/print_basic_information.py) shows how to print basic information about a project. diff --git a/program-analysis/slither/exercise1.md b/program-analysis/slither/exercise1.md index 724a90ea..c4d5e8ae 100644 --- a/program-analysis/slither/exercise1.md +++ b/program-analysis/slither/exercise1.md @@ -1,4 +1,5 @@ # Exercice 1 : Function overridden protection + The goal is to create a script that fills a missing feature of Solidity: function overriding protection. [exercises/exercise1/coin.sol](exercises/exercise1/coin.sol) contains a function that must never be overridden: diff --git a/program-analysis/slither/static_analysis.md b/program-analysis/slither/static_analysis.md index 041581da..8bbc0b2d 100644 --- a/program-analysis/slither/static_analysis.md +++ b/program-analysis/slither/static_analysis.md @@ -1,4 +1,3 @@ - ## Static analysis The capabilities and design of the Slither static analysis framework has been described in blog posts ([1](https://blog.trailofbits.com/2018/10/19/slither-a-solidity-static-analysis-framework/), [2](https://blog.trailofbits.com/2019/05/27/slither-the-leading-static-analyzer-for-smart-contracts/)) and an [academic paper](https://github.com/trailofbits/publications/blob/master/papers/wetseb19.pdf). @@ -19,7 +18,7 @@ In contrast to a dynamic analysis, which reasons about a single execution path, AST are used every time the compiler parses code. It is probably the most basic structure upon which static analysis can be performed. -In a nutshell, an AST is a structured tree where, usually, each leaf contains a variable or a constant and internal nodes are operands or control flow operations. Consider the following code: +In a nutshell, an AST is a structured tree where, usually, each leaf contains a variable or a constant and internal nodes are operands or control flow operations. Consider the following code: ```solidity function safeAdd(uint a, uint b) pure internal returns(uint){ @@ -69,7 +68,7 @@ Many other code representations exist. Each representation has advantages and dr ### Analysis -The simplest type of analyses you can perform with Slither are syntactic analyses. +The simplest type of analyses you can perform with Slither are syntactic analyses. ### Syntax analysis @@ -112,7 +111,7 @@ for(uint i; i < range; ++){ } ``` -Your analysis will need to know when to stop. There are two main strategies here: (1) iterate on each node a finite number of times, (2) compute a so-called *fixpoint*. A fixpoint basically means that analyzing this node does not provide any meaningful information. +Your analysis will need to know when to stop. There are two main strategies here: (1) iterate on each node a finite number of times, (2) compute a so-called _fixpoint_. A fixpoint basically means that analyzing this node does not provide any meaningful information. An example of fixpoint used can be found in the reentrancy detectors: Slither explores the nodes, and look for externals calls, write and read to storage. Once it has reached a fixpoint ([reentrancy.py#L125-L131](https://github.com/crytic/slither/blob/master/slither/detectors/reentrancy/reentrancy.py#L125-L131)), it stops the exploration, and analyze the results to see if a reentrancy is present, through different reentrancy patterns ([reentrancy_benign.py](https://github.com/crytic/slither/blob/b275bcc824b1b932310cf03b6bfb1a1fef0ebae1/slither/detectors/reentrancy/reentrancy_benign.py), [reentrancy_read_before_write.py](https://github.com/crytic/slither/blob/b275bcc824b1b932310cf03b6bfb1a1fef0ebae1/slither/detectors/reentrancy/reentrancy_read_before_write.py), [reentrancy_eth.py](https://github.com/crytic/slither/blob/b275bcc824b1b932310cf03b6bfb1a1fef0ebae1/slither/detectors/reentrancy/reentrancy_eth.py)). diff --git a/resources/tob_blogposts.md b/resources/tob_blogposts.md index fb1546ad..7a817bd9 100644 --- a/resources/tob_blogposts.md +++ b/resources/tob_blogposts.md @@ -1,6 +1,6 @@ # Trail of Bits blogposts -The following contains the blockchain related blogposts made by Trail of Bits. +The following contains the blockchain related blogposts made by Trail of Bits. - [Trail of Bits blogposts](#trail-of-bits-blogposts) - [Consensus algorithms](#consensus-algorithms) @@ -16,118 +16,114 @@ The following contains the blockchain related blogposts made by Trail of Bits. Research in the distributes systems area -| Date | Title | Description | -|-----|-----|-----| -| 2021/11/11 | [Motivating global stabilization](https://blog.trailofbits.com/2021/11/11/motivating-global-stabilization/) | Review of Fischer, Lynch, and Paterson’s classic impossibility result and global stabilization time assumption | -| 2019/10/25 | [Formal Analysis of the CBC Casper Consensus Algorithm with TLA+](https://blog.trailofbits.com/2019/10/25/formal-analysis-of-the-cbc-casper-consensus-algorithm-with-tla/) | Verification of finality of the Correct By Construction (CBC) PoS consensus protocol | -| 2019/07/12 | [On LibraBFT’s use of broadcasts](https://blog.trailofbits.com/2019/07/12/librabft/) | Liveness of LibraBFT and HotStuff algorithms | -| 2019/07/02 | [State of the Art Proof-of-Work: RandomX](https://blog.trailofbits.com/2019/07/02/state/) | Summary of our audit of ASIC and GPU-resistant PoW algorithm | -| 2018/10/12 | [Introduction to Verifiable Delay Functions (VDFs)](https://blog.trailofbits.com/2018/10/12/introduction-to-verifiable-delay-functions-vdfs/) | Basics of VDFs - a class of hard to compute, not paralelizable, but easily verifiable functions | +| Date | Title | Description | +| ---------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------- | +| 2021/11/11 | [Motivating global stabilization](https://blog.trailofbits.com/2021/11/11/motivating-global-stabilization/) | Review of Fischer, Lynch, and Paterson’s classic impossibility result and global stabilization time assumption | +| 2019/10/25 | [Formal Analysis of the CBC Casper Consensus Algorithm with TLA+](https://blog.trailofbits.com/2019/10/25/formal-analysis-of-the-cbc-casper-consensus-algorithm-with-tla/) | Verification of finality of the Correct By Construction (CBC) PoS consensus protocol | +| 2019/07/12 | [On LibraBFT’s use of broadcasts](https://blog.trailofbits.com/2019/07/12/librabft/) | Liveness of LibraBFT and HotStuff algorithms | +| 2019/07/02 | [State of the Art Proof-of-Work: RandomX](https://blog.trailofbits.com/2019/07/02/state/) | Summary of our audit of ASIC and GPU-resistant PoW algorithm | +| 2018/10/12 | [Introduction to Verifiable Delay Functions (VDFs)](https://blog.trailofbits.com/2018/10/12/introduction-to-verifiable-delay-functions-vdfs/) | Basics of VDFs - a class of hard to compute, not paralelizable, but easily verifiable functions | ## Fuzzing compilers Our work in the topic of fuzzing the `solc` compiler -| Date | Title | Description | -|-----|-----|-----| +| Date | Title | Description | +| ---------- | ----------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------- | | 2021/03/23 | [A Year in the Life of a Compiler Fuzzing Campaign](https://blog.trailofbits.com/2021/03/23/a-year-in-the-life-of-a-compiler-fuzzing-campaign/) | Results and feature of fuzzing solc | -| 2020/06/05 | [Breaking the Solidity Compiler with a Fuzzer](https://blog.trailofbits.com/2020/06/05/breaking-the-solidity-compiler-with-a-fuzzer/) | Our approach to fuzzing solc | - +| 2020/06/05 | [Breaking the Solidity Compiler with a Fuzzer](https://blog.trailofbits.com/2020/06/05/breaking-the-solidity-compiler-with-a-fuzzer/) | Our approach to fuzzing solc | ## General Security research, analyses, announcements, and writeups -| Date | Title | Description | -|-----|-----|-----| -| 2022/10/12 | [Porting the Solana eBPF JIT compiler to ARM64](https://blog.trailofbits.com/2022/10/12/solana-jit-compiler-ebpf-arm64/) | Low-level writeup of the work done to make Solana compiler work on ARM64 | -| 2022/06/24 | [Managing risk in blockchain deployments](https://blog.trailofbits.com/2022/06/24/managing-risk-in-blockchain-deployments/) | Summary of "Do You Really Need a Blockchain? An Operational Risk Assessment" report | -| 2022/06/21 | [Are blockchains decentralized?](https://blog.trailofbits.com/2022/06/21/are-blockchains-decentralized/) | Summary of "Are Blockchains Decentralize? Unintended Centralities in Distributed Ledgers" report | -| 2020/08/05 | [Accidentally stepping on a DeFi lego](https://blog.trailofbits.com/2020/08/05/accidentally-stepping-on-a-defi-lego/) | Writeup of a vulnerability in yVault project | -| 2020/05/15 | [Bug Hunting with Crytic](https://blog.trailofbits.com/2020/05/15/bug-hunting-with-crytic/) | Description of 9 bugs found by Trail of Bits tools in public projects | -| 2019/11/13 | [Announcing the Crytic $10k Research Prize](https://blog.trailofbits.com/2019/11/13/announcing-the-crytic-10k-research-prize/) | Academic research prize promoting open source work | -| 2019/10/24 | [Watch Your Language: Our First Vyper Audit](https://blog.trailofbits.com/2019/10/24/watch-your-language-our-first-vyper-audit/) | Pros and cons of Vyper language and disclosure of vulnerability in the Vyper's compiler | +| Date | Title | Description | +| ---------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| 2022/10/12 | [Porting the Solana eBPF JIT compiler to ARM64](https://blog.trailofbits.com/2022/10/12/solana-jit-compiler-ebpf-arm64/) | Low-level writeup of the work done to make Solana compiler work on ARM64 | +| 2022/06/24 | [Managing risk in blockchain deployments](https://blog.trailofbits.com/2022/06/24/managing-risk-in-blockchain-deployments/) | Summary of "Do You Really Need a Blockchain? An Operational Risk Assessment" report | +| 2022/06/21 | [Are blockchains decentralized?](https://blog.trailofbits.com/2022/06/21/are-blockchains-decentralized/) | Summary of "Are Blockchains Decentralize? Unintended Centralities in Distributed Ledgers" report | +| 2020/08/05 | [Accidentally stepping on a DeFi lego](https://blog.trailofbits.com/2020/08/05/accidentally-stepping-on-a-defi-lego/) | Writeup of a vulnerability in yVault project | +| 2020/05/15 | [Bug Hunting with Crytic](https://blog.trailofbits.com/2020/05/15/bug-hunting-with-crytic/) | Description of 9 bugs found by Trail of Bits tools in public projects | +| 2019/11/13 | [Announcing the Crytic $10k Research Prize](https://blog.trailofbits.com/2019/11/13/announcing-the-crytic-10k-research-prize/) | Academic research prize promoting open source work | +| 2019/10/24 | [Watch Your Language: Our First Vyper Audit](https://blog.trailofbits.com/2019/10/24/watch-your-language-our-first-vyper-audit/) | Pros and cons of Vyper language and disclosure of vulnerability in the Vyper's compiler | | 2019/08/08 | [246 Findings From our Smart Contract Audits: An Executive Summary](https://blog.trailofbits.com/2019/08/08/246-findings-from-our-smart-contract-audits-an-executive-summary/) | Publication of data aggregated from our audits. Discussion about possibility of automatic and manual detection of vulnerabilities, and usefulness of unit tests | -| 2018/11/19 | [Return of the Blockchain Security Empire Hacking](https://blog.trailofbits.com/2018/11/19/return-of-the-blockchain-security-empire-hacking/) | -| 2018/02/09 | [Parity Technologies engages Trail of Bits](https://blog.trailofbits.com/2018/02/09/parity-technologies-engages-trail-of-bits/) | | -| 2017/11/06 | [Hands on the Ethernaut CTF](https://blog.trailofbits.com/2017/11/06/hands-on-the-ethernaut-ctf/) | First write-up on Ethernaut | +| 2018/11/19 | [Return of the Blockchain Security Empire Hacking](https://blog.trailofbits.com/2018/11/19/return-of-the-blockchain-security-empire-hacking/) | +| 2018/02/09 | [Parity Technologies engages Trail of Bits](https://blog.trailofbits.com/2018/02/09/parity-technologies-engages-trail-of-bits/) | | +| 2017/11/06 | [Hands on the Ethernaut CTF](https://blog.trailofbits.com/2017/11/06/hands-on-the-ethernaut-ctf/) | First write-up on Ethernaut | ## Guidance General guidance -| Date | Title | Description | -|-----|-----|-----| -| 2021/02/05 | [Confessions of a smart contract paper reviewer](https://blog.trailofbits.com/2021/02/05/confessions-of-a-smart-contract-paper-reviewer/) | Six requirements for a good research paper | -| 2018/11/27 | [10 Rules for the Secure Use of Cryptocurrency Hardware Wallets](https://blog.trailofbits.com/2018/11/27/10-rules-for-the-secure-use-of-cryptocurrency-hardware-wallets/) | Recommendations for the secure use of hardware wallets. | -| 2018/10/04 | [Ethereum security guidance for all](https://blog.trailofbits.com/2018/10/04/ethereum-security-guidance-for-all/) | Announcement of office hours, Blockchain Security Contacts, and Awesome Ethereum Security | -| 2018/04/06 | [How to prepare for a security review](https://blog.trailofbits.com/2018/04/06/how-to-prepare-for-a-security-audit/) | Checklist for before having a security audit | +| Date | Title | Description | +| ---------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------- | +| 2021/02/05 | [Confessions of a smart contract paper reviewer](https://blog.trailofbits.com/2021/02/05/confessions-of-a-smart-contract-paper-reviewer/) | Six requirements for a good research paper | +| 2018/11/27 | [10 Rules for the Secure Use of Cryptocurrency Hardware Wallets](https://blog.trailofbits.com/2018/11/27/10-rules-for-the-secure-use-of-cryptocurrency-hardware-wallets/) | Recommendations for the secure use of hardware wallets. | +| 2018/10/04 | [Ethereum security guidance for all](https://blog.trailofbits.com/2018/10/04/ethereum-security-guidance-for-all/) | Announcement of office hours, Blockchain Security Contacts, and Awesome Ethereum Security | +| 2018/04/06 | [How to prepare for a security review](https://blog.trailofbits.com/2018/04/06/how-to-prepare-for-a-security-audit/) | Checklist for before having a security audit | ## Presentations Talks, videos, and slides -| Date | Title | Description | -|-----|-----|-----| -| 2019/01/18 | [Empire Hacking: Ethereum Edition 2](https://blog.trailofbits.com/2019/01/18/empire-hacking-ethereum-edition-2/) | Talks include: `Anatomy of an unsafe smart contract programming language`, `Evaluating digital asset security fundamentals`, `Contract upgrade risks and recommendations`, `How to buidl an enterprise-grade mainnet Ethereum client`, `Failures in on-chain privacy`, `Secure micropayment protocols`, `Designing the Gemini dollar: a regulated, upgradeable, transparent stablecoin`, `Property testing with Echidna and Manticore for secure smart contracts`, `Simple is hard: Making your awesome security thing usable` | -| 2018/11/16 | [Trail of Bits @ Devcon IV Recap](https://blog.trailofbits.com/2018/11/16/trail-of-bits-devcon-iv-recap/) | Talks include: `Using Manticore and Symbolic Execution to Find Smart Contract Bugs`, `Blockchain Autopsies`, `Current State of Security` | -| 2017/12/22 | [Videos from Ethereum-focused Empire Hacking](https://blog.trailofbits.com/2017/12/22/videos-from-ethereum-focused-empire-hacking/) | Talks include: `A brief history of smart contract security`, `A CTF Field Guide for smart contracts`, `Automatic bug finding for the blockchain`, `Addressing infosec needs with blockchain technology` | - +| Date | Title | Description | +| ---------- | ----------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| 2019/01/18 | [Empire Hacking: Ethereum Edition 2](https://blog.trailofbits.com/2019/01/18/empire-hacking-ethereum-edition-2/) | Talks include: `Anatomy of an unsafe smart contract programming language`, `Evaluating digital asset security fundamentals`, `Contract upgrade risks and recommendations`, `How to buidl an enterprise-grade mainnet Ethereum client`, `Failures in on-chain privacy`, `Secure micropayment protocols`, `Designing the Gemini dollar: a regulated, upgradeable, transparent stablecoin`, `Property testing with Echidna and Manticore for secure smart contracts`, `Simple is hard: Making your awesome security thing usable` | +| 2018/11/16 | [Trail of Bits @ Devcon IV Recap](https://blog.trailofbits.com/2018/11/16/trail-of-bits-devcon-iv-recap/) | Talks include: `Using Manticore and Symbolic Execution to Find Smart Contract Bugs`, `Blockchain Autopsies`, `Current State of Security` | +| 2017/12/22 | [Videos from Ethereum-focused Empire Hacking](https://blog.trailofbits.com/2017/12/22/videos-from-ethereum-focused-empire-hacking/) | Talks include: `A brief history of smart contract security`, `A CTF Field Guide for smart contracts`, `Automatic bug finding for the blockchain`, `Addressing infosec needs with blockchain technology` | ## Tooling Description of our tools and their use cases -| Date | Tool | Title | Description | -|-----|-----|-----|-----| -| 2022/08/17 | slither | [Using mutants to improve Slither](https://blog.trailofbits.com/2022/08/17/using-mutants-to-improve-slither/) | Inserting random bugs into smart contracts and detecting them with various static analysis tools - to improve Slither's detectors | -| 2022/07/28 | slither | [Shedding smart contract storage with Slither](https://blog.trailofbits.com/2022/07/28/shedding-smart-contract-storage-with-slither/) | Announcement of the slither-read-storage tool | -| 2022/04/20 | | [Amarna: Static analysis for Cairo programs](https://blog.trailofbits.com/2022/04/20/amarna-static-analysis-for-cairo-programs/) | Overview of Cairo footguns and announcement of the new static analysis tool | -| 2022/03/02 | echidna | [Optimizing a smart contract fuzzer](https://blog.trailofbits.com/2022/03/02/optimizing-a-smart-contract-fuzzer/) | Measuring and improving performance of Echidna (Haskell code) | -| 2021/12/16 | slither | [Detecting MISO and Opyn’s msg.value reuse vulnerability with Slither](https://blog.trailofbits.com/2021/12/16/detecting-miso-and-opyns-msg-value-reuse-vulnerability-with-slither/) | Description of Slither's new detectors: delegatecall-loop and msg-value-loop | -| 2021/04/02 | | [Solar: Context-free, interactive analysis for Solidity](https://blog.trailofbits.com/2021/04/02/solar-context-free-interactive-analysis-for-solidity/) | Proof-of-concept static analysis framework | -| 2020/10/23 | slither | [Efficient audits with machine learning and Slither-simil](https://blog.trailofbits.com/2020/10/23/efficient-audits-with-machine-learning-and-slither-simil/) | Detect similar Solidity functions with Slither and ML | -| 2020/08/17 | echidna | [Using Echidna to test a smart contract library](https://blog.trailofbits.com/2020/08/17/using-echidna-to-test-a-smart-contract-library/) | Designing and testing properties with differential fuzzing | -| 2020/07/12 | manticore | [Contract verification made easier](https://blog.trailofbits.com/2020/07/12/new-manticore-verifier-for-smart-contracts/) | Re-use Echidna properties with Manticore with manticore-verifier | -| 2020/06/12 | slither | [Upgradeable contracts made safer with Crytic](https://blog.trailofbits.com/2020/06/12/upgradeable-contracts-made-safer-with-crytic/) | 17 new Slither detectors for upgradeable contracts | -| 2020/03/30 | echidna | [An Echidna for all Seasons](https://blog.trailofbits.com/2020/03/30/an-echidna-for-all-seasons/) | Announcement of new features in Echidna | -| 2020/03/03 | manticore | [Manticore discovers the ENS bug](https://blog.trailofbits.com/2020/03/03/manticore-discovers-the-ens-bug/) | Using symbolic analysis to find vulnerability in Ethereum Name Service contract | -| 2020/01/31 | manticore | [Symbolically Executing WebAssembly in Manticore](https://blog.trailofbits.com/2020/01/31/symbolically-executing-webassembly-in-manticore/) | Using symbolic analysis on an artificial WASM binary | -| 2019/08/02 | | [Crytic: Continuous Assurance for Smart Contracts](https://blog.trailofbits.com/2019/08/02/crytic-continuous-assurance-for-smart-contracts/) | New product that integrates static analysis with GitHub pipeline | -| 2019/07/03 | slither | [Avoiding Smart Contract \"Gridlock\" with Slither](https://blog.trailofbits.com/2019/07/03/avoiding-smart-contract-gridlock-with-slither/) | Description of a DoS vulnerability resulting from a strict equality check, and Slither's dangerous-strict-equality detector | -| 2019/05/27 | slither | [Slither: The Leading Static Analyzer for Smart Contracts](https://blog.trailofbits.com/2019/05/27/slither-the-leading-static-analyzer-for-smart-contracts/) | Slither design and comparison with other static analysis tools | -| 2018/10/19 | slither | [Slither – a Solidity static analysis framework](https://blog.trailofbits.com/2018/10/19/slither-a-solidity-static-analysis-framework/) | Introduction to Slither's API and printers | -| 2018/09/06 | rattle | [Rattle – an Ethereum EVM binary analysis framework](https://blog.trailofbits.com/2018/09/06/rattle-an-ethereum-evm-binary-analysis-framework/) | Turn EVM bytecode to infinite-register SSA form | -| 2018/05/03 | echidna | [State Machine Testing with Echidna](https://blog.trailofbits.com/2018/05/03/state-machine-testing-with-echidna/) | Example use case of Echidna's Haskell API | -| 2018/03/23 | | [Use our suite of Ethereum security tools](https://blog.trailofbits.com/2018/03/23/use-our-suite-of-ethereum-security-tools/) | Overview of our tools and documents: Not So Smart Contracts, Slither, Echidna, Manticore, EVM Opcode Database, Ethersplay, IDA-EVM, Rattle | -| 2018/03/09 | echidna | [Echidna, a smart fuzzer for Ethereum](https://blog.trailofbits.com/2018/03/09/echidna-a-smart-fuzzer-for-ethereum/) | First release and introduction to Echidna | -| 2017/04/27 | manticore | [Manticore: Symbolic execution for humans](https://blog.trailofbits.com/2017/04/27/manticore-symbolic-execution-for-humans/) | First release and introduction to Manticore (not adopted for EVM yet) | +| Date | Tool | Title | Description | +| ---------- | ---------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------ | +| 2022/08/17 | slither | [Using mutants to improve Slither](https://blog.trailofbits.com/2022/08/17/using-mutants-to-improve-slither/) | Inserting random bugs into smart contracts and detecting them with various static analysis tools - to improve Slither's detectors | +| 2022/07/28 | slither | [Shedding smart contract storage with Slither](https://blog.trailofbits.com/2022/07/28/shedding-smart-contract-storage-with-slither/) | Announcement of the slither-read-storage tool | +| 2022/04/20 | | [Amarna: Static analysis for Cairo programs](https://blog.trailofbits.com/2022/04/20/amarna-static-analysis-for-cairo-programs/) | Overview of Cairo footguns and announcement of the new static analysis tool | +| 2022/03/02 | echidna | [Optimizing a smart contract fuzzer](https://blog.trailofbits.com/2022/03/02/optimizing-a-smart-contract-fuzzer/) | Measuring and improving performance of Echidna (Haskell code) | +| 2021/12/16 | slither | [Detecting MISO and Opyn’s msg.value reuse vulnerability with Slither](https://blog.trailofbits.com/2021/12/16/detecting-miso-and-opyns-msg-value-reuse-vulnerability-with-slither/) | Description of Slither's new detectors: delegatecall-loop and msg-value-loop | +| 2021/04/02 | | [Solar: Context-free, interactive analysis for Solidity](https://blog.trailofbits.com/2021/04/02/solar-context-free-interactive-analysis-for-solidity/) | Proof-of-concept static analysis framework | +| 2020/10/23 | slither | [Efficient audits with machine learning and Slither-simil](https://blog.trailofbits.com/2020/10/23/efficient-audits-with-machine-learning-and-slither-simil/) | Detect similar Solidity functions with Slither and ML | +| 2020/08/17 | echidna | [Using Echidna to test a smart contract library](https://blog.trailofbits.com/2020/08/17/using-echidna-to-test-a-smart-contract-library/) | Designing and testing properties with differential fuzzing | +| 2020/07/12 | manticore | [Contract verification made easier](https://blog.trailofbits.com/2020/07/12/new-manticore-verifier-for-smart-contracts/) | Re-use Echidna properties with Manticore with manticore-verifier | +| 2020/06/12 | slither | [Upgradeable contracts made safer with Crytic](https://blog.trailofbits.com/2020/06/12/upgradeable-contracts-made-safer-with-crytic/) | 17 new Slither detectors for upgradeable contracts | +| 2020/03/30 | echidna | [An Echidna for all Seasons](https://blog.trailofbits.com/2020/03/30/an-echidna-for-all-seasons/) | Announcement of new features in Echidna | +| 2020/03/03 | manticore | [Manticore discovers the ENS bug](https://blog.trailofbits.com/2020/03/03/manticore-discovers-the-ens-bug/) | Using symbolic analysis to find vulnerability in Ethereum Name Service contract | +| 2020/01/31 | manticore | [Symbolically Executing WebAssembly in Manticore](https://blog.trailofbits.com/2020/01/31/symbolically-executing-webassembly-in-manticore/) | Using symbolic analysis on an artificial WASM binary | +| 2019/08/02 | | [Crytic: Continuous Assurance for Smart Contracts](https://blog.trailofbits.com/2019/08/02/crytic-continuous-assurance-for-smart-contracts/) | New product that integrates static analysis with GitHub pipeline | +| 2019/07/03 | slither | [Avoiding Smart Contract \"Gridlock\" with Slither](https://blog.trailofbits.com/2019/07/03/avoiding-smart-contract-gridlock-with-slither/) | Description of a DoS vulnerability resulting from a strict equality check, and Slither's dangerous-strict-equality detector | +| 2019/05/27 | slither | [Slither: The Leading Static Analyzer for Smart Contracts](https://blog.trailofbits.com/2019/05/27/slither-the-leading-static-analyzer-for-smart-contracts/) | Slither design and comparison with other static analysis tools | +| 2018/10/19 | slither | [Slither – a Solidity static analysis framework](https://blog.trailofbits.com/2018/10/19/slither-a-solidity-static-analysis-framework/) | Introduction to Slither's API and printers | +| 2018/09/06 | rattle | [Rattle – an Ethereum EVM binary analysis framework](https://blog.trailofbits.com/2018/09/06/rattle-an-ethereum-evm-binary-analysis-framework/) | Turn EVM bytecode to infinite-register SSA form | +| 2018/05/03 | echidna | [State Machine Testing with Echidna](https://blog.trailofbits.com/2018/05/03/state-machine-testing-with-echidna/) | Example use case of Echidna's Haskell API | +| 2018/03/23 | | [Use our suite of Ethereum security tools](https://blog.trailofbits.com/2018/03/23/use-our-suite-of-ethereum-security-tools/) | Overview of our tools and documents: Not So Smart Contracts, Slither, Echidna, Manticore, EVM Opcode Database, Ethersplay, IDA-EVM, Rattle | +| 2018/03/09 | echidna | [Echidna, a smart fuzzer for Ethereum](https://blog.trailofbits.com/2018/03/09/echidna-a-smart-fuzzer-for-ethereum/) | First release and introduction to Echidna | +| 2017/04/27 | manticore | [Manticore: Symbolic execution for humans](https://blog.trailofbits.com/2017/04/27/manticore-symbolic-execution-for-humans/) | First release and introduction to Manticore (not adopted for EVM yet) | ## Upgradeability Our work related to contracts upgradeability -| Date | Title | Description | -|-----|-----|-----| -| 2020/12/16 | [Breaking Aave Upgradeability](https://blog.trailofbits.com/2020/12/16/breaking-aave-upgradeability/) | Description of Delegatecall Proxy vulnerability in formally-verified Aave contracts | -| 2020/10/30 | [Good idea, bad design: How the Diamond standard falls short](https://blog.trailofbits.com/2020/10/30/good-idea-bad-design-how-the-diamond-standard-falls-short/) | Audit of Diamond standard's implementation | -| 2018/10/29 | [How contract migration works](https://blog.trailofbits.com/2018/10/29/how-contract-migration-works/) | Alternative to upgradability mechanism - moving data to a new contract | -| 2018/09/05 | [Contract upgrade anti-patterns](https://blog.trailofbits.com/2018/09/05/contract-upgrade-anti-patterns/) | Discussion of risks and recommendations for Data Separation and Delegatecall Proxy patterns. Disclosure of vulnerability in Zeppelin Proxy contract. | - +| Date | Title | Description | +| ---------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- | +| 2020/12/16 | [Breaking Aave Upgradeability](https://blog.trailofbits.com/2020/12/16/breaking-aave-upgradeability/) | Description of Delegatecall Proxy vulnerability in formally-verified Aave contracts | +| 2020/10/30 | [Good idea, bad design: How the Diamond standard falls short](https://blog.trailofbits.com/2020/10/30/good-idea-bad-design-how-the-diamond-standard-falls-short/) | Audit of Diamond standard's implementation | +| 2018/10/29 | [How contract migration works](https://blog.trailofbits.com/2018/10/29/how-contract-migration-works/) | Alternative to upgradability mechanism - moving data to a new contract | +| 2018/09/05 | [Contract upgrade anti-patterns](https://blog.trailofbits.com/2018/09/05/contract-upgrade-anti-patterns/) | Discussion of risks and recommendations for Data Separation and Delegatecall Proxy patterns. Disclosure of vulnerability in Zeppelin Proxy contract. | ## Zero-knowledge Our work in Zero-Knowledge Proofs space -| Date | Title | Description | -|-----|-----|-----| -| 2022/04/18 | [The Frozen Heart vulnerability in PlonK](https://blog.trailofbits.com/2022/04/18/the-frozen-heart-vulnerability-in-plonk/) | | -| 2022/04/15 | [The Frozen Heart vulnerability in Bulletproofs](https://blog.trailofbits.com/2022/04/15/the-frozen-heart-vulnerability-in-bulletproofs/) | | -| 2022/04/14 | [The Frozen Heart vulnerability in Girault’s proof of knowledge](https://blog.trailofbits.com/2022/04/14/the-frozen-heart-vulnerability-in-giraults-proof-of-knowledge/) | | -| 2022/04/13 | [Coordinated disclosure of vulnerabilities affecting Girault, Bulletproofs, and PlonK](https://blog.trailofbits.com/2022/04/13/part-1-coordinated-disclosure-of-vulnerabilities-affecting-girault-bulletproofs-and-plonk/) | Introducing new "Frozen Heart" class of vulnerabilities | -| 2021/12/21 | [Disclosing Shamir’s Secret Sharing vulnerabilities and announcing ZKDocs](https://blog.trailofbits.com/2021/12/21/disclosing-shamirs-secret-sharing-vulnerabilities-and-announcing-zkdocs/) | | -| 2021/02/19 | [Serving up zero-knowledge proofs](https://blog.trailofbits.com/2021/02/19/serving-up-zero-knowledge-proofs/) | Fiat-Shamir transformation explained | -| 2020/12/14 | [Reverie: An optimized zero-knowledge proof system](https://blog.trailofbits.com/2020/12/14/reverie-an-optimized-zero-knowledge-proof-system/) | Rust implementation of the MPC-in-the-head proof system | -| 2020/05/21 | [Reinventing Vulnerability Disclosure using Zero-knowledge Proofs](https://blog.trailofbits.com/2020/05/21/reinventing-vulnerability-disclosure-using-zero-knowledge-proofs/) | Announcement of DARPA sponsored work on ZK proofs of exploitability | -| 2019/10/04 | [Multi-Party Computation on Machine Learning](https://blog.trailofbits.com/2019/10/04/multi-party-computation-on-machine-learning/) | Implementation of 3-party computation protocol for perceptron and support vector machine (SVM) algorithms | - +| Date | Title | Description | +| ---------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------- | +| 2022/04/18 | [The Frozen Heart vulnerability in PlonK](https://blog.trailofbits.com/2022/04/18/the-frozen-heart-vulnerability-in-plonk/) | | +| 2022/04/15 | [The Frozen Heart vulnerability in Bulletproofs](https://blog.trailofbits.com/2022/04/15/the-frozen-heart-vulnerability-in-bulletproofs/) | | +| 2022/04/14 | [The Frozen Heart vulnerability in Girault’s proof of knowledge](https://blog.trailofbits.com/2022/04/14/the-frozen-heart-vulnerability-in-giraults-proof-of-knowledge/) | | +| 2022/04/13 | [Coordinated disclosure of vulnerabilities affecting Girault, Bulletproofs, and PlonK](https://blog.trailofbits.com/2022/04/13/part-1-coordinated-disclosure-of-vulnerabilities-affecting-girault-bulletproofs-and-plonk/) | Introducing new "Frozen Heart" class of vulnerabilities | +| 2021/12/21 | [Disclosing Shamir’s Secret Sharing vulnerabilities and announcing ZKDocs](https://blog.trailofbits.com/2021/12/21/disclosing-shamirs-secret-sharing-vulnerabilities-and-announcing-zkdocs/) | | +| 2021/02/19 | [Serving up zero-knowledge proofs](https://blog.trailofbits.com/2021/02/19/serving-up-zero-knowledge-proofs/) | Fiat-Shamir transformation explained | +| 2020/12/14 | [Reverie: An optimized zero-knowledge proof system](https://blog.trailofbits.com/2020/12/14/reverie-an-optimized-zero-knowledge-proof-system/) | Rust implementation of the MPC-in-the-head proof system | +| 2020/05/21 | [Reinventing Vulnerability Disclosure using Zero-knowledge Proofs](https://blog.trailofbits.com/2020/05/21/reinventing-vulnerability-disclosure-using-zero-knowledge-proofs/) | Announcement of DARPA sponsored work on ZK proofs of exploitability | +| 2019/10/04 | [Multi-Party Computation on Machine Learning](https://blog.trailofbits.com/2019/10/04/multi-party-computation-on-machine-learning/) | Implementation of 3-party computation protocol for perceptron and support vector machine (SVM) algorithms |