Full Smart Contract Upgradeability Discussion

Sure drop just drop the link here. I will have a look :slight_smile:

Hi @Bhujanga

Here you go, This is the Github Link:
https://github.com/Suveett/CryptoKitties.git
Please download the CryptoKittiesUpgradeable.zip file(which contains the Proxy.sol, Storage.sol, Kittycontract.sol and KittycontractUpdated.sol) and not the CryptoKitties.zip file (This is the normal Project)

I have done the Unit testing in the deployer only (although its not recommended, but Honestly i also couldn’t figure out how to implement a Unit testing on a Kittycontract through a Proxy Interaction without deploying ? )

But now, all the Tests are actually working Fine, thats my biggest relief, Just have a look if you can add some points and make this project Better and more Knowledgeable / Informative for me as well as you, perhaps. Or Kindly enlighten me if I have absolutely followed the wrong approach and maybe I should have followed a Newer better approach

Also, I am not so strong in JS, so somehow (inspite of several trials), my Kitties are not showing on my Marketplace.html page and catalogue.html page ( and the funny part is that the Console is showing No errors also, so maybe its a matter of visibility and not functionality - which i am unable to figure out- So Please help me if you can while you scroll through the Project).

On the Blockchain side (in solidity), everything is working/ compiling well.

One More thing I have not been able to understand yet is that while my Truffle shows only 4 deployments as I had intended - migrations, ArrayUtils, Kittycontract and Proxy), my Ganache shows 5 deployments (including the KittycontractUpdated.sol )
Can you shed some light on this ? :point_down: :thinking:
Screenshot 2021-06-25 at 1.46.07 PM
Screenshot 2021-06-25 at 1.57.57 PM

But since migrate --reset , My Ganache has hibernated and non -responsive .
Maybe this Project is not supposed to be done on ganache :smile: :thinking: ?? I am just curious to learn More.
Please enlighten me

Thanks a ton in advance and Best Regards
Suveett Kalra

P.S. - Also, please leave your number (whatsapp), or your telegram name or discord name. This is the only way i can ask Tarun to get in touch with you
Cheers

I stoped using ganache GUI for the same reason, some times it goes buggy, it close it self, stop responding, so i have tried ganache CLI, which is through a command line, also truffle develop creates an instance of a local blockchain, or hardhat node does the same trick.

Carlos Z

1 Like

Hi @Mariano_Collarte , I don’t see how this resolves your original concern? I like your suggestion of resetting _initialized in upgrade().

In my opinion, calling the initialize function a second time from the proxy (i.e. after another update of the functional contract) would be reverted because the _initialized variable of the proxy has already been set to true after the first contract update and is never reset to false. Thus the statement require(!_initialized); in the initialize function would fail, wouldn’t it?

@dan-i or @thecil, could you please elaborate on that?

I’ve already looked at the link @dan-i shared with @Michal_Kosior on the same question: https://docs.openzeppelin.com/upgrades-plugins/1.x/proxies#the-constructor-caveat
My concern still exists. Am I missing something?

@Ishoboy

Please refer to this blog post which explains how storage collision can occur.

The crux of the potential issues is due to how EVM stores state:

  • Storage layout for state variables begin at position 0 and increments for each new state variable. So the first state variable is stored at position 0, the second state variable is stored at position 1, the third stored at position 2, etc.
  • Each struct or array element uses the next storage position, as if each one was defined separately on its own.

Therefore, I don’t think you’ll see an issue with your example as the second state variable, test, is written to slot 1 and numDogs state variable which exists in both contracts is unaffected at slot 0.

Although I haven’t tested this, I think you may run into trouble if your new Functional Contract defined a new address state variable, testAddress and the Functional Contact’s revised setNumDogs() function called by delegatecall also updated testAddress to, say, the msg.sender.

Since only _currentAddress variable of address type exists in the Proxy and the Proxy scope is used during delegatecall, then the _currentAddress variable declared inside Proxy would be updated to be the msg.sender and the testAddress would remain unaltered.

