1

I have a simple test contract:

pragma solidity ^0.4.8;

contract Test {
  uint public myVal;

  function callIt() {
      this.call.gas(50000)(bytes4(sha3("setMyVal(uint256)")), 123);
  }

  function setMyVal(uint _newVal) internal {
      myVal = _newVal;
  }
}

I am testing the contract in remix. It seems that I cannot call the setMyVal from callIt if setMyVal is set to internal - why? I am still calling it from within the same contract. Is the signature in that case different from bytes4(sha3("setMyVal(uint256)"))?

FYI: All works well when removing the internal keyword. But I would like to not allow these functions to be called from the outside. In case it matters: I am looking at using this pattern similar to function pointers, similarly as discussed before.

  • 1
    I happened across this question, and I'm curious what was the benefit of using an external call rather than just calling the function? I see you're limiting the gas... but within the same contract, I can't imagine why. – maurelian Nov 24 '17 at 17:21
2

There are two kinds of function call in Solidity which are very different.

  1. Internal calls happen via a JUMP command and can be used with any function not marked external. These are far cheaper than external calls and mantain things like msg.sender, msg.gas, calldata, etc. Internal calls can only happen within a contract, and can access functions marked internal

  2. External function calls happen either via a transaction from an "externally-owned account" or via the CALL opcode, and rely on the ABI interface to dispatch the call to the correct function. These kinds of call change the sender, calldata, value, etc. They cannot reach internal functions.

If you want to be able to call functions using the CALL method, you should leave the functions public, but create a modifier to disallow calls from other addresses.

pragma solidity ^0.4.8;

contract Test {
  uint public myVal;

  modifier onlySelf(){
      if (msg.sender != address(this)) throw;
      _;
  }

  function callIt() {
      this.call.gas(50000)(bytes4(sha3("setMyVal(uint256)")), 123);
  }

  function setMyVal(uint _newVal) onlySelf {
      myVal = _newVal;
  }
} 
2

If I'm not mistaken, this.call ... makes the call external. Yes, it will coincidentally originate from the same address but it's going to arrive in the form of an external message. Calling a function within the same contract will not create such a message.

I simplified that with

bool s = setMyVal(newVal);

This is a more idiomatic way to call the internal function.

I added a log and some return values to help expose what's going on. You can pass a value into "doIt", so named because it's going to do something.

I see you're trying to pass 50,000 gas. The following way will send it all and then get the remainder back; usually acceptable in an "internal" call situation.

pragma solidity ^0.4.8;

contract Test {
  uint public myVal;

  event LogNewVal(bool success, uint newVal);

  function doIt(uint newVal) returns(bool success) {
      bool s = setMyVal(newVal);
      LogNewVal(s, newVal);
      return true;
  }

  function setMyVal(uint _newVal) internal returns(bool success){
      myVal = _newVal;
      return true;
  }
}

In Remix to show it working.

enter image description here

Hope it helps.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.