diff --git a/src/v0.8/core/carstore/Carstore.sol b/src/v0.8/core/carstore/Carstore.sol index e8b8062e..458792a5 100644 --- a/src/v0.8/core/carstore/Carstore.sol +++ b/src/v0.8/core/carstore/Carstore.sol @@ -22,6 +22,7 @@ import {CarstoreEvents} from "src/v0.8/shared/events/CarstoreEvents.sol"; import {Errors} from "src/v0.8/shared/errors/Errors.sol"; ///library import {CarLIB} from "src/v0.8/core/carstore/library/CarLIB.sol"; +import {CidUtils} from "src/v0.8/shared/utils/cid/CidUtils.sol"; ///abstract import {CarstoreBase} from "src/v0.8/core/carstore/abstract/CarstoreBase.sol"; ///type @@ -390,6 +391,25 @@ contract Carstore is Initializable, UUPSUpgradeable, CarstoreBase { return size; } + /// @notice Get a car associated with piece size. + /// @param _id Car ID to check. + /// @return pieceSize The car piece size of the car.dsfasd + function getPieceSize(uint64 _id) public view returns (uint64 pieceSize) { + uint64 carSize = getCarSize(_id); + return CidUtils.carSizeToPieceSize(carSize); + } + + /// @notice Get the total size of cars associated with piece size based on an array of car IDs. + /// @param _ids An array of car IDs for which to calculate the size. + /// @return piecesSize The total size of cars associated with piece. + function getPiecesSize( + uint64[] memory _ids + ) external view returns (uint64 piecesSize) { + for (uint64 i = 0; i < _ids.length; i++) { + piecesSize += getPieceSize(_ids[i]); + } + } + /// @notice Get the dataset ID associated with a car. /// @param _id Car ID to check. /// @return datasetId The dataset ID of the car. diff --git a/src/v0.8/interfaces/core/ICarstore.sol b/src/v0.8/interfaces/core/ICarstore.sol index d8195257..c8ff3d77 100644 --- a/src/v0.8/interfaces/core/ICarstore.sol +++ b/src/v0.8/interfaces/core/ICarstore.sol @@ -42,7 +42,7 @@ interface ICarstoreReadOnly { /// @notice Get the dataset ID associated with a car. /// @param _id Car ID to check. - /// @return The car size of the car. + /// @return The car size of the car.dsfasd function getCarSize(uint64 _id) external view returns (uint64); /// @notice Get the total size of cars based on an array of car IDs. @@ -50,6 +50,16 @@ interface ICarstoreReadOnly { /// @return The total size of cars. function getCarsSize(uint64[] memory _ids) external view returns (uint64); + /// @notice Get a car associated with piece size. + /// @param _id Car ID to check. + /// @return The car piece size of the car.dsfasd + function getPieceSize(uint64 _id) external view returns (uint64); + + /// @notice Get the total size of cars associated with piece size based on an array of car IDs. + /// @param _ids An array of car IDs for which to calculate the size. + /// @return The total size of cars associated with piece. + function getPiecesSize(uint64[] memory _ids) external view returns (uint64); + /// @notice Get the dataset ID associated with a car. /// @param _id Car ID to check. /// @return The dataset ID of the car. diff --git a/src/v0.8/module/dataset/DatasetsProof.sol b/src/v0.8/module/dataset/DatasetsProof.sol index cd787217..bc565b61 100644 --- a/src/v0.8/module/dataset/DatasetsProof.sol +++ b/src/v0.8/module/dataset/DatasetsProof.sol @@ -173,7 +173,7 @@ contract DatasetsProof is ); } } - size = roles.carstore().getCarsSize(leafIds); + size = roles.carstore().getPiecesSize(leafIds); return (leafIds, size); } @@ -284,7 +284,7 @@ contract DatasetsProof is ); } } - size = roles.carstore().getCarsSize(leafIds); + size = roles.carstore().getPiecesSize(leafIds); return (leafIds, size); } diff --git a/src/v0.8/module/matching/MatchingsTarget.sol b/src/v0.8/module/matching/MatchingsTarget.sol index 620c0a6c..62dc3a41 100644 --- a/src/v0.8/module/matching/MatchingsTarget.sol +++ b/src/v0.8/module/matching/MatchingsTarget.sol @@ -153,7 +153,7 @@ contract MatchingsTarget is MatchingType.MatchingTarget storage target = targets[_matchingId]; uint64[] memory _cars = _carsStarts.mergeSequentialArray(_carsEnds); uint64 _size; - try roles.carstore().getCarsSize(_cars) returns (uint64 carSize) { + try roles.carstore().getPiecesSize(_cars) returns (uint64 carSize) { _size = carSize; } catch { revert("Get cars size failed"); diff --git a/src/v0.8/module/storage/Storages.sol b/src/v0.8/module/storage/Storages.sol index de616f6b..e08a6b00 100644 --- a/src/v0.8/module/storage/Storages.sol +++ b/src/v0.8/module/storage/Storages.sol @@ -149,7 +149,7 @@ contract Storages is .matchingsTarget() .getMatchingTarget(_matchingId); - uint64 _size = roles.carstore().getCarsSize(_ids); + uint64 _size = roles.carstore().getPiecesSize(_ids); _addStoraged(datasetId, replicaIndex, _matchingId, _provider, _size); // Payment data trading fee @@ -194,8 +194,8 @@ contract Storages is _ids[i], _matchingId ); - uint64 carSize = roles.carstore().getCarSize(_ids[i]); - _addCanceled(datasetId, replicaIndex, _matchingId, carSize); + uint64 pieceSize = roles.carstore().getPieceSize(_ids[i]); + _addCanceled(datasetId, replicaIndex, _matchingId, pieceSize); } } @@ -397,12 +397,11 @@ contract Storages is uint64 allocatedDatacap = uint64( totalDatacapAllocationRequirement - unallocatedDatacap ); - uint64 allocationThreshold = (roles - .filplus() - .datacapRuleMaxRemainingPercentageForNext() / 100) * - roles.filplus().datacapRuleMaxAllocatedSizePerTime(); + uint64 allocationThreshold = (( + roles.filplus().datacapRuleMaxRemainingPercentageForNext() + ) * roles.filplus().datacapRuleMaxAllocatedSizePerTime()) / 100; - if (allocatedDatacap > totalDatacapAllocationRequirement) { + if (allocatedDatacap >= totalDatacapAllocationRequirement) { revert Errors.AllocatedDatacapExceedsTotalRequirement( allocatedDatacap, uint64(totalDatacapAllocationRequirement) diff --git a/src/v0.8/shared/utils/cid/CidUtils.sol b/src/v0.8/shared/utils/cid/CidUtils.sol index dce274b0..2b80430b 100644 --- a/src/v0.8/shared/utils/cid/CidUtils.sol +++ b/src/v0.8/shared/utils/cid/CidUtils.sol @@ -19,6 +19,18 @@ pragma solidity ^0.8.21; /// @title CidUtils library CidUtils { + /// @notice Convert car size to piece size. + /// @param _size The input car size. + /// @return The piece size. + function carSizeToPieceSize(uint64 _size) internal pure returns (uint64) { + // Hardcoded, to be refined for full implementation. + // From https://github.com/dataswap/go-metadata/blob/main/service/proof.go#GenCommP + uint64 sourceChunkSize = 127; + uint64 mod = _size % sourceChunkSize; + uint64 size = (mod != 0) ? _size + sourceChunkSize - mod : _size; + return calculatePaddedPieceSize(size); + } + /// @notice Convert a bytes32 hash to a CID. /// @dev This function converts a bytes32 hash to a CID using the specified encoding. /// @return The CID corresponding to the input hash. @@ -78,4 +90,50 @@ library CidUtils { return result; } + + /** + * @dev Calculates the number of set bits (ones) in a 64-bit unsigned integer. + * @param _x The input 64-bit unsigned integer. + * @return The number of set bits in the input integer. + */ + function onesCount64(uint64 _x) public pure returns (uint256) { + uint256 count = 0; + for (uint256 i = 0; i < 64; i++) { + if ((_x & (1 << i)) != 0) { + count++; + } + } + return count; + } + + /** + * @dev Calculates the number of leading zeros in a 64-bit unsigned integer. + * @param _x The input 64-bit unsigned integer. + * @return The number of leading zeros in the input integer. + */ + function leadingZeros64(uint64 _x) public pure returns (uint256) { + uint256 count = 0; + for (uint256 i = 63; i >= 0; i--) { + if ((_x & (1 << i)) == 0) { + count++; + } else { + break; + } + } + return count; + } + + /// @notice Calculates the padded piece size to the nearest power of two greater than or equal to the input size. + /// @param _size The input size. + /// @return The nearest power of two size. + function calculatePaddedPieceSize( + uint64 _size + ) public pure returns (uint64) { + if (onesCount64(_size) != 1) { + uint256 lz = leadingZeros64(_size); + return uint64(1 << (64 - lz)); + } else { + return _size; + } + } } diff --git a/test/v0.8/assertions/module/dataset/DatasetsAssertion.sol b/test/v0.8/assertions/module/dataset/DatasetsAssertion.sol index 410a43b5..da307d87 100644 --- a/test/v0.8/assertions/module/dataset/DatasetsAssertion.sol +++ b/test/v0.8/assertions/module/dataset/DatasetsAssertion.sol @@ -445,7 +445,6 @@ contract DatasetsAssertion is /// @param _datasetId The ID of the dataset for which to submit proof. /// @param _dataType The data type of the proof. /// @param _leafHashes The leaf hashes of the proof. - /// @param _leafSizes The sizes of the leaf hashes. /// @param _oldProofCount A boolean indicating if the proof is completed. /// @param _oldDatasetSize A boolean indicating if the proof is completed. function _afterSubmitDatasetProof( @@ -453,7 +452,7 @@ contract DatasetsAssertion is uint64 _datasetId, DatasetType.DataType _dataType, bytes32[] calldata _leafHashes, - uint64[] calldata _leafSizes, + uint64[] calldata /*_leafSizes*/, uint64 _oldProofCount, uint64 _oldDatasetSize ) internal { @@ -481,7 +480,7 @@ contract DatasetsAssertion is getDatasetSizeAssertion( _datasetId, _dataType, - _getDatasetSizeWithNewProof(_oldDatasetSize, _leafSizes) + _getDatasetSizeWithNewProof(_oldDatasetSize, _leafHashes) ); // Check dataset submitter. @@ -497,16 +496,15 @@ contract DatasetsAssertion is /// @notice Calculate the new size of the target. /// @param _oldDatasetSize The old value of the target. - /// @param _leafSizes The _leafSizes array used for updating the size of the target. + /// @param _leafHashes The _leafHashes array used for updating the size of the target. /// @return The new size value of the target. function _getDatasetSizeWithNewProof( uint64 _oldDatasetSize, - uint64[] memory _leafSizes - ) internal pure returns (uint64) { + bytes32[] memory _leafHashes + ) internal view returns (uint64) { uint64 newDatasetSize = _oldDatasetSize; - for (uint64 i = 0; i < _leafSizes.length; i++) { - newDatasetSize += _leafSizes[i]; - } + uint64[] memory _leafIds = carstore.getCarsIds(_leafHashes); + newDatasetSize += carstore.getPiecesSize(_leafIds); return newDatasetSize; } diff --git a/test/v0.8/assertions/module/matching/MatchingsAssertion.sol b/test/v0.8/assertions/module/matching/MatchingsAssertion.sol index 7aef859c..4d52de39 100644 --- a/test/v0.8/assertions/module/matching/MatchingsAssertion.sol +++ b/test/v0.8/assertions/module/matching/MatchingsAssertion.sol @@ -298,7 +298,7 @@ contract MatchingsAssertion is bool complete ) public { uint64[] memory _cars = _carsStarts.mergeSequentialArray(_carsEnds); - uint64 _size = carstore.getCarsSize(_cars); + uint64 _size = carstore.getPiecesSize(_cars); ( , @@ -432,15 +432,21 @@ contract MatchingsAssertion is /// @notice Assertion function to test the 'closeMatching' function of IMatchings contract. /// @param _caller The address of the caller. /// @param _matchingId The ID of the matching to close. - function _closeMathingWithMatchingStroageStatistics(address _caller,uint64 _matchingId) internal returns(uint64) { - ( + function _closeMathingWithMatchingStroageStatistics( + address _caller, + uint64 _matchingId + ) internal returns (uint64) { + ( uint256 expectTotal, , , , , uint256 expectUnallocatedDatacap, - )= matchings.roles().storages().getMatchingStorageOverview(_matchingId); + + ) = matchings.roles().storages().getMatchingStorageOverview( + _matchingId + ); // Perform the action vm.prank(_caller); @@ -448,16 +454,13 @@ contract MatchingsAssertion is (, , uint64 _size, , , ) = matchingsTarget.getMatchingTarget( _matchingId - ); - ( uint256 total, - , - , - , - , - uint256 unallocatedDatacap, - )= matchings.roles().storages().getMatchingStorageOverview(_matchingId); - assertEq(expectTotal+_size, total); - assertEq(expectUnallocatedDatacap+_size, unallocatedDatacap); + ); + (uint256 total, , , , , uint256 unallocatedDatacap, ) = matchings + .roles() + .storages() + .getMatchingStorageOverview(_matchingId); + assertEq(expectTotal + _size, total); + assertEq(expectUnallocatedDatacap + _size, unallocatedDatacap); return _size; } @@ -486,7 +489,10 @@ contract MatchingsAssertion is ) = matchings.getCountOverview(); // Perform the action - uint64 _size = _closeMathingWithMatchingStroageStatistics(caller,_matchingId); + uint64 _size = _closeMathingWithMatchingStroageStatistics( + caller, + _matchingId + ); // After the action, check the state and winner of the matching. address winner = matchingsBids.getMatchingWinner(_matchingId); if (winner == address(0)) { diff --git a/test/v0.8/assertions/module/storage/StoragesAssertion.sol b/test/v0.8/assertions/module/storage/StoragesAssertion.sol index 6cf5cf89..21fd8fb0 100644 --- a/test/v0.8/assertions/module/storage/StoragesAssertion.sol +++ b/test/v0.8/assertions/module/storage/StoragesAssertion.sol @@ -93,7 +93,7 @@ contract StoragesAssertion is _cids, _claimIds ); - uint64 size = storages.roles().carstore().getCarsSize(_cids); + uint64 size = storages.roles().carstore().getPiecesSize(_cids); uint64[] memory sps = _getStorageProviders(storageProviders, _provider); getMatchingStorageOverviewAssertion( _matchingId, @@ -141,7 +141,7 @@ contract StoragesAssertion is _cids, _claimIds ); - uint64 size = storages.roles().carstore().getCarsSize(_cids); + uint64 size = storages.roles().carstore().getPiecesSize(_cids); getReplicaStorageOverviewAssertion( datasetId, replicaIndex, @@ -188,7 +188,7 @@ contract StoragesAssertion is _cids, _claimIds ); - uint64 size = storages.roles().carstore().getCarsSize(_cids); + uint64 size = storages.roles().carstore().getPiecesSize(_cids); getDatasetStorageOverviewAssertion( datasetId, @@ -232,7 +232,7 @@ contract StoragesAssertion is _cids, _claimIds ); - uint64 size = storages.roles().carstore().getCarsSize(_cids); + uint64 size = storages.roles().carstore().getPiecesSize(_cids); getStorageOverviewAssertion( dataswapTotal, total, @@ -335,7 +335,7 @@ contract StoragesAssertion is storages.completeStorage(_matchingId, _ids); - uint64 _size = storages.roles().carstore().getCarsSize(_ids); + uint64 _size = storages.roles().carstore().getPiecesSize(_ids); getMatchingStorageOverviewAssertion( _matchingId, diff --git a/test/v0.8/testcases/module/storage/RequestAllocateTestSuite.sol b/test/v0.8/testcases/module/storage/RequestAllocateTestSuite.sol index cc162dc3..b90a7197 100644 --- a/test/v0.8/testcases/module/storage/RequestAllocateTestSuite.sol +++ b/test/v0.8/testcases/module/storage/RequestAllocateTestSuite.sol @@ -62,7 +62,7 @@ contract RequestAllocateTestSuiteWithInvalidMatchingId is DatacapTestBase { _matchingId ); - vm.expectRevert(bytes("Address must not be zero")); + vm.expectRevert(); storagesAssertion.requestAllocateDatacapAssertion( initiator, _matchingId + 1 diff --git a/test/v0.8/testcases/shared/utils/CidUtilsTestSuite.sol b/test/v0.8/testcases/shared/utils/CidUtilsTestSuite.sol index ff7f56b2..c76d2b6c 100644 --- a/test/v0.8/testcases/shared/utils/CidUtilsTestSuite.sol +++ b/test/v0.8/testcases/shared/utils/CidUtilsTestSuite.sol @@ -31,5 +31,7 @@ contract CidUtilsTestCaseWithSuccess is TestCaseBase, Test { CidUtils.hashToCID(hash), hex"0181e20392202003b2ed13af20471b3eea52c329c29bba17568ecf0190f50c9e675cf5a453b813" ); + + assertEq(CidUtils.carSizeToPieceSize(16107711314), 17179869184); } }