Welcome to the discussion thread about this lecture section. Here you can feel free to discuss the topic at hand and ask questions.
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!
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;
}
}
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.
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 couldn
t 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
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-
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
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
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.