Skip to content

Commit d044775

Browse files
anvacaruehildenb
andauthored
Implement prank cheat code (#1446)
* add prank cheatcode * remove #checkSinglePrank * add docs * check depth * expected depth should be equal to prank depth plus one * Update include/kframework/foundry.md Co-authored-by: Everett Hildenbrandt <[email protected]> * update foundry.k.check * initialize singleCaller cell to false Co-authored-by: Everett Hildenbrandt <[email protected]>
1 parent 14b3c93 commit d044775

File tree

4 files changed

+57
-9
lines changed

4 files changed

+57
-9
lines changed

include/kframework/foundry.md

Lines changed: 39 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -581,6 +581,21 @@ Finally, the original sender of the transaction, `ACCTFROM` is changed to the ne
581581
[priority(40)]
582582
```
583583

584+
We define a new rule for the `#halt ~> #return _ _` production that will trigger the `#endPrank` rules if the prank was set only for a single call and if the current call depth is equal to the depth at which `prank` was invoked plus one.
585+
586+
587+
```{.k .bytes}
588+
rule <k> (. => #endPrank) ~> #halt ~> #return _RETSTART _RETWIDTH ... </k>
589+
<callDepth> CD </callDepth>
590+
<prank>
591+
<singleCall> true </singleCall>
592+
<depth> PD </depth>
593+
...
594+
</prank>
595+
requires CD ==Int PD +Int 1
596+
[priority(40)]
597+
```
598+
584599
#### `startPrank` - Sets `msg.sender` and `tx.origin` for all subsequent calls until `stopPrank` is called.
585600

586601
```
@@ -594,14 +609,31 @@ The `#loadAccount` production is used to load accounts into the state if they ar
594609

595610
```{.k .bytes}
596611
rule [foundry.call.startPrank]:
597-
<k> #call_foundry SELECTOR ARGS => #loadAccount #asWord(ARGS) ~> #setPrank #asWord(ARGS) .Account ... </k>
612+
<k> #call_foundry SELECTOR ARGS => #loadAccount #asWord(ARGS) ~> #setPrank #asWord(ARGS) .Account false ... </k>
598613
requires SELECTOR ==Int selector ( "startPrank(address)" )
599614
600615
rule [foundry.call.startPrankWithOrigin]:
601-
<k> #call_foundry SELECTOR ARGS => #loadAccount #asWord(#range(ARGS, 0, 32)) ~> #loadAccount #asWord(#range(ARGS, 32, 32)) ~> #setPrank #asWord(#range(ARGS, 0, 32)) #asWord(#range(ARGS, 32, 32)) ... </k>
616+
<k> #call_foundry SELECTOR ARGS => #loadAccount #asWord(#range(ARGS, 0, 32)) ~> #loadAccount #asWord(#range(ARGS, 32, 32)) ~> #setPrank #asWord(#range(ARGS, 0, 32)) #asWord(#range(ARGS, 32, 32)) false ... </k>
602617
requires SELECTOR ==Int selector ( "startPrank(address,address)" )
603618
```
604619

620+
#### `prank` - Impersonate `msg.sender` and `tx.origin` for only for the next call.
621+
622+
```
623+
function prank(address) external;
624+
function prank(address sender, address origin) external;
625+
```
626+
627+
```{.k .bytes}
628+
rule [foundry.call.prank]:
629+
<k> #call_foundry SELECTOR ARGS => #loadAccount #asWord(ARGS) ~> #setPrank #asWord(ARGS) .Account true ... </k>
630+
requires SELECTOR ==Int selector ( "prank(address)" )
631+
632+
rule [foundry.call.prankWithOrigin]:
633+
<k> #call_foundry SELECTOR ARGS => #loadAccount #asWord(#range(ARGS, 0, 32)) ~> #loadAccount #asWord(#range(ARGS, 32, 32)) ~> #setPrank #asWord(#range(ARGS, 0, 32)) #asWord(#range(ARGS, 32, 32)) true ... </k>
634+
requires SELECTOR ==Int selector ( "prank(address,address)" )
635+
```
636+
605637
#### `stopPrank` - Stops impersonating `msg.sender` and `tx.origin`.
606638

607639
```
@@ -736,12 +768,12 @@ Utils
736768
</expected>
737769
```
738770

739-
- `#setPrank NEWCALLER NEWORIGIN` will set the `<prank/>` subconfiguration for the given accounts.
771+
- `#setPrank NEWCALLER NEWORIGIN SINGLEPRANK` will set the `<prank/>` subconfiguration for the given accounts.
740772

741773
```k
742-
syntax KItem ::= "#setPrank" Int Account [klabel(foundry_setPrank)]
743-
// -------------------------------------------------------------------
744-
rule <k> #setPrank NEWCALLER NEWORIGIN => . ... </k>
774+
syntax KItem ::= "#setPrank" Int Account Bool [klabel(foundry_setPrank)]
775+
// ------------------------------------------------------------------------
776+
rule <k> #setPrank NEWCALLER NEWORIGIN SINGLEPRANK => . ... </k>
745777
<callDepth> CD </callDepth>
746778
<caller> CL </caller>
747779
<origin> OG </origin>
@@ -752,7 +784,7 @@ Utils
752784
<newOrigin> _ => NEWORIGIN </newOrigin>
753785
<active> false => true </active>
754786
<depth> _ => CD </depth>
755-
<singleCall> _ => false </singleCall>
787+
<singleCall> _ => SINGLEPRANK </singleCall>
756788
</prank>
757789
```
758790

kevm-pyk/src/kevm_pyk/solc_to_k.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -414,6 +414,7 @@ def _init_term(
414414
KVariable('ACCOUNTS_INIT'),
415415
]
416416
),
417+
'SINGLECALL_CELL': FALSE,
417418
'EXPECTEDREVERT_CELL': FALSE,
418419
}
419420

