| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263 |
- contract CallFlags {
- uint8 roundtrips;
- // See https://github.com/paritytech/substrate/blob/5ea6d95309aaccfa399c5f72e5a14a4b7c6c4ca1/frame/contracts/src/wasm/runtime.rs#L373
- enum CallFlag { FORWARD_INPUT, CLONE_INPUT, TAIL_CALL, ALLOW_REENTRY }
- function bitflags(CallFlag[] _flags) internal pure returns (uint32 flags) {
- for (uint n = 0; n < _flags.length; n++) {
- flags |= (2 ** uint32(_flags[n]));
- }
- }
- // Reentrancy is required for reaching the `foo` function for itself.
- //
- // Cloning and forwarding should have the effect of calling this function again, regardless of what _address was passed.
- // Furthermore:
- // Cloning the input should work together with reentrancy.
- // Forwarding the input should fail due to reading the input more than once in the loop
- // Tail call should work with any combination of input forwarding.
- function echo(
- address _address,
- bytes4 _selector,
- uint32 _x,
- CallFlag[] _flags
- ) public payable returns(uint32 ret) {
- for (uint n = 0; n < 2; n++) {
- if (roundtrips > 1) {
- return _x;
- }
- roundtrips += 1;
- bytes input = abi.encode(_selector, _x);
- (bool ok, bytes raw) = _address.call{flags: bitflags(_flags)}(input);
- require(ok);
- ret = abi.decode(raw, (uint32));
- roundtrips -= 1;
- }
- }
- @selector([0,0,0,0])
- function foo(uint32 x) public pure returns(uint32) {
- return x;
- }
- // Yields different result for tail calls
- function tail_call_it(
- address _address,
- bytes4 _selector,
- uint32 _x,
- CallFlag[] _flags
- ) public returns(uint32 ret) {
- bytes input = abi.encode(_selector, _x);
- (bool ok, bytes raw) = _address.call{flags: bitflags(_flags)}(input);
- require(ok);
- ret = abi.decode(raw, (uint32));
- ret += 1;
- }
- // Does this.call() on this instead of address.call()
- function call_this(uint32 _x) public view returns (uint32) {
- return this.foo{flags: bitflags([CallFlag.ALLOW_REENTRY])}(_x);
- }
- }
|