book icon indicating copy to clipboard operation
book copied to clipboard

Document invariant testing + patterns

Open gakonst opened this issue 2 years ago • 4 comments

https://github.com/foundry-rs/foundry/pull/1572

https://github.com/maple-labs/revenue-distribution-token/tree/e0eca03c2ff05c36000a097de678543d7234f7cc/contracts/test

document simple invariant breaking, the actor model from Maple's RDT, usage of targetContract(s) etc

gakonst avatar Aug 03 '22 17:08 gakonst

Getting this done.

Perelyn-sama avatar Aug 05 '22 22:08 Perelyn-sama

Thoughts on patterns:

Open Invariant Testing

This testing pattern deploys all relevant contracts in the setUp function and exposes all the functions in these contracts to the fuzzer. This pattern must use revert_on_failure = false in the foundry.toml, since this pattern will make calls with unbounded values.

Pros Cons
- Checks all functions
- Unbounded params
- Single actor
- Reversions

Bounded Actor-Based Invariant Testing

This testing pattern deploys all relevant contracts in the setUp function and deploys wrapper contracts to call the functions on the contract. These contracts act as actors in a more realistic simulation of interactions against the desired contracts. These contracts can have relevant permissions and will perform calls with parameters bounded to reasonable values. This pattern must use revert_on_failure = true in the foundry.toml, since this pattern should expose any unexpected reversions over the course of the fuzzing campaign.

User contract reference.

To take it a step further, a contract can be used to dynamically deploy new actors during the fuzzing campaign and perform actions from these actors (example).

Another use case for this pattern is to create a contract that will call the vm.warp cheatcode at random intervals to simulate the passage of time and ensure that invariants are still held (example).

This pattern must add all non-wrapper contracts deployed in the setUp function into the excludeContracts array as to ensure that these contracts are only called through the wrapper contracts.

Pros Cons
- Many actors
- Can simulate passage of time
- Can expose unexpected reversions
- Potential human error in incorrect implementations of wrapper functions

Unbounded Actor-Based Invariant Testing

Similar pattern to above, except with unbounded parameters. This allows for the contract to be called without any artificially bounded parameters, potentially exposing previously unconceived vectors to break invariants. This pattern must use revert_on_failure = false in the foundry.toml, since this pattern will make calls with unbounded values.

Pros Cons
- Many actors
- Can simulate passage of time
- Unbounded parameters
- Reversions

lucas-manuel avatar Aug 08 '22 18:08 lucas-manuel

Hey @lucas-manuel can we get examples of the first and last example too please, thanks

Perelyn-sama avatar Aug 15 '22 07:08 Perelyn-sama

Currently all the invariant examples we have are private, but here is an open source implementation of bounded actor-based invariant testing: https://github.com/maple-labs/revenue-distribution-token/blob/add-forge-invariants/contracts/test/Invariants.t.sol

lucas-manuel avatar Aug 23 '22 13:08 lucas-manuel

When are Invariant tests expected to be released to the public? Looking forward to it. Thanks!

JacoboLansac avatar Oct 09 '22 22:10 JacoboLansac

They are already released!

gakonst avatar Oct 09 '22 23:10 gakonst

They are already released!

What! According to the foundry book they are not yet supported. https://book.getfoundry.sh/forge/advanced-testing

Am I looking at the wrong version of the foundry book? Or, can I have a link to the documentation of invariant tests? Damn I'm excited!

JacoboLansac avatar Oct 10 '22 06:10 JacoboLansac

https://github.com/foundry-rs/foundry/tree/master/testdata%2Ffuzz%2Finvariant

Perelyn-sama avatar Oct 10 '22 11:10 Perelyn-sama

https://github.com/foundry-rs/foundry/tree/master/testdata%2Ffuzz%2Finvariant

And an example project where it is used? Thank you very much!

JacoboLansac avatar Oct 10 '22 14:10 JacoboLansac

Scroll up

Perelyn-sama avatar Oct 10 '22 19:10 Perelyn-sama

There is no official docs for this still?

azflin avatar Jan 18 '23 15:01 azflin

Soon :) For now take a look at https://github.com/lucas-manuel/invariant-example and https://github.com/foundry-rs/book/pull/760

gakonst avatar Jan 19 '23 00:01 gakonst

take a look at https://github.com/lucas-manuel/invariant-example and https://github.com/foundry-rs/book/pull/760

Also maple-core-v2.

PaulRBerg avatar Jan 23 '23 12:01 PaulRBerg

what is the best way of managing blockchain time in invariant tests? So far I did a work around using a storage variable of the handler contract and a modifier that would warp time before each of the target functions, but I was wondering if there was a better way. Thanks

JacoboLansac avatar May 08 '23 20:05 JacoboLansac

What does dictionary_weight mean and how does it affect the fuzzer performance? I can't find any docs related to it.

aviggiano avatar May 09 '23 16:05 aviggiano

Could you guys please open new issues about these questions, for us to document them in the book?

gakonst avatar May 10 '23 07:05 gakonst