Solidity state variable resets to default inside function - blockchain

For this project, I am coding smart contracts for Ethereum using Solidity.
In the following code, the variable numCertificates should initially be 1. Nonetheless, newCertificateId is 0 when assigned. According to the debugger (I'm using remix.ethereum.org), for some reason, numCertificates becomes 0 as soon as the line where newCertificateId is assigned is reached.
I have played around with remix a lot, and according to it, numCertificates is 1 until exactly the aforementioned line is reached. Also, I think that if I modify numCertificates in another function, the variable stays the same as before.
My attempts at trying to figure this out lead me to believe that when I access numCertificates, I am not accessing the public state variable but something else.
Why does this code have this problem and how can it be solved?
pragma solidity ^0.4.21;
contract MyToken {
// ... lots of irrelevant stuff here
mapping (uint64 => Certificate) public certificates;
uint64 numCertificates = 1;
// ... lots of irrelevant stuff here
function MyToken() public {
// ... likely irrelevant code
}
function produceCertificate(
// ... likely irrelevant parameters
) public {
// Create the certificate in memory
numCertificates;// only for debbuging
Certificate storage newCertificate = constructCertificate(meterId, timestamp, carbonMitigationValue, owner);
uint64 newCertificateId = numCertificates;
newCertificate.certificateId = newCertificateId;
// Save the certificate
certificates[newCertificateId] = newCertificate;
numCertificates++;
}
function constructCertificate(
uint64 meterId,
uint32 timestamp,
uint48 value,
address owner
) internal returns (Certificate storage newCertificate) {
newCertificate.meterId = meterId;
newCertificate.timestamp = timestamp;
newCertificate.value = value;
newCertificate.owners.push(owner);
newCertificate.ownershipSplit[owner] = value;
newCertificate.burned = false; // by default new certificates are fresh
return newCertificate;
}
}

Related

there is a problem in the gas requirement

I have been written a smart contract, I am trying to execute the following code but I have these problems:
1- "Gas requirement of function EKM.register_PK is infinite: If the gas requirement of a function is higher than the block gas limit, it cannot be executed. Please avoid loops in your functions or actions that modify large areas of storage (this includes clearing or copying arrays in storage)
Pos: 32:0:"
2- "Use "assert(x)" if you never ever want x to be false, not in any circumstance (apart from a bug in your code). Use "require(x)" if x can be false, due to e.g. invalid input or a failing external component.
more
Pos: 30:2:"
My code:
pragma solidity >=0.8.13;
//SPDX-License-Identifier:MIT
contract EKM{
/**
* #dev VTA is a state variable
*/
address public VTA;
/**
* #dev mapping address as key to struct user with mapping name users
*/
mapping (uint => user) public users;
/**
* #dev assigning the contract deployer as the VTA
*/
constructor() {
VTA =msg.sender;
}
struct user {
string PKname;
string PKvehicle;
uint256 vP;
bool status;
}
event addPK(string name, string PKv, uint256 VPv) ;
function register_PK(uint ID_v, string memory PKname, string memory PKvehicle, uint256 vP) public returns(bool){
require(users[ID_v].status == true,"register the public key of the user");
if(msg.sender != VTA)
{revert();}
if(ID_v == 0)
{return false;}
else
{
ID_v++;
users[ID_v]= user(PKname,PKvehicle,vP,true);
//PKname=users[ID_v].PKname;
//PKvehicle=users[ID_v].PKvehicle;
// vP=users[ID_v].vP;
emit addPK(PKname, PKvehicle, vP);
return true;
}
}
}
what should I do?
Go to solidity static analysis ,and then gas and economy , untick all options except. This on local calls:
Invocation of local functions via 'this' and Delete dynamic array:
Use require/assert to ensure complete deletion. it will work

At remix.ethereum.org, blockhash function always zeroes all variables

I'm having a problem with the blockhash function at remix.ethereum.org.
Despite several attempts with different codes the blockhash function always causes problems and the result is that all variables are returned with a value of zero.
In the case below, the _previousBlockNumber variable always return zeroed.
If the blockhash function line is commented out then the error does not occur and at least the _previousBlockNumber variable returns correctly.
I've tried several different versions of compilers.
pragma solidity ^0.5.5;
contract Test {
constructor() public {
}
function rand() public view returns(uint,bytes32) {
uint _previousBlockNumber;
bytes32 _previousBlockHash;
_previousBlockNumber = uint(block.number - 1);
bytes32 _previousBlockHash = bytes32(blockhash(_previousBlockNumber));
return (_previousBlockNumber,_previousBlockHash);
}
}
It's a bug issue?
Thanks for any help.
I tried to run this code to fix the problem and it's working for me with some changes. Same contract you can find on Rinkebey Testnet with this address 0x86ee6d633fd691e77dc79cbdb2a9fb108f79ecbd.
pragma solidity ^0.5.5;
contract Test {
uint256 i;
constructor() public {
}
function rand() public view returns(uint,bytes32) {
uint _previousBlockNumber;
bytes32 _previousBlockHash;
_previousBlockNumber = uint(block.number - 1);
_previousBlockHash = bytes32(blockhash(_previousBlockNumber));
return (_previousBlockNumber,_previousBlockHash);
}
function setI(uint256 k) public{
i = k;
}
}
Initially, you were declaring the _previousBlockHash two times, and second time on the line of blockhash function. I fix it and working fine.
Secondly, in the current contract code you are not changing any state of the contract and not doing any transaction, rand() is just an call, which will not add any other block. So it will always remain 0. I add one dummy transaction function for testing which is working fine now.
Lastly, try to run this on live test network to see actual things.
Hope it will work.

Solidity 0.5.0 too much variables

I try to compile a smart contract using Truffle framework and I get following output:
Compiling ./contracts/PartProduction.sol...
InternalCompilerError: Stack too deep, try using fewer variables.
Compilation failed. See above.
Truffle v5.0.1 (core: 5.0.1)
Node v11.6.0
The source code of the smart contract written with Solidity 0.5.0 is:
pragma solidity 0.5.0;
contract PartProduction {
enum State {
productionRequested,
parametersObtained,
manufacturerObtained,
productionForwardedToManufacturer,
printing,
printed,
postProcessing,
postProcessed,
qualityChecking,
qualityChecked,
productionFinished
}
enum Priority {
low,
normal,
high
}
struct Company {
address vehicleEthAddress;
address myWebService;
}
struct Manufacturer {
string id;
string location;
address productionMachine1;
address productionMachine2;
address productionMachine3;
}
struct Production {
string productionParameters;
string designParameters;
State state;
Priority priority;
string partNumber;
uint256 cost;
uint256 productionForwardedTime;
uint256 productionStartTime;
uint256 productionEndTime;
address partID;
string myIdentifier;
string location;
}
Company public company;
Manufacturer public manufacturer;
Production public production;
constructor(
address _vehicleEthAddress,
string memory _myIdentifier,
string memory _vehicleLocation,
string memory _partNumber,
Priority _priority)internal {
company.myWebService = msg.sender;
company.vehicleEthAddress = _vehicleEthAddress;
production.partID = address(this);
production.state = State.productionRequested;
production.partNumber = _partNumber;
production.priority = _priority;
production.myIdentifier = _myIdentifier;
production.location = _vehicleLocation;
}
function setParameters(string calldata _designParametersHash, string calldata _productionParametersHash) external {
require(msg.sender == company.myWebService);
require(production.state == State.productionRequested);
production.designParameters = _designParametersHash;
production.productionParameters = _productionParametersHash;
production.state = State.parametersObtained;
}
function setManufacturer(string calldata _manufacturerId, string calldata _manufacturerLocation) external {
require(msg.sender == company.myWebService);
require(production.state == State.parametersObtained);
manufacturer.id = _manufacturerId;
manufacturer.location = _manufacturerLocation;
production.state = State.manufacturerObtained;
}
function forwardProductionData(uint256 _productionForwardedTime) external {
require(msg.sender == company.myWebService);
require(production.state == State.manufacturerObtained);
production.state = State.manufacturerObtained;
production.productionForwardedTime = _productionForwardedTime;
}
function registerproductionMachine1(address _productionMachine1) external {
require(msg.sender == company.myWebService);
manufacturer.productionMachine1 = _productionMachine1;
}
}
I would like to know if there is a way to understand and identify the part where the number of variables exceeds. Should I turn everything into a mapping? The compiler does not provide me with further information.
Also, I found this question, it's similar, but I'm not sure it's the same problem, a cons it is to save the variables in memory (memory keyword) when you do a get, another is to set them. Is the use of mapping the only possible alternative to tackle this problem? Furthermore, the smart contract is not concluded, many other parts will be added later.
As far as I can see, your stack is too deep for the struct production, you can use a trick here to solve this issue, create a separate smart contract with the name Production, define the structure there and import the contract in this smart contract. This will help you in both reducing your gas consumption while deploying the contract and this stack too deep issue.
This you can do for other structs as well if you wish. The only thing you need to take care of is the mapping while you implement for mapping the structure to a particular contract. As for each contact it will be counted as separate map.
Let me know if you need any further assistance. I want you to try out this solution hopefully, this will work.

How to get the delta value of an GameplayAbility attribute on client (after attribute value change)?

In my Unreal Engine project, which uses GameplayAbilitySystem and the default server->client architecture, the client gets notified of an attribute value changes that happened on the server.
Additionally, I'm trying to get not only the new value, but also the amount the value changed (delta = new value - old value). This should be possible using the attribute value change delegate, since it contains FOnAttributeChangeData with its members NewValue and OldValue.
On the server, both values are correct. However, on the client, FOnAttributeChangeData::NewValue == FOnAttributeChangeData::OldValue and both have the value being identical to NewValue on the server.
This is because the delegate is called after the replication happened ...
UPROPERTY(ReplicatedUsing=OnRep_MyAttribute)
FGameplayAttributeData MyAttribute;
void UAttributeSetBase::OnRep_MyAttribute()
{
GAMEPLAYATTRIBUTE_REPNOTIFY(UAttributeSetBase, MyAttribute);
}
(this is default GAS setup of ActionRPG)
... so the client has no knowledge about the value it had before replication.
How do I get the value of the attribute, which it had before it got updated by the server?
How do I forward this value to the delegate?
Getting the old value (question 1)
UnrealEngine OnRep functions provide the previous state of an replicated variable as first parameter in the OnRep function. So add the parameter
void UAttributeSetBase::OnRep_MyAttribute(const FGameplayAttributeData& Previous)
{
const auto PreviousValue = Previous.GetCurrentValue(); // See below for possible usage.
GAMEPLAYATTRIBUTE_REPNOTIFY(UAttributeSetBase, MyAttribute);
}
Thanks #Dan from Unreal GAS discord channel.
Forward the value to the delegate (question 2)
Idea
When your goal is to not modify the UE4 source code, one possibility is to cache the previous value within the attribute set, so you are able to access it from outside.
Cache that value for each attribute in the attribute set OnRep function.
Use the cached value in the delegate, but only if it is valid. Since the value is assigned within the OnRep function, it won't exist on the server. This is perfectly fine since we want to retain the behaviour on the server, which uses FOnAttributeChangeData::OldValue (which has the correct value only on the server).
Example implementation
Caching the previous value
AttributeSetBase.h:
// Wrapper for a TMap. If you need thread safety, use another container or allocator.
class CachePreviousDataFromReplication
{
TMap<FName, FGameplayAttributeData> CachedPreviousData;
public:
void Add(const FName, const FGameplayAttributeData&);
auto Find(const FName) const -> const FGameplayAttributeData*;
};
class YOUR_API UAttributeSetBase : public UAttributeSet
{
// ...
private:
UFUNCTION() void OnRep_MyAttribute(const FGameplayAttributeData& Previous);
// ...
private:
CachePreviousDataFromReplication CachedDataFromReplication;
public:
// \param[in] AttributeName Use GET_MEMBER_NAME_CHECKED() to retrieve the name.
auto GetPreviousDataFromReplication(const FName AttributeName) const -> const FGameplayAttributeData*;
}
AttributeSetBase.cpp:
void CachePreviousDataFromReplication::Add(const FName AttributeName, const FGameplayAttributeData& AttributeData)
{
this->CachedPreviousData.Add(AttributeName, AttributeData);
}
auto CachePreviousDataFromReplication::Find(const FName AttributeName) const -> const FGameplayAttributeData*
{
return CachedPreviousData.Find(AttributeName);
}
void UAttributeSetBase::OnRep_MyAttribute(const FGameplayAttributeData& Previous)
{
CachedDataFromReplication.Add(GET_MEMBER_NAME_CHECKED(UAttributeSetBase, MyAttribute), Previous); // Add this to every OnRep function.
GAMEPLAYATTRIBUTE_REPNOTIFY(UAttributeSetBase, MyAttribute);
}
auto UAttributeSetBase::GetPreviousDataFromReplication(const FName AttributeName) const -> const FGameplayAttributeData*
{
return CachedDataFromReplication.Find(AttributeName);
}
Accessing the previous value in the delegate
ACharacterBase.h:
class YOUR_API ACharacterBase : public ACharacter, public IAbilitySystemInterface
{
// ...
void OnMyAttributeValueChange(const FOnAttributeChangeData& Data); // The callback to be registered within GAS.
// ...
}
ACharacterBase.cpp:
void ACharacterBase::OnMyAttributeValueChange(const FOnAttributeChangeData& Data)
{
// This delegate is fired either from
// 1. `SetBaseAttributeValueFromReplication` or from
// 2. `InternalUpdateNumericalAttribute`
// #1 is called on clients, after the attribute has changed its value. This implies,
// that the previous value is not present on the client anymore. Therefore, the
// value of `Data.OldValue` is erroneously identical to `Data.NewValue`.
// In that case (and only in that case), the previous value is retrieved from a cache
// in the AttributeSet. This cache will be only present on client, after it had
// received an update from replication.
auto deltaValue = 0.f;
if (Data.NewValue == Data.OldValue)
{
const auto attributeName = GET_MEMBER_NAME_CHECKED(UAttributeSetBase, MyAttribute);
if (auto previousData = AttributeSetComponent->GetPreviousDataFromReplication(attributeName))
{
// This will be called on the client, when coming from replication.
deltaValue = Data.NewValue - previousData->GetCurrentValue();
}
}
else
{
// This might be called on the server or clients, when coming from
// `InternalUpdateNumericalAttribute`.
deltaValue = Data.NewValue - Data.OldValue;
}
// Use deltaValue as you like.
}

Where would a transaction take place in my Smart Contract

I am making a simple smart contract that is essentially a ledger that people can sign with a string (UI to come) and then pass onto a next person (using their ether address). I just wanted to create something that could be passed from person to person while recording its journey.
The logic of 'transferring' the signing-ledger is all done within the smart contract, with it existing as a mapping and the key value of an address changing from 0 to 1 signifying ownership (1 person owning it at a time). Because there's no actual transfer of ether/actual monetary value, where would actual ethereum transactions be occurring in this contract?
Also to sign the ledger I verify that the public key signing it has 1 as its value in the mapping, but how would I check that that person owns that public key (using a private key)?
my solidity code so far:
pragma solidity ^0.4.4;
contract Pass{
mapping(address => bool) ownership;
mapping(address => string) notes;
constructor(address genesis) public {
ownership[genesis] = true; //this address starts with it
}
function checkOwnership(address p) public view returns(bool){
if(ownership[p]){
return true;
}
return false;
}
function sign(string signedNote) public returns(uint){ // 1 on success 0 on fail
if(checkOwnership(msg.sender)){ //if msg.sender owns the note
notes[msg.sender] = signedNote;
return 1;
}
return 0;
}
function pass(address recipient) public returns(uint){ // 1 on success 0 on fail
if(checkOwnership(msg.sender)){ //if msg.sender owns the note
ownership[msg.sender] = 0;
ownership[recipient] = 1;
return 1;
}
return 0;
}
function viewNotes(address participant) public returns(string){ // signed note on success nothing on fail
if(notes[participant] !== 0){
return (notes(participant));
}
}
}
The logic of 'transferring' the signing-ledger is all done within the smart contract, with it existing as a mapping and the key value of an address changing from 0 to 1 signifying ownership (1 person owning it at a time)
This is a common pattern known as the owner pattern. You can simplify this by simply keeping track of a single owner address and updating that, instead of using a mapping, since you only care about the current owner. Something as simple as:
address public owner;
modifier onlyOwner() {
require(msg.sender == owner);
_;
}
constructor() {
owner = msg.sender;
}
function transferOwnership(address _owner) onlyOwner {
owner = _owner;
}
Open Zeppelin has a more complete implementation of ownership here.
Because there's no actual transfer of ether/actual monetary value, where would actual ethereum transactions be occurring in this contract?
Transactions do not require ether movement. You can call any public/external function on your contract with a 0 value transaction, and pass data to it. The transaction will execute on the blockchain like any other, and run the code you invoke within the contract.
Also to sign the ledger I verify that the public key signing it has 1 as its value in the mapping, but how would I check that that person owns that public key (using a private key)?
You are already checking is msg.sender matches the whitelisted address. For basic transactions, this means that the transaction has been signed by the address in msg.sender (msg.sender can also be a contract, if another contract calls yours. To check who actually signed the transaction in all scenarios, you must use tx.origin).