[marketplace] free slot after too many proofs missed
Needs tests
This commit is contained in:
parent
fdc0e7d58a
commit
7487663534
|
@ -64,6 +64,25 @@ contract AccountLocks {
|
||||||
require(accountLocks.length == 0, "Account locked");
|
require(accountLocks.length == 0, "Account locked");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Removes an account lock
|
||||||
|
function _removeAccountLock(address account, bytes32 lockId) internal {
|
||||||
|
require(accounts[account].locks.length > 0, "Account lock doesn't exist");
|
||||||
|
bytes32[] storage accountLocks = accounts[account].locks;
|
||||||
|
uint256 index = 0;
|
||||||
|
while (true) {
|
||||||
|
if (index >= accountLocks.length) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (accountLocks[index] == lockId) {
|
||||||
|
accountLocks[index] = accountLocks[accountLocks.length - 1];
|
||||||
|
accountLocks.pop();
|
||||||
|
} else {
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
function removeInactiveLocks(bytes32[] storage lockIds) private {
|
function removeInactiveLocks(bytes32[] storage lockIds) private {
|
||||||
uint256 index = 0;
|
uint256 index = 0;
|
||||||
while (true) {
|
while (true) {
|
||||||
|
|
|
@ -51,6 +51,12 @@ contract Collateral is AccountLocks {
|
||||||
internal
|
internal
|
||||||
collateralInvariant
|
collateralInvariant
|
||||||
{
|
{
|
||||||
|
// TODO: perhaps we need to add a minCollateral parameter so that
|
||||||
|
// a host's collateral can't drop below a certain amount, possibly
|
||||||
|
// preventing malicious behaviour when collateral drops too low for it
|
||||||
|
// to matter that it will be lost. Also, we need collateral to be high
|
||||||
|
// enough to cover repair costs in case of repair as well as marked
|
||||||
|
// proofs as missing fees.
|
||||||
uint256 amount = (balanceOf(account) * percentage) / 100;
|
uint256 amount = (balanceOf(account) * percentage) / 100;
|
||||||
funds.slashed += amount;
|
funds.slashed += amount;
|
||||||
subtract(account, amount);
|
subtract(account, amount);
|
||||||
|
|
|
@ -47,13 +47,36 @@ contract Marketplace is Collateral, Proofs {
|
||||||
emit StorageRequested(id, request.ask);
|
emit StorageRequested(id, request.ask);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function _freeSlot(
|
||||||
|
bytes32 slotId
|
||||||
|
) internal marketplaceInvariant {
|
||||||
|
bytes32 requestId = _getRequestIdForSlot(slotId);
|
||||||
|
RequestContext storage context = requestContexts[requestId];
|
||||||
|
require(context.state == RequestState.Started, "Invalid state");
|
||||||
|
require(!_isCancelled(requestId), "Request cancelled");
|
||||||
|
|
||||||
|
Slot storage slot = _slot(slotId);
|
||||||
|
require(slot.host != address(0), "Slot not filled");
|
||||||
|
|
||||||
|
_removeAccountLock(slot.host, requestId);
|
||||||
|
// TODO: burn host's collateral except for repair costs + mark proof
|
||||||
|
// missing reward
|
||||||
|
|
||||||
|
_unexpectProofs(slotId);
|
||||||
|
|
||||||
|
slot.host = address(0);
|
||||||
|
slot.requestId = 0;
|
||||||
|
context.slotsFilled -= 1;
|
||||||
|
emit SlotFreed(requestId, slotId);
|
||||||
|
}
|
||||||
|
|
||||||
function fillSlot(
|
function fillSlot(
|
||||||
bytes32 requestId,
|
bytes32 requestId,
|
||||||
uint256 slotIndex,
|
uint256 slotIndex,
|
||||||
bytes calldata proof
|
bytes calldata proof
|
||||||
) public marketplaceInvariant {
|
) public marketplaceInvariant {
|
||||||
Request storage request = requests[requestId];
|
Request storage request = _request(requestId);
|
||||||
require(request.client != address(0), "Unknown request");
|
// TODO: change below to check !_isCancelled(requestId) instead?
|
||||||
require(request.expiry > block.timestamp, "Request expired");
|
require(request.expiry > block.timestamp, "Request expired");
|
||||||
require(slotIndex < request.ask.slots, "Invalid slot");
|
require(slotIndex < request.ask.slots, "Invalid slot");
|
||||||
RequestContext storage context = requestContexts[requestId];
|
RequestContext storage context = requestContexts[requestId];
|
||||||
|
@ -160,11 +183,13 @@ contract Marketplace is Collateral, Proofs {
|
||||||
}
|
}
|
||||||
|
|
||||||
function _request(bytes32 id) internal view returns (Request storage) {
|
function _request(bytes32 id) internal view returns (Request storage) {
|
||||||
|
Request storage request = requests[id];
|
||||||
|
require(request.client != address(0), "Unknown request");
|
||||||
return requests[id];
|
return requests[id];
|
||||||
}
|
}
|
||||||
|
|
||||||
function _slot(bytes32 slotId) internal view returns (Slot memory) {
|
function _slot(bytes32 slotId) internal view returns (Slot storage) {
|
||||||
Slot memory slot = slots[slotId];
|
Slot storage slot = slots[slotId];
|
||||||
require(slot.host != address(0), "Slot empty");
|
require(slot.host != address(0), "Slot empty");
|
||||||
return slot;
|
return slot;
|
||||||
}
|
}
|
||||||
|
@ -292,8 +317,9 @@ contract Marketplace is Collateral, Proofs {
|
||||||
event SlotFilled(
|
event SlotFilled(
|
||||||
bytes32 indexed requestId,
|
bytes32 indexed requestId,
|
||||||
uint256 indexed slotIndex,
|
uint256 indexed slotIndex,
|
||||||
bytes32 indexed slotId
|
bytes32 slotId
|
||||||
);
|
);
|
||||||
|
event SlotFreed(bytes32 indexed requestId, bytes32 slotId);
|
||||||
event RequestCancelled(bytes32 indexed requestId);
|
event RequestCancelled(bytes32 indexed requestId);
|
||||||
|
|
||||||
modifier marketplaceInvariant() {
|
modifier marketplaceInvariant() {
|
||||||
|
|
|
@ -63,6 +63,13 @@ contract Proofs {
|
||||||
markers[id] = uint256(blockhash(block.number - 1)) % period;
|
markers[id] = uint256(blockhash(block.number - 1)) % period;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function _unexpectProofs(
|
||||||
|
bytes32 id
|
||||||
|
) internal {
|
||||||
|
require(ids[id], "Proof id not in use");
|
||||||
|
ids[id] = false;
|
||||||
|
}
|
||||||
|
|
||||||
function _getPointer(bytes32 id, uint256 proofPeriod)
|
function _getPointer(bytes32 id, uint256 proofPeriod)
|
||||||
internal
|
internal
|
||||||
view
|
view
|
||||||
|
@ -111,7 +118,8 @@ contract Proofs {
|
||||||
pointer = _getPointer(id, proofPeriod);
|
pointer = _getPointer(id, proofPeriod);
|
||||||
bytes32 challenge = _getChallenge(pointer);
|
bytes32 challenge = _getChallenge(pointer);
|
||||||
uint256 probability = (probabilities[id] * (256 - downtime)) / 256;
|
uint256 probability = (probabilities[id] * (256 - downtime)) / 256;
|
||||||
isRequired = uint256(challenge) % probability == 0;
|
// TODO: add test for below change
|
||||||
|
isRequired = ids[id] && uint256(challenge) % probability == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
function _isProofRequired(bytes32 id, uint256 proofPeriod)
|
function _isProofRequired(bytes32 id, uint256 proofPeriod)
|
||||||
|
|
|
@ -9,6 +9,7 @@ contract Storage is Collateral, Marketplace {
|
||||||
uint256 public collateralAmount;
|
uint256 public collateralAmount;
|
||||||
uint256 public slashMisses;
|
uint256 public slashMisses;
|
||||||
uint256 public slashPercentage;
|
uint256 public slashPercentage;
|
||||||
|
uint256 public missThreshold;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
IERC20 token,
|
IERC20 token,
|
||||||
|
@ -17,7 +18,8 @@ contract Storage is Collateral, Marketplace {
|
||||||
uint8 _proofDowntime,
|
uint8 _proofDowntime,
|
||||||
uint256 _collateralAmount,
|
uint256 _collateralAmount,
|
||||||
uint256 _slashMisses,
|
uint256 _slashMisses,
|
||||||
uint256 _slashPercentage
|
uint256 _slashPercentage,
|
||||||
|
uint256 _missThreshold
|
||||||
)
|
)
|
||||||
Marketplace(
|
Marketplace(
|
||||||
token,
|
token,
|
||||||
|
@ -30,6 +32,7 @@ contract Storage is Collateral, Marketplace {
|
||||||
collateralAmount = _collateralAmount;
|
collateralAmount = _collateralAmount;
|
||||||
slashMisses = _slashMisses;
|
slashMisses = _slashMisses;
|
||||||
slashPercentage = _slashPercentage;
|
slashPercentage = _slashPercentage;
|
||||||
|
missThreshold = _missThreshold;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getRequest(bytes32 requestId) public view returns (Request memory) {
|
function getRequest(bytes32 requestId) public view returns (Request memory) {
|
||||||
|
@ -82,8 +85,12 @@ contract Storage is Collateral, Marketplace {
|
||||||
slotMustAcceptProofs(slotId)
|
slotMustAcceptProofs(slotId)
|
||||||
{
|
{
|
||||||
_markProofAsMissing(slotId, period);
|
_markProofAsMissing(slotId, period);
|
||||||
if (_missed(slotId) % slashMisses == 0) {
|
uint256 missed = _missed(slotId);
|
||||||
|
if (missed % slashMisses == 0) {
|
||||||
_slash(_host(slotId), slashPercentage);
|
_slash(_host(slotId), slashPercentage);
|
||||||
}
|
}
|
||||||
|
if (missed > missThreshold) {
|
||||||
|
_freeSlot(slotId);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,7 @@ async function deployStorage({ deployments, getNamedAccounts }) {
|
||||||
const collateralAmount = 100
|
const collateralAmount = 100
|
||||||
const slashMisses = 3
|
const slashMisses = 3
|
||||||
const slashPercentage = 10
|
const slashPercentage = 10
|
||||||
|
const missThreshold = 20
|
||||||
const args = [
|
const args = [
|
||||||
token.address,
|
token.address,
|
||||||
proofPeriod,
|
proofPeriod,
|
||||||
|
@ -14,6 +15,7 @@ async function deployStorage({ deployments, getNamedAccounts }) {
|
||||||
collateralAmount,
|
collateralAmount,
|
||||||
slashMisses,
|
slashMisses,
|
||||||
slashPercentage,
|
slashPercentage,
|
||||||
|
missThreshold,
|
||||||
]
|
]
|
||||||
const { deployer } = await getNamedAccounts()
|
const { deployer } = await getNamedAccounts()
|
||||||
await deployments.deploy("Storage", { args, from: deployer })
|
await deployments.deploy("Storage", { args, from: deployer })
|
||||||
|
|
Loading…
Reference in New Issue