@@ -839,3 +839,45 @@ func ExamplePrecompileEnvironment() {
839
839
// variable to include it in this example function.
840
840
_ = actualCaller
841
841
}
842
+
843
+ func TestReentrancyGuard (t * testing.T ) {
844
+ sut := common .HexToAddress ("7E57ED" )
845
+ eve := common .HexToAddress ("BAD" )
846
+ eveCalled := false
847
+
848
+ zero := func () * uint256.Int {
849
+ return uint256 .NewInt (0 )
850
+ }
851
+
852
+ returnIfGuarded := []byte ("guarded" )
853
+
854
+ hooks := & hookstest.Stub {
855
+ PrecompileOverrides : map [common.Address ]libevm.PrecompiledContract {
856
+ eve : vm .NewStatefulPrecompile (func (env vm.PrecompileEnvironment , input []byte ) (ret []byte , err error ) {
857
+ eveCalled = true
858
+ return env .Call (sut , []byte {}, env .Gas (), zero ()) // i.e. reenter
859
+ }),
860
+ sut : vm .NewStatefulPrecompile (func (env vm.PrecompileEnvironment , input []byte ) (ret []byte , err error ) {
861
+ // The argument is optional and used only to allow more than one
862
+ // guard in a contract.
863
+ if err := env .ReentrancyGuard (nil ); err != nil {
864
+ return returnIfGuarded , err
865
+ }
866
+ if env .Addresses ().Caller == eve {
867
+ // A real precompile MUST NOT panic under any circumstances.
868
+ // It is done here to avoid a loop should the guard not
869
+ // work.
870
+ panic ("reentrancy" )
871
+ }
872
+ return env .Call (eve , []byte {}, env .Gas (), zero ())
873
+ }),
874
+ },
875
+ }
876
+ hooks .Register (t )
877
+
878
+ _ , evm := ethtest .NewZeroEVM (t )
879
+ got , _ , err := evm .Call (vm.AccountRef {}, sut , []byte {}, 1e6 , zero ())
880
+ require .True (t , eveCalled , "Malicious contract called" )
881
+ assert .Equal (t , err , vm .ErrExecutionReverted , "Precompile reverted" )
882
+ assert .Equal (t , returnIfGuarded , got , "Precompile reverted with expected data" )
883
+ }
0 commit comments