5

as part of learning solidity and smart-contract development, I am developing a simple part management/tracking system. I have a struct and a mapping for a list of parts as such:

struct Part {
   uint pNumber;
   string pName;
   string pDesc;
   string pManuf;
   string[] owners;
}
mapping(uint => Part) public part_store;
uint public partsCount;

I'm adding new parts to the mapping using the following method:

function createPart (string _pName, string _pDesc, string _pManuf) public {
        partsCount++;
        part_store[partsCount].pNumber = partsCount;
        part_store[partsCount].pName = _pName;
        part_store[partsCount].pDesc = _pDesc;
        part_store[partsCount].pManuf = _pManuf; 
        part_store[partsCount].owners.push(_pManuf);

        /* Trigger event */
        emit partCreatedEvent(partsCount);
    }

Everything is compiling without errors and I'm able to submit this transaction through Truffle. I get a transaction ID when I create new parts.

Now I'm trying to read the data inside of part but I don't see the array where I pushed the data. It seems that the last data in the object is the manufacturer. But it doesn't show that I've pushed the original manufacturer as owner of that part.

> contract.part_store(1)
Result:
[ BigNumber { s: 1, e: 0, c: [1] },
   'part name',
   'part desc',
   'part Manuf' ]
>

Have I not properly defined the array and pushed data to it? How can I read the data inside of that array? I need an array because this is an easy way to store owners for the parts since owners can change (i.e. defining a new owner by pushing new owner to the array for the specific part).

Thanks all.

EDIT: It seems that if I define an array outside of a struct and public, I am able to read the value:

string[] public test1;
string[] test2;
function writeElem() public {
   test1.push("t1");
   test2.push("t2");
}

results:

> contract.writeElem()
...tx: 0x88...
...txHas: 0x88...
> contract.test1(0)
't1'
> contract.test2(0)
TypeError: app.test2 is not a function
> contract.test2
undefined

I don't think I can define variables in struct public or private so maybe that's why I'm unable to read that data? Could it be something with data access for arrays in Solidity?

2 Answers 2

3

What's happening is the "free" getter you're using doesn't support the indexed value so it just leaves it out. The "free" getter from the public mapping is roughly

function part_store(uint index) public view returns(uint, string, string, string) {
  Part storage p = part_store[index];
  return (p.pNumber, p.pName, p.pDesc, p.pManu);
}

You have to make a function to fetch the missing information. You have latitude. You could simply carry on with what I started and add the array, but I'm not a big fan of it due to scaling concerns and gas cost.

You could instead

function getProductOwnerCount(uint part) public view returns(uint) { 
  return prod_store[part].owners.length; 
}

function getProductOwnerAtIndex(uint part, uint index) public view returns(address) { 
  return prod_store[part].owners[index]; 
}

Those two functions let any observer establish the array length (so they don't walk off the end) and fetch whatever row they're interested in. Or, the client can iterate over all rows to get them all. It's worth noting that clients may already know about most of the owners if they have been watching event logs and events have been emitted each time an owner was added (should).

Hope it helps.

3
  • Thank you for your comment. I've already tried a similar way to getProductOwnerAtIndex. However the array will store a string list of names rather than addresses. In this case it'll say ...returns(string) and not address. When I try to do that I get TypeError: Data location must be "memory" for return parameter in function, but none was given.
    – MB41
    Commented Dec 4, 2018 at 0:37
  • I just answered my own question. You can return strings as long as you use the memory keyword as such ...returns(string memory) {. Likewise do the same for string arrays but need to also define pragma experimental ABIEncoderV2; to be able to do that. Thanks for pointing me in the right direction.
    – MB41
    Commented Dec 4, 2018 at 1:05
  • 1
    Right. New compiler thing. Commented Dec 4, 2018 at 1:07
0

Was able to find an answer to my question. You can return strings as long as you use the memory keyword.

function getProductOwner() public view returns(string memory) {
    return part_store[1].owners[0];
}

Likewise do the same for string arrays but need to also add a new pragma definition at the top of the source page to be able to do that. You will get warnings but no errors, I'm assuming this is because it's a new feature that will eventually be fully functional in Solidity.

pragma experimental ABIEncoderV2;

function getProductOwners() public view returns(string[] memory) {
    return part_store[1].owners;
}

Here's the test I ran in Remix. enter image description here

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.