0

I've deployed the following contracts on the rinkeby testnet. They are completely separate with different addresses:

pragma solidity ^0.4.11;

contract Backend {

  address public delegateContract;
  address[] public previousDelegates;


  event DelegateChanged(address oldAddress, address newAddress);

  function Backend() {
    // constructor
  }

  function changeDelegate(address _newDelegate) returns (bool) {
    if (_newDelegate != delegateContract) {
          previousDelegates.push(delegateContract);
          var oldDelegate = delegateContract;
          delegateContract = _newDelegate;
          DelegateChanged(oldDelegate, _newDelegate);
          return true;
      }
      return false;

  }

  function add(uint256 var1, uint256 var2) {
    delegateContract.delegatecall(bytes4(sha3("add(uint256,uint256)")), var1, var2);
  }

}

and

pragma solidity ^0.4.11;

contract Delegate {

  uint public total;

  function Delegate() {
    // constructor
  }

  function add(uint256 var1, uint256 var2) {
    total = var1 + var2;
  }
}

I'm running some commands in the geth console, I successfully am able to set the delegateContract with changeDelegate function. Here are the commands in the console:

backend.changeDelegate(delegate.address, {from:sender})
"0x3a4e83d03b4c7367eb2ed61630c4809470d3ca5bdedbb02741da7701c0e14b29"
> backend.delegateContract.call()
"0x1eb1746e49ffc5fb38c20ce07242db3bae89c9eb"
> backend.add(1,1,{from:sender})
"0x8cbc47f9f8f2382c10a1d93c47eb9de3e2fb8f6c63b62c387096f6250311c58b"
> backend.delegateContract.call()
"0x0000000000000000000000000000000000000002"

When I run the add function, it seems to corrupt the previously set delegateContract address. When I call backend.total.call() no changes are happening.

Any idea why this is occurring?

1

You forgot to declare the total variable in the storage of the Backend contract. That is the reason why you don't see nothing when you perform backend.total.call().

Regarding the add function of your Backend contract: when the add function of the Backend contract is executed, it uses a delegatecall to your Delegate contract. This means that the add function of the Delegate contract will run in the context of your Backend contract. In other words you allow the Delegate contract's add function to change the Backend contract's storage. And here comes the problem. Since you do not have a total storage variable in your Backend contract, your delegate call will update the storage of the Backend contract at some random place or will not modify your storage at all, simply because there is no such field as total in the Backend contract.

This comparison of the different call types is pretty good. You might be interested!

  • This is fascinating. I added total, address public delegateContract; and address[] public previousDelegates; for it to finally work. It updated the total of the Backend contract, not the delegate. If the whole purpose of this set up is to be able to write upgradeable contracts, how am I able to upgrade the delegate if I am constrained by being unable to new variables or methods? – Michael O'Rourke Oct 6 '17 at 10:45
  • 1
    Well, you are only constrained to the function signature. So the general idea is that Backend remains intact all the time, you just deploy newer versions of the Delegate contract and adjust accordingly the address of the Delegate contracts in the Backend contract. The assumption is that the delegated function signatures do not change over time....if it changes then obviously you can not call those functions without deploying a new Backend contract. – István András Seres Oct 6 '17 at 11:48

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.