From 273ed314fcaaaac11d01147998005802d3dc0ed5 Mon Sep 17 00:00:00 2001 From: sirius Date: Wed, 13 Mar 2024 11:47:53 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=F0=9F=8E=B8=20Handling=20of=20the=20ad?= =?UTF-8?q?dCanceled=20function=20in=20the=20Storages?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ✅ Closes: #218 --- src/v0.8/core/carstore/Carstore.sol | 32 ++++++---- .../finance/escrow/EscrowDataTradingFee.sol | 25 ++++++-- .../EscrowDatacapChunkLandCollateral.sol | 12 +++- src/v0.8/interfaces/core/ICarstore.sol | 8 +++ src/v0.8/interfaces/module/IStorages.sol | 12 ++++ src/v0.8/module/storage/Storages.sol | 64 +++++++++++++++++++ src/v0.8/types/StorageType.sol | 1 + 7 files changed, 133 insertions(+), 21 deletions(-) diff --git a/src/v0.8/core/carstore/Carstore.sol b/src/v0.8/core/carstore/Carstore.sol index 7b80f04a..27764f5c 100644 --- a/src/v0.8/core/carstore/Carstore.sol +++ b/src/v0.8/core/carstore/Carstore.sol @@ -155,13 +155,7 @@ contract Carstore is Initializable, UUPSUpgradeable, CarstoreBase { uint64 _id, uint64 _matchingId, bool _matchingState - ) - external - onlyRole(roles, RolesType.DATASWAP_CONTRACT) - onlyCarExist(this, _id) - onlyNotZero(_matchingId) - onlyCarReplicaExist(this, _id, _matchingId) - { + ) external onlyRole(roles, RolesType.DATASWAP_CONTRACT) { if (_matchingState) { _emitRepicaEvent( _id, @@ -186,6 +180,24 @@ contract Carstore is Initializable, UUPSUpgradeable, CarstoreBase { ); } } + /// @dev Reports a failure in car replica storage. + /// @param _id The ID associated with the car replica. + /// @param _matchingId The ID of the matching process related to the storage failure. + function __reportCarReplicaStorageFailed( + uint64 _id, + uint64 _matchingId + ) + external + onlyRole(roles, RolesType.DATASWAP_CONTRACT) + onlyCarReplicaState( + this, + _id, + _matchingId, + CarReplicaType.State.Matched + ) + { + _emitRepicaEvent(_id, _matchingId, CarReplicaType.Event.StorageFailed); + } function _checkCarReplicaDealState( uint64 _id, @@ -211,9 +223,6 @@ contract Carstore is Initializable, UUPSUpgradeable, CarstoreBase { ) external onlyRole(roles, RolesType.DATASWAP_CONTRACT) - onlyCarExist(this, _id) - onlyNotZero(_matchingId) - onlyCarReplicaExist(this, _id, _matchingId) onlyCarReplicaState(this, _id, _matchingId, CarReplicaType.State.Stored) { _checkCarReplicaDealState( @@ -240,9 +249,6 @@ contract Carstore is Initializable, UUPSUpgradeable, CarstoreBase { ) external onlyRole(roles, RolesType.DATASWAP_CONTRACT) - onlyCarExist(this, _id) - onlyNotZero(_matchingId) - onlyCarReplicaExist(this, _id, _matchingId) onlyCarReplicaState(this, _id, _matchingId, CarReplicaType.State.Stored) { _checkCarReplicaDealState( diff --git a/src/v0.8/core/finance/escrow/EscrowDataTradingFee.sol b/src/v0.8/core/finance/escrow/EscrowDataTradingFee.sol index bfb61b1c..cac7b5ac 100644 --- a/src/v0.8/core/finance/escrow/EscrowDataTradingFee.sol +++ b/src/v0.8/core/finance/escrow/EscrowDataTradingFee.sol @@ -174,7 +174,12 @@ contract EscrowDataTradingFee is EscrowBase { _datasetId ); - uint256 amount = __getRequirement(_datasetId,_destMatchingId,payer, _token); + uint256 amount = __getRequirement( + _datasetId, + _destMatchingId, + payer, + _token + ); FinanceType.PayeeInfo[] memory payees = new FinanceType.PayeeInfo[](1); payees[0] = FinanceType.PayeeInfo(payer, amount); @@ -194,13 +199,21 @@ contract EscrowDataTradingFee is EscrowBase { uint64 _matchingId, address _payer, address _token - ) public view override onlyRole(roles, RolesType.DATASWAP_CONTRACT) returns (uint256 amount) { + ) + public + view + override + onlyRole(roles, RolesType.DATASWAP_CONTRACT) + returns (uint256 amount) + { if (_payer == roles.matchingsBids().getMatchingWinner(_matchingId)) { amount = roles.matchingsBids().getMatchingBidAmount( _matchingId, _payer ); - } else if (_payer == roles.datasets().getDatasetMetadataSubmitter(_datasetId)) { + } else if ( + _payer == roles.datasets().getDatasetMetadataSubmitter(_datasetId) + ) { // Source account balance (, , uint256 balance, ) = roles.finance().getAccountEscrow( _datasetId, @@ -222,7 +235,9 @@ contract EscrowDataTradingFee is EscrowBase { _datasetId, DatasetType.DataType.Source ) * - roles.datasetsRequirement().getDatasetReplicasCount(_datasetId) - + roles.datasetsRequirement().getDatasetReplicasCount( + _datasetId + ) - usedSize; amount = (balance / unusedSize) * matchingSize; @@ -342,7 +357,7 @@ contract EscrowDataTradingFee is EscrowBase { function _isEscrowRefund(uint64 _matchingId) internal view returns (bool) { return _matchingId != 0 && - roles.storages().isStorageExpiration(_matchingId); + roles.storages().isStorageCompleted(_matchingId); } /// @dev Internal function to check if a parent account refund is applicable. diff --git a/src/v0.8/core/finance/escrow/EscrowDatacapChunkLandCollateral.sol b/src/v0.8/core/finance/escrow/EscrowDatacapChunkLandCollateral.sol index 05465fbe..789b3d6e 100644 --- a/src/v0.8/core/finance/escrow/EscrowDatacapChunkLandCollateral.sol +++ b/src/v0.8/core/finance/escrow/EscrowDatacapChunkLandCollateral.sol @@ -40,7 +40,13 @@ contract EscrowDatacapChunkLandCollateral is EscrowBase { uint64 _matchingId, address _payer, address _token - ) public view override onlyRole(roles, RolesType.DATASWAP_CONTRACT) returns (uint256 amount) { + ) + public + view + override + onlyRole(roles, RolesType.DATASWAP_CONTRACT) + returns (uint256 amount) + { (, , uint256 current, ) = roles.finance().getAccountEscrow( _datasetId, _matchingId, @@ -141,7 +147,7 @@ contract EscrowDatacapChunkLandCollateral is EscrowBase { uint64 _matchingId ) internal view override returns (bool refund) { return ((_matchingId != 0 && - roles.storages().isStorageExpiration(_matchingId)) || + roles.storages().isStorageCompleted(_matchingId)) || roles.datasets().getDatasetState(_datasetId) == DatasetType.State.Rejected); } @@ -154,6 +160,6 @@ contract EscrowDatacapChunkLandCollateral is EscrowBase { uint64 _matchingId ) internal view override returns (bool burn) { return (_matchingId != 0 && - roles.storages().isStorageExpiration(_matchingId)); + roles.storages().isStorageCompleted(_matchingId)); } } diff --git a/src/v0.8/interfaces/core/ICarstore.sol b/src/v0.8/interfaces/core/ICarstore.sol index 3e9aa251..c761a76d 100644 --- a/src/v0.8/interfaces/core/ICarstore.sol +++ b/src/v0.8/interfaces/core/ICarstore.sol @@ -213,6 +213,14 @@ interface ICarstore is ICarstoreReadOnly { bool _matchingState ) external; + /// @dev Reports a failure in car replica storage. + /// @param _id The ID associated with the car replica. + /// @param _matchingId The ID of the matching process related to the storage failure. + function __reportCarReplicaStorageFailed( + uint64 _id, + uint64 _matchingId + ) external; + /// @notice Report that storage deal for a replica has expired. /// @dev This function allows reporting that the storage deal for a replica has expired. /// @param _id Car ID associated with the replica. diff --git a/src/v0.8/interfaces/module/IStorages.sol b/src/v0.8/interfaces/module/IStorages.sol index e2182878..a5e732df 100644 --- a/src/v0.8/interfaces/module/IStorages.sol +++ b/src/v0.8/interfaces/module/IStorages.sol @@ -35,6 +35,11 @@ interface IStorages is IStorageStatistics { uint64[] memory _claimIds ) external; + /// @dev Completes the storage process for a given matching ID. + /// @param _matchingId The ID of the matching. + /// @param _ids An array of content identifiers of the matched data. + function completeStorage(uint64 _matchingId, uint64[] memory _ids) external; + /// @dev Gets the list of done cars in the matchedstore. /// @param _matchingId The ID of the matching. /// @return An array of content identifiers of the done cars. @@ -59,6 +64,13 @@ interface IStorages is IStorageStatistics { uint64 _matchingId ) external view returns (bool); + /// @dev Checks if the storage process is completed for a given matching ID. + /// @param _matchingId The ID of the matching. + /// @return A boolean indicating whether the storage process is completed or not. + function isStorageCompleted( + uint64 _matchingId + ) external view returns (bool); + /// @dev Requests the allocation of matched datacap for a matching process. /// @param _matchingId The ID of the matching process. function requestAllocateDatacap( diff --git a/src/v0.8/module/storage/Storages.sol b/src/v0.8/module/storage/Storages.sol index 5b7513b9..80ac4350 100644 --- a/src/v0.8/module/storage/Storages.sol +++ b/src/v0.8/module/storage/Storages.sol @@ -161,6 +161,62 @@ contract Storages is ); } + /// @dev Completes the storage process for a given matching ID. + /// @param _matchingId The ID of the matching. + function completeStorage(uint64 _matchingId, uint64[] memory _ids) public { + StorageType.Storage storage storage_ = storages[_matchingId]; + ( + uint64 datasetId, + uint64[] memory cars, + , + , + , + uint16 replicaIndex + ) = roles.matchingsTarget().getMatchingTarget(_matchingId); + + if (storage_.doneCars.length < cars.length) { + require(isStorageExpiration(_matchingId), "Storage is in progress"); + require( + storage_.doneCars.length + _ids.length == cars.length, + "invalid cars number" + ); + + for (uint256 i = 0; i < _ids.length; i++) { + require( + CarReplicaType.State.Matched == + roles.carstore().getCarReplicaState( + _ids[i], + _matchingId + ), + "Invalid Replica State" + ); + roles.carstore().__reportCarReplicaStorageFailed( + _ids[i], + _matchingId + ); + uint64 carSize = roles.carstore().getCarSize(_ids[i]); + _addCanceled(datasetId, replicaIndex, _matchingId, carSize); + } + } + + storage_.completed = true; + + // Payment data trading fee + roles.finance().claimEscrow( + datasetId, + _matchingId, + FinanceType.FIL, + FinanceType.Type.EscrowDatacapChunkLandCollateral + ); + + roles.finance().claimEscrow( + datasetId, + _matchingId, + FinanceType.FIL, + FinanceType.Type.EscrowDataTradingFee + ); + } + /// @dev Gets the list of done cars in the matchedstore. function getStoredCars( uint64 _matchingId @@ -213,6 +269,14 @@ contract Storages is } } + /// @dev Checks if the storage process is completed for a given matching ID. + /// @param _matchingId The ID of the matching. + /// @return A boolean indicating whether the storage process is completed or not. + function isStorageCompleted(uint64 _matchingId) public view returns (bool) { + StorageType.Storage storage storage_ = storages[_matchingId]; + return storage_.completed; + } + /// @dev Internal function to allocate matched datacap. // solhint-disable-next-line function _allocateDatacap( diff --git a/src/v0.8/types/StorageType.sol b/src/v0.8/types/StorageType.sol index fc5846ae..940c5860 100644 --- a/src/v0.8/types/StorageType.sol +++ b/src/v0.8/types/StorageType.sol @@ -23,5 +23,6 @@ library StorageType { /// @notice Struct representing a storage deal. struct Storage { uint64[] doneCars; + bool completed; } }