Developers Forum for XinFin XDC Network

Discussion on: Issue Report – Unexpected Gas Behavior on XDC Network

Collapse
gzliudan profile image
Daniel Liu • Edited on

A better version:

function postCertificate(
        string memory _studentname,
        address _studentAdd,
        string memory _uri,
        string memory _hash,
        string memory _type,
        string memory _issuerName
    ) external onlyInstitute {
        bytes32 byte_hash = stringToBytes32(_hash);
        require(
            certificates[byte_hash].timestamp == 0,
            "Certificate with this hash already exists"
        );

        uint256 id = institute_ID[msg.sender];

        // write certificate (keeps existing Cert layout)
        certificates[byte_hash] = Cert(
            institutes[id],
            _studentname,
            _studentAdd,
            _hash,
            _type,
            _uri,
            block.timestamp,
            msg.sender,
            _issuerName
        );

        // update student info in-place to avoid copying storage arrays to memory
        studentInstituteId[_studentAdd] = id;
        Student storage s = studentInfo[_studentAdd];
        s.uri.push(_uri);
        uint256 len = s.instituteName.length;
        if (
            len == 0 ||
            !compareStrings(
                s.instituteName[len - 1],
                institutes[id].instituteName
            )
        ) {
            s.instituteName.push(institutes[id].instituteName);
        }
        s.name = _studentname;
        s.studentAdd = _studentAdd;

        emit CertificatePosted(_hash, id, _studentname, _issuerName);
    }
Enter fullscreen mode Exit fullscreen mode

What I changed:

  • Replaced the whole-struct assignment that copied studentInfo[_studentAdd].instituteName and .uri into a new Student with an in-place storage update:
    • `Student storage s = studentInfo[_studentAdd];
    • s.uri.push(_uri);
    • s.name = _studentname;
    • s.studentAdd = _studentAdd;
  • Kept certificate storage logic intact (still assigns Cert to certificates[byte_hash]) to avoid larger structural changes in this patch.
  • This removes the expensive pattern of copying storage arrays into memory & back, preventing gasUsed from growing linearly with array length for this function.

Why this helps

  • Avoids copying dynamic arrays from storage to memory and then back on assignment — that copy cost grows with array length and was the main cause of per-tx gas inflation.
  • Now only the necessary storage writes are performed: push new URI, optionally push instituteName if new, set simple fields. This reduces both SLOAD/SSTORE counts and memory copy overhead.

Next recommendations (optional)

  • Convert Cert.institute to store only instituteId (uint256) instead of embedding Institute to avoid repeated string writes for every certificate.
  • Apply the same storage-in-place pattern to bulkUpload.
  • Consider changing URI storage to mapping(uint256 => string) + counter for very large histories.