2 Likes

Hey Jon,
Thank you for your explanation, I really appreciate it,
I’l read it later the blog post you refer. :slight_smile:

1 Like

Hi @Bhujanga

Could you find the time to go through my Contracts ?

Also, did Tarun get in ouch with you ??

Thanks and Regards

Suveett Kalra

Hi @filip Could you please take a look and comment on this issue? The question has come up a few times already but has not been answered clearly yet imo.

Screenshot 2021-07-12 193658

I followed Fillip’s instruction: npm install - g [email protected]

I’m at a complete loss. I will say that I have encountered so many problems with the courses that use the PowerShell, which include this one and the previous version of ETH Smart Contract 201 before the new one replaced it.

1 Like

Hi! I have a problem with the fallback function in the Proxy contract.

Proxy.sol
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.4.0 <0.9.0;

import './Storage.sol';

contract Proxy is Storage{

    address currentAddress;

    constructor(address _curretsAddress){
        currentAddress = _curretsAddress;
    }

    function upgrade(address _newAddress) public{
        currentAddress = _newAddress;
    }

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

        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)}
        }
    }//if someone makes a call to function that doen´t exist.

}

I get this error:
Capturar

Hi @RBeato,
If you try your code along with receive() , maybe it won’t throw an error.
For reference, check out my code -

// SPDX-License-Identifier: MIT
pragma solidity >=0.4.22 <0.9.0;
import './Storage.sol';

contract Proxy is Storage{
  
  address currentAddress;

  constructor(address _address){
     currentAddress = _address;
  }

  function upgrade(address _address) public {
      currentAddress = _address;
  }
  
  receive() payable external{}

  fallback() external{
    address implementation = currentAddress;
    require(currentAddress != address(0),"Contract address is zero");
    bytes memory data = msg.data;
    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)}
    }
  }
}

This is working fine on my machine

2 Likes

hey @RBeato,
I tried your code and got it to work.
If you still wanna run the same code without receive() then try to change the solc version in truffle-config.js. something like below-

compilers: {
    solc: {
      version: "0.8.0", 
2 Likes

I forgot to set the solc version. Thank you!

2 Likes

Regarding the A Better Way to Upgrade video, in solidity 0.8.0, (or after 0.6.0) one should mark the Dogs.sol functions with virtual to be able to override them in
DogsUpdated.sol.

You don’t have to do that, because number of functions remain the same, you still can access the same functions (even though they are a bit changed). You need however to do proxy.upgrade() when you add some new function.

16274267779978586843453586372746

why am I having this why migrating my contracts…

pls i want to post my code everything was done correctly yet i am still not able to migrate it…pls help me review it so i can make the corrections.thanks.

PhaxProxy.sol

//SPDX-License-Identifier: MIT
pragma solidity >0.8.0;
import "./Storage.sol";

contract PhaxProxy is Storage {

address currentAddress;

constructor(address _currentAddress) public {
currentAddress = _currentAddress;
}

function upgrade(address _newAddress) public {
    currentAddress = _newAddress;
}

fallback () payable external {
//redirect to currentaddress
 address implementation = currentAddress;
 require(currentAddress != address(0));
 bytes memory data = msg.data;

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)}
 }

/*assembly {
                calldatacopy(0, 0, calldatasize())
                let result := delegatecall(gas(), implementation, 0, calldatasize(), 0, 0)
                returndatacopy(0, 0, returndatasize())
                switch result
                case 0 { revert(0, returndatasize()) }
                default { return(0, returndatasize()) }
            }*/

}

}


PhaxSwap.sol

//SPDX-License-Identifier: MIT
pragma solidity >0.8.0;
import "./Storage.sol";

