@@ -839,3 +839,45 @@ func ExamplePrecompileEnvironment() {
839839 // variable to include it in this example function.
840840 _ = actualCaller
841841}
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