0

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 {

    struct Certificate {
      uint64 certificateId;
      uint64 meterId;

      uint32 timestamp;
      uint48 value;
      address[] owners;

      mapping (address => uint48) ownershipSplit;

      bool burned;
    }

    mapping (uint64 => Certificate) public certificates;
    uint64 numCertificates = 1;

    function MyToken() public {
      // ... irrelevant stuff
    }

    function produceCertificate(
      uint64 meterId,
      uint32 timestamp,
      uint48 value,
      address owner
      ) 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;
    }
}
  • 1
    Is difficult to help here because your code is incomplete and is not possible to reproduce the issue. – Jaime Jun 28 '18 at 10:45
  • @Jaime The code posted reproduces the issue – Nic Szerman Jun 28 '18 at 10:49
  • No, the struct Certificate is not defined – Jaime Jun 28 '18 at 10:51
  • @Jaime My bad you are right, adding the details right now – Nic Szerman Jun 28 '18 at 10:53
  • @Jaime I added the parameters of produceCertificate and the Certificate struct – Nic Szerman Jun 28 '18 at 10:59
1

The issue seems to be the use of storage pointier that you are doing. I can not understand what are you pointing at when you use:

Certificate storage newCertificate = constructCertificate(meterId, timestamp, Value, owner);

I changed your code to this:

pragma solidity ^0.4.21;

contract MyToken {

    struct Certificate {
      uint64 certificateId;
      uint64 meterId;
      uint32 timestamp;
      uint48 value;
      address[] owners;
      mapping (address => uint48) ownershipSplit;
      bool burned;
    }

    mapping (uint64 => Certificate) public certificates;
    uint64 public numCertificates = 1;

    function MyToken() public {
      // ... irrelevant stuff
    }

    function produceCertificate(
      uint64 meterId,
      uint32 timestamp,
      uint48 value,
      address owner
      ) public {
        // Create the certificate in memory
        //numCertificates;// only for debbuging
        Certificate storage newCertificate = certificates[numCertificates];
        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
        newCertificate.certificateId = numCertificates;
        numCertificates= numCertificates +1;
    }

}

In this code, you define a pointer to the structure that is the mapping, in the position indicated by numCertificates (which actually the Id of the new certificate).

Therefore the changes to newCertficate are actually changes made to certificates[numCertificates] directly.

Note that I removed the function produceCertificate for simplicity.

Hope this helps

  • Thank you. Do you know why the uninitialized storage pointer cause the problems? – Nic Szerman Jun 29 '18 at 1:00
  • 1
    probably the memory positions of the variables in the structure were overlapping with the variables that you defined initially. – Jaime Jun 29 '18 at 6:21

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.