Skip to content

Commit 539a339

Browse files
committed
storage provider limits, storage picker update
1 parent 6e223a8 commit 539a339

File tree

7 files changed

+154
-31
lines changed

7 files changed

+154
-31
lines changed

src/facets/AllocateFacet.sol

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -49,12 +49,16 @@ contract AllocateFacet is IFacet, Modifiers, PausableUpgradeable {
4949
if (allocReq.length * replicaSize < appConfig.minRequiredStorageProviders) {
5050
revert ErrorLib.NotEnoughAllocationData();
5151
}
52-
uint256 requiredCollateral = appConfig.collateralPerCID * allocReq.length * replicaSize;
53-
if (msg.value < requiredCollateral) {
54-
revert ErrorLib.InsufficientCollateral(requiredCollateral);
52+
{
53+
uint256 requiredCollateral = appConfig.collateralPerCID * allocReq.length * replicaSize;
54+
if (msg.value < requiredCollateral) {
55+
revert ErrorLib.InsufficientCollateral(requiredCollateral);
56+
}
5557
}
56-
57-
uint64[] memory providers = StorageEntityPicker._pickStorageProviders(appConfig.minRequiredStorageProviders);
58+
uint256 maxSpacePerProvider =
59+
_calculateMaxAllocationSizePerProvider(allocReq, replicaSize, appConfig.minRequiredStorageProviders);
60+
uint64[] memory providers =
61+
StorageEntityPicker._pickStorageProviders(appConfig.minRequiredStorageProviders, maxSpacePerProvider);
5862

5963
int64 termMin = FilecoinEpochCalculator.getTermMin();
6064
int64 termMax = FilecoinEpochCalculator.calcTermMax();
@@ -99,4 +103,21 @@ contract AllocateFacet is IFacet, Modifiers, PausableUpgradeable {
99103

100104
return packageId;
101105
}
106+
107+
/**
108+
* @dev Calculate the worst case (maximum) allocation size based on the request.
109+
* cost: approx 20 gas per allocReq entry.
110+
*/
111+
function _calculateMaxAllocationSizePerProvider(
112+
Types.AllocationRequest[] calldata allocReq,
113+
uint256 replicaSize,
114+
uint256 minProviders
115+
) internal pure returns (uint256) {
116+
uint256 totalBytes = 0;
117+
for (uint256 i = 0; i < allocReq.length; i++) {
118+
totalBytes += uint256(allocReq[i].size) * replicaSize;
119+
}
120+
// ceil(a/b) == (a + b - 1) / b
121+
return (totalBytes + minProviders - 1) / minProviders;
122+
}
102123
}

src/facets/StorageEntityManagerFacet.sol

Lines changed: 43 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -20,14 +20,13 @@ import {Events} from "../libraries/Events.sol";
2020
contract StorageEntityManagerFacet is IFacet, Modifiers {
2121
// get the function selectors for this facet for deployment and update scripts
2222
function selectors() external pure returns (bytes4[] memory selectors_) {
23-
selectors_ = new bytes4[](7);
23+
selectors_ = new bytes4[](6);
2424
selectors_[0] = this.createStorageEntity.selector;
2525
selectors_[1] = this.addStorageProviders.selector;
2626
selectors_[2] = this.removeStorageProviders.selector;
27-
selectors_[3] = this.changeStorageEntityActiveStatus.selector;
28-
selectors_[4] = this.getStorageEntity.selector;
29-
selectors_[5] = this.isStorageProviderUsed.selector;
30-
selectors_[6] = this.getStorageEntities.selector;
27+
selectors_[3] = this.setStorageEntityActiveStatus.selector;
28+
selectors_[4] = this.isStorageProviderUsed.selector;
29+
selectors_[5] = this.setStorageProviderDetails.selector;
3130
}
3231

3332
function createStorageEntity(address entityOwner, uint64[] calldata storageProviders)
@@ -63,7 +62,7 @@ contract StorageEntityManagerFacet is IFacet, Modifiers {
6362

6463
Storage.StorageEntity storage se = Storage.s().storageEntities[entityOwner];
6564

66-
_ensureStorageEntityNotExists(se);
65+
_ensureStorageEntityExists(se);
6766

6867
for (uint256 i = 0; i < storageProviders.length; i++) {
6968
se.storageProviders.push(storageProviders[i]);
@@ -79,16 +78,25 @@ contract StorageEntityManagerFacet is IFacet, Modifiers {
7978
{
8079
Storage.StorageEntity storage se = Storage.s().storageEntities[entityOwner];
8180

82-
_ensureStorageEntityNotExists(se);
81+
_ensureStorageEntityExists(se);
82+
8383

8484
for (uint256 j = 0; j < storageProviders.length; j++) {
8585
uint64 sp = storageProviders[j];
86+
87+
_ensureStorageProviderIsAssignedToStorageEntity(se, sp);
88+
8689
Storage.s().usedStorageProviders[sp] = false;
8790
for (uint256 i = 0; i < se.storageProviders.length; i++) {
8891
if (se.storageProviders[i] == sp) {
8992
se.storageProviders[i] = se.storageProviders[se.storageProviders.length - 1];
9093
se.storageProviders.pop();
9194
Storage.s().usedStorageProviders[sp] = false;
95+
96+
se.providerDetails[sp] = Storage.ProviderDetails({
97+
isActive: false,
98+
spaceLeft: 0
99+
});
92100
break;
93101
}
94102
}
@@ -97,13 +105,13 @@ contract StorageEntityManagerFacet is IFacet, Modifiers {
97105
emit Events.StorageProviderRemoved(msg.sender, entityOwner, storageProviders);
98106
}
99107

100-
function changeStorageEntityActiveStatus(address entityOwner, bool isActive)
108+
function setStorageEntityActiveStatus(address entityOwner, bool isActive)
101109
external
102110
onlyOwnerOrStorageEntity(entityOwner)
103111
{
104112
Storage.StorageEntity storage se = Storage.s().storageEntities[entityOwner];
105113

106-
_ensureStorageEntityNotExists(se);
114+
_ensureStorageEntityExists(se);
107115

108116
se.isActive = isActive;
109117

@@ -118,26 +126,41 @@ contract StorageEntityManagerFacet is IFacet, Modifiers {
118126
}
119127
}
120128

121-
function _ensureStorageEntityNotExists(Storage.StorageEntity storage se) internal view {
129+
function _ensureStorageEntityExists(Storage.StorageEntity storage se) internal view {
122130
if (se.owner == address(0)) {
123131
revert ErrorLib.StorageEntityDoesNotExist();
124132
}
125133
}
126134

127-
function getStorageEntity(address entityOwner) external view returns (Storage.StorageEntity memory) {
128-
return Storage.s().storageEntities[entityOwner];
129-
}
130-
131135
function isStorageProviderUsed(uint64 storageProvider) external view returns (bool) {
132136
return Storage.s().usedStorageProviders[storageProvider];
133137
}
134138

135-
function getStorageEntities() external view returns (Storage.StorageEntity[] memory) {
136-
address[] storage entityAddresses = Storage.s().entityAddresses;
137-
Storage.StorageEntity[] memory storageEntities = new Storage.StorageEntity[](entityAddresses.length);
138-
for (uint256 i = 0; i < entityAddresses.length; i++) {
139-
storageEntities[i] = Storage.s().storageEntities[entityAddresses[i]];
139+
function setStorageProviderDetails(
140+
address entityOwner,
141+
uint64 storageProvider,
142+
Storage.ProviderDetails memory details
143+
) external onlyOwnerOrStorageEntity(entityOwner) {
144+
Storage.StorageEntity storage se = Storage.s().storageEntities[entityOwner];
145+
146+
_ensureStorageEntityExists(se);
147+
148+
_ensureStorageProviderIsAssignedToStorageEntity(se, storageProvider);
149+
150+
se.providerDetails[storageProvider] = details;
151+
}
152+
153+
function _ensureStorageProviderIsAssignedToStorageEntity(Storage.StorageEntity storage se, uint64 storageProvider) internal view {
154+
// Check if sp is assigned to the entity
155+
bool isAssigned = false;
156+
for (uint256 i = 0; i < se.storageProviders.length; i++) {
157+
if (se.storageProviders[i] == storageProvider) {
158+
isAssigned = true;
159+
break;
160+
}
161+
}
162+
if (!isAssigned) {
163+
revert ErrorLib.StorageProviderNotAssignedToEntity();
140164
}
141-
return storageEntities;
142165
}
143166
}

src/facets/ViewFacet.sol

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,14 @@ import {FilecoinConverter} from "../libraries/FilecoinConverter.sol";
1414
contract ViewFacet is IFacet {
1515
// get the function selectors for this facet for deployment and update scripts
1616
function selectors() external pure returns (bytes4[] memory selectors_) {
17-
selectors_ = new bytes4[](5);
17+
selectors_ = new bytes4[](7);
1818
selectors_[0] = this.getAllocationPackage.selector;
1919
selectors_[1] = this.getClientPackagesWithClaimStatus.selector;
2020
selectors_[2] = this.getPackageWithClaimStatus.selector;
2121
selectors_[3] = this.checkProviderClaims.selector;
2222
selectors_[4] = this.getAppConfig.selector;
23+
selectors_[5] = this.getStorageEntity.selector;
24+
selectors_[6] = this.getStorageEntities.selector;
2325
}
2426

2527
function getAppConfig() external view returns (Storage.AppConfig memory appConfig) {
@@ -163,4 +165,41 @@ contract ViewFacet is IFacet {
163165

164166
return result.batch_info.success_count == allocationIds.length;
165167
}
168+
169+
function getStorageEntity(address entityOwner) external view returns (Types.StorageEntityView memory) {
170+
if (Storage.s().storageEntities[entityOwner].owner == address(0)) {
171+
revert ErrorLib.StorageEntityDoesNotExist();
172+
}
173+
return _storageEntityToView(Storage.s().storageEntities[entityOwner]);
174+
}
175+
176+
function getStorageEntities() external view returns (Types.StorageEntityView[] memory) {
177+
address[] storage entityAddresses = Storage.s().entityAddresses;
178+
Types.StorageEntityView[] memory storageEntities = new Types.StorageEntityView[](entityAddresses.length);
179+
for (uint256 i = 0; i < entityAddresses.length; i++) {
180+
storageEntities[i] = _storageEntityToView(Storage.s().storageEntities[entityAddresses[i]]);
181+
}
182+
return storageEntities;
183+
}
184+
185+
function _storageEntityToView(Storage.StorageEntity storage se)
186+
internal
187+
view
188+
returns (Types.StorageEntityView memory)
189+
{
190+
Types.StorageEntityView memory entityView;
191+
entityView.isActive = se.isActive;
192+
entityView.owner = se.owner;
193+
entityView.storageProviders = se.storageProviders;
194+
entityView.providerDetails = new Types.ProviderDetailsView[](se.storageProviders.length);
195+
for (uint256 i = 0; i < se.storageProviders.length; i++) {
196+
uint64 providerId = se.storageProviders[i];
197+
entityView.providerDetails[i] = Types.ProviderDetailsView({
198+
providerId: providerId,
199+
spaceLeft: se.providerDetails[providerId].spaceLeft,
200+
isActive: se.providerDetails[providerId].isActive
201+
});
202+
}
203+
return entityView;
204+
}
166205
}

src/libraries/Errors.sol

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,4 +119,7 @@ library ErrorLib {
119119

120120
// 0x35278d12
121121
error Overflow();
122+
123+
// 0x8865bd93
124+
error StorageProviderNotAssignedToEntity();
122125
}

src/libraries/Storage.sol

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,10 +40,16 @@ library Storage {
4040
uint256 collateral; // Collateral amount
4141
}
4242

43+
struct ProviderDetails {
44+
bool isActive; // Whether the provider is active
45+
uint256 spaceLeft; // Space left for the provider
46+
}
47+
4348
struct StorageEntity {
4449
bool isActive; // Whether the storage entity is active
4550
address owner; // Owner address, used to verify ownership
4651
uint64[] storageProviders; // List of storage providers
52+
mapping(uint64 => ProviderDetails) providerDetails; // Mapping by provider ID
4753
}
4854

4955
/**

src/libraries/StorageEntityPicker.sol

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,10 @@ library StorageEntityPicker {
4141
* @param numEntities The number of storage providers to pick
4242
*/
4343
// slither-disable-next-line weak-prng
44-
function _pickStorageProviders(uint256 numEntities) internal returns (uint64[] memory) {
44+
function _pickStorageProviders(uint256 numEntities, uint256 maxSpacePerProvider)
45+
internal
46+
returns (uint64[] memory)
47+
{
4548
address[] storage entityAddresses = Storage.s().entityAddresses;
4649
uint256 entityLength = entityAddresses.length;
4750

@@ -59,10 +62,25 @@ library StorageEntityPicker {
5962
address entityAddress = entityAddresses[index];
6063

6164
Storage.StorageEntity storage se = Storage.s().storageEntities[entityAddress];
62-
// SE is active, and has at least one storage provider
63-
if (se.isActive && se.storageProviders.length > 0) {
64-
storageProviders[pickedCount] = Storage.s().storageEntities[entityAddress].storageProviders[0];
65-
pickedCount++;
65+
66+
if (!se.isActive || se.storageProviders.length == 0) {
67+
// If the SE is not active
68+
// or doesn't have at least one provider
69+
// then we can skip it
70+
continue;
71+
}
72+
// Select one storage provider from the active storage entity that has enough space left
73+
for (uint256 j = 0; j < se.storageProviders.length; j++) {
74+
uint64 provider = se.storageProviders[j];
75+
76+
if (
77+
se.providerDetails[provider].isActive
78+
&& se.providerDetails[provider].spaceLeft >= maxSpacePerProvider
79+
) {
80+
storageProviders[pickedCount] = provider;
81+
pickedCount++;
82+
break; // Break the loop after picking one provider
83+
}
6684
}
6785
}
6886

src/libraries/Types.sol

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,4 +132,17 @@ library Types {
132132
// 15301680 -> 1A 00E9A4A0 -> 1 + 4 bytes
133133
int64 expiration;
134134
}
135+
136+
struct StorageEntityView {
137+
bool isActive;
138+
address owner;
139+
uint64[] storageProviders;
140+
ProviderDetailsView[] providerDetails;
141+
}
142+
143+
struct ProviderDetailsView {
144+
bool isActive; // Whether the provider is active
145+
uint64 providerId; // Provider ID
146+
uint256 spaceLeft; // Space left for the provider
147+
}
135148
}

0 commit comments

Comments
 (0)