tests/foundry/foundry.k.check.expected

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2433,6 +2433,8 @@ module PLAINPRANKTEST-BIN-RUNTIME
24332433

24342434
syntax PlainPrankTestMethod ::= "testFail_startPrank_existingAlready" "(" ")" [symbol(), klabel(method_PlainPrankTest_testFail_startPrank_existingAlready)]
24352435

2436+
syntax PlainPrankTestMethod ::= "test_prank_zeroAddress_true" "(" ")" [symbol(), klabel(method_PlainPrankTest_test_prank_zeroAddress_true)]
2437+
24362438
syntax PlainPrankTestMethod ::= "test_startPrankWithOrigin_true" "(" ")" [symbol(), klabel(method_PlainPrankTest_test_startPrankWithOrigin_true)]
24372439

24382440
syntax PlainPrankTestMethod ::= "test_startPrank_true" "(" ")" [symbol(), klabel(method_PlainPrankTest_test_startPrank_true)]
@@ -2455,6 +2457,9 @@ module PLAINPRANKTEST-BIN-RUNTIME
24552457
rule ( PlainPrankTest . testFail_startPrank_existingAlready ( ) => #abiCallData ( "testFail_startPrank_existingAlready" , .TypedArgs ) )
24562458

24572459

2460+
rule ( PlainPrankTest . test_prank_zeroAddress_true ( ) => #abiCallData ( "test_prank_zeroAddress_true" , .TypedArgs ) )
2461+
2462+
24582463
rule ( PlainPrankTest . test_startPrankWithOrigin_true ( ) => #abiCallData ( "test_startPrankWithOrigin_true" , .TypedArgs ) )
24592464

24602465

@@ -2482,6 +2487,9 @@ module PLAINPRANKTEST-BIN-RUNTIME
24822487
rule ( selector ( "testFail_startPrank_existingAlready" ) => 2262269573 )
24832488

24842489

2490+
rule ( selector ( "test_prank_zeroAddress_true" ) => 3793950116 )
2491+
2492+
24852493
rule ( selector ( "test_startPrankWithOrigin_true" ) => 1559633499 )
24862494

24872495

tests/foundry/test/PlainPrankTest.t.sol

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@ contract AdditionalToken {
1313
}
1414

1515
function incrementCount() public {
16-
require(msg.sender != owner);
17-
count = count + 1;
16+
if(msg.sender != owner)
17+
count = count + 1;
1818
}
1919
}
2020

@@ -56,4 +56,11 @@ contract PlainPrankTest is Test {
5656
vm.stopPrank();
5757
}
5858

59+
function test_prank_zeroAddress_true() public {
60+
AdditionalToken token = new AdditionalToken();
61+
vm.prank(address(0));
62+
token.incrementCount();
63+
token.incrementCount();
64+
assert(token.count() == 1);
65+
}
5966
}

0 commit comments

Comments
 (0)