contract PhaxSwap is Storage {
    modifier onlyOwner{
        require(msg.sender == owner);
        _;
    }

    constructor(){
    owner = msg.sender;
    }

    function setMeatShop(uint256 toSet) public onlyOwner {
        _uintStorage["Meat"] = toSet;
    }

    
    function getMeatShop() public view returns(uint256) {
        return _uintStorage["Meat"];
    }

}

PhaxSwap2.sol

//SPDX-License-Identifier: MIT
pragma solidity >0.8.0;
import "./Storage.sol";

contract PhaxSwapUpgraded is Storage {
    modifier onlyOwner{
        require(msg.sender == owner);
        _;
    }

    constructor() public {
      initailized(msg.sender);
    }
    
    function initailized(address _owner) public {
          require(!_initialized);
          owner =_owner;
          _initialized = true;
      }

    function setMeatShop(uint256 toSet) public onlyOwner {
        _uintStorage["Meat"] = toSet;
    }

    
    function getMeatShop() public view returns(uint256) {
        return _uintStorage["Meat"];
    }

}

Storage.sol

//SPDX-License-Identifier: MIT

pragma solidity >0.8.0;

contract Storage {
  mapping (string => uint256) _uintStorage;
  mapping (string => address) _addressStorage;
  mapping (string => bool) _boolStorage;
  mapping (string => string) _stringStorage;
  mapping (string => bytes4) _bytesStorage;
  address public owner;
  bool public _initialized;
}
  

migration file

const PhaxSwap = artifacts.require("PhaxSwap");
const PhaxSwapUpgraded = artifacts.require(" PhaxSwapUpgraded");
const PhaxProxy = artifacts.require("PhaxProxy");


module.exports = async function (deployer, network, accounts) {
   const swap = await PhaxSwap.new();
   const phax = await PhaxProxy.new(swap.address);
    
   //create proxy meatt to fool truffle
   var proxyMeat = await PhaxSwap.at(phax.address);
   
   //set the number of meat through the proxy
   await proxyMeat.setMeatShop(10);

   //tested
     var nrofMeatShop = await proxyMeat.getMeatShop();
     console.log("Before Ugrade :" + nrofMeatShop.toNumber());

     //new version of contract to deploy
     const swap2 =await  PhaxSwapUpgraded.new();
     
     proxy.upgrade(PhaxSwapUpgraded.address);

     proxyMeat = await PhaxSwapUpgraded.at(phax.address);
     proxyMeat.initialized(accounts[0]);

      nrofMeatShop = await proxyMeat.getMeatShop();
      console.log( "After upgrade :" + nrofMeatShop.toNumber());

       //set the number of meat through the proxy
       await proxyMeat.setMeatShop(30);


}

errors while migrating:

_PhaxFiles_migration.js
========================

C:\Users\HP\AppData\Roaming\npm\node_modules\truffle\build\459.bundled.js:26375
        throw new Error("Could not find artifacts for " + import_path + " from any sources");
        ^

Error: Could not find artifacts for  PhaxSwapUpgraded from any sources
    at Resolver.require (C:\Users\HP\AppData\Roaming\npm\node_modules\truffle\build\webpack:\packages\resolver\dist\lib\resolver.js:61:1)
    at Object.require (C:\Users\HP\AppData\Roaming\npm\node_modules\truffle\build\webpack:\packages\migrate\index.js:172:1)
    at ResolverIntercept.require (C:\Users\HP\AppData\Roaming\npm\node_modules\truffle\build\webpack:\packages\migrate\ResolverIntercept.js:22:1)
    at C:\Users\HP\Desktop\upgradable\migrations\2_PhaxFiles_migration.js:2:36
    at Script.runInContext (vm.js:144:12)
    at Script.runInNewContext (vm.js:149:17)
    at Object.file (C:\Users\HP\AppData\Roaming\npm\node_modules\truffle\build\webpack:\packages\require\require.js:94:1)
    at Migration._load (C:\Users\HP\AppData\Roaming\npm\node_modules\truffle\build\webpack:\packages\migrate\Migration.js:49:1)
    at processTicksAndRejections (internal/process/task_queues.js:95:5)
    at Migration.run (C:\Users\HP\AppData\Roaming\npm\node_modules\truffle\build\webpack:\packages\migrate\Migration.js:218:1)
    at Object.runMigrations (C:\Users\HP\AppData\Roaming\npm\node_modules\truffle\build\webpack:\packages\migrate\index.js:150:1)
    at Object.runFrom (C:\Users\HP\AppData\Roaming\npm\node_modules\truffle\build\webpack:\packages\migrate\index.js:110:1)
    at runMigrations (C:\Users\HP\AppData\Roaming\npm\node_modules\truffle\build\webpack:\packages\core\lib\commands\migrate.js:258:1)
    at Object.run (C:\Users\HP\AppData\Roaming\npm\node_modules\truffle\build\webpack:\packages\core\lib\commands\migrate.js:223:1)
- Fetching solc version list from solc-bin. Attempt #1
- Fetching solc version list from solc-bin. Attempt #1
- Blocks: 0            Seconds: 0
- Saving migration to chain.

pls help me check properly and teach me what i am not doing right

Guys just FYI
with latest solidity we don’t use function keyword
instead of using

function() payable external {}

Use

fallback() payable external {}

See release of 0.6.0 https://solidity.readthedocs.io/en/v0.7.4/060-breaking-changes.html#semantic-and-syntactic-changes

1 Like

Had to give it another read myself, you beat me to the post! Happy Hacking.

2 Likes

Ok tying to compile in pragma solidity 0.8.6; using a fallback() keyword but getting an error where doing same code in pragma solidity 0.5.2; using funciton() keyword it compiles correctly. Here’s my code and error, was trying to google it but cant find answers:

pragma solidity 0.8.6;

import "./Storage.sol";

contract Proxy is Storage {

    address currentAddress;

    constructor(address _currentAddress) public {
        currentAddress = _currentAddress;
    }

    function upgrade(address _newAddress) public {
        currentAddress = _newAddress;
    }

    fallback() payable external {
        address implementation = currentAddress;
        require(currentAddress != address(0));
        bytes memory data = msg.data;

        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)}
        }
    }


}

C:\Users\kamil\Documents\Ethereum-201\Proxy>truffle compile

Compiling your contracts...
===========================
> Compiling .\contracts\Dogs.sol
> Compiling .\contracts\Proxy.sol
> Compiling .\contracts\Storage.sol
> Compiling .\contracts\Storage.sol

> Compilation warnings encountered:

    Warning: SPDX license identifier not provided in source file. Before publishing, consider adding a comment 
containing "SPDX-License-Identifier: <SPDX-License>" to each source file. Use "SPDX-License-Identifier: UNLICENSED" for non-open-source code. Please see https://spdx.org for more information.
--> /C/Users/kamil/Documents/Ethereum-201/Proxy/contracts/Dogs.sol

,Warning: SPDX license identifier not provided in source file. Before publishing, consider adding a comment containing "SPDX-License-Identifier: <SPDX-License>" to each source file. Use "SPDX-License-Identifier: UNLICENSED" for non-open-source code. Please see https://spdx.org for more information.
--> /C/Users/kamil/Documents/Ethereum-201/Proxy/contracts/Storage.sol


ParserError: Builtin function "gas" must be called.
  --> /C/Users/kamil/Documents/Ethereum-201/Proxy/contracts/Proxy.sol:23:40:
   |
23 |             let result := delegatecall(gas, implementation, add(data, 0x20), mload(data), 0, 0)
   |                                        ^^^

Compilation failed. See above.
Truffle v5.3.7 (core: 5.3.7)
Node v16.2.0

C:\Users\kamil\Documents\Ethereum-201\Proxy>

seem to be more changes in newer version. Should will be aware of that?

many thanks
Kamil

1 Like