Skip to content

Instantly share code, notes, and snippets.

@fengkiej
Created July 29, 2019 12:39
Show Gist options
  • Save fengkiej/9bac2f6cc32cd9c4df01fda33ef96daa to your computer and use it in GitHub Desktop.
Save fengkiej/9bac2f6cc32cd9c4df01fda33ef96daa to your computer and use it in GitHub Desktop.
Created using remix-ide: Realtime Ethereum Contract Compiler and Runtime. Load this file by pasting this gists URL or ID at https://remix.ethereum.org/#version=soljson-v0.5.2+commit.1df8f40c.js&optimize=false&gist=
pragma solidity ^0.5.0;
pragma experimental ABIEncoderV2;
//self sign
import "./ConsensusContract.sol";
contract CertificationContract {
enum CertificationType {
NONE, N2A, A2A, A2U
}
enum AccountType {
NONE, NATIONAL_LAB, ACCREDITED_LAB, USER
}
struct Account {
string name;
AccountType accountType;
uint256[] certHashes;
}
struct Certificate {
string accrediationNo;
string calibrationCertNo;
string[2] uri;
address issuedBy;
address issuedTo;
uint256 issuedOn;
uint256 expiredOn;
uint256 parentCertificate;
CertificationType certType;
}
ConsensusContract consensusContract;
bool setup;
string public measurementType;
mapping (uint256 => Certificate) public certs;
mapping (address => Account) public accounts;
modifier onlyByConsensus() {
require(msg.sender == address(consensusContract));
_;
}
modifier onlyOnce() {
require(setup == false);
_;
}
constructor(string memory _measurementType) public {
measurementType = _measurementType;
}
function setupConsensusContract(ConsensusContract _consensusContract) public onlyOnce {
consensusContract = _consensusContract;
setup = true;
}
function registerCertificate(uint256 _certificateHash, string memory _accrediationNumber, string memory _calibrationCertNumber,
string[2] memory _uri, address _to, uint256 _expiredOn, CertificationType _certType, uint256 _signUsingCertHash) public {
require(accounts[msg.sender].accountType == AccountType.NATIONAL_LAB || accounts[msg.sender].accountType == AccountType.ACCREDITED_LAB);
require(_expiredOn >= now);
if(accounts[msg.sender].accountType != AccountType.NATIONAL_LAB) {
require(isValid(_signUsingCertHash));
require(certs[_signUsingCertHash].issuedTo == msg.sender);
}
if(_certType == CertificationType.N2A) {
require(accounts[msg.sender].accountType == AccountType.NATIONAL_LAB);
require(accounts[_to].accountType == AccountType.ACCREDITED_LAB);
_registerCertificate(_certificateHash, _accrediationNumber, _calibrationCertNumber, _uri, _to, _expiredOn, _certType, _signUsingCertHash);
} else if (_certType == CertificationType.A2A) {
require(accounts[msg.sender].accountType == AccountType.ACCREDITED_LAB);
require(accounts[_to].accountType == AccountType.ACCREDITED_LAB);
_registerCertificate(_certificateHash, _accrediationNumber, _calibrationCertNumber, _uri, _to, _expiredOn, _certType, _signUsingCertHash);
} else if (_certType == CertificationType.A2U) {
require(accounts[msg.sender].accountType == AccountType.ACCREDITED_LAB);
require(accounts[_to].accountType == AccountType.USER);
_registerCertificate(_certificateHash, _accrediationNumber, _calibrationCertNumber, _uri, _to, _expiredOn, _certType, _signUsingCertHash);
} else {
revert();
}
}
function _registerCertificate(uint256 _certificateHash, string memory _accrediationNumber, string memory _calibrationCertNumber,
string[2] memory _uri, address _to, uint256 _expiredOn, CertificationType _certType, uint256 _signUsingCertHash) internal {
Certificate memory cert = Certificate(_accrediationNumber, _calibrationCertNumber, _uri, msg.sender, _to, now, _expiredOn, _signUsingCertHash, _certType);
require(certs[_certificateHash].issuedBy == address(0));
certs[_certificateHash] = cert;
accounts[_to].certHashes.push(_certificateHash);
}
function registerAccount(string memory _name, AccountType _accountType) public {
require(accounts[msg.sender].accountType == AccountType.NONE);
require(_accountType != AccountType.NATIONAL_LAB);
uint256[] memory empty;
accounts[msg.sender] = Account(_name, _accountType, empty);
}
function registerNationalLab(string calldata _name, address _newNationalLab) external onlyByConsensus {
accounts[_newNationalLab].accountType = AccountType.NATIONAL_LAB;
accounts[_newNationalLab].name = _name;
}
function getAccountCertificates() public view returns (uint256[] memory) {
return accounts[msg.sender].certHashes;
}
function getValidAccountCertificates() public view returns (uint256[] memory) {
/*uint256[] memory certList = accounts[msg.sender].certHashes;
//uint256[] memory result = new uint256[](certList.length);
for(uint256 i = 0; i < certList.length; i++) {
if(isValid(certList[i])) result[i] = certList[i];
}
return result;*/
}
function getParentCertificate(uint256 _hash) public view returns (uint256) {
return certs[_hash].parentCertificate;
}
function isValid(uint256 _hash) public view returns (bool) {
Certificate memory cert = certs[_hash];
return (now < cert.expiredOn || now > cert.issuedOn);
}
function getNow() public view returns (uint256) {
return now;
}
function traceCert(uint256 _hash) public view returns (uint256[8] memory) {
uint8 loc = 0;
Account memory issuer = accounts[certs[getParentCertificate(_hash)].issuedBy];
uint256[8] memory parentCertificates;
parentCertificates[loc]= _hash;
while(issuer.accountType != AccountType.NATIONAL_LAB) {
_hash = getParentCertificate(_hash);
issuer = accounts[certs[getParentCertificate(_hash)].issuedBy];
parentCertificates[++loc] = _hash;
}
return parentCertificates;
}
function revokeCertificate(uint256 _hash) public {
Certificate memory cert = certs[_hash];
require(msg.sender == cert.issuedBy);
delete certs[_hash];
}
}
pragma solidity ^0.5.0;
pragma experimental ABIEncoderV2;
//remove member function
//no double voting
//new consortium for future work
import "./CertificationContract.sol";
contract ConsensusContract {
struct Member {
string name;
uint256 consortiumID;
}
struct Proposal {
address newMemberAddress;
string name;
uint256 consortiumID;
uint256 confirmationsRequired;
}
CertificationContract certificationContract;
//consortiums maps from consortiumID to consortiumName, it starts at 1
mapping (uint256 => string) public consortiums;
mapping (address => Member) public consortiumMembers;
mapping (uint256 => Proposal) public proposals;
uint256 lastProposalID;
uint256[8] public numberofConsortiumMembers;
modifier onlyConsortiumMember(uint256 consortiumID) {
require(consortiumMembers[msg.sender].consortiumID == consortiumID);
_;
}
constructor(CertificationContract _certificationContract, address[] memory _seedMemberAddresses, string[] memory _seedMemberNames,uint256[] memory _seedMemberConsortiums) public {
require(_seedMemberAddresses.length == _seedMemberNames.length);
require(_seedMemberAddresses.length == _seedMemberConsortiums.length);
certificationContract = _certificationContract;
certificationContract.setupConsensusContract(this);
for(uint256 i = 0; i < _seedMemberAddresses.length; i++) {
_addNewMember(_seedMemberAddresses[i], _seedMemberNames[i], _seedMemberConsortiums[i]);
}
}
function proposeNewMember(address _newMemberAddress, string memory _name, uint256 _consortiumID) public onlyConsortiumMember(_consortiumID) {
require(_consortiumID != 0);
Proposal memory newProposal = Proposal(_newMemberAddress, _name, _consortiumID, numberofConsortiumMembers[_consortiumID]);
proposals[lastProposalID] = newProposal;
lastProposalID++;
}
function confirmProposal(uint256 _proposalID) public {
require(proposals[_proposalID].consortiumID == consortiumMembers[msg.sender].consortiumID);
proposals[_proposalID].confirmationsRequired--;
if(proposals[_proposalID].confirmationsRequired == 0 && proposals[_proposalID].newMemberAddress != address(0)) {
_addNewMember(proposals[_proposalID].newMemberAddress, proposals[_proposalID].name, proposals[_proposalID].consortiumID);
}
}
function _addNewMember(address _newMemberAddress, string memory _name, uint256 _consortiumID) internal {
Member memory newMember = Member(_name, _consortiumID);
consortiumMembers[_newMemberAddress] = newMember;
numberofConsortiumMembers[_consortiumID]++;
certificationContract.registerNationalLab(_name, _newMemberAddress);
}
}
//assumption 1: National Lab issuers are selected by consensus on MultisigConsensus.sol.
//assumption 2: ////reviseEach issuer can only have one certificate, it is replacable if the issuer releases it's current certificate.
//assumption 3: Issuing party may revoke a certificate.
//assumption 4: The validity of a certificate trickles down. --revise
//assumption 5: Every type of issuer can issue certs.
//assumption 6: uri file visibility is determined on the server.
//assumption 7: Issuer can't issue beyond it's current expiredOn.
//assumption 8: ACCREDITED_LAB must have accreditaion number
//asssmption 9: one deployed contract can support 1 measurement
//notes: national lab is part of what? non-issuer indexing per benua
//print: issuance, url[2], validity, company name, expiry, calibrationno, accreditaion no,
//tracevalidity
pragma solidity ^0.5.1;
contract CalibrationCertification {
address multisigConsensusContractAddress;
enum IssuerType {
NONE, NATIONAL_LAB, ACCREDITED_LAB, USER
}
enum CertificationType {
NONE, N2A, A2A, A2U
}
struct Issuer {
string name;
IssuerType issuerType;
uint256 certHash;
}
struct Certificate {
string accrediationNo;
string calibrationCertNo;
string uri;
address issuedBy;
address issuedTo;
uint256 issuedOn;
uint256 expiredOn;
CertificationType certType;
}
mapping (uint256 => Certificate) certs;
mapping (address => Issuer) public issuers;
modifier onlyByConsensus() {
require(msg.sender == multisigConsensusContractAddress);
_;
}
constructor(address _multisigConsensusContractAddress) public {
multisigConsensusContractAddress = _multisigConsensusContractAddress;
}
function registerCertificate(uint256 _hash, string memory _uri, address _to,
uint256 _expiredOn, CertificationType _certType) public {
require(isValid(issuers[msg.sender].certHash));
require(issuers[_to].certHash == 0);
require(_expiredOn < certs[(issuers[msg.sender].certHash)].expiredOn);
if(_certType == CertificationType.N2A) {
require(issuers[msg.sender].issuerType == IssuerType.NATIONAL_LAB);
_registerCertificate(_hash, _uri, _to, now, _expiredOn, _certType);
_registerCertToReceiver(_to, IssuerType.ACCREDITED_LAB, _hash);
}
else if(_certType == CertificationType.A2A) {
require(issuers[msg.sender].issuerType == IssuerType.ACCREDITED_LAB);
_registerCertificate(_hash, _uri, _to, now, _expiredOn, _certType);
_registerCertToReceiver(_to, IssuerType.ACCREDITED_LAB, _hash);
}
else if(_certType == CertificationType.A2U) {
require(issuers[msg.sender].issuerType == IssuerType.ACCREDITED_LAB);
_registerCertificate(_hash, _uri, _to, now, _expiredOn, _certType);
_registerCertToReceiver(_to, IssuerType.USER, _hash);
}
else {
revert();
}
}
function revokeCertificate(uint256 _hash) public {
Certificate memory cert = certs[_hash];
require(msg.sender == cert.issuedBy);
issuers[cert.issuedTo].certHash = 0;
delete certs[_hash];
}
function isExpired(uint256 _hash) public view returns (bool) {
Certificate memory cert = certs[_hash];
return now > cert.expiredOn;
}
function getParentIssuer(uint256 _hash) internal view returns (address) {
return certs[_hash].issuedBy;
}
function traceCert(uint256 _hash) public view returns (uint256[8] memory) {
uint8 loc = 0;
Issuer memory issuer = issuers[getParentIssuer(_hash)];
uint256[8] memory parentCertificates;
parentCertificates[loc]= _hash;
while(issuer.issuerType != IssuerType.NATIONAL_LAB) {
_hash = issuer.certHash;
issuer = issuers[getParentIssuer(_hash)];
parentCertificates[++loc] = _hash;
}
return parentCertificates;
}
function _registerCertificate(uint256 _hash, string memory _uri, address _to, uint256 _issuedOn, uint256 _expiredOn, CertificationType _certType) internal {
Certificate memory cert = Certificate(" ", " ", _uri, msg.sender, _to, _issuedOn, _expiredOn, _certType);
require(certs[_hash].issuedBy == address(0));
certs[_hash] = cert;
}
function registerAsIssuer(string memory _name) public {
issuers[msg.sender] = Issuer(_name, IssuerType.NONE, 0);
}
function _registerCertToReceiver(address _to, IssuerType _issuerType, uint256 _hash) public {
require(bytes(issuers[_to].name).length > 0);
issuers[_to].issuerType = _issuerType;
issuers[_to].certHash = _hash;
}
function issuerName(address _addr) public view returns (string memory) {
return issuers[_addr].name;
}
function renewCertificate(uint256 _hash, uint256 _expiredOn) public {
require(certs[_hash].issuedBy == msg.sender);
certs[_hash].expiredOn = _expiredOn;
}
function registerNationalLab(address _newNationalLab) public onlyByConsensus {
require(bytes(issuers[_newNationalLab].name).length > 0);
issuers[_newNationalLab].issuerType = IssuerType.NATIONAL_LAB;
}
function isValid(uint256 _hash) public view returns (bool) {
bool parentValidity = true;
Issuer memory issuer = issuers[getParentIssuer(_hash)];
Certificate memory cert;
bool certValidity = !isExpired(_hash) && (certs[_hash].issuedOn > 0);
while(issuer.issuerType != IssuerType.NATIONAL_LAB) {
_hash = issuer.certHash;
cert = certs[_hash];
if(isExpired(_hash) || cert.issuedOn == 0) {
parentValidity = false;
break;
}
issuer = issuers[getParentIssuer(_hash)];
}
return certValidity && parentValidity;
}
function issuerCertHash(address _issuer) public view returns (uint256) {
return issuers[_issuer].certHash;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment