contract GatekeeperOne {
address public entrant;
modifier gateOne() {
require(msg.sender != tx.origin);
_;
}
modifier gateTwo() {
require(msg.gas % 8191 == 0);
_;
}
modifier gateThree(bytes8 _gateKey) {
require(uint32(_gateKey) == uint16(_gateKey));
require(uint32(_gateKey) != uint64(_gateKey));
require(uint32(_gateKey) == uint16(tx.origin));
_;
}
function enter(bytes8 _gateKey) public gateOne gateTwo gateThree(_gateKey) returns (bool) {
entrant = tx.origin;
return true;
}
}
contract test{
GatekeeperOne public t;
function test()public payable{
t = GatekeeperOne(0x5c3c1540dfcd795b0aca58a496e3c30fe2405b07);
}
function attack()public payable{
t.call.gas(41171)(bytes4(keccak256("good(bytes8)")), 0x123);
}
function attack2()public payable{
t.enter(0x123);
}
function()public payable{}
}
when I execute the attack() it will be sucessful. And attack2() will fail.
the error message:
transact to test.attack2
errored:
VM error: revert. revert The transaction has been reverted to the
initial state. Note: The constructor should be payable if you send
value. Debug the transaction to get more information.
Best Answer
As already said by smarx you are calling two different functions, therefore they behave differently.
About the question in the title:
You can get insight into the difference between
<address>.call
and<address>.<function>
from the documentation of Solidity, in Section 4.4.4 (page 68) and in Section 4.4.5 (pages 70-71), respectively.<address>.call
<address>.function
Conclusion
So the former is low-level in the sense that you have to check the return value manually, while the second let the exception bubble up (is more high-level).