Skip to content

Commit

Permalink
feat: issue and revoke validation (#146)
Browse files Browse the repository at this point in the history
* feat: issuance and revocation check

* refactor: issuance and revocation check
  • Loading branch information
superical authored Mar 5, 2024
1 parent 72f8acc commit 66d02ce
Show file tree
Hide file tree
Showing 2 changed files with 88 additions and 23 deletions.
17 changes: 8 additions & 9 deletions contracts/BaseDocumentStore.sol
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ contract BaseDocumentStore is Initializable {
* @notice Emitted when a document is revoked
* @param document The hash of the revoked document
*/
event DocumentRevoked(bytes32 indexed document);
event DocumentRevoked(bytes32 indexed documentRoot, bytes32 indexed document);

/**
* @notice Initialises the contract with a name
Expand All @@ -49,9 +49,9 @@ contract BaseDocumentStore is Initializable {
* @notice Issues a document
* @param document The hash of the document to issue
*/
function _issue(bytes32 document) internal onlyNotIssued(document) {
function _issue(bytes32 document) internal {
documentIssued[document] = block.number;
emit DocumentIssued(document);
// emit DocumentIssued(document);
}

/**
Expand Down Expand Up @@ -97,11 +97,8 @@ contract BaseDocumentStore is Initializable {
* @param document The hash of the document to revoke
* @return A boolean indicating whether the document was successfully revoked
*/
function _revoke(bytes32 document) internal onlyNotRevoked(document) returns (bool) {
function _revoke(bytes32 document) internal {
documentRevoked[document] = block.number;
emit DocumentRevoked(document);

return true;
}

function _bulkRevoke(bytes32[] memory documents) internal {
Expand All @@ -115,7 +112,7 @@ contract BaseDocumentStore is Initializable {
* @param document The hash of the document to check
* @return A boolean indicating whether the document has been revoked
*/
function isRevoked(bytes32 document) public view returns (bool) {
function _isRevoked(bytes32 document) internal view returns (bool) {
return documentRevoked[document] != 0;
}

Expand Down Expand Up @@ -143,6 +140,7 @@ contract BaseDocumentStore is Initializable {
* @param document The hash of the document to check
*/
modifier onlyNotIssued(bytes32 document) {
// TODO: TO BE REMOVED
require(!isIssued(document), "Error: Only hashes that have not been issued can be issued");
_;
}
Expand All @@ -152,7 +150,8 @@ contract BaseDocumentStore is Initializable {
* @param claim The hash of the document to check
*/
modifier onlyNotRevoked(bytes32 claim) {
require(!isRevoked(claim), "Error: Hash has been revoked previously");
// TODO: TO BE REMOVED
require(!_isRevoked(claim), "Error: Hash has been revoked previously");
_;
}
}
94 changes: 80 additions & 14 deletions contracts/DocumentStore.sol
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,11 @@ import "./base/DocumentStoreAccessControl.sol";
* @notice A contract for storing and revoking documents with access control
*/
contract DocumentStore is DocumentStoreAccessControl, BaseDocumentStore {
error InactiveDocument(bytes32 documentRoot, bytes32 document);
error DocumentAlreadyRevoked(bytes32 document);
error DocumentAlreadyIssued(bytes32 document);
error InvalidDocument();

using MerkleProof for bytes32[];

/**
Expand All @@ -39,8 +44,14 @@ contract DocumentStore is DocumentStoreAccessControl, BaseDocumentStore {
* @notice Issues a document
* @param document The hash of the document to issue
*/
function issue(bytes32 documentRoot) public onlyRole(ISSUER_ROLE) onlyNotIssued(document) {
function issue(bytes32 documentRoot) public onlyRole(ISSUER_ROLE) {
if (isRootIssued(documentRoot)) {
revert DocumentAlreadyIssued(documentRoot);
}

_issue(documentRoot);

emit DocumentIssued(documentRoot);
}

/**
Expand All @@ -56,35 +67,90 @@ contract DocumentStore is DocumentStoreAccessControl, BaseDocumentStore {
* @param document The hash of the document to revoke
* @return A boolean indicating whether the revocation was successful
*/
function revoke(bytes32 document) public onlyRole(REVOKER_ROLE) onlyNotRevoked(document) returns (bool) {
return _revoke(document);
function revokeRoot(bytes32 documentRoot) public onlyRole(REVOKER_ROLE) {
revoke(documentRoot, documentRoot, new bytes32[](0));
}

function revoke(
bytes32 documentRoot,
bytes32 document,
bytes32[] memory proof
) public onlyRole(REVOKER_ROLE) {
bool isActive = isActive(documentRoot, document, proof);
if (!isActive) {
revert InActiveDocument(documentRoot, document);
}
_revoke(document);
emit DocumentRevoked(documentRoot, document);
}

/**
* @notice Revokes documents in bulk
* @param documents The hashes of the documents to revoke
*/
function bulkRevoke(bytes32[] memory documents) public onlyRole(REVOKER_ROLE) {
return _bulkRevoke(documents);
function bulkRevoke(
bytes32[] documentRoots,
bytes32[] documents,
bytes32[][] memory proofs
) public onlyRole(REVOKER_ROLE) {
for (uint256 i = 0; i < documentRoots.length; i++) {
revoke(documentRoots[i], documents[i], proofs[i]);
}
}

function bulkRevokeRoot(bytes32[] documentRoots, bytes32[][] memory proofs) public onlyRole(REVOKER_ROLE) {
for (uint256 i = 0; i < documentRoots.length; i++) {
revoke(documentRoots[i], documentRoots[i], proofs[i]);
}
}

function isIssued(
bytes32 documentRoot,
bytes32 document,
bytes32[] memory proof
) public view returns (bool) {
require(document != 0x0 && documentRoot != 0x0, "Invalid document");
) public view onlyValidDocument(documentRoot, document) returns (bool) {
if (documentRoot == document && proof.length == 0) {
return _isIssued(document) && !isRevoked(document);
return _isIssued(document);
}
return
_isIssued(documentRoot) &&
!isRevoked(documentRoot) &&
!isRevoked(document) &&
proof.verify(documentRoot, document);
return _isIssued(documentRoot) && proof.verify(documentRoot, document);
}

function isIssued(bytes32 documentRoot) public view returns (bool) {
function isRootIssued(bytes32 documentRoot) public view returns (bool) {
return isIssued(documentRoot, documentRoot, new bytes32[](0));
}

function isRevoked(
bytes32 documentRoot,
bytes32 document,
bytes32[] memory proof
) public view onlyValidDocument(documentRoot, document) returns (bool) {
if (documentRoot == document && proof.length == 0) {
return _isRevoked(document);
}
return (_isRevoked(documentRoot) || _isRevoked(document)) && proof.verify(documentRoot, document);
}

/**
* @notice Checks if a document has been revoked
* @param document The hash of the document to check
* @return A boolean indicating whether the document has been revoked
*/
function isRootRevoked(bytes32 documentRoot) public view returns (bool) {
return isRevoked(documentRoot, documentRoot, new bytes32[](0));
}

function isActive(
bytes32 documentRoot,
bytes32 document,
bytes32[] memory proof
) public view returns (bool) {
return isIssued(documentRoot, document, proof) && !isRevoked(documentRoot, document, proof);
}

modifier onlyValidDocument(bytes32 documentRoot, bytes32 document) {
if (document == 0x0 || documentRoot == 0x0) {
revert InvalidDocument();
}
_;
}
}

0 comments on commit 66d02ce

Please sign in to comment.