6

This question addresses how a value stored in a contract variable from the outside.

Is there any similar way to access a value of tuples stored in mapping(with and without knowing a key of mapping).

Consider the following smart contract.

pragma solidity ^0.4.24;
contract Student{
    struct stu{
        string name;
        uint age;
        bool tookTest;
    }
    mapping(uint => stu) studentNames;
    function addStudent (uint ID, string _name, uint _age) {
        studentNames[ID] = stu(_name, _age, false);
    }
    function updateStudent (uint ID) {
        studentNames[ID].tookTest = true;
    }
}

I want to all the tuples stored in studentNames and I know only contract address.

Is that possible?

Soham Lawar
  • 2,567
  • 14
  • 38
  • A mapping maps all possible keys, so you cannot get just the values which you have explicitly added, without knowing the keys which you have explicitly used. In order to achieve that, every time you add a value, you need to store the key in an array (but ideally, only if it's the first time that you are using this key). – goodvibration Sep 04 '18 at 14:57
  • If you also plan to delete values from the mapping, then you need to scan the array and delete the appropriate key (or you can establish a more sophisticated data-structure which will allow you to delete the key from the array in a constant number of operations - if you want this solution, then I've got one ready). – goodvibration Sep 04 '18 at 14:57

2 Answers2

5

A mapping maps all possible keys, so you cannot get just the values which you have explicitly added, without knowing the keys which you have explicitly used. In order to achieve that, every time you add a value, you need to store the key in an array (but ideally, only if it's the first time that you are using this key).

If you also plan to delete values from the mapping, then you need to scan the array and delete the appropriate key, or you can establish a more sophisticated data-structure which will allow you to delete the key from the array in a constant number of operations.

For example:

pragma solidity ^0.4.24;

contract StudentManager {
    uint[] public studentList;

    struct Student {
        bool valid;
        uint index;
        string name;
        uint age;
        bool tookTest;
    }

    mapping(uint => Student) public students;

    /* Update or insert a student */
    function upsert(uint ID, string _name, uint _age, bool _tookTest) external {
        Student storage student = students[ID];
        if (!student.valid) {
            student.valid = true;
            student.index = studentList.length;
            studentList.push(ID);
        }
        student.name = _name;
        student.age = _age;
        student.tookTest = _tookTest;
    }

    /* Remove a student */
    function remove(uint ID) external {
        Student storage student = students[ID];
        require(student.index < studentList.length);
        require(ID == studentList[student.index]);
        uint lastStudent = studentList[studentList.length - 1];
        students[lastStudent].index = student.index;
        studentList[student.index] = lastStudent;
        studentList.length -= 1;
        delete students[ID];
    }

    /* Get the total number of students */
    function studentCount() external view returns (uint) {
        return studentList.length;
    }
}
goodvibration
  • 26,003
  • 5
  • 46
  • 86
4

You can do it if you add one array to store the mapping key; then you can return the key array to client, and client can iterate keys to get the student information for each key.

Tony Dang
  • 2,151
  • 2
  • 9
  • 16
  • Can you share commands/code to iterate keys – Soham Lawar Sep 04 '18 at 13:43
  • You need to write a function on smart contract to return the key array to client; then you can use javascript to iterate the returned array from smart contract. – Tony Dang Sep 04 '18 at 13:45
  • I don't want to use arrays to store keys and my mapping is private(I have modified a code). Is there any possibility to access mapping outside a contract? – Soham Lawar Sep 04 '18 at 13:59
  • you can read smart contract storage by using rpc api

    https://medium.com/aigang-network/how-to-read-ethereum-contract-storage-44252c8af925

    – Tony Dang Sep 04 '18 at 14:04
  • Ha Dang is correct. You cannot enumerate the keys in a mapping because all keys exist. You can either a) track keys in an array, or you can b) externalize the requirement, meaning dismiss it completely. It is recommended to emit events for all important state changes. Having done so, it would then be possible for an observing software client to know all the keys without inspecting the contract state. This method does not work for other contracts, which brings us back to storing an index. – Rob Hitchens Sep 04 '18 at 14:10
  • I would add a caution about private information because nothing in a contract can give the information confidentiality. You have to use extreme care hash or encrypt in software clients first so contracts have no way to know (reveal) the actual secrets. Done this way, secret keys would be bytes32 hashes of keys and the contract would carry on using those values instead of keys that should not be observable by others. – Rob Hitchens Sep 04 '18 at 14:13