mirror of
https://github.com/0xbow-io/privacy-pools-core.git
synced 2026-01-10 09:58:00 -05:00
fix: update the updateRoot method to accept a string instead of bytes32 (#56)
This commit is contained in:
@@ -67,8 +67,8 @@ contract UpdateRoot is Script {
|
||||
// @notice The deployed Entrypoint
|
||||
Entrypoint public entrypoint;
|
||||
|
||||
// @notice Placeholder IPFS hash
|
||||
bytes32 public IPFS_HASH = keccak256('ipfs_hash');
|
||||
// @notice Placeholder IPFS CID
|
||||
string public IPFS_CID = 'ipfs_cid_ipfs_cid_ipfs_cid_ipfs_cid_ipfs_cid_';
|
||||
// @notice New computed root
|
||||
uint256 public newRoot;
|
||||
|
||||
@@ -96,7 +96,7 @@ contract UpdateRoot is Script {
|
||||
vm.startBroadcast();
|
||||
|
||||
// Update root
|
||||
entrypoint.updateRoot(newRoot, IPFS_HASH);
|
||||
entrypoint.updateRoot(newRoot, IPFS_CID);
|
||||
|
||||
vm.stopBroadcast();
|
||||
}
|
||||
|
||||
@@ -87,16 +87,17 @@ contract Entrypoint is AccessControlUpgradeable, UUPSUpgradeable, ReentrancyGuar
|
||||
//////////////////////////////////////////////////////////////*/
|
||||
|
||||
/// @inheritdoc IEntrypoint
|
||||
function updateRoot(uint256 _root, bytes32 _ipfsHash) external onlyRole(_ASP_POSTMAN) returns (uint256 _index) {
|
||||
function updateRoot(uint256 _root, string memory _ipfsCID) external onlyRole(_ASP_POSTMAN) returns (uint256 _index) {
|
||||
// Check provided values are non-zero
|
||||
if (_root == 0) revert EmptyRoot();
|
||||
if (_ipfsHash == 0) revert EmptyIPFSHash();
|
||||
uint256 _cidLength = bytes(_ipfsCID).length;
|
||||
if (_cidLength < 32 || _cidLength > 64) revert InvalidIPFSCIDLength();
|
||||
|
||||
// Push new association set and update index
|
||||
associationSets.push(AssociationSetData(_root, _ipfsHash, block.timestamp));
|
||||
associationSets.push(AssociationSetData(_root, _ipfsCID, block.timestamp));
|
||||
_index = associationSets.length - 1;
|
||||
|
||||
emit RootUpdated(_root, _ipfsHash, block.timestamp);
|
||||
emit RootUpdated(_root, _ipfsCID, block.timestamp);
|
||||
}
|
||||
|
||||
/*///////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -43,12 +43,14 @@ interface IEntrypoint {
|
||||
/**
|
||||
* @notice Struct for the onchain association set data
|
||||
* @param root The ASP root
|
||||
* @param ipfsHash The IPFS hash of the ASP data
|
||||
* @param ipfsCID The IPFS v1 CID of the ASP data. A content-addressed identifier computed by hashing
|
||||
* the content with SHA-256, adding multicodec/multihash prefixes, and encoding in base32/58.
|
||||
* This uniquely identifies data by its content rather than location.
|
||||
* @param timestamp The timestamp on which the root was updated
|
||||
*/
|
||||
struct AssociationSetData {
|
||||
uint256 root;
|
||||
bytes32 ipfsHash;
|
||||
string ipfsCID;
|
||||
uint256 timestamp;
|
||||
}
|
||||
|
||||
@@ -59,10 +61,10 @@ interface IEntrypoint {
|
||||
/**
|
||||
* @notice Emitted when pushing a new root to the association root set
|
||||
* @param _root The latest ASP root
|
||||
* @param _ipfsHash The IPFS hash of the association set data
|
||||
* @param _ipfsCID The IPFS CID of the association set data
|
||||
* @param _timestamp The timestamp of root update
|
||||
*/
|
||||
event RootUpdated(uint256 _root, bytes32 _ipfsHash, uint256 _timestamp);
|
||||
event RootUpdated(uint256 _root, string _ipfsCID, uint256 _timestamp);
|
||||
|
||||
/**
|
||||
* @notice Emitted when pushing a new root to the association root set
|
||||
@@ -186,9 +188,9 @@ interface IEntrypoint {
|
||||
error InvalidPoolState();
|
||||
|
||||
/**
|
||||
* @notice Thrown when trying to push a root with an empty IPFS hash
|
||||
* @notice Thrown when trying to push a an IPFS CID with an invalid length
|
||||
*/
|
||||
error EmptyIPFSHash();
|
||||
error InvalidIPFSCIDLength();
|
||||
|
||||
/**
|
||||
* @notice Thrown when trying to push a root with an empty root
|
||||
@@ -244,10 +246,10 @@ interface IEntrypoint {
|
||||
/**
|
||||
* @notice Push a new root to the association root set
|
||||
* @param _root The new ASP root
|
||||
* @param _ipfsHash The IPFS hash of the association set data
|
||||
* @param _ipfsCID The IPFS v1 CID of the association set data
|
||||
* @return _index The index of the newly added root
|
||||
*/
|
||||
function updateRoot(uint256 _root, bytes32 _ipfsHash) external returns (uint256 _index);
|
||||
function updateRoot(uint256 _root, string memory _ipfsCID) external returns (uint256 _index);
|
||||
|
||||
/**
|
||||
* @notice Make a native asset deposit into the Privacy Pool
|
||||
@@ -354,10 +356,13 @@ interface IEntrypoint {
|
||||
* @notice Returns the association set data at an index
|
||||
* @param _index The index of the array
|
||||
* @return _root The updated ASP root
|
||||
* @return _ipfsHash The IPFS hash for the association set data
|
||||
* @return _ipfsCID The IPFS v1 CID for the association set data
|
||||
* @return _timestamp The timestamp of the root update
|
||||
*/
|
||||
function associationSets(uint256 _index) external view returns (uint256 _root, bytes32 _ipfsHash, uint256 _timestamp);
|
||||
function associationSets(uint256 _index)
|
||||
external
|
||||
view
|
||||
returns (uint256 _root, string memory _ipfsCID, uint256 _timestamp);
|
||||
|
||||
/**
|
||||
* @notice Returns the latest ASP root
|
||||
|
||||
@@ -27,7 +27,7 @@ contract IntegrationERC20 is IntegrationBase {
|
||||
|
||||
// Push ASP root with label included
|
||||
vm.prank(_POSTMAN);
|
||||
_entrypoint.updateRoot(_shadowASPMerkleTree._root(), bytes32('IPFS_HASH'));
|
||||
_entrypoint.updateRoot(_shadowASPMerkleTree._root(), 'ipfs_cid_ipfs_cid_ipfs_cid_ipfs_cid_ipfs_cid_ipfs_cid');
|
||||
|
||||
// Bob withdraws the total amount of Alice's commitment
|
||||
_selfWithdraw(
|
||||
@@ -53,7 +53,7 @@ contract IntegrationERC20 is IntegrationBase {
|
||||
|
||||
// Push ASP root with label included
|
||||
vm.prank(_POSTMAN);
|
||||
_entrypoint.updateRoot(_shadowASPMerkleTree._root(), bytes32('IPFS_HASH'));
|
||||
_entrypoint.updateRoot(_shadowASPMerkleTree._root(), 'ipfs_cid_ipfs_cid_ipfs_cid_ipfs_cid_ipfs_cid_ipfs_cid');
|
||||
|
||||
// Bob receives the total amount of Alice's commitment
|
||||
_withdrawThroughRelayer(
|
||||
@@ -79,7 +79,7 @@ contract IntegrationERC20 is IntegrationBase {
|
||||
|
||||
// Push ASP root with label included
|
||||
vm.prank(_POSTMAN);
|
||||
_entrypoint.updateRoot(_shadowASPMerkleTree._root(), bytes32('IPFS_HASH'));
|
||||
_entrypoint.updateRoot(_shadowASPMerkleTree._root(), 'ipfs_cid_ipfs_cid_ipfs_cid_ipfs_cid_ipfs_cid_ipfs_cid');
|
||||
|
||||
// Bob withdraws 2000 DAI of Alice's commitment
|
||||
_selfWithdraw(
|
||||
@@ -105,7 +105,7 @@ contract IntegrationERC20 is IntegrationBase {
|
||||
|
||||
// Push ASP root with label included
|
||||
vm.prank(_POSTMAN);
|
||||
_entrypoint.updateRoot(_shadowASPMerkleTree._root(), bytes32('IPFS_HASH'));
|
||||
_entrypoint.updateRoot(_shadowASPMerkleTree._root(), 'ipfs_cid_ipfs_cid_ipfs_cid_ipfs_cid_ipfs_cid_ipfs_cid');
|
||||
|
||||
// Withdraw 2000 DAI to Bob
|
||||
_commitment = _selfWithdraw(
|
||||
@@ -167,7 +167,7 @@ contract IntegrationERC20 is IntegrationBase {
|
||||
|
||||
// Push ASP root with label included
|
||||
vm.prank(_POSTMAN);
|
||||
_entrypoint.updateRoot(_shadowASPMerkleTree._root(), bytes32('IPFS_HASH'));
|
||||
_entrypoint.updateRoot(_shadowASPMerkleTree._root(), 'ipfs_cid_ipfs_cid_ipfs_cid_ipfs_cid_ipfs_cid_ipfs_cid');
|
||||
|
||||
// Bob receives half of Alice's commitment
|
||||
_withdrawThroughRelayer(
|
||||
@@ -193,7 +193,7 @@ contract IntegrationERC20 is IntegrationBase {
|
||||
|
||||
// Push ASP root with label included
|
||||
vm.prank(_POSTMAN);
|
||||
_entrypoint.updateRoot(_shadowASPMerkleTree._root(), bytes32('IPFS_HASH'));
|
||||
_entrypoint.updateRoot(_shadowASPMerkleTree._root(), 'ipfs_cid_ipfs_cid_ipfs_cid_ipfs_cid_ipfs_cid_ipfs_cid');
|
||||
|
||||
// Withdraw 2000 DAI to Bob
|
||||
_commitment = _withdrawThroughRelayer(
|
||||
@@ -255,7 +255,9 @@ contract IntegrationERC20 is IntegrationBase {
|
||||
|
||||
// Push ASP root without label
|
||||
vm.prank(_POSTMAN);
|
||||
_entrypoint.updateRoot(uint256(keccak256('some_root')) % SNARK_SCALAR_FIELD, bytes32('IPFS_HASH'));
|
||||
_entrypoint.updateRoot(
|
||||
uint256(keccak256('some_root')) % SNARK_SCALAR_FIELD, 'ipfs_cid_ipfs_cid_ipfs_cid_ipfs_cid_ipfs_cid_ipfs_cid'
|
||||
);
|
||||
|
||||
// Fail to withdraw
|
||||
_withdrawThroughRelayer(
|
||||
@@ -284,7 +286,7 @@ contract IntegrationERC20 is IntegrationBase {
|
||||
|
||||
// Push ASP root with label included
|
||||
vm.prank(_POSTMAN);
|
||||
_entrypoint.updateRoot(_shadowASPMerkleTree._root(), bytes32('IPFS_HASH'));
|
||||
_entrypoint.updateRoot(_shadowASPMerkleTree._root(), 'ipfs_cid_ipfs_cid_ipfs_cid_ipfs_cid_ipfs_cid_ipfs_cid');
|
||||
|
||||
// Withdraw 4000 DAI through relayer
|
||||
_commitment = _withdrawThroughRelayer(
|
||||
@@ -300,7 +302,9 @@ contract IntegrationERC20 is IntegrationBase {
|
||||
|
||||
// Remove label from ASP
|
||||
vm.prank(_POSTMAN);
|
||||
_entrypoint.updateRoot(uint256(keccak256('some_root')) % SNARK_SCALAR_FIELD, bytes32('IPFS_HASH'));
|
||||
_entrypoint.updateRoot(
|
||||
uint256(keccak256('some_root')) % SNARK_SCALAR_FIELD, 'ipfs_cid_ipfs_cid_ipfs_cid_ipfs_cid_ipfs_cid_ipfs_cid'
|
||||
);
|
||||
|
||||
// Fail to withdraw
|
||||
_withdrawThroughRelayer(
|
||||
@@ -329,7 +333,7 @@ contract IntegrationERC20 is IntegrationBase {
|
||||
|
||||
// Push ASP root with label included
|
||||
vm.prank(_POSTMAN);
|
||||
_entrypoint.updateRoot(_shadowASPMerkleTree._root(), bytes32('IPFS_HASH'));
|
||||
_entrypoint.updateRoot(_shadowASPMerkleTree._root(), 'ipfs_cid_ipfs_cid_ipfs_cid_ipfs_cid_ipfs_cid_ipfs_cid');
|
||||
|
||||
// Fully spend child commitment
|
||||
_selfWithdraw(
|
||||
@@ -370,7 +374,7 @@ contract IntegrationERC20 is IntegrationBase {
|
||||
|
||||
// Push ASP root with label included
|
||||
vm.prank(_POSTMAN);
|
||||
_entrypoint.updateRoot(_shadowASPMerkleTree._root(), bytes32('IPFS_HASH'));
|
||||
_entrypoint.updateRoot(_shadowASPMerkleTree._root(), 'ipfs_cid_ipfs_cid_ipfs_cid_ipfs_cid_ipfs_cid_ipfs_cid');
|
||||
|
||||
// Fail to withdraw commitment that was already ragequitted
|
||||
_selfWithdraw(
|
||||
|
||||
@@ -23,7 +23,7 @@ contract IntegrationNative is IntegrationBase {
|
||||
|
||||
// Push ASP root with label included
|
||||
vm.prank(_POSTMAN);
|
||||
_entrypoint.updateRoot(_shadowASPMerkleTree._root(), bytes32('IPFS_HASH'));
|
||||
_entrypoint.updateRoot(_shadowASPMerkleTree._root(), 'ipfs_cid_ipfs_cid_ipfs_cid_ipfs_cid_ipfs_cid_ipfs_cid');
|
||||
|
||||
// Bob withdraws the total amount of Alice's commitment
|
||||
_selfWithdraw(
|
||||
@@ -49,7 +49,7 @@ contract IntegrationNative is IntegrationBase {
|
||||
|
||||
// Push ASP root with label included
|
||||
vm.prank(_POSTMAN);
|
||||
_entrypoint.updateRoot(_shadowASPMerkleTree._root(), bytes32('IPFS_HASH'));
|
||||
_entrypoint.updateRoot(_shadowASPMerkleTree._root(), 'ipfs_cid_ipfs_cid_ipfs_cid_ipfs_cid_ipfs_cid_ipfs_cid');
|
||||
|
||||
// Bob receives withdraws total amount of Alice's commitment through a relayer
|
||||
_withdrawThroughRelayer(
|
||||
@@ -75,7 +75,7 @@ contract IntegrationNative is IntegrationBase {
|
||||
|
||||
// Push ASP root with label included
|
||||
vm.prank(_POSTMAN);
|
||||
_entrypoint.updateRoot(_shadowASPMerkleTree._root(), bytes32('IPFS_HASH'));
|
||||
_entrypoint.updateRoot(_shadowASPMerkleTree._root(), 'ipfs_cid_ipfs_cid_ipfs_cid_ipfs_cid_ipfs_cid_ipfs_cid');
|
||||
|
||||
// Bob withdraws the total amount of Alice's commitment
|
||||
_selfWithdraw(
|
||||
@@ -101,7 +101,7 @@ contract IntegrationNative is IntegrationBase {
|
||||
|
||||
// Push ASP root with label included
|
||||
vm.prank(_POSTMAN);
|
||||
_entrypoint.updateRoot(_shadowASPMerkleTree._root(), bytes32('IPFS_HASH'));
|
||||
_entrypoint.updateRoot(_shadowASPMerkleTree._root(), 'ipfs_cid_ipfs_cid_ipfs_cid_ipfs_cid_ipfs_cid_ipfs_cid');
|
||||
|
||||
// Withdraw 20 ETH to Bob
|
||||
_commitment = _selfWithdraw(
|
||||
@@ -175,7 +175,7 @@ contract IntegrationNative is IntegrationBase {
|
||||
|
||||
// Push ASP root with label included
|
||||
vm.prank(_POSTMAN);
|
||||
_entrypoint.updateRoot(_shadowASPMerkleTree._root(), bytes32('IPFS_HASH'));
|
||||
_entrypoint.updateRoot(_shadowASPMerkleTree._root(), 'ipfs_cid_ipfs_cid_ipfs_cid_ipfs_cid_ipfs_cid_ipfs_cid');
|
||||
|
||||
// Bob receives the total amount of Alice's commitment through a relayer
|
||||
_withdrawThroughRelayer(
|
||||
@@ -201,7 +201,7 @@ contract IntegrationNative is IntegrationBase {
|
||||
|
||||
// Push ASP root with label included
|
||||
vm.prank(_POSTMAN);
|
||||
_entrypoint.updateRoot(_shadowASPMerkleTree._root(), bytes32('IPFS_HASH'));
|
||||
_entrypoint.updateRoot(_shadowASPMerkleTree._root(), 'ipfs_cid_ipfs_cid_ipfs_cid_ipfs_cid_ipfs_cid_ipfs_cid');
|
||||
|
||||
// Withdraw 20 ETH to Bob
|
||||
_commitment = _withdrawThroughRelayer(
|
||||
@@ -275,7 +275,9 @@ contract IntegrationNative is IntegrationBase {
|
||||
|
||||
// Push ASP root without label
|
||||
vm.prank(_POSTMAN);
|
||||
_entrypoint.updateRoot(uint256(keccak256('some_root')) % SNARK_SCALAR_FIELD, bytes32('IPFS_HASH'));
|
||||
_entrypoint.updateRoot(
|
||||
uint256(keccak256('some_root')) % SNARK_SCALAR_FIELD, 'ipfs_cid_ipfs_cid_ipfs_cid_ipfs_cid_ipfs_cid_ipfs_cid'
|
||||
);
|
||||
|
||||
// Fail to withdraw because the label is not included in the latest ASP root
|
||||
_withdrawThroughRelayer(
|
||||
@@ -304,7 +306,7 @@ contract IntegrationNative is IntegrationBase {
|
||||
|
||||
// Push ASP root with label included
|
||||
vm.prank(_POSTMAN);
|
||||
_entrypoint.updateRoot(_shadowASPMerkleTree._root(), bytes32('IPFS_HASH'));
|
||||
_entrypoint.updateRoot(_shadowASPMerkleTree._root(), 'ipfs_cid_ipfs_cid_ipfs_cid_ipfs_cid_ipfs_cid_ipfs_cid');
|
||||
|
||||
// Withdraw 40 ETH through relayer
|
||||
_commitment = _withdrawThroughRelayer(
|
||||
@@ -320,7 +322,9 @@ contract IntegrationNative is IntegrationBase {
|
||||
|
||||
// Remove label from ASP
|
||||
vm.prank(_POSTMAN);
|
||||
_entrypoint.updateRoot(uint256(keccak256('some_root')) % SNARK_SCALAR_FIELD, bytes32('IPFS_HASH'));
|
||||
_entrypoint.updateRoot(
|
||||
uint256(keccak256('some_root')) % SNARK_SCALAR_FIELD, 'ipfs_cid_ipfs_cid_ipfs_cid_ipfs_cid_ipfs_cid_ipfs_cid'
|
||||
);
|
||||
|
||||
// Fail to withdraw because label is not included in the latest ASP root
|
||||
_withdrawThroughRelayer(
|
||||
@@ -349,7 +353,7 @@ contract IntegrationNative is IntegrationBase {
|
||||
|
||||
// Push ASP root with label included
|
||||
vm.prank(_POSTMAN);
|
||||
_entrypoint.updateRoot(_shadowASPMerkleTree._root(), bytes32('IPFS_HASH'));
|
||||
_entrypoint.updateRoot(_shadowASPMerkleTree._root(), 'ipfs_cid_ipfs_cid_ipfs_cid_ipfs_cid_ipfs_cid_ipfs_cid');
|
||||
|
||||
// Fully spend commitment
|
||||
_selfWithdraw(
|
||||
@@ -390,7 +394,7 @@ contract IntegrationNative is IntegrationBase {
|
||||
|
||||
// Push ASP root with label included
|
||||
vm.prank(_POSTMAN);
|
||||
_entrypoint.updateRoot(_shadowASPMerkleTree._root(), bytes32('IPFS_HASH'));
|
||||
_entrypoint.updateRoot(_shadowASPMerkleTree._root(), 'ipfs_cid_ipfs_cid_ipfs_cid_ipfs_cid_ipfs_cid_ipfs_cid');
|
||||
|
||||
// Fail to withdraw commitment that was already ragequitted
|
||||
_selfWithdraw(
|
||||
|
||||
@@ -25,7 +25,7 @@ contract IntegrationProofs is IntegrationBase {
|
||||
|
||||
// Push ASP root with label included
|
||||
vm.prank(_POSTMAN);
|
||||
_entrypoint.updateRoot(_shadowASPMerkleTree._root(), bytes32('IPFS_HASH'));
|
||||
_entrypoint.updateRoot(_shadowASPMerkleTree._root(), 'ipfs_cid_ipfs_cid_ipfs_cid_ipfs_cid_ipfs_cid_ipfs_cid');
|
||||
|
||||
_withdrawal = IPrivacyPool.Withdrawal({processooor: _BOB, data: abi.encode(_BOB, address(0), 0)});
|
||||
|
||||
|
||||
@@ -59,7 +59,7 @@ contract Setup is HandlerActors, GhostStorage, FuzzUtils {
|
||||
entrypoint.registerPool(token, IPrivacyPool(tokenPool), MIN_DEPOSIT, FEE_VETTING, MAX_RELAY_FEE);
|
||||
|
||||
vm.prank(POSTMAN);
|
||||
entrypoint.updateRoot(1, 'a');
|
||||
entrypoint.updateRoot(1, 'ipfs_cid_ipfs_cid_ipfs_cid_ipfs_cid_ipfs_cid_ipfs_cid');
|
||||
|
||||
createNewActors(5);
|
||||
|
||||
|
||||
@@ -90,8 +90,8 @@ contract EntrypointForTest is Entrypoint {
|
||||
scopeToPool[_scope] = IPrivacyPool(_pool);
|
||||
}
|
||||
|
||||
function mockAssociationSets(uint256 _root, bytes32 _ipfsHash) external {
|
||||
associationSets.push(IEntrypoint.AssociationSetData({root: _root, ipfsHash: _ipfsHash, timestamp: block.timestamp}));
|
||||
function mockAssociationSets(uint256 _root, string memory _ipfsCID) external {
|
||||
associationSets.push(IEntrypoint.AssociationSetData({root: _root, ipfsCID: _ipfsCID, timestamp: block.timestamp}));
|
||||
}
|
||||
|
||||
function mockMaxRelayFeeBPS(IERC20 _asset, uint256 _maxRelayFeeBPS) external {
|
||||
@@ -220,49 +220,66 @@ contract UnitRootUpdate is UnitEntrypoint {
|
||||
*/
|
||||
function test_UpdateRootGivenValidRootAndIpfsHash(
|
||||
uint256 _root,
|
||||
bytes32 _ipfsHash,
|
||||
string memory _ipfsCID,
|
||||
uint256 _timestamp
|
||||
) external givenCallerHasPostmanRole {
|
||||
vm.assume(_root != 0);
|
||||
vm.assume(_ipfsHash != 0);
|
||||
uint256 _length = bytes(_ipfsCID).length;
|
||||
vm.assume(_length >= 32 && _length <= 64);
|
||||
|
||||
vm.warp(_timestamp);
|
||||
|
||||
vm.expectEmit(address(_entrypoint));
|
||||
emit IEntrypoint.RootUpdated(_root, _ipfsHash, _timestamp);
|
||||
emit IEntrypoint.RootUpdated(_root, _ipfsCID, _timestamp);
|
||||
|
||||
uint256 _index = _entrypoint.updateRoot(_root, _ipfsHash);
|
||||
(uint256 _retrievedRoot, bytes32 _retrievedIpfsHash, uint256 _retrievedTimestamp) = _entrypoint.associationSets(0);
|
||||
uint256 _index = _entrypoint.updateRoot(_root, _ipfsCID);
|
||||
(uint256 _retrievedRoot, string memory _retrievedIpfsCID, uint256 _retrievedTimestamp) =
|
||||
_entrypoint.associationSets(0);
|
||||
assertEq(_retrievedRoot, _root, 'Retrieved root should match input root');
|
||||
assertEq(_retrievedIpfsHash, _ipfsHash, 'Retrieved IPFS hash should match input hash');
|
||||
assertEq(_retrievedIpfsCID, _ipfsCID, 'Retrieved IPFS CID should match input CID');
|
||||
assertEq(_retrievedTimestamp, _timestamp, 'Retrieved timestamp should match block timestamp');
|
||||
assertEq(_index, 0, 'First root update should have index 0');
|
||||
|
||||
_index = _entrypoint.updateRoot(_root, _ipfsHash);
|
||||
vm.expectEmit(address(_entrypoint));
|
||||
emit IEntrypoint.RootUpdated(_root, 'ipfs_cid_ipfs_cid_ipfs_cid_ipfs_cid_ipfs_cid_ipfs_cid', _timestamp);
|
||||
|
||||
_index = _entrypoint.updateRoot(_root, 'ipfs_cid_ipfs_cid_ipfs_cid_ipfs_cid_ipfs_cid_ipfs_cid');
|
||||
assertEq(_index, 1, 'Second root update should have index 1');
|
||||
}
|
||||
|
||||
function test_UpdateRootWhenRootIsZero(bytes32 _ipfsHash) external givenCallerHasPostmanRole {
|
||||
vm.assume(_ipfsHash != 0);
|
||||
function test_UpdateRootWhenRootIsZero(string memory _ipfsCID) external givenCallerHasPostmanRole {
|
||||
uint256 _length = bytes(_ipfsCID).length;
|
||||
vm.assume(_length >= 32 && _length <= 64);
|
||||
|
||||
vm.expectRevert(abi.encodeWithSelector(IEntrypoint.EmptyRoot.selector));
|
||||
_entrypoint.updateRoot(0, _ipfsHash);
|
||||
_entrypoint.updateRoot(0, _ipfsCID);
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Test that the Entrypoint reverts when the IPFS hash is zero
|
||||
*/
|
||||
function test_UpdateRootWhenIpfsHashIsZero(uint256 _root) external givenCallerHasPostmanRole {
|
||||
function test_UpdateRootWhenIpfsCIDHasInvalidLength(uint256 _root) external givenCallerHasPostmanRole {
|
||||
vm.assume(_root != 0);
|
||||
vm.expectRevert(abi.encodeWithSelector(IEntrypoint.EmptyIPFSHash.selector));
|
||||
_entrypoint.updateRoot(_root, 0);
|
||||
string memory _shortCID = 'This is a 31-byte string exampl';
|
||||
assertEq(bytes(_shortCID).length, 31);
|
||||
|
||||
vm.expectRevert(abi.encodeWithSelector(IEntrypoint.InvalidIPFSCIDLength.selector));
|
||||
_entrypoint.updateRoot(_root, _shortCID);
|
||||
|
||||
string memory _longCID = 'This string contains exactly sixty-five bytes for your testing ne';
|
||||
assertEq(bytes(_longCID).length, 65);
|
||||
|
||||
vm.expectRevert(abi.encodeWithSelector(IEntrypoint.InvalidIPFSCIDLength.selector));
|
||||
_entrypoint.updateRoot(_root, _longCID);
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Test that the Entrypoint reverts when the caller lacks the postman role
|
||||
*/
|
||||
function test_UpdateRootWhenCallerLacksPostmanRole(address _caller, uint256 _root, bytes32 _ipfsHash) external {
|
||||
function test_UpdateRootWhenCallerLacksPostmanRole(address _caller, uint256 _root, string memory _ipfsCID) external {
|
||||
vm.assume(_caller != _POSTMAN);
|
||||
uint256 _length = bytes(_ipfsCID).length;
|
||||
vm.assume(_length >= 32 && _length <= 64);
|
||||
|
||||
vm.expectRevert(
|
||||
abi.encodeWithSelector(
|
||||
@@ -270,7 +287,7 @@ contract UnitRootUpdate is UnitEntrypoint {
|
||||
)
|
||||
);
|
||||
vm.prank(_caller);
|
||||
_entrypoint.updateRoot(_root, _ipfsHash);
|
||||
_entrypoint.updateRoot(_root, _ipfsCID);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1441,7 +1458,7 @@ contract UnitViewMethods is UnitEntrypoint {
|
||||
*/
|
||||
function test_LatestRootGivenAssociationSetsExist() external {
|
||||
// Mock association set with root value 1
|
||||
_entrypoint.mockAssociationSets(1, keccak256('ipfsHash'));
|
||||
_entrypoint.mockAssociationSets(1, 'ipfs_cid_ipfs_cid_ipfs_cid_ipfs_cid_ipfs_cid_ipfs_cid');
|
||||
|
||||
// Verify latest root is returned correctly
|
||||
assertEq(_entrypoint.latestRoot(), 1, 'Latest root should be 1');
|
||||
@@ -1452,8 +1469,8 @@ contract UnitViewMethods is UnitEntrypoint {
|
||||
*/
|
||||
function test_RootByIndexGivenValidIndex() external {
|
||||
// Mock multiple association sets with different roots
|
||||
_entrypoint.mockAssociationSets(1, keccak256('ipfsHash'));
|
||||
_entrypoint.mockAssociationSets(2, keccak256('ipfsHash'));
|
||||
_entrypoint.mockAssociationSets(1, 'ipfs_cid_ipfs_cid_ipfs_cid_ipfs_cid_ipfs_cid_ipfs_cid');
|
||||
_entrypoint.mockAssociationSets(2, 'ipfs_cid_ipfs_cid_ipfs_cid_ipfs_cid_ipfs_cid_ipfs_cid');
|
||||
|
||||
// Verify roots are returned correctly by index
|
||||
assertEq(_entrypoint.rootByIndex(0), 1, 'First root should be 1');
|
||||
|
||||
@@ -20,8 +20,8 @@ Entrypoint::updateRoot
|
||||
│ │ └── It emits RootUpdated event
|
||||
│ ├── When root is zero
|
||||
│ │ └── It reverts with EmptyRoot
|
||||
│ └── When ipfs hash is zero
|
||||
│ └── It reverts with EmptyIPFSHash
|
||||
│ └── When ipfs CID is longer or shorter than expected
|
||||
│ └── It reverts with InvalidIPFSCIDLength
|
||||
└── When caller lacks postman role
|
||||
└── It reverts with AccessControlUnauthorizedAccount
|
||||
|
||||
|
||||
Reference in New Issue
Block a user