Skip to content

Commit 38f8193

Browse files
0xgregthedevfredo
andauthored
Feat/test cases (#23)
* feat: add int test cases * fix: example trigger * fix: triggers * fix: triggers * fix * fix * fix: target address * fix: target address * fix: target address checksum * feat: add test cases * feat: add test cases * fix: build issues * feat: update storage change * feat: debug fork pre state * fix: debug fork pre state * feat: highlight behavior of bug in testforking * fix: naming * chore: wip StateChanges * chore: wip StateChanges * feat: update new target address * fix: test cases * chore: debug Wip * feat: update Forking to new abstraction * fix: contract name * fix: deployment addresses * fix: final forking fixes * fix: forking * feat: update tests to be simplified * fix: fix fork test * fix: contract names for triggers * feat: add test cases * fix: call inputs * chore: fmt * chore: rename fns for int tests * fix: issue with logs * fix: forking and logs * chore: remove unused imports (#24) --------- Co-authored-by: formerly luehrsFred <luehrs.fred@gmail.com>
1 parent 7216071 commit 38f8193

File tree

14 files changed

+504
-0
lines changed

14 files changed

+504
-0
lines changed

src/test-cases/common/Target.sol

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
// SPDX-License-Identifier: MIT
2+
pragma solidity ^0.8.28;
3+
4+
Target constant TARGET = Target(payable(0xdCCf1eEB153eF28fdc3CF97d33f60576cF092e9c));
5+
6+
contract Target {
7+
event Log(uint256 value);
8+
9+
uint256 value = 1;
10+
11+
function readStorage() external view returns (uint256) {
12+
return value;
13+
}
14+
15+
function writeStorage(uint256 value_) public {
16+
value = value_;
17+
emit Log(value);
18+
}
19+
20+
function incrementStorage() public {
21+
uint256 _value = value + 1;
22+
writeStorage(_value);
23+
}
24+
25+
function writeStorageAndRevert(uint256 value_) external {
26+
writeStorage(value_);
27+
revert("revert from Target");
28+
}
29+
30+
receive() external payable {}
31+
32+
fallback() external {}
33+
}
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
// SPDX-License-Identifier: UNLICENSED
2+
pragma solidity ^0.8.13;
3+
4+
import {Assertion} from "../../Assertion.sol";
5+
import {PhEvm} from "../../PhEvm.sol";
6+
import {Target, TARGET} from "../common/Target.sol";
7+
8+
contract TestCallInputs is Assertion {
9+
constructor() payable {}
10+
11+
function getCallInputs() external view {
12+
PhEvm.CallInputs[] memory callInputs = ph.getCallInputs(address(TARGET), Target.readStorage.selector);
13+
require(callInputs.length == 1, "callInputs.length != 1");
14+
PhEvm.CallInputs memory callInput = callInputs[0];
15+
16+
require(callInput.target_address == address(TARGET), "callInput.target_address != target");
17+
require(callInput.input.length == 0, "callInput.input.length != 0");
18+
require(callInput.value == 0, "callInput.value != 0");
19+
20+
callInputs = ph.getCallInputs(address(TARGET), Target.writeStorage.selector);
21+
require(callInputs.length == 2, "callInputs.length != 2");
22+
23+
callInput = callInputs[0];
24+
require(callInput.target_address == address(TARGET), "callInput.target_address != target");
25+
require(callInput.input.length == 32, "callInput.input.length != 32");
26+
uint256 param = abi.decode(callInput.input, (uint256));
27+
require(param == 1, "First writeStorage param should be 1");
28+
require(callInput.value == 0, "callInput.value != 0");
29+
30+
callInput = callInputs[1];
31+
require(callInput.target_address == address(TARGET), "callInput.target_address != target");
32+
require(callInput.input.length == 32, "callInput.input.length != 32");
33+
param = abi.decode(callInput.input, (uint256));
34+
require(param == 2, "Second writeStorage param should be 2");
35+
require(callInput.value == 0, "callInput.value != 0");
36+
}
37+
38+
function callInputsWrongTarget() external view {
39+
PhEvm.CallInputs[] memory callInputs =
40+
ph.getCallInputs(address(0x000000000000000000000000000000000000dEaD), Target.readStorage.selector);
41+
require(callInputs.length == 1, "Wrong target: callInputs.length != 1");
42+
}
43+
44+
function callNoSelector() external view {
45+
PhEvm.CallInputs[] memory callInputs = ph.getCallInputs(address(TARGET), bytes4(0));
46+
require(callInputs.length == 1, "No selector: callInputs.length != 1");
47+
}
48+
49+
function triggers() external view override {
50+
registerCallTrigger(this.getCallInputs.selector);
51+
registerCallTrigger(this.callInputsWrongTarget.selector);
52+
registerCallTrigger(this.callNoSelector.selector);
53+
}
54+
}
55+
56+
contract TriggeringTx {
57+
constructor() payable {
58+
TARGET.writeStorage(1);
59+
TARGET.writeStorage(2);
60+
TARGET.readStorage();
61+
62+
address fallbackTarget = address(0x000000000000000000000000000000000000dEaD);
63+
(bool success,) = fallbackTarget.call(abi.encodeWithSelector(TARGET.readStorage.selector));
64+
require(success, "call failed");
65+
66+
(success,) = address(TARGET).call("");
67+
require(success, "call failed");
68+
}
69+
}
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
// SPDX-License-Identifier: UNLICENSED
2+
pragma solidity ^0.8.28;
3+
4+
import {Assertion} from "../../Assertion.sol";
5+
6+
import {Target, TARGET} from "../common/Target.sol";
7+
8+
contract TestForking is Assertion {
9+
uint256 public sum = 0;
10+
uint256 public someInitValue = 1;
11+
12+
function forkSwitchStorage() external {
13+
//Test fork switching reads from underlying state
14+
require(TARGET.readStorage() == 2, "postStateValue != 2 (no switch)");
15+
ph.forkPreState();
16+
uint256 preStateValue = TARGET.readStorage();
17+
require(preStateValue == 1, "preStateValue != 1");
18+
19+
ph.forkPostState();
20+
//Test fork switching reads from underlying state
21+
require(TARGET.readStorage() == 2, "postStateValue != 2 (switch)");
22+
}
23+
24+
function forkSwitchNewDeployedContract() external {
25+
address newTarget = address(0x40f7EBE92dD6bdbEECADFFF3F9d7A1B33Cf8d7c0);
26+
27+
require(newTarget.code.length != 0, "post state newTarget.code.length should not be 0");
28+
29+
ph.forkPreState();
30+
require(newTarget.code.length == 0, "pre state newTarget.code.length should be 0");
31+
32+
ph.forkPostState();
33+
require(newTarget.code.length != 0, "post state newTarget.code.length should not be 0");
34+
}
35+
36+
function forkSwitchBalance() external {
37+
require(address(TARGET).balance == 1000, "balance != 1000");
38+
ph.forkPreState();
39+
require(address(TARGET).balance == 0, "balance != 0");
40+
ph.forkPostState();
41+
require(address(TARGET).balance == 1000, "balance != 1000");
42+
}
43+
44+
function persistTargetContracts() external {
45+
require(someInitValue == 1, "someInitValue != 1");
46+
require(sum == 0, "expectedSum != 0");
47+
48+
require(TARGET.readStorage() == 2, "postStateValue != 2 (no switch)");
49+
sum += TARGET.readStorage();
50+
51+
ph.forkPreState();
52+
require(TARGET.readStorage() == 1, "preStateValue != 1");
53+
54+
sum += TARGET.readStorage();
55+
56+
ph.forkPostState();
57+
require(TARGET.readStorage() == 2, "postStateValue != 2 (switch)");
58+
sum += TARGET.readStorage();
59+
60+
ph.forkPreState();
61+
require(TARGET.readStorage() == 1, "preStateValue != 1");
62+
sum += TARGET.readStorage();
63+
64+
require(sum == 6, "sum != 6");
65+
}
66+
67+
function triggers() external view override {
68+
registerCallTrigger(this.forkSwitchStorage.selector);
69+
registerCallTrigger(this.forkSwitchNewDeployedContract.selector);
70+
registerCallTrigger(this.persistTargetContracts.selector);
71+
registerCallTrigger(this.forkSwitchBalance.selector);
72+
}
73+
}
74+
75+
contract TriggeringTx {
76+
constructor() payable {
77+
TARGET.incrementStorage();
78+
// Deploy new target @ 0x40f7EBE92dD6bdbEECADFFF3F9d7A1B33Cf8d7c0
79+
new Target();
80+
81+
(bool success,) = address(TARGET).call{value: 1000}("");
82+
require(success, "call failed");
83+
}
84+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
// SPDX-License-Identifier: UNLICENSED
2+
pragma solidity ^0.8.28;
3+
4+
import {Assertion} from "../../Assertion.sol";
5+
6+
import {Target, TARGET} from "../common/Target.sol";
7+
8+
contract TestGetAdopter is Assertion {
9+
constructor() payable {}
10+
11+
function getAdopter() external view {
12+
address adopter = ph.getAssertionAdopter();
13+
require(adopter == address(TARGET), "adopter != target");
14+
}
15+
16+
function triggers() external view override {
17+
registerCallTrigger(this.getAdopter.selector);
18+
}
19+
}
20+
21+
contract TriggeringTx {
22+
constructor() payable {
23+
TARGET.writeStorage(1);
24+
}
25+
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
// SPDX-License-Identifier: UNLICENSED
2+
pragma solidity ^0.8.13;
3+
4+
import {Assertion} from "../../Assertion.sol";
5+
6+
import {Target, TARGET} from "../common/Target.sol";
7+
8+
contract TestLoad is Assertion {
9+
constructor() payable {}
10+
11+
function _loadCount() internal view returns (uint256) {
12+
return uint256(ph.load(address(TARGET), 0));
13+
}
14+
15+
function load() external {
16+
require(_loadCount() == 2, "postStateCount != 2 (no switch)");
17+
require(TARGET.readStorage() == _loadCount(), "readStorage != postStateCount (no switch)");
18+
19+
ph.forkPreState();
20+
require(_loadCount() == 1, "preStateCount != 1");
21+
require(TARGET.readStorage() == _loadCount(), "readStorage != preStateCount");
22+
23+
ph.forkPostState();
24+
require(_loadCount() == 2, "postStateCount != 2 (switch)");
25+
require(TARGET.readStorage() == _loadCount(), "readStorage != postStateCount (switch)");
26+
}
27+
28+
function triggers() external view override {
29+
registerCallTrigger(this.load.selector);
30+
}
31+
}
32+
33+
contract TriggeringTx {
34+
constructor() payable {
35+
TARGET.incrementStorage();
36+
}
37+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
// SPDX-License-Identifier: UNLICENSED
2+
pragma solidity ^0.8.28;
3+
4+
import {Assertion} from "../../Assertion.sol";
5+
import {PhEvm} from "../../PhEvm.sol";
6+
import {Target, TARGET} from "../common/Target.sol";
7+
8+
contract TestLogs is Assertion {
9+
constructor() payable {}
10+
11+
function getLogs() external {
12+
require(TARGET.readStorage() == 1, "val != 1");
13+
PhEvm.Log[] memory logs = ph.getLogs();
14+
require(logs.length == 1, "logs.length != 2");
15+
16+
PhEvm.Log memory log = logs[0];
17+
require(log.emitter == address(TARGET), "log.address != target");
18+
require(log.topics.length == 1, "log.topics.length != 1");
19+
require(log.topics[0] == Target.Log.selector, "log.topics[0] != Target.Log.selector");
20+
require(log.data.length == 32, "log.data.length != 32");
21+
require(bytes32(log.data) == bytes32(uint256(1)), "log.data != 1");
22+
}
23+
24+
function triggers() external view override {
25+
registerCallTrigger(this.getLogs.selector);
26+
}
27+
}
28+
29+
contract TriggeringTx {
30+
constructor() payable {
31+
TARGET.writeStorage(1);
32+
}
33+
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
// SPDX-License-Identifier: UNLICENSED
2+
pragma solidity ^0.8.28;
3+
4+
import {Assertion} from "../../Assertion.sol";
5+
import {console} from "forge-std/console.sol";
6+
import {Target, TARGET} from "../common/Target.sol";
7+
8+
contract TestStateChanges1 is Assertion {
9+
constructor() payable {}
10+
11+
function getStateChanges1() external view {
12+
bytes32[] memory changes = ph.getStateChanges(address(TARGET), bytes32(0));
13+
14+
require(changes.length == 2, "changes.length != 2");
15+
16+
require(uint256(changes[0]) == 1, "changes[0] != 1");
17+
require(uint256(changes[1]) == 5, "changes[1] != 5");
18+
}
19+
20+
function triggers() external view override {
21+
registerCallTrigger(this.getStateChanges1.selector);
22+
}
23+
}
24+
25+
contract TriggeringTx {
26+
constructor() payable {
27+
TARGET.writeStorage(5);
28+
29+
// Test that state changes before reverts are not included.
30+
try TARGET.writeStorageAndRevert(10) {
31+
revert("Expected revert");
32+
} catch Error(string memory) {
33+
console.log("Caught revert as expected");
34+
}
35+
}
36+
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
// SPDX-License-Identifier: UNLICENSED
2+
pragma solidity ^0.8.28;
3+
4+
import {Assertion} from "../../Assertion.sol";
5+
import {console} from "forge-std/console.sol";
6+
import {Target, TARGET} from "../common/Target.sol";
7+
8+
contract TestStateChanges2 is Assertion {
9+
constructor() payable {}
10+
11+
function getStateChanges2() external view {
12+
bytes32[] memory changes = ph.getStateChanges(address(TARGET), bytes32(0));
13+
14+
require(changes.length == 3, "changes.length != 3");
15+
16+
require(uint256(changes[0]) == 1, "changes[0] != 1");
17+
require(uint256(changes[1]) == 5, "changes[1] != 5");
18+
require(uint256(changes[2]) == 15, "changes[2] != 15");
19+
}
20+
21+
function triggers() external view override {
22+
registerCallTrigger(this.getStateChanges2.selector);
23+
}
24+
}
25+
26+
contract TriggeringTx {
27+
constructor() payable {
28+
TARGET.writeStorage(5);
29+
30+
// Test that state changes before reverts are not included.
31+
try TARGET.writeStorageAndRevert(10) {
32+
revert("Expected revert");
33+
} catch Error(string memory) {
34+
console.log("Caught revert as expected");
35+
}
36+
37+
TARGET.writeStorage(15);
38+
}
39+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
// SPDX-License-Identifier: UNLICENSED
2+
pragma solidity ^0.8.28;
3+
4+
import {Assertion} from "../../Assertion.sol";
5+
import {console} from "forge-std/console.sol";
6+
import {Target, TARGET} from "../common/Target.sol";
7+
8+
contract TestStateChangesNone is Assertion {
9+
constructor() payable {}
10+
11+
function getStateChangesNone() external view {
12+
bytes32[] memory changes = ph.getStateChanges(address(TARGET), bytes32(0));
13+
require(changes.length == 0, "changes.length != 0");
14+
}
15+
16+
function triggers() external view override {
17+
registerCallTrigger(this.getStateChangesNone.selector);
18+
}
19+
}
20+
21+
contract TriggeringTx {
22+
constructor() payable {
23+
// Test that state changes before reverts are not included.
24+
try TARGET.writeStorageAndRevert(10) {
25+
revert("Expected revert");
26+
} catch Error(string memory) {
27+
console.log("Caught revert as expected");
28+
}
29+
30+
(bool success,) = address(TARGET).call("");
31+
require(success, "call failed");
32+
}
33+
}

0 commit comments

Comments
 (0)