...by Daniel Szego
quote
"Simplicity is the ultimate sophistication."
Leonardo da Vinci

Wednesday, August 1, 2018

Solidity Pattern and Practices: CRUD (Create Read Update Delete) on asset


So let we imagine the situation that want to create some basic asset on the ethereum blockchain that mimics the CRUD (Create Read Update Delete) operations, possible considering different roles and rights as well for the different operations. We could use something similar. For the first run we can defined an enumeration giving the first set of basic access controls and some kind of an internal data structure that we want to modify:

contract CRUDAsset {

  enum RightsEnum{
      Create,
      Read,
      Update,
      Delete,
      Admin
  } 
  
  struct DataStruct {
      uint data;
  }

  DataStruct data;

As a second step we can define a possible right configuration for each address and give modifiers that check the existence of these modifiers and of course a constructor that gives admin right for the first account.  

  mapping(address => RightsEnum) rights;
  
  constructor(){
      rights[msg.sender] = RightsEnum.Admin;
  }
  
  modifier CanCreate {
      require(rights[msg.sender] == RightsEnum.Create);
      _;
  }
  
  modifier CanRead {
      require(rights[msg.sender] == RightsEnum.Read);
      _;
  }
  
  modifier CanUpdate {
      require(rights[msg.sender] == RightsEnum.Update);
      _;
  }

  modifier CanDelete {
      require(rights[msg.sender] == RightsEnum.Delete);
      _;
  }

  modifier IsAdmin {
      require(rights[msg.sender] == RightsEnum.Admin);
      _;
  }

After this step we can define the CRUD (Create, Read, Update, Delete) operations with the given access rights.  

  function Create(uint _initialData) CanCreate {
      data = DataStruct(_initialData);
  }

  function Read() CanRead returns (uint) {
      return data.data;
  }

  function Update(uint _newData) CanUpdate {
      data.data = _newData;
  }
  
  function Delete(uint _newData) CanDelete {
      data.data = 0;
  }

  function AddRight(address _to, uint _right) IsAdmin {
      rights[msg.sender] = RightsEnum(_right);
  }
}

Certainly, the structure can be refined in several ways: 
- It is not a general schema for any kind of a data, it is valid only for the one specified DataStruct structure. It is even difficult to extend it to general data structures as the basic elements has to be defined at the moment in the function signatures. 
- Read actually means only reading out from the contract or from the user interface. The variable is not secret if someone has direct access to a blockchain node. The situation can be fine-tuned with encryption or with zkSNARKs. 
- The model has the one address -> one access model. It can be extended on a long run to a one address - multiply access right version.