0

The setup of the contracts has 3 contracts: a library contract, a Controller contract with modifiers and a main contract as follows:

DataSet.sol  

library DataSet {  

  struct IndexValue { uint keyIndex; uint256 value;}  
  struct KeyFlag { uint key; bool deleted; }  
  struct KeyValue { uint key; uint value; }  


  struct Data {
      mapping(uint => IndexValue) data;  
      KeyFlag[] keys;  
      //KeyValue[] kvpairs;  
      uint size;  
  }  

  function stringToBytes32(string memory source) returns (bytes32 result) {  
      assembly {  
          result := mload(add(source, 32))  
      }  
  }  


  function getCurrent(Data storage self) returns(uint index){  
      return self.size - 1;  
  }  

}  

Controlled.sol:  

contract Controlled {  
    address public userAddr;  

    struct User {  
      address a;  
      string name;  
      string email;  
      uint phone;  
    }  

    mapping (address => User) Users;  

    function registerUser(string _name, string _email, uint _phone) returns (bool success) {  
      Users[msg.sender].a = msg.sender;  
      Users[msg.sender].name = _name;  
      Users[msg.sender].email = _email;  
      Users[msg.sender].phone = _phone;  
    }



    modifier onlyUser {
        if (msg.sender != userAddr) throw;
        _;
    }

}  


contract Main is Controlled {  
  using DataSet for *;    
  DataSet.Data d;  

  struct userProduct {  
    address user_address;  
    uint id;  
    string description;  
    uint price;  
  }  

   userProduct[] products;  


  function newUserProduct  (  
    address u,
    uint i,
    string d,
    uint p) onlyUser returns (bool added) {

    userProduct memory newProduct;
    newProduct.user_address = msg.sender;
    newProduct.id = i;  
    newProduct.description = d;
    newProduct.price = p;
    products.push(newProduct);
    added = true;
  }  

  function getUserInfo (uint g) constant returns (address ,bytes32, uint ) {  
      for (uint i = 0; i <= products.length; i++) {  
          if (products[i].id == g) {  
             return(products[i].user_address, DataSet.stringToBytes32(products[i].description), products[i].price);  
          }  
      }  
  }  
}  

Registering the user by invoking Controlled.registerUser works fine after which associating a product to the user by invoking Main.newUserProduct also works fine to give a tx_id. However, when I try to call getUserInfo, I either get an invalid jump error while using embark and returns [0x, 0x, 0x] while using truffle. I am unable to resolve the issue whether it is the case of the modifier or if the library is not correctly being instantiated. Any suggestions would be immensely helpful!

Rob Hitchens
  • 55,151
  • 11
  • 89
  • 145
skarred14
  • 945
  • 1
  • 9
  • 18

1 Answers1

1

I've got something that will help you press on.

The modifier

modifier onlyUser {
    if (msg.sender != userAddr) throw;
    _;
}

prevented all efforts to set a product, because userAddr was never set (==0x0). Added a constructor to look after it and now I can add a product.

After that, getUserProduct() started working. I added "public" to some state vars and some logs to help see what's going on. Watch for other small changes I may have slipped in while debugging.

Worked once. No Warranty. :-)

pragma solidity ^0.4.6;

library DataSet {  

  struct IndexValue { uint keyIndex; uint256 value;}  
  struct KeyFlag { uint key; bool deleted; }  
  struct KeyValue { uint key; uint value; }  


  struct Data {
      mapping(uint => IndexValue) data;  
      KeyFlag[] keys;  
      //KeyValue[] kvpairs;  
      uint size;  
  }  

  function stringToBytes32(string memory source) returns (bytes32 result) {  
      assembly {  
          result := mload(add(source, 32))  
      }  
  }  


  function getCurrent(Data storage self) returns(uint index){  
      return self.size - 1;  
  }  

}  

contract Controlled {  
    address public userAddr;  

    struct User {  
      address a;  
      string name;  
      string email;  
      uint phone;  
    }  

    mapping (address => User) public Users;  

    event LogNewUser(address user, string name, string email, uint phone);

    function Controlled() {
        userAddr = msg.sender;
    }

    function registerUser(string _name, string _email, uint _phone) returns (bool success) {  
      Users[msg.sender].a = msg.sender;  
      Users[msg.sender].name = _name;  
      Users[msg.sender].email = _email;  
      Users[msg.sender].phone = _phone;  
      LogNewUser(msg.sender, _name, _email, _phone);
      return true;
    }

    modifier onlyUser {
        if (msg.sender != userAddr) throw;
        _;
    }

}  

contract Main is Controlled {  

  using DataSet for *;    
  DataSet.Data d;  

  struct userProduct {  
    address user_address;  
    uint id;  
    string desc;  
    uint price;  
  }  

  userProduct[] public products; 

  event LogNewUserProduct(address user, uint index, string description, uint price);

  function newUserProduct  (  
    address u,
    uint i,
    string d,
    uint p) onlyUser returns (bool added) {

    userProduct memory newProduct;
    newProduct.user_address = msg.sender;
    newProduct.id = i;  
    newProduct.desc= d;
    newProduct.price = p;
    products.push(newProduct);
    LogNewUserProduct(msg.sender, i, d, p);
    return true;
  }  

  function getUserInfo (uint g) constant returns (address ,bytes32, uint ) {  
      for (uint i = 0; i <= products.length; i++) {  
          if (products[i].id == g) {  
             return(products[i].user_address, DataSet.stringToBytes32(products[i].desc), products[i].price);  
          }  
      }  
  }  
}  

Here it is in Remix to show it working.

enter image description here

Side tip

It's hard to discern the data structure you're aiming for. If you can clarify that for me I might send back a simplified version of this for you.

There are example patterns over here that might help: Are there well-solved and simple storage patterns for Solidity?

Admittedly, it gets a little tricky applying the patterns to joins and there's no generalized example of that in the post.

Hope it helps.

Update

I'm a little confused by who's supposed to do what.

onlyAdmin must be able to create/update attributes/delete the product from the struct array. onlyManager must be able to update attributes/delete the product and onlyTester must be able to update the product attributes

As a caution item, in general, I try to externalize access control concerns. "owner" can be a contract designed to reflect access control concerns.

This scaffold might give you some ideas about how to proceed.

pragma solidity ^0.4.6;

contract Store {

    address public owner;

    enum UserType {owner, admin, tester}

    struct User {
        bytes32 name;
        bytes32 email;
        bytes32 phone;
        UserType userType;
        uint userIndex;
    }

    mapping(address => User) public userStructs;
    address[] public userList;

    struct Product {
        uint price;
        bytes32 description;
        uint productIndex;
    }

    mapping(bytes32 => Product) public productStructs;
    bytes32[] public productList;

    modifier onlyOwner {
        if(msg.sender != owner) throw;
        _;
    }

    modifier onlyAdmin {
        if(!isUser(msg.sender)) throw;
        if(userStructs[msg.sender].userType != UserType.admin) throw;
        _;
    }

    modifier onlyTester {
       if(!isUser(msg.sender)) throw;  
       if(userStructs[msg.sender].userType != UserType.tester) throw;
        _;
    }

    // constructor

    function Store() {
        owner = msg.sender;
    }

    // simple counts

    function getUserCount() public constant returns(uint userCount) { return userList.length; }
    function getProductCount() public constant returns(uint productCount) { return productList.length; }

    // Id checks

    function isUser(address user) 
        public
        constant
        returns(bool isIndeed) 
    {
        if(userList.length == 0) return false;
        return userList[userStructs[user].userIndex] == user;
    }

    function isProduct(bytes32 productId)
        public
        constant
        returns(bool isIndeed)
    {
        if(productList.length == 0) return false;
        return productList[productStructs[productId].productIndex] == productId;
    }

    // inserts

    function createAdmin(address userAddress, bytes32 userName, bytes32 userEmail)
        onlyOwner
        returns(bool success)
    {
        if(isUser(userAddress)) throw;
        userStructs[userAddress].name = userName;
        userStructs[userAddress].email = userEmail;
        userStructs[userAddress].userType = UserType.admin;
        userStructs[userAddress].userIndex = userList.push(userAddress) - 1;
        return true;
    }

    function createTester(address userAddress, bytes32 userName, bytes32 userEmail)
        onlyOwner
        returns(bool success)
    {
        if(isUser(userAddress)) throw;
        userStructs[userAddress].name = userName;
        userStructs[userAddress].email = userEmail;
        userStructs[userAddress].userType = UserType.tester;
        userStructs[userAddress].userIndex = userList.push(userAddress) - 1;
        return true;        
    }

    function createProduct(bytes32 productId, uint productPrice, bytes32 productDescription)
        onlyAdmin
        returns(bool success)
    {
        if(isProduct(productId)) throw;
        productStructs[productId].price = productPrice;
        productStructs[productId].description = productDescription;
        productStructs[productId].productIndex = productList.push(productId);
        return true;
    }

    function updateProduct(bytes32 productId, uint productPrice, bytes32 productDescription)
        onlyTester
        returns(bool success)
    {
        if(!isProduct(productId)) throw;
        if(isProduct(productId)) throw;
        productStructs[productId].price = productPrice;
        productStructs[productId].description = productDescription;
        productStructs[productId].productIndex = productList.push(productId);
        return true;        
    }

}
Rob Hitchens
  • 55,151
  • 11
  • 89
  • 145
  • I am aiming for a data structure wherein i can add any number of users but classify by roles. And accordingly set modifiers. For example, user type admin, business manager and tester. Each of them should be able to register themselves using Controlled.sol, and the functions in Main have corresponding functionalities, i.e., onlyAdmin, onlyManager and onlyTester. Hopefully this question makes sense – skarred14 Apr 06 '17 at 14:09
  • Where do the products fit in? User:Product relationship. – Rob Hitchens Apr 06 '17 at 15:08
  • Basically, onlyAdmin must be able to create/update attributes/delete the product from the struct array. onlyManager must be able to update attributes/delete the product and onlyTester must be able to update the product attributes – skarred14 Apr 06 '17 at 17:25
  • thanks for the update! this was very helpful. I separated the product pieces into a new contract that inherits from the Store contract. I was able to compile and run it fine on the online solidity compiler. I added in a getter to be able to retrieve the product info, which worked well on the online compiler. However, when i run the same in truffle/embark, i am getting either empty results like ['0x','0x'] or an invalid jump error respectively. Not sure what the issue is. – skarred14 Apr 07 '17 at 06:33