Comments (6)
Hey @pcaversaccio, that sounds really great, and yup, didn't expect this to be a fast task.
We can have a general chit chat on discord or twitter about how the fuzzy tests need to be implemented for each smart contract so that we have a plan of action. And then we can get down to working on the PRs!
Also, since you are interested in fuzz testing, I think you might also be interested in fuzz invariant testing. Forge hasn't put the documentation for it in their book yet, but yeah you might want to take a look. If you like it, we can implement that too along with fuzz tests. I think invariants would be helpful because for auth stuff, invariants make a lot of sense.
References:
foundry-rs/book#497
https://github.com/foundry-rs/foundry/tree/master/testdata%2Ffuzz%2Finvariant
https://github.com/maple-labs/revenue-distribution-token/blob/add-forge-invariants/contracts/test/Invariants.t.sol
Do let me know if you like the idea or not. Till then, I will try learning vyper and also I will grok the codebase, so that by the time you end up refactoring, we can start implementing.
from snekmate.
Hi @pcaversaccio, this looks like a solid plan, and I agree that a method to fuzz the initial constructor state needs to be looked into. What if we create a helper function, just for deployment. So suppose
struct deployERC1155Params {
string _BASE_URI;
}
function deployERC1155(deployERC1155Params memory params) public {
bytes memory args = abi.encode(params._BASE_URI);
ERC1155Extended = IERC1155Extended(
vyperDeployer.deployContract("src/tokens/", "ERC1155", args)
);
}
Now suppose when we are writing a fuzz test, let's assume the test you had included, it can be written as
function testGrantRoleSuccess(address account, deployERC1155Params memory init) public {
deployERC1155(init);
address admin = address(vyperDeployer);
vm.startPrank(admin);
vm.expectEmit(true, true, true, false);
emit RoleGranted(ADDITIONAL_ROLE_1, account, admin);
accessControl.grantRole(ADDITIONAL_ROLE_1, account);
assertTrue(accessControl.hasRole(ADDITIONAL_ROLE_1, account));
vm.stopPrank();
}
This will ensure that in each iteration of the fuzz test you would have a fresh contract with fresh contructor args + the struct makes it elegant and also prevents "stack too deep" error (as contracts like ERC20 have a lot of contructor params)
from snekmate.
Hey! I have some experience with fuzzing in foundry (and foundry in general), for sure I can help. Although I don't have experience with vyper, but have coded in python so wouldn't take much time to pick up. Do u think I can help?
from snekmate.
@hrik2001 thanks for your message. Sounds great - to be clear this won't be a fast task since we need to add to all tests the appropriate fuzz tests. I need to refactor something small this week within the tests but thereafter you could start. So wrt the workflow I would suggest the following workflow:
- I create a separate branch
fuzz-tests
against which you can open PRs; - We should go step-by-step, i.e. contract by contract, and should add the fuzz tests at the end of the unit tests for each contract;
- We will need to adjust the CI as well and create a dedicated Foundry profile (i.e.
profile.ci
) withfuzz_runs = 10000
.
Do we have a plan?
from snekmate.
@hrik2001 concerning the invariants test - yes we can and should add them where it makes sense. The main difference to normal property-based testing is that the invariant tests do not assume a certain initial state for the contracts (while this is true for normal fuzz tests or even symbolic execution). Thus we should use it only when we want to test for uncertain initial states.
We should define the fuzz tests at the end of the unit tests for each contract and thereafter the invariants tests as a separate contract. When it comes to the exact unit tests, I would go step-by-step through each unit test and assess whether a fuzz test would make sense. An example:
/// The current unit test
function testGrantRoleSuccess() public {
address admin = address(vyperDeployer);
address account = vm.addr(1);
vm.startPrank(admin);
vm.expectEmit(true, true, true, false);
emit RoleGranted(ADDITIONAL_ROLE_1, account, admin);
accessControl.grantRole(ADDITIONAL_ROLE_1, account);
assertTrue(accessControl.hasRole(ADDITIONAL_ROLE_1, account));
vm.stopPrank();
}
/// How the fuzz test could look like
function testGrantRoleSuccess(address account) public {
address admin = address(vyperDeployer);
vm.startPrank(admin);
vm.expectEmit(true, true, true, false);
emit RoleGranted(ADDITIONAL_ROLE_1, account, admin);
accessControl.grantRole(ADDITIONAL_ROLE_1, account);
assertTrue(accessControl.hasRole(ADDITIONAL_ROLE_1, account));
vm.stopPrank();
}
We should also look into a smart way to fuzz the constructor states - probably we will need a separate test that creates a new contract in itself to test the initial state, like that:
function testInitialSetup(string memory _BASE_URI) public {
bytes memory args = abi.encode(_BASE_URI);
ERC1155Extended = IERC1155Extended(
vyperDeployer.deployContract("src/tokens/", "ERC1155", args)
);
assertTrue(ERC1155Extended.owner() == deployer);
assertTrue(ERC1155Extended.is_minter(deployer));
assertEq(
ERC1155Extended.uri(0),
string.concat(_BASE_URI, Strings.toString(uint256(0)))
);
assertEq(
ERC1155Extended.uri(1),
string.concat(_BASE_URI, Strings.toString(uint256(1)))
);
}
What are your thoughts?
from snekmate.
That makes sense - generally, we should not overcomplicate the implementations tho and try to keep everything KISS. One peculiarity you will observe is that we can't fuzz for the entire type space since Vyper doesn't allow dynamically sized objects but you need to statically allocate memory to it, e.g. in the above case _BASE_URI: immutable(String[80])
where the string would allow for a max amount of 80 characters. So we need to vm.assume
always what is possible otherwise the tests will fail..
I created a branch called feat/fuzz-tests
and a draft PR #61 against we will work. I already committed the CI changes. If you disagree with the params lmk.
from snekmate.
Related Issues (20)
- ♻️ Make Test Suite Compatible With Foundry `v1.0` HOT 2
- 🔁 Upgrade to Solidity Version `0.8.21` HOT 4
- 💥 Implement `deployBlueprint` Function in `VyperDeployer` Utility Function HOT 3
- 🔁 Upgrade to Vyper Version `0.3.10`
- ♻️ Remove `increase_allowance` and `decrease_allowance` from `ERC20` and `ERC4626`
- 🔁 Upgrade to Solidity Version `0.8.22`
- 💥 `ERC-4337` Functionalities
- 💥 Add `P256Verifier` to 🐍 snekmate
- 💥 Vyper-Based Multisig Wallet HOT 5
- 💥 `Governor` Contract
- 💥 `TimelockController` Contract HOT 1
- 👷♂️ Add Slither to CI Pipeline
- 💥 Integrate 🐍 snekmate Contracts with Halmos
- 🔁 Upgrade Solidity Version to `0.8.23`
- 💥 Amend `stateful` (a.k.a. `invariant`) Tests
- 🐛 `VyperDeployer` Fails in Forking Mode HOT 10
- 🔁 Upgrade Solidity Version to `0.8.24`
- 🐛 Unable to Call `distribute_token` in `BatchDistributor` via Etherscan HOT 2
- 💥 Make `owner` Explicit in Constructor
- 🔖 Meta: `0.1.0` Checklist
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from snekmate.