Ethereum Blockchain – Ideal Way to Store Hash Using Solidity

blockchaincontract-designdatabasehashsolidity

I would like to store a certificate on the blockchain. I only need to store its hash and if its been verified by both parties or not.

Should I create a struct that is made up of bytes32 for the hash, and a boolean to see if its confirmed or not. And then create a mapping of this struct. Do I need some sort of ID for the mapping? to map the id with the struct?

The certificate would be aimed for person X and his public key would be known on the frontend. This person will then have to sign with his private key and if its been signed then the boolean value should be set to true.

I will be using a database to store all the data. Upon someone searching for the certificate. The data will be pulled from the database. Hash the data and then confirm that the hash is on the blockchain.

On a side note: If i require permissions for different users, should the permissions be on the blockchain, in the struct I add a variable to store all the public keys that have permission to view this certificate.

This is what I think the frontend would look like:

     hashedData = web3.utils.sha3(JSON.stringify(certificate));
contracts.mycontract.deployed().then(function(result) {
           return result.createCertificate(public_addresskey,hashedData,{ from: account }); //get logged in public key from metamask 
         }).then(function(result) {
            //send post request to backend to create db entry

         }).catch(function(err) {
           console.error(err);
           // show error to the user.
         });

Best Answer

The contract might look something like the sketch below.

There is a struct to contain everything but the id. A mapping from hash => Cert for random access (using the hash as id) and a certList to enumerate the certificates in case the hash isn't known. That should not happen because it emits events for each important state change. I left out access control to keep it brief. You would probably want to protect the newCert() function with onlyOwner, a whiteList or role-based access control.

To "confirm" a cert, the recipient confirms by signing a transaction. The existence of a true in this field shows that the user mentioned did indeed sign because there is no other way for this to occur.

pragma solidity 0.5.1;

contract Certificates {

    struct Cert {
        address recipient;
        bool confirmed;
    }

    mapping(bytes32 => Cert) public certs;
    bytes32[] public certList;

    event LogNewCert(address sender, bytes32 cert, address recipient);
    event LogConfirmed(address sender, bytes32 cert);

    function isCert(bytes32 cert) public view returns(bool isIndeed) {
        if(cert == 0) return false;
        return certs[cert].recipient != address(0);
    }

    function createCert(bytes32 cert, address recipient) public {
        require(recipient != address(0));
        require(!isCert(cert));
        Cert storage c = certs[cert];
        c.recipient = recipient;
        certList.push(cert);
        emit LogNewCert(msg.sender, cert, recipient);
    }

    function confirmCert(bytes32 cert) public {
        require(certs[cert].recipient == msg.sender);
        require(certs[cert].confirmed == false);
        certs[cert].confirmed = true;
        emit LogConfirmed(msg.sender, cert);
    }

    function isUserCert(bytes32 cert, address user) public view returns(bool) {
        if(!isCert(cert)) return false;
        if(certs[cert].recipient != user) return false;
        return certs[cert].confirmed;
    }
}

Hope it helps.

Related Topic