Basic Smart Contract Upgradeability Discussion

Welcome to the discussion thread about this lecture section. Here you can feel free to discuss the topic at hand and ask questions.

1 Like

Corrected: Not sure why, but after submitting different integers into the input and calling the getNumberOfDogs several times, the transaction details finally started showing the correct values. Wouldn’t work the first few times, but works every time now. Didn’t change anything. Just repeated the same process from the video with different numbers until it decided to start working. Weird…

For some reason, after I upgrade the contract, it no longer shows the bool and byte arguments. Nor does it return the number of dogs after I set after upgrading.

I’ve rewatched the videos and reviewed the code on Github, but I see no difference or reason for this. I’ve even tried copying and pasting the Github code to test, and the decoded output still show no values after upgrading. What am I doing wrong?

Below is the code before copying and pasting directly from Github.

Storage Contract:

pragma solidity 0.5.1;

contract Storage {
    uint256 number;
    
    function getNumber() internal view returns (uint){
        return number;
    }
    
    function setNumber(uint256 _number) internal{
        number = _number;
    }
    
}

Functionality Contract:

pragma solidity 0.5.1;

import "./Storage.sol";

contract Dogs is Storage {
    
    function getNumberOfDogs() public view returns(uint256) {
        return Storage.getNumber();
    }
    
    function setNumberOfDogs(uint256 toSet) public {
        Storage.setNumber(toSet);
    }
}

Proxy Contract:

pragma solidity 0.5.1;

import "./Storage.sol";

contract ProxyDog is Storage {
    
    address public currentAddress;
    
    constructor(address _currentAddress) public {
        currentAddress = _currentAddress;
    }
    
    function upgrade(address _currentAddress) public {
        currentAddress = _currentAddress;
    }
    
    function getNumberOfDogs() public returns (bool, bytes memory){
        (bool res, bytes memory data) = currentAddress.delegatecall(abi.encodePacked(bytes4(keccak256("getNumberOfDogs()"))));
        return (res, data);
    }
    
    function setNumberOfDogs(uint256 _number) public returns (bool, bytes memory){
        (bool res, bytes memory data) = currentAddress.delegatecall(abi.encodePacked(bytes4(keccak256("setNumberOfDogs(uint256)")), _number));
        return (res, data);
    }
}

Weird, but it all works now?

Yeah, it all works now. Just a small technical stumble I guess. Onward and upward!

2 Likes

Once I updated the contract it didnt gave me any output… I tryed all again… and had the same issue.

“decoded input” -
“decoded output” -

What function did you call?

both setNumberOfDogs and getNumberOfDogs… its weird… dont worry about. Will see later how it goes everything in the advanced example.

Hey @filip

Why does the “Storage contract” have the get and set functions in it?
Those functions are then repeated in the “Functional contract”.

Why don’t we just store the variable uint number in the “storage”, then write the get and set function in the “functional” only?

Storage.sol

pragma solidity 0.5.12;

contract Storage {
    uint number;
}

Functional.sol

pragma solidity 0.5.12;

import "./Storage.sol";

contract Functional is Storage {
    
    function setNumber (uint _number) public  {
        number = _number;
    }
    
    function getNumber () public view returns (uint) {
        return number;
    }
}
2 Likes

I’m wondering. We didn’t deploy storage contract.
The storage data where are being saved?
The storage data have the address of the proxy contract?

This is explained in the video. The Storage contract just defines the common set of variables and functions used (inherited) by both the Proxy and Dog contracts. The Storage contract doesn’t need to be deployed since it’s never meant to be interacted with directly. In fact, when you say contract Proxy is Storage solidity copies the code for Storage directly into the Proxy contract.

A similar thing happens with delegatecall(). You can think of delegatecall() in the getNumberOfDogs() function as copying the function code of the Dog contract into the Proxy contract. If you do this literally it looks like:

function getNumberOfDogs() public returns (bool, bytes memory) {
        (bool res, bytes memory data) = currentAddress.delegatecall(

function getNumberOfDogs() public view returns (uint256) {
        return Storage.getNumber();
});
        return (res, data);
    }

This makes it clear the code is running on the Proxy contract, therefore the data is also stored on Proxy contract.

2 Likes

When I deployed the updated dog contract I cant see the getNumberOfDogs from the proxy contraxt. Any idea why? I also tried to copy source code, but still couldnt see the output??

status 0x1 Transaction mined and execution succeed
transaction hash 0x279b7dc04ed6f94063b54f231e35a022f8fb01ef515ea83eac97f61c2aac111c
from 0x9a99d34aa3c4afaab4040bac5822a1b686a8a810
to 0x73abd6294c409331046eb196bbf501aedf5bd5d3 0x73abd6294c409331046eb196bbf501aedf5bd5d3
gas 3000000 gas
transaction cost 24956 gas
execution cost 3684 gas
hash 0x279b7dc04ed6f94063b54f231e35a022f8fb01ef515ea83eac97f61c2aac111c
input 0x168…0a5ed
decoded input -
decoded output -
value 0 wei

Same problem here, just get:

decoded input -
decoded output -

@pmk @andersbraath1
It seems that you are using remix and not truffle how did you guys get this output ?
If so how do you create the proxyDog contract using the proxy address in remix ?

var proxyDog = await Dogs.at(proxy.address)

Because you will have to create an others contract using the Dogs contract interface, and the proxy address.

If you follow @filip video and do everything on truffle console it’s working

1 Like

The strange thing is that if I only deployed the upgraded Dog contract without deploying the first Dog contract first, it shows up. Don`t know why. At the time I did not manage to set up truffle correctly, but in smart contract course 201 it is shown. However, will have to go back and try after I finish that course. Thanks anyways!

@gabba @filip sir i am getting error while compiling

my code-

pragma solidity 0.6.8;
import “./storage.sol”;

contract Proxy is Storage {

address currentAddress;

constructor(address _currentAddress) public {
owner = msg.sender;
currentAddress = _currentAddress;
}
function upgrade(address _newAddress) public {
require(msg.sender == owner);
currentAddress = _newAddress;
}

//FALLBACK FUNCTION.
function () payable external {
address implementation = currentAddress;
require(currentAddress != address(0));
bytes memory data = msg.data;

//DELEGATECALL EVERY FUNCTION CALL
assembly {
  let result := delegatecall(gas, implementation, add(data, 0x20), mload(data), 0, 0)
  let size := returndatasize
  let ptr := mload(0x40)
  returndatacopy(ptr, 0, size)
  switch result
  case 0 {revert(ptr, size)}
  default {return(ptr, size)}
}

}
}

error shown-

Hi @Gandharv_dalal

The syntax for the fallback has changed
you are using solidity 0.6.8 the fallback should be declare this way

fallback() external payable {}

This syntax is for 0.5.0

function () payable external {

I ll recommend you to use solidity 0.5.0 if you are following the video because it was made with the version 5

1 Like

ok ok …thanks :slight_smile: @gabba

Composition vs inheritance.
Could this be done by deploying all 3 contracts and not using inheritance at all?
Just having Dog/Dog2 interact with Storage.

Hi @sahowe1

The advantage of using an upgradeable contract is that your users are always interacting with the same address. If you create a smart contract for your dapp and there is no external interaction you can just change your contract address in your frontend.

But if your contract have a bug and other people are using this address you will have no way to tell them to use an other address (dog2). if you change it in the proxy contract it doesn’t change anything for them because they are still interacting with the proxy

1 Like

Hi Gabba, I understand the idea of the proxy being a fixed access point for the user as you described, and pointing to Dog (Dog2 after the fix)

The thing I don’t quite understand is why everything needs to inherit from the storage contract with all of the complications this causes. If Storage was separate it could be called by Dog/Dog2.

Steve.

1 Like