## Appendix A  
The Solidity source code for the proposed smart contract is provided in the appendix.  
1// SPDX-License-Identifier: MIT
2 pragma solidity >=0.6.0 <0.9.0;
3 pragma experimental ABIEncoderV2;
4
5 contractdatastore{
6 addresspublicowner;
7
8 eventGrantRole(bytes32 indexedrole,addressindexedaccount);
9 eventRemoveRole(bytes32 indexedrole,addressindexedaccount);
10
11 constructor(){
12 owner=msg.sender;
13-grantRole(Admin,msg.sender);
14}
15
16 mapping(atring=>uint[])publictagindex;
17 string[]publicdatabase;
18 uintcounter=0;
19 mapping(bytes32=>mapping(address=>bool))publicroles;
20
21 bytes32 privateconstantAdmin=kececak256(abi.encodePacked(\"Admin\"));
22 bytes32 publicconstantRead=kecak256(abi.encodePacked(\"Read\"));
23 bytes32 publicconstantWrite=kecak256(abi.encodePacked(\"Write\"));
24
25 modifieronlyRole(bytes32_role){
26 require(roles[_role][msg.sender],\"notauthorized\");
27-i
28}
29
30 function_grantRole(bytes32_role,address_account)internal{
31 if(_role==Admin){
32 roles[Admin][_account]=true;
33 roles[Write][_account]=true;
34 roles[Read][_account]=true;
35}elseif(_role==Write){
36 roles[Write][_account]=true;
37 roles[Read][_account]=true;
38}else{
39 roles[_role][_account]=true;
40}
41
42 emitGrantRole(_role,_account);
43}
44
45 functiongrantAdminRole(address_account)externalonlyRole(Admin){
46 require(_account!=address(0),\"Roles:accountisthezeroddres\");
47 require(!roles[Admin][_account],\"theRolewithaddressisalreadyavailable\");
48 if(msg.sender==owner){
49_grantRole(Admin,_account);
50}else{
51 revert(\"adminnotauthorizedtograntAdminRole\");* 52 }
* 53 }
* 54
* 55 functiongrantWriteRole(address_account)externalonlyRole(Admin){
* 56 require(_account!=address(0),\"Roles:accountisthezeroddress\");
* 57 require(!roles[Write][_account],\"theRolewithaddressisalreadyavailable\");//
* 58 -_grantRole(Write,_account);
* 59 }
* 60
* 61 functiongrantReadRole(address_account)externalonlyRole(Admin){
* 62 require(_account!=address(0),\"Roles:accountisthezeroddress\");
* 63 require(!roles[Read][_account],\"theRolewithaddressisalreadyavailable\");//
* 64 -_grantRole(Read,_account);
* 65 }
* 66
* functiondeleteAdminRole(address_account)externalonlyRole(Admin){
* 68 require(roles[Admin][_account],\"theRolewithaddressisnotavailabletobedeleted\");//checkiftheaddressavailable
* 69 if(msg.sender=owner){
* 70 deleteRole(Admin,_account);
* 71 } else{
* 72 revert(\"adminnotauthorizedtodeleteowner\");
* 73 }
* 74 }
* 75
* functiondeleteWriteRole(address_account)externalonlyRole(Admin){
* 77 require(roles[Write][_account],\"theRolewithaddressisnotavailabletobedeleted\");//checkiftheaddressavailable
* 78 deleteRole(Write,_account);
* 79 }
* 80
* functiondeleteReadRole(address_account)externalonlyRole(Admin){
* 82 require(roles[Read][_account],\"theRolewithaddressisnotavailabletobedeleted\");//checkiftheaddressavailable
* 83 deleteRole(Read,_account);
* 84 }
* 85
* functiondeleteRole(bytes32_role,address_account)internalonlyRole(Admin){
* 87 if(_role=Admin){
* 88 roles[Admin][_account]=false;//falsemeansdeactivethecontent
* 89 roles[Write][_account]=false;
* 90 roles[Read][_account]=false;
* 91 } else{
* 92 roles[Write][_account]=false;
* 93 roles[Read][_account]=false;
* 94 } else{
* 95 roles[_role][_account]=false;
* 96 }
* emitRemoveRole(_role,_account);
* 98 }
* 99
* functionwrite(stringmemorytag,stringmemorydata)publiconlyRole(Write){
* 101 database.push(data);
* tagindex[tag].push(counter);
* counter++;
* 105
* functionread(stringmemorytag)publiconlyRole(Read)viewreturns(string[]memory){
* uint[]memoryindices=tagindex[tag];
* uintlength=indices.length;
* string[]memoryresult=newstring[](length);
* for(uinti=0;i<length;i++){
* stringmemoryentry=database[indices[i]];