I'm Solidity Newbie.
I'm learning how to implement Transparent Proxy using Openzeppelin's TransparentUpgradeableProxy contract, but am having some problems.
Step 1: I tried to deploy a simple contract MyConV0, then implemented deploy and call method, everything is fine.
// File MyConV0.sol
pragma solidity ^0.8.0;
import "hardhat/console.sol";
contract MyConV0 {
string private _name;
string private _symbol;
constructor(string memory name_, string memory symbol_) public {
_name = name_;
_symbol = symbol_;
console.log(_symbol);
}
function symbol() public view returns (string memory) {
console.log(_symbol);
return _symbol;
}
function name() public view returns (string memory) {
console.log('Name: ');
console.log(_name);
return _name;
}
function getVersion() pure external returns(uint256) {
return 0;
}
}
Step 2: I tried to upgrade to MyConV1 to be able to Upgradable with TransparentUpgradeableProxy but failed.
// File: MyConV1
pragma solidity ^0.8.0;
import "#openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
import "#openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol";
import "#openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
import "hardhat/console.sol";
contract MyConV1 is Initializable, OwnableUpgradeable {
string private _name;
string private _symbol;
function initialize(string memory name_, string memory symbol_) initializer public {
__Ownable_init();
_name = name_;
_symbol = symbol_;
console.log(_symbol);
}
function symbol() public view returns (string memory) {
console.log('Symbol: ');
console.log(_symbol);
return _symbol;
}
function name() public view returns (string memory) {
console.log('Name: ');
console.log(_name);
return _name;
}
function getVersion() pure external returns(uint256) {
return 1;
}
}
Refer TransparentUpgradableProxy: https://docs.openzeppelin.com/contracts/4.x/api/proxy#TransparentUpgradeableProxy
// The test file in JS using ethers.js and Hardhat environment
async function main() {
let t0, t1, t2, t3, t4, v1, v2, v3, v4;
const [owner, proxyAdmin, user, other] = await ethers.getSigners();
// --- 0. Deploy MyConV0
let input0 = [ 'TotoName', 'Toto' ];
let con0 = await deploy_verify_contract("MyConV0", input0);
t0 = await con0.symbol() ;
console.log(t0); // worked -> Toto
// --- 1. Deploy MyConV1
let input1 = [ ];
let con1 = await deploy_verify_contract("MyConV1", input1);
// --- 2. get data
let abi = [ `function initialize( string name_,
string symbol_,
)` ];
let iface = new ethers.utils.Interface(abi);
let data = iface.encodeFunctionData("initialize", [ 'TotoName', 'Toto' ]);
// --- 3. deploy trans proxy
let input2 = [ con1.address, owner.address, data ];
let con2 = await deploy_verify_contract("TransparentUpgradeableProxy1", input2);
// --- 4. call proxy method
t2 = await con2.implementation();
console.log(t2); // DO NOT WORK, t2 is object tx, and do not contains the results like step 0
// --- 5. call MyConV1 contact via proxy -> ERROR: "TypeError: con2.symbol is not a function"
t3 = await con2.symbol();
console.log(t3);
}
async function deploy_verify_contract(contractName, input, lib = {}){
const _contract = await hre.ethers.getContractFactory(contractName, lib);
const contract = await _contract.deploy(...input);
await contract.deployed();
console.log( contractName + " deployed to:", contract.address );
return contract;
}
I used Hardhat's console.log function and it seems to have successfully deployed the Proxy, and sent the correct data to the MyConV1.initialize function, but don't know how to call the proxy properly. Specifically with the above code, I don't understand a few points:
Have I deployed the proxy correctly?
Why can't I get the correct return data of the proxy's implementation() function?
Why can't I call MyConV1's function through the proxy?
Hope you guys can help me how to correct the code, I have not been able to solve this problem for a few days.
You are not calling UpgradeTo() on proxy contract to set the implementation contract's address. After you have set the implementation contract in proxy you have to initialise the implementation contract via proxy contract only! not any other way or directly calling it on implementation contract (it wont work!!)
Related
I'm consuming a POST service in .net that returns the next structure, the service return data correctly
enter image description here
public sendExcelInBase64ToBackEnd(data: any) {
this.customOptions = {
headers: this.customHttp.buildHeader(),
};
this.customHttp.Post<SerialResultDTO>('/serialsExcel', data, this.customOptions).subscribe(val => { // <- val data returns ok
this.serialResult = val;
let x = this.serialResult.Success;
console.log(x);
console.log(val.Success); // <- prints undefined
})
return null;
}
When I try print in console 'val.Success' it prints undefined!!, Why this happens??
I want assign all atributes to a custom class in angular, but in chrome debug it shows object data, but in time of asign to my model class it gets undefined!!
Someone can help me please!! I appreciate that!!
Your image shows a lowercase success, but you try to log a titlecase Success. Change to
public sendExcelInBase64ToBackEnd(data: any) {
this.customOptions = {
headers: this.customHttp.buildHeader(),
};
this.customHttp.Post<SerialResultDTO>('/serialsExcel', data, this.customOptions).subscribe(val => {
this.serialResult = val;
let x = this.serialResult.success;
console.log(x);
console.log(val.success);
})
return null;
}
I tried to send a Map to a compute, but computer is never called. The strange point is if I replace Map with int, it works:
void A()
{
var map=Map();
map["p1"]=90;
D("before compute");
var r1 = await compute(p1, 10);
D("after compute(p1) : $r1");
var r2 = await compute(p2, map);
// code never reaches here!
D("after compute(p2) : $r2");
}
static int p2(Map p)
{
return p["p1"]*10;
}
static int p1(int z)
{
return z*10;
}
output is :
after compute(p1) : 100
Flutter compute methods use Isolates and its only transfer (null, num, bool, double, String) types.
https://api.flutter.dev/flutter/dart-isolate/SendPort/send.html
Just define exact type of Map that "p2" receives as parameter:
static int p2(Map<String,int> p)
{
return p["p1"]*10;
}
Try passing a const parameter:
var r2 = await compute(p2, {"p1":90});
I got this error from metamask.
It was working fine couple of hours ago. I have tried reinstalling/ disable and re-enabling again but nothing worked.
Also,
My smart contract is fully functional (Tested in Remix Browser based IDE) and no other errors or logs are present anywhere. I also restarted Ganache and re-compiled and re-migrated my contracts with no luck.
Here is my solidity code:
pragma solidity ^0.4.18;
contract Voting {
address mainAddress;
bytes32[] candidateNames;
mapping(bytes32 => uint) candidateVotes;
mapping(bytes32 => bytes32) candidatesDetails;
function Voting() public {
mainAddress = msg.sender;
}
modifier isMainAddress {
if (msg.sender == mainAddress) {
_;
}
}
function getAllCandidates() public view returns (bytes32[]) {
return candidateNames;
}
function setCandidate(bytes32 newCandidate) isMainAddress public {
candidateNames.push(newCandidate);
}
function setVote(bytes32 candidate) public {
candidateVotes[candidate] = candidateVotes[candidate] + 1;
}
function getVote(bytes32 candidate) public view returns (uint) {
return candidateVotes[candidate];
}
function setDescrption(bytes32 candidateName, bytes32 candidatesDesc) isMainAddress public {
candidatesDetails[candidateName] = candidatesDesc;
}
function getDescription(bytes32 candidateName) public view returns (bytes32){
return candidatesDetails[candidateName];
}
}
And I am calling these functions like :
let votingContractInstance;
const contract = require('truffle-contract')
const votingContract = contract(VotingContract)
votingContract.setProvider(this.state.web3.currentProvider)
this.state.web3.eth.getAccounts((error, accounts) => {
votingContract.deployed().then((instance) => {
votingContractInstance = instance
return votingContractInstance.setVote(this.state.candidateName);
}).then((result) => {
this.setState(() => ({
allCandidates: result
}));
})
})
All of the calls are made by this way only.
I am using one of the truffle boxes (REACT box) and no logs/errors are present in console either.
Did you figure this out? Can you just call this.setState({ allcandidates: result })
Also, the result from setVote isn't anything because you don't have it return anything in the solc contract.
I thought that I got threads in .NET, but when I have added LINQ expression it made me a little confused.
Like I wrote in the topic of this discussion I dont why the thread doesnt return control to the main action of my controller.
I have written what makes me silly in comments, so let me skip to the true example:
public class ValuesController : ApiController
{
public async Task<List<SomeProduct>> Get()
{
var collection = new List<Mother>() {
new Mother()
{
internalField = new List<Child>()
{
new Child()
{
theLastOne = "VAL"
},
new Child()
{
theLastOne = "VAL"
}
}
}
};
var oss =
from m in collection
from s in m.internalField
select Convert(m, s).Result;
//1-The above code doesnt enter into CONVERT function (I have a breakpoint there)
return oss.ToList();//2- this list enter into COnvertt
}
private async Task<SomeProduct> Convert(Mother ms, Child ss)
{
var ossNEW = new SomeProduct();
await update(ossNEW, ms);
return ossNEW;
}
private async Task update(SomeProduct oss, Mother ms)
{//3 - Naturally it comes here
await Task.Run(()=>
{
//This task is executed (It is example code, pls do not care, that threads do not have any sense
oss.copyOfTheLastOne = ms.internalField.First().theLastOne;
oss.valeFromAnUpdateFunction = "works";
}); //Flow comes here and THIS line does not return control to the main action, why? :)
}
}
public class SomeProduct
{
public string copyOfTheLastOne;
public string valeFromAnUpdateFunction;
}
public class Mother
{
public List<Child> internalField;
}
public class Child
{
public string theLastOne;
}
I have solved this example by adding an "executor", which takes list of the tasks and manage it.
public class ValuesController : ApiController
{
public async Task<List<SomeProduct>> Get()
{
var collection = new List<Mother>() {
new Mother()
{
internalField = new List<Child>()
{
new Child()
{
theLastOne = "VAL"
},
new Child()
{
theLastOne = "VAL"
}
}
}
};
var oss =
from m in collection
from s in m.internalField
select Convert(m, s);
List<Task<SomeProduct>> downloadTasks = oss.ToList();
List<SomeProduct> ossNew = new List<SomeProduct>();
while (downloadTasks.Count > 0)
{
var firstFinishedTask = await Task.WhenAny(downloadTasks);
downloadTasks.Remove(firstFinishedTask);
ossNew.Add(await firstFinishedTask);
}
return ossNew;
}
private async Task<SomeProduct> Convert(Mother ms, Child ss)
{
var ossNEW = new SomeProduct();
await update(ossNEW, ms);
return ossNEW;
}
private async Task update(SomeProduct oss, Mother ms)
{
await Task.Run(()=>
{
oss.copyOfTheLastOne = ms.internalField.First().theLastOne;
oss.valeFromAnUpdateFunction = "works";
});
}
To fully understand the problem, I would like to know why the UPDATE function does not return control to the main action and why RESULT on CONVERT function does not force to run program synchronously?
I would like to know why the UPDATE function does not return control to the main action and why RESULT on CONVERT function does not force to run program synchronously?
You're running into a common deadlock problem that I explain in full on my blog, due to the use of Result. Use await instead of Result and your problem goes away (in your case, since you have a collection, you'll want to await Task.WhenAll):
public async Task<SomeProduct[]> Get()
{
var collection = new List<Mother>() {
new Mother()
{
internalField = new List<Child>()
{
new Child()
{
theLastOne = "VAL"
},
new Child()
{
theLastOne = "VAL"
}
}
}
};
var oss =
from m in collection
from s in m.internalField
select Convert(m, s);
return Task.WhenAll(oss);
}
On a side note, you shouldn't use Task.Run in your implementations, particularly on ASP.NET. On ASP.NET, Task.Run completely removes all the benefits of async and adds overhead.
I have a case where I need to call several different web endpoints and need to do the same setup and tear down for every call. I am trying to write a more generic method where I can pass in the method I want to execute along with the package to send to the endpoint and expect a string return.
From my code I can make this call:
var ret = WebServiceHandler.Execute(WebServiceHandler.LoadNewAsset(package));
The definition of Execute looks like:
internal static string Execute<T>(Func<T, string> executeThisAction)
{
Func<T, string> resp;
Setup();
resp = executeThisAction;
CleanUp();
return resp.ToString();
}
This is one of the methods I want to execute:
internal static Func<CarsWS_AssetLoad, string> LoadNewAsset(AssetLoad package)
{
string resp;
try
{
// Make the web service call...
var assetLoadReturn = _service.LoadNewAsset(new LoadNewAssetRequest {UserCredentialsHeader = _credentials, asset = package});
// Evaluate results...
if (assetLoadReturn.LoadNewAssetResult.responseType == "Success")
resp = (result != null && !String.IsNullOrEmpty(result.asset.assetID))
? "Got assetID: " + result.asset.assetID
: "No assetID returned.";
else
resp = result.responseDescription.Trim();
}
catch (Exception ex)
{
resp = "Error calling LoadNewAsset()." + Environment.NewLine + ex.GetFullMessage();
}
return resp; // <== THIS IS NOT A VALID RETURN <== //
}
My brain is shutting off at this point. How do I return the string back up the call stack correctly???
I assume that in your LoadNewAsset method the CarsWS_AssetLoad class is actually the same as AssetLoad and it was just a editing issue with your question.
That being the case, I think this is what you want:
internal static string Execute<T>(Func<T, string> executeThisAction, AssetLoad package)
{
string resp;
Setup();
resp = executeThisAction(package);
CleanUp();
return resp;
}
internal static Func<AssetLoad, string> LoadNewAsset()
{
return package =>
{
string resp;
var assetLoadReturn = _service.LoadNewAsset(new LoadNewAssetRequest {UserCredentialsHeader = _credentials, asset = package});
if (assetLoadReturn.LoadNewAssetResult.responseType == "Success")
resp = (result != null && !String.IsNullOrEmpty(result.asset.assetID))
? "Got assetID: " + result.asset.assetID
: "No assetID returned.";
else
resp = result.responseDescription.Trim();
return resp;
};
}
The use of the variable result in the LoadNewAsset is a little confusing too. Did you mean to use LoadNewAsset instead?
The above code should be able to workable for you, but it's really not the right way to go about coding this.
I assume that the Setup & CleanUp code is all about instantiating the _service that you're calling?
So the key is to code it this way:
internal static string Execute<T>(Func<IAssetService, T, string> serviceCall, AssetLoad package)
{
string resp;
var service = Setup();
resp = serviceCall(service, package);
CleanUp(service);
return resp;
}
internal static Func<IAssetService, AssetLoad, string> GetLoadNewAssetFunc()
{
return (service, package) =>
{
string resp;
var assetLoadReturn = service.LoadNewAsset(new LoadNewAssetRequest {UserCredentialsHeader = _credentials, asset = package});
if (assetLoadReturn.LoadNewAssetResult.responseType == "Success")
resp = (result != null && !String.IsNullOrEmpty(result.asset.assetID))
? "Got assetID: " + result.asset.assetID
: "No assetID returned.";
else
resp = result.responseDescription.Trim();
return resp;
};
}
Ideally if you would bring the Setup & CleanUp code into the Execute method so that the only way to call the set-up and clean-up code is thru the Execute method.
Even better, if the service class implements IDisposable then your execute code would look like this:
internal static string Execute<T>(Func<IAssetService, T, string> serviceCall, AssetLoad package)
{
using (var service = Setup())
{
return serviceCall(service, package);
}
}
Let me know if I've missed anything.
Replace:
internal static string Execute<T>(Func<T, string> executeThisAction)
with
internal static string Execute<T>(Func<T, string> executeThisAction, T argument)
then replace:
internal static Func<CarsWS_AssetLoad, string> LoadNewAsset(AssetLoad package)
with
internal static string LoadNewAsset(AssetLoad package)
then to call it:
var ret = WebServiceHandler.Execute(WebServiceHandler.LoadNewAsset, package);