0

I am working on a fish supply chain contract in Solidity. Within the contract, I have defined two structs: fish_info and temperature_location. The fish_info struct contains an array of temperature_location structs, with a fixed length of 10. I'm trying to store a dynamic array of fish_info structs in a mapping, where each fish is recorded based on the date.

    pragma solidity >=0.7.0 <0.9.0;
pragma experimental ABIEncoderV2;
/**
 * fish supply chain
 */
contract FishData {
    //fish information
    struct fish_info {
        string species;
        string initialLocation;
        uint256 initialTimestamp;
        uint256 initialTemperature;
        temperature_location[10] history;
    }
    
    struct temperature_location {
        uint256 timestamp;
        uint256 temperature;
        string location;
        bool safety;
    }
    
 
    mapping (uint256 => fish_info[]) public fish_infoList;

    event RecordData(uint256 indexed date, string species, string initialLocation, uint256 initialTimestamp, temperature_location[10] history);

    /**
     * record Capture Data
     */
    function recordCaptureData (uint256 date, string memory species, string memory initialLocation, uint256 initialTimestamp, uint256 initialTemperature) public {
        temperature_location memory initialHistory;
        fish_info memory newinfo;
        initialHistory = temperature_location(block.timestamp, initialTemperature, initialLocation, true);
        newinfo.history[0] = initialHistory;
        newinfo = fish_info(species, initialLocation, block.timestamp, initialTemperature, newinfo.history);
        

        fish_infoList[date].push(newinfo);
        emit RecordData(date, newinfo.species, newinfo.initialLocation, newinfo.initialTimestamp, newinfo.history);
    }
}

The error specifically occurs when I try to assign initialHistory to newinfo.history[0]. It seems that Solidity does not yet support copying a dynamic array of structs to storage, even though pragma experimental ABIEncoderV2 is used.

I'm seeking guidance on how to overcome this issue and successfully store a dynamic array of structs in storage, within the constraints of Solidity's current capabilities. Any help or suggestions would be greatly appreciated. Thank you!

2 Answers 2

0

Looks like it is indeed impossible. What I suggest is to use another mapping to store the temperature_location[], while the fish_info will have another member - an id. This id would then be used to obtain the temperature_location[] from the mapping. I modified your code accordingly:

pragma solidity >=0.7.0 <0.9.0;
pragma experimental ABIEncoderV2;
/**
 * fish supply chain
 */
contract FishData {
    //fish information
    struct fish_info {
        uint256 id;
        string species;
        string initialLocation;
        uint256 initialTimestamp;
        uint256 initialTemperature;
    }

    struct temperature_location {
        uint256 timestamp;
        uint256 temperature;
        string location;
        bool safety;
    }
    
    uint256 fishInfoId;
    mapping (uint256 => fish_info[]) public fish_infoList;
    mapping (uint256 => temperature_location[]) public locationList;

    event RecordData(uint256 indexed date, string species, string initialLocation, uint256 initialTimestamp, temperature_location[] history);

    /**
     * record Capture Data
     */
    function recordCaptureData (uint256 date, string memory species, string memory initialLocation, uint256 initialTimestamp, uint256 initialTemperature) public {
        temperature_location memory initialHistory;
        fish_info memory newinfo;
        initialHistory = temperature_location(block.timestamp, initialTemperature, initialLocation, true);
        
        newinfo = fish_info(fishInfoId, species, initialLocation, block.timestamp, initialTemperature);
        
        locationList[fishInfoId].push(initialHistory);

        fish_infoList[date].push(newinfo);

        fishInfoId++;
        emit RecordData(date, newinfo.species, newinfo.initialLocation, newinfo.initialTimestamp, locationList[fishInfoId]);
    }
}

with this approach your code can retain the structure of the function and the event, however there will be slightly more to keep in the storage.

2
  • thank you! using mapping and fishInfoId is a good way, I also solve this problem with code following:
    – meitedaf
    Jun 8, 2023 at 8:52
  • Interesting, so you used the state variable array as a buffer instead of memory. That worked indeed, but has a huge gas cost in it due to multiple sstore, my functions costs 322467, while yours 908314. You might want to consider that too. Jun 8, 2023 at 9:47
0
pragma solidity >=0.7.0 <0.9.0;
pragma experimental ABIEncoderV2;
/**
 * fish supply chain
 */
contract FishData {
    struct fish_info {
        string species;
        string initialLocation;
        uint256 initialTimestamp;
        uint256 initialTemperature;
        temperature_location[10] history;
    }
    struct temperature_location {
        uint256 timestamp;
        uint256 temperature;
        string location;
        bool safety;
    }
    mapping (uint256 => fish_info[]) public fish_infoList;
    event RecordData(uint256 indexed date, string species, string initialLocation, uint256 initialTimestamp, temperature_location[10] history);
    temperature_location[10] public historys;
    fish_info public newinfo;
function recordCaptureData (uint256 date, string memory species, string memory initialLocation, uint256 initialTimestamp, uint256 initialTemperature) public {
        
        historys[0].timestamp = block.timestamp;
        historys[0].temperature = initialTemperature;
        historys[0].location = initialLocation;
        historys[0].safety = true;

        newinfo.species = species;
        newinfo.initialLocation = initialLocation;
        newinfo.initialTimestamp = block.timestamp;
        newinfo.initialTemperature = initialTemperature;
        newinfo.history = historys;
        
        fish_infoList[date].push(newinfo);
        emit RecordData(date, newinfo.species, newinfo.initialLocation, newinfo.initialTimestamp, newinfo.history);
    }
}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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