clean up tests
1. Replace all instances of `now()` with `await currentTime()` to get a more accurate representation of time from the block timestamp. Update examples.js to be async. 2. Move `RequestState` to `marketplace.js` 3. Delete `TestStorage` as `slashAmount` function no longer needed.
This commit is contained in:
parent
ad040cfee6
commit
321132b6fa
|
@ -49,7 +49,6 @@ contract AccountLocks {
|
|||
function _extendLockExpiryTo(bytes32 lockId, uint256 expiry) internal {
|
||||
Lock storage lock = locks[lockId];
|
||||
require(lock.owner != address(0), "Lock does not exist");
|
||||
// require(lock.owner == msg.sender, "Only lock creator can extend expiry");
|
||||
require(lock.expiry >= block.timestamp, "Lock already expired");
|
||||
lock.expiry = expiry;
|
||||
}
|
||||
|
|
|
@ -232,7 +232,7 @@ contract Marketplace is Collateral, Proofs {
|
|||
|
||||
function proofEnd(bytes32 slotId) public view returns (uint256) {
|
||||
Slot memory slot = _slot(slotId);
|
||||
uint256 end = _end(slotId);
|
||||
uint256 end = _end(slot.requestId);
|
||||
if (!_slotAcceptsProofs(slotId)) {
|
||||
return end < block.timestamp ? end : block.timestamp - 1;
|
||||
}
|
||||
|
@ -263,7 +263,7 @@ contract Marketplace is Collateral, Proofs {
|
|||
// TODO: add check for _isFinished
|
||||
if (_isCancelled(requestId)) {
|
||||
return RequestState.Cancelled;
|
||||
else if (_isFinished(requestId) {
|
||||
} else if (_isFinished(requestId)) {
|
||||
return RequestState.Finished;
|
||||
} else {
|
||||
RequestContext storage context = _context(requestId);
|
||||
|
@ -361,15 +361,6 @@ contract Marketplace is Collateral, Proofs {
|
|||
assert(funds.received == funds.balance + funds.sent);
|
||||
}
|
||||
|
||||
function acceptsProofs(bytes32 requestId) private view {
|
||||
RequestState s = state(requestId);
|
||||
require(s == RequestState.New || s == RequestState.Started, "Invalid state");
|
||||
// must test these states separately as they handle cases where the state hasn't
|
||||
// yet been updated by a transaction
|
||||
require(!_isCancelled(requestId), "Request cancelled");
|
||||
require(!_isFinished(requestId), "Request finished");
|
||||
}
|
||||
|
||||
/// @notice Modifier that requires the request state to be that which is accepting proof submissions from hosts occupying slots.
|
||||
/// @dev Request state must be new or started, and must not be cancelled, finished, or failed.
|
||||
/// @param slotId id of the slot, that is mapped to a request, for which to obtain state info
|
||||
|
|
|
@ -82,6 +82,7 @@ contract Storage is Collateral, Marketplace {
|
|||
|
||||
function markProofAsMissing(bytes32 slotId, uint256 period)
|
||||
public
|
||||
slotMustAcceptProofs(slotId)
|
||||
{
|
||||
_markProofAsMissing(slotId, period);
|
||||
address host = _host(slotId);
|
||||
|
|
|
@ -37,7 +37,7 @@ contract TestMarketplace is Marketplace {
|
|||
function testAcceptsProofs(bytes32 slotId)
|
||||
public
|
||||
view
|
||||
slotAcceptsProofs(slotId)
|
||||
slotMustAcceptProofs(slotId)
|
||||
// solhint-disable-next-line no-empty-blocks
|
||||
{
|
||||
|
||||
|
|
|
@ -1,36 +0,0 @@
|
|||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
import "./Storage.sol";
|
||||
|
||||
// exposes internal functions of Storage for testing
|
||||
contract TestStorage is Storage {
|
||||
constructor(
|
||||
IERC20 token,
|
||||
uint256 _proofPeriod,
|
||||
uint256 _proofTimeout,
|
||||
uint8 _proofDowntime,
|
||||
uint256 _collateralAmount,
|
||||
uint256 _slashMisses,
|
||||
uint256 _slashPercentage,
|
||||
uint256 _minCollateralThreshold
|
||||
)
|
||||
Storage(
|
||||
token,
|
||||
_proofPeriod,
|
||||
_proofTimeout,
|
||||
_proofDowntime,
|
||||
_collateralAmount,
|
||||
_slashMisses,
|
||||
_slashPercentage,
|
||||
_minCollateralThreshold
|
||||
)
|
||||
// solhint-disable-next-line no-empty-blocks
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
function slashAmount(address account, uint256 percentage) public view returns (uint256) {
|
||||
return _slashAmount(account, percentage);
|
||||
}
|
||||
}
|
|
@ -18,7 +18,7 @@ async function deployStorage({ deployments, getNamedAccounts }) {
|
|||
minCollateralThreshold,
|
||||
]
|
||||
const { deployer } = await getNamedAccounts()
|
||||
await deployments.deploy("TestStorage", { args, from: deployer })
|
||||
await deployments.deploy("Storage", { args, from: deployer })
|
||||
}
|
||||
|
||||
async function mine256blocks({ network, ethers }) {
|
||||
|
@ -32,5 +32,5 @@ module.exports = async (environment) => {
|
|||
await deployStorage(environment)
|
||||
}
|
||||
|
||||
module.exports.tags = ["TestStorage"]
|
||||
module.exports.tags = ["Storage"]
|
||||
module.exports.dependencies = ["TestToken"]
|
||||
|
|
|
@ -1,10 +1,16 @@
|
|||
const { ethers } = require("hardhat")
|
||||
const { expect } = require("chai")
|
||||
const { hexlify, randomBytes, toHexString } = ethers.utils
|
||||
const { advanceTimeTo, snapshot, revert, advanceTime } = require("./evm")
|
||||
const {
|
||||
advanceTimeTo,
|
||||
snapshot,
|
||||
revert,
|
||||
advanceTime,
|
||||
currentTime,
|
||||
} = require("./evm")
|
||||
const { exampleLock } = require("./examples")
|
||||
const { now, hours } = require("./time")
|
||||
const { waitUntilExpired } = require("./marketplace")
|
||||
const { hours } = require("./time")
|
||||
const { waitUntilCancelled } = require("./marketplace")
|
||||
|
||||
describe("Account Locks", function () {
|
||||
let locks
|
||||
|
@ -16,12 +22,12 @@ describe("Account Locks", function () {
|
|||
|
||||
describe("creating a lock", function () {
|
||||
it("allows creation of a lock with an expiry time", async function () {
|
||||
let { id, expiry } = exampleLock()
|
||||
let { id, expiry } = await exampleLock()
|
||||
await locks.createLock(id, expiry)
|
||||
})
|
||||
|
||||
it("fails to create a lock with an existing id", async function () {
|
||||
let { id, expiry } = exampleLock()
|
||||
let { id, expiry } = await exampleLock()
|
||||
await locks.createLock(id, expiry)
|
||||
await expect(locks.createLock(id, expiry + 1)).to.be.revertedWith(
|
||||
"Lock already exists"
|
||||
|
@ -33,7 +39,7 @@ describe("Account Locks", function () {
|
|||
let lock
|
||||
|
||||
beforeEach(async function () {
|
||||
lock = exampleLock()
|
||||
lock = await exampleLock()
|
||||
await locks.createLock(lock.id, lock.expiry)
|
||||
})
|
||||
|
||||
|
@ -44,7 +50,7 @@ describe("Account Locks", function () {
|
|||
|
||||
it("fails to lock account when lock does not exist", async function () {
|
||||
let [account] = await ethers.getSigners()
|
||||
let nonexistent = exampleLock().id
|
||||
let nonexistent = (await exampleLock()).id
|
||||
await expect(locks.lock(account.address, nonexistent)).to.be.revertedWith(
|
||||
"Lock does not exist"
|
||||
)
|
||||
|
@ -55,7 +61,7 @@ describe("Account Locks", function () {
|
|||
let lock
|
||||
|
||||
beforeEach(async function () {
|
||||
lock = exampleLock()
|
||||
lock = await exampleLock()
|
||||
await locks.createLock(lock.id, lock.expiry)
|
||||
})
|
||||
|
||||
|
@ -64,7 +70,7 @@ describe("Account Locks", function () {
|
|||
})
|
||||
|
||||
it("fails to unlock a lock that does not exist", async function () {
|
||||
let nonexistent = exampleLock().id
|
||||
let nonexistent = (await exampleLock()).id
|
||||
await expect(locks.unlock(nonexistent)).to.be.revertedWith(
|
||||
"Lock does not exist"
|
||||
)
|
||||
|
@ -85,7 +91,7 @@ describe("Account Locks", function () {
|
|||
|
||||
it("unlocks an account whose locks have been unlocked", async function () {
|
||||
let [account] = await ethers.getSigners()
|
||||
let lock = exampleLock()
|
||||
let lock = await exampleLock()
|
||||
await locks.createLock(lock.id, lock.expiry)
|
||||
await locks.lock(account.address, lock.id)
|
||||
await locks.unlock(lock.id)
|
||||
|
@ -94,7 +100,7 @@ describe("Account Locks", function () {
|
|||
|
||||
it("unlocks an account whose locks have expired", async function () {
|
||||
let [account] = await ethers.getSigners()
|
||||
let lock = { ...exampleLock(), expiry: now() }
|
||||
let lock = { ...(await exampleLock()), expiry: currentTime() }
|
||||
await locks.createLock(lock.id, lock.expiry)
|
||||
await locks.lock(account.address, lock.id)
|
||||
await locks.unlockAccount()
|
||||
|
@ -102,7 +108,7 @@ describe("Account Locks", function () {
|
|||
|
||||
it("unlocks multiple accounts tied to the same lock", async function () {
|
||||
let [account0, account1] = await ethers.getSigners()
|
||||
let lock = exampleLock()
|
||||
let lock = await exampleLock()
|
||||
await locks.createLock(lock.id, lock.expiry)
|
||||
await locks.lock(account0.address, lock.id)
|
||||
await locks.lock(account1.address, lock.id)
|
||||
|
@ -113,7 +119,7 @@ describe("Account Locks", function () {
|
|||
|
||||
it("fails to unlock when some locks are still locked", async function () {
|
||||
let [account] = await ethers.getSigners()
|
||||
let [lock1, lock2] = [exampleLock(), exampleLock()]
|
||||
let [lock1, lock2] = [await exampleLock(), await exampleLock()]
|
||||
await locks.createLock(lock1.id, lock1.expiry)
|
||||
await locks.createLock(lock2.id, lock2.expiry)
|
||||
await locks.lock(account.address, lock1.id)
|
||||
|
@ -133,7 +139,7 @@ describe("Account Locks", function () {
|
|||
})
|
||||
|
||||
async function addLock() {
|
||||
let { id, expiry } = exampleLock()
|
||||
let { id, expiry } = await exampleLock()
|
||||
await locks.createLock(id, expiry)
|
||||
await locks.lock(account.address, id)
|
||||
return id
|
||||
|
@ -168,15 +174,18 @@ describe("Account Locks", function () {
|
|||
|
||||
describe("extend lock expiry", function () {
|
||||
let expiry
|
||||
let newExpiry
|
||||
let id
|
||||
|
||||
beforeEach(async function () {
|
||||
await snapshot()
|
||||
|
||||
let lock = exampleLock()
|
||||
let lock = await exampleLock()
|
||||
id = lock.id
|
||||
expiry = lock.expiry
|
||||
await locks.createLock(id, expiry)
|
||||
newExpiry = (await currentTime()) + hours(1)
|
||||
|
||||
let [account] = await ethers.getSigners()
|
||||
await locks.lock(account.address, id)
|
||||
})
|
||||
|
@ -186,30 +195,21 @@ describe("Account Locks", function () {
|
|||
})
|
||||
|
||||
it("fails when lock id doesn't exist", async function () {
|
||||
let other = exampleLock()
|
||||
let other = await exampleLock()
|
||||
await expect(
|
||||
locks.extendLockExpiryTo(other.id, now() + hours(1))
|
||||
locks.extendLockExpiryTo(other.id, newExpiry)
|
||||
).to.be.revertedWith("Lock does not exist")
|
||||
})
|
||||
|
||||
it("fails when lock is already expired", async function () {
|
||||
waitUntilExpired(expiry)
|
||||
await expect(locks.extendLockExpiry(id, hours(1))).to.be.revertedWith(
|
||||
await waitUntilCancelled(expiry)
|
||||
await expect(locks.extendLockExpiryTo(id, newExpiry)).to.be.revertedWith(
|
||||
"Lock already expired"
|
||||
)
|
||||
})
|
||||
|
||||
it("successfully updates lock expiry", async function () {
|
||||
await expect(locks.extendLockExpiryTo(id, now() + hours(1))).not.to.be
|
||||
.reverted
|
||||
})
|
||||
|
||||
it("unlocks account after expiry", async function () {
|
||||
await expect(locks.extendLockExpiryTo(id, now() + hours(1))).not.to.be
|
||||
.reverted
|
||||
await expect(locks.unlockAccount()).to.be.revertedWith("Account locked")
|
||||
advanceTime(hours(1))
|
||||
await expect(locks.unlockAccount()).not.to.be.reverted
|
||||
await expect(locks.extendLockExpiryTo(id, newExpiry)).not.to.be.reverted
|
||||
})
|
||||
})
|
||||
})
|
||||
|
|
|
@ -97,7 +97,7 @@ describe("Collateral", function () {
|
|||
beforeEach(async function () {
|
||||
await token.approve(collateral.address, 42)
|
||||
await collateral.deposit(42)
|
||||
lock = exampleLock()
|
||||
lock = await exampleLock()
|
||||
await collateral.createLock(lock.id, lock.expiry)
|
||||
await collateral.lock(account0.address, lock.id)
|
||||
})
|
||||
|
|
|
@ -2,13 +2,14 @@ const { ethers } = require("hardhat")
|
|||
const { hexlify, randomBytes } = ethers.utils
|
||||
const { expect } = require("chai")
|
||||
const { exampleRequest } = require("./examples")
|
||||
const { now, hours, minutes } = require("./time")
|
||||
const { hours, minutes } = require("./time")
|
||||
const { requestId, slotId, askToArray } = require("./ids")
|
||||
const { waitUntilExpired, waitUntilAllSlotsFilled } = require("./marketplace")
|
||||
const {
|
||||
waitUntilCancelled,
|
||||
waitUntilStarted,
|
||||
waitUntilFinished,
|
||||
waitUntilFailed,
|
||||
RequestState
|
||||
} = require("./marketplace")
|
||||
const { price, pricePerSlot } = require("./price")
|
||||
const {
|
||||
|
@ -16,7 +17,7 @@ const {
|
|||
revert,
|
||||
ensureMinimumBlockHeight,
|
||||
advanceTime,
|
||||
currentTime
|
||||
currentTime,
|
||||
} = require("./evm")
|
||||
|
||||
describe("Marketplace", function () {
|
||||
|
@ -53,7 +54,7 @@ describe("Marketplace", function () {
|
|||
proofDowntime
|
||||
)
|
||||
|
||||
request = exampleRequest()
|
||||
request = await exampleRequest()
|
||||
request.client = client.address
|
||||
|
||||
slot = {
|
||||
|
@ -108,80 +109,6 @@ describe("Marketplace", function () {
|
|||
})
|
||||
})
|
||||
|
||||
describe("freeing a slot", function () {
|
||||
var id
|
||||
beforeEach(async function () {
|
||||
slot.index = 0
|
||||
id = slotId(slot)
|
||||
|
||||
switchAccount(client)
|
||||
await token.approve(marketplace.address, price(request))
|
||||
await marketplace.requestStorage(request)
|
||||
switchAccount(host)
|
||||
await token.approve(marketplace.address, collateral)
|
||||
await marketplace.deposit(collateral)
|
||||
})
|
||||
|
||||
it("fails to free slot when slot not filled", async function () {
|
||||
slot.index = 5
|
||||
let nonExistentId = slotId(slot)
|
||||
await expect(marketplace.freeSlot(nonExistentId)).to.be.revertedWith(
|
||||
"Slot empty"
|
||||
)
|
||||
})
|
||||
|
||||
it("fails to free slot when not started", async function () {
|
||||
await marketplace.fillSlot(slot.request, slot.index, proof)
|
||||
await expect(marketplace.freeSlot(id)).to.be.revertedWith("Invalid state")
|
||||
})
|
||||
|
||||
it("fails to free slot when finished", async function () {
|
||||
await waitUntilStarted(
|
||||
marketplace,
|
||||
request.ask.slots,
|
||||
slot.request,
|
||||
proof
|
||||
)
|
||||
await waitUntilFinished(marketplace, slotId(slot))
|
||||
await expect(marketplace.freeSlot(id)).to.be.revertedWith(
|
||||
"Request finished"
|
||||
)
|
||||
})
|
||||
|
||||
it("successfully frees slot", async function () {
|
||||
await waitUntilStarted(
|
||||
marketplace,
|
||||
request.ask.slots,
|
||||
slot.request,
|
||||
proof
|
||||
)
|
||||
await expect(marketplace.freeSlot(id)).not.to.be.reverted
|
||||
})
|
||||
|
||||
it("emits event once slot is freed", async function () {
|
||||
await waitUntilStarted(
|
||||
marketplace,
|
||||
request.ask.slots,
|
||||
slot.request,
|
||||
proof
|
||||
)
|
||||
await expect(await marketplace.freeSlot(id))
|
||||
.to.emit(marketplace, "SlotFreed")
|
||||
.withArgs(slot.request, id)
|
||||
})
|
||||
|
||||
it("cannot get slot once freed", async function () {
|
||||
await waitUntilStarted(
|
||||
marketplace,
|
||||
request.ask.slots,
|
||||
slot.request,
|
||||
proof
|
||||
)
|
||||
await marketplace.freeSlot(id)
|
||||
await expect(marketplace.slot(id)).to.be.revertedWith("Slot empty")
|
||||
})
|
||||
})
|
||||
|
||||
describe("filling a slot", function () {
|
||||
beforeEach(async function () {
|
||||
switchAccount(client)
|
||||
|
@ -233,7 +160,7 @@ describe("Marketplace", function () {
|
|||
})
|
||||
|
||||
it("is rejected when request is unknown", async function () {
|
||||
let unknown = exampleRequest()
|
||||
let unknown = await exampleRequest()
|
||||
await expect(
|
||||
marketplace.fillSlot(requestId(unknown), 0, proof)
|
||||
).to.be.revertedWith("Unknown request")
|
||||
|
@ -241,7 +168,7 @@ describe("Marketplace", function () {
|
|||
|
||||
it("is rejected when request is cancelled", async function () {
|
||||
switchAccount(client)
|
||||
let expired = { ...request, expiry: now() - hours(1) }
|
||||
let expired = { ...request, expiry: (await currentTime()) - hours(1) }
|
||||
await token.approve(marketplace.address, price(request))
|
||||
await marketplace.requestStorage(expired)
|
||||
switchAccount(host)
|
||||
|
@ -260,7 +187,7 @@ describe("Marketplace", function () {
|
|||
await waitUntilFinished(marketplace, slotId(slot))
|
||||
await expect(
|
||||
marketplace.fillSlot(slot.request, slot.index, proof)
|
||||
).to.be.revertedWith("Request finished")
|
||||
).to.be.revertedWith("Request not accepting proofs")
|
||||
})
|
||||
|
||||
it("is rejected when request is failed", async function () {
|
||||
|
@ -273,7 +200,7 @@ describe("Marketplace", function () {
|
|||
await waitUntilFailed(marketplace, slot, request.ask.maxSlotLoss)
|
||||
await expect(
|
||||
marketplace.fillSlot(slot.request, slot.index, proof)
|
||||
).to.be.revertedWith("Invalid state")
|
||||
).to.be.revertedWith("Request not accepting proofs")
|
||||
})
|
||||
|
||||
it("is rejected when slot index not in range", async function () {
|
||||
|
@ -330,8 +257,21 @@ describe("Marketplace", function () {
|
|||
)
|
||||
})
|
||||
|
||||
it("fails to free slot when finished", async function () {
|
||||
await waitUntilStarted(
|
||||
marketplace,
|
||||
request.ask.slots,
|
||||
slot.request,
|
||||
proof
|
||||
)
|
||||
await waitUntilFinished(marketplace, slotId(slot))
|
||||
await expect(marketplace.freeSlot(id)).to.be.revertedWith(
|
||||
"Slot not accepting proofs"
|
||||
)
|
||||
})
|
||||
|
||||
it("successfully frees slot", async function () {
|
||||
await waitUntilAllSlotsFilled(
|
||||
await waitUntilStarted(
|
||||
marketplace,
|
||||
request.ask.slots,
|
||||
slot.request,
|
||||
|
@ -341,7 +281,7 @@ describe("Marketplace", function () {
|
|||
})
|
||||
|
||||
it("emits event once slot is freed", async function () {
|
||||
await waitUntilAllSlotsFilled(
|
||||
await waitUntilStarted(
|
||||
marketplace,
|
||||
request.ask.slots,
|
||||
slot.request,
|
||||
|
@ -353,7 +293,7 @@ describe("Marketplace", function () {
|
|||
})
|
||||
|
||||
it("cannot get slot once freed", async function () {
|
||||
await waitUntilAllSlotsFilled(
|
||||
await waitUntilStarted(
|
||||
marketplace,
|
||||
request.ask.slots,
|
||||
slot.request,
|
||||
|
@ -388,12 +328,6 @@ describe("Marketplace", function () {
|
|||
expect(endBalance - startBalance).to.equal(pricePerSlot(request))
|
||||
})
|
||||
|
||||
it("is only allowed when the contract is finished", async function () {
|
||||
await expect(
|
||||
marketplace.payoutSlot(slot.request, slot.index)
|
||||
).to.be.revertedWith("Contract not ended")
|
||||
})
|
||||
|
||||
it("is only allowed when the contract has ended", async function () {
|
||||
await marketplace.fillSlot(slot.request, slot.index, proof)
|
||||
await expect(
|
||||
|
@ -454,6 +388,8 @@ describe("Marketplace", function () {
|
|||
await marketplace.fillSlot(slot.request, i, proof)
|
||||
}
|
||||
await expect(await marketplace.state(slot.request)).to.equal(
|
||||
RequestState.Started
|
||||
)
|
||||
})
|
||||
it("fails when all slots are already filled", async function () {
|
||||
const lastSlot = request.ask.slots - 1
|
||||
|
@ -531,7 +467,7 @@ describe("Marketplace", function () {
|
|||
await marketplace.deposit(collateral)
|
||||
})
|
||||
|
||||
it("state is Cancelled when client withdraws funds", async function () {
|
||||
it("changes state to Cancelled when client withdraws funds", async function () {
|
||||
await expect(await marketplace.state(slot.request)).to.equal(
|
||||
RequestState.New
|
||||
)
|
||||
|
@ -599,7 +535,7 @@ describe("Marketplace", function () {
|
|||
})
|
||||
|
||||
it("changes state to Cancelled once request is cancelled", async function () {
|
||||
await waitUntilExpired(request.expiry)
|
||||
await waitUntilCancelled(request.expiry)
|
||||
await expect(await marketplace.state(slot.request)).to.equal(
|
||||
RequestState.Cancelled
|
||||
)
|
||||
|
@ -607,7 +543,7 @@ describe("Marketplace", function () {
|
|||
|
||||
it("changes isCancelled to true once request is cancelled", async function () {
|
||||
await expect(await marketplace.isCancelled(slot.request)).to.be.false
|
||||
await waitUntilExpired(request.expiry)
|
||||
await waitUntilCancelled(request.expiry)
|
||||
await expect(await marketplace.isCancelled(slot.request)).to.be.true
|
||||
})
|
||||
|
||||
|
@ -620,7 +556,7 @@ describe("Marketplace", function () {
|
|||
it("changes isSlotCancelled to true once request is cancelled", async function () {
|
||||
await marketplace.fillSlot(slot.request, slot.index, proof)
|
||||
await expect(await marketplace.isSlotCancelled(slotId(slot))).to.be.false
|
||||
await waitUntilExpired(request.expiry)
|
||||
await waitUntilCancelled(request.expiry)
|
||||
await expect(await marketplace.isSlotCancelled(slotId(slot))).to.be.true
|
||||
})
|
||||
|
||||
|
@ -629,7 +565,7 @@ describe("Marketplace", function () {
|
|||
await expect(await marketplace.proofEnd(slotId(slot))).to.be.gt(
|
||||
await currentTime()
|
||||
)
|
||||
await waitUntilExpired(request.expiry)
|
||||
await waitUntilCancelled(request.expiry)
|
||||
await expect(await marketplace.proofEnd(slotId(slot))).to.be.lt(
|
||||
await currentTime()
|
||||
)
|
||||
|
@ -651,7 +587,7 @@ describe("Marketplace", function () {
|
|||
await waitUntilCancelled(request.expiry)
|
||||
await expect(
|
||||
marketplace.testAcceptsProofs(slotId(slot))
|
||||
).to.be.revertedWith("Request cancelled")
|
||||
).to.be.revertedWith("Slot not accepting proofs")
|
||||
})
|
||||
|
||||
it("fails when request Cancelled (state set to Cancelled)", async function () {
|
||||
|
@ -661,7 +597,7 @@ describe("Marketplace", function () {
|
|||
await marketplace.withdrawFunds(slot.request)
|
||||
await expect(
|
||||
marketplace.testAcceptsProofs(slotId(slot))
|
||||
).to.be.revertedWith("Invalid state")
|
||||
).to.be.revertedWith("Slot not accepting proofs")
|
||||
})
|
||||
|
||||
it("fails when request Finished (isFinished is true)", async function () {
|
||||
|
@ -674,7 +610,7 @@ describe("Marketplace", function () {
|
|||
await waitUntilFinished(marketplace, slotId(slot))
|
||||
await expect(
|
||||
marketplace.testAcceptsProofs(slotId(slot))
|
||||
).to.be.revertedWith("Request finished")
|
||||
).to.be.revertedWith("Slot not accepting proofs")
|
||||
})
|
||||
|
||||
it("fails when request Finished (state set to Finished)", async function () {
|
||||
|
@ -688,7 +624,7 @@ describe("Marketplace", function () {
|
|||
await marketplace.payoutSlot(slot.request, slot.index)
|
||||
await expect(
|
||||
marketplace.testAcceptsProofs(slotId(slot))
|
||||
).to.be.revertedWith("Invalid state")
|
||||
).to.be.revertedWith("Slot not accepting proofs")
|
||||
})
|
||||
|
||||
it("fails when request Failed", async function () {
|
||||
|
@ -708,6 +644,5 @@ describe("Marketplace", function () {
|
|||
).to.be.revertedWith("Slot empty")
|
||||
})
|
||||
})
|
||||
|
||||
})
|
||||
})
|
||||
|
|
|
@ -10,7 +10,7 @@ const {
|
|||
advanceTime,
|
||||
advanceTimeTo,
|
||||
} = require("./evm")
|
||||
const { periodic, hours, now, minutes } = require("./time")
|
||||
const { periodic, hours, minutes } = require("./time")
|
||||
|
||||
describe("Proofs", function () {
|
||||
const id = hexlify(randomBytes(32))
|
||||
|
|
|
@ -32,9 +32,9 @@ describe("Storage", function () {
|
|||
beforeEach(async function () {
|
||||
;[client, host] = await ethers.getSigners()
|
||||
|
||||
await deployments.fixture(["TestToken", "TestStorage"])
|
||||
await deployments.fixture(["TestToken", "Storage"])
|
||||
token = await ethers.getContract("TestToken")
|
||||
storage = await ethers.getContract("TestStorage")
|
||||
storage = await ethers.getContract("Storage")
|
||||
|
||||
await token.mint(client.address, 1_000_000_000)
|
||||
await token.mint(host.address, 1_000_000_000)
|
||||
|
@ -44,7 +44,7 @@ describe("Storage", function () {
|
|||
slashPercentage = await storage.slashPercentage()
|
||||
minCollateralThreshold = await storage.minCollateralThreshold()
|
||||
|
||||
request = exampleRequest()
|
||||
request = await exampleRequest()
|
||||
request.client = client.address
|
||||
slot = {
|
||||
request: requestId(request),
|
||||
|
@ -121,12 +121,7 @@ describe("Storage", function () {
|
|||
it("frees slot when collateral slashed below minimum threshold", async function () {
|
||||
const id = slotId(slot)
|
||||
|
||||
await waitUntilAllSlotsFilled(
|
||||
storage,
|
||||
request.ask.slots,
|
||||
slot.request,
|
||||
proof
|
||||
)
|
||||
await waitUntilStarted(storage, request.ask.slots, slot.request, proof)
|
||||
|
||||
// max slashes before dropping below collateral threshold
|
||||
const maxSlashes = 10
|
||||
|
@ -193,7 +188,6 @@ describe("Storage", function () {
|
|||
await expect(await storage.willProofBeRequired(id)).to.be.false
|
||||
})
|
||||
|
||||
|
||||
it("does not require proofs once cancelled", async function () {
|
||||
const id = slotId(slot)
|
||||
await storage.fillSlot(slot.request, slot.index, proof)
|
||||
|
@ -225,89 +219,6 @@ describe("Storage", function () {
|
|||
expect(BigNumber.from(challenge2).isZero())
|
||||
})
|
||||
})
|
||||
describe("freeing a slot", function () {
|
||||
beforeEach(async function () {
|
||||
period = (await storage.proofPeriod()).toNumber()
|
||||
;({ periodOf, periodEnd } = periodic(period))
|
||||
})
|
||||
|
||||
async function waitUntilProofIsRequired(id) {
|
||||
await advanceTimeTo(periodEnd(periodOf(await currentTime())))
|
||||
while (
|
||||
!(
|
||||
(await storage.isProofRequired(id)) &&
|
||||
(await storage.getPointer(id)) < 250
|
||||
)
|
||||
) {
|
||||
await advanceTime(period)
|
||||
}
|
||||
}
|
||||
|
||||
async function markProofAsMissing(slotId, onMarkAsMissing) {
|
||||
for (let i = 0; i < slashMisses; i++) {
|
||||
await waitUntilProofIsRequired(slotId)
|
||||
let missedPeriod = periodOf(await currentTime())
|
||||
await advanceTime(period)
|
||||
if (i === slashMisses - 1 && typeof onMarkAsMissing === "function") {
|
||||
onMarkAsMissing(missedPeriod)
|
||||
} else await storage.markProofAsMissing(slotId, missedPeriod)
|
||||
}
|
||||
}
|
||||
|
||||
it("frees slot when collateral slashed below minimum threshold", async function () {
|
||||
const id = slotId(slot)
|
||||
|
||||
await waitUntilStarted(storage, request.ask.slots, slot.request, proof)
|
||||
|
||||
while (true) {
|
||||
await markProofAsMissing(id)
|
||||
let balance = await storage.balanceOf(host.address)
|
||||
let slashAmount = await storage.slashAmount(
|
||||
host.address,
|
||||
slashPercentage
|
||||
)
|
||||
if (balance - slashAmount < minCollateralThreshold) {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
let onMarkAsMissing = async function (missedPeriod) {
|
||||
await expect(
|
||||
await storage.markProofAsMissing(id, missedPeriod)
|
||||
).to.emit(storage, "SlotFreed")
|
||||
}
|
||||
await markProofAsMissing(id, onMarkAsMissing)
|
||||
await expect(storage.getSlot(id)).to.be.revertedWith("Slot empty")
|
||||
})
|
||||
})
|
||||
describe("contract state", function () {
|
||||
it("isCancelled is true once request is cancelled", async function () {
|
||||
await expect(await storage.isCancelled(slot.request)).to.equal(false)
|
||||
await waitUntilCancelled(request.expiry)
|
||||
await expect(await storage.isCancelled(slot.request)).to.equal(true)
|
||||
})
|
||||
|
||||
it("isSlotCancelled fails when slot is empty", async function () {
|
||||
await expect(storage.isSlotCancelled(slotId(slot))).to.be.revertedWith(
|
||||
"Slot empty"
|
||||
)
|
||||
})
|
||||
|
||||
it("isSlotCancelled is true once request is cancelled", async function () {
|
||||
await storage.fillSlot(slot.request, slot.index, proof)
|
||||
await waitUntilCancelled(request.expiry)
|
||||
await expect(await storage.isSlotCancelled(slotId(slot))).to.equal(true)
|
||||
})
|
||||
|
||||
it("isFinished is true once started and contract duration lapses", async function () {
|
||||
await expect(await storage.isFinished(slot.request)).to.be.false
|
||||
// fill all slots, should change state to RequestState.Started
|
||||
await waitUntilStarted(storage, request.ask.slots, slot.request, proof)
|
||||
await expect(await storage.isFinished(slot.request)).to.be.false
|
||||
advanceTime(request.ask.duration + 1)
|
||||
await expect(await storage.isFinished(slot.request)).to.be.true
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
// TODO: implement checking of actual proofs of storage, instead of dummy bool
|
||||
|
|
|
@ -1,35 +1,41 @@
|
|||
const { ethers } = require("hardhat")
|
||||
const { now, hours } = require("./time")
|
||||
const { hours } = require("./time")
|
||||
const { currentTime } = require("./evm")
|
||||
const { hexlify, randomBytes } = ethers.utils
|
||||
|
||||
const exampleRequest = () => ({
|
||||
client: hexlify(randomBytes(20)),
|
||||
ask: {
|
||||
slots: 4,
|
||||
slotSize: 1 * 1024 * 1024 * 1024, // 1 Gigabyte
|
||||
duration: hours(10),
|
||||
proofProbability: 4, // require a proof roughly once every 4 periods
|
||||
reward: 84,
|
||||
maxSlotLoss: 2,
|
||||
},
|
||||
content: {
|
||||
cid: "zb2rhheVmk3bLks5MgzTqyznLu1zqGH5jrfTA1eAZXrjx7Vob",
|
||||
erasure: {
|
||||
totalChunks: 12,
|
||||
const exampleRequest = async () => {
|
||||
const now = await currentTime()
|
||||
return {
|
||||
client: hexlify(randomBytes(20)),
|
||||
ask: {
|
||||
slots: 4,
|
||||
slotSize: 1 * 1024 * 1024 * 1024, // 1 Gigabyte
|
||||
duration: hours(10),
|
||||
proofProbability: 4, // require a proof roughly once every 4 periods
|
||||
reward: 84,
|
||||
maxSlotLoss: 2,
|
||||
},
|
||||
por: {
|
||||
u: Array.from(randomBytes(480)),
|
||||
publicKey: Array.from(randomBytes(96)),
|
||||
name: Array.from(randomBytes(512)),
|
||||
content: {
|
||||
cid: "zb2rhheVmk3bLks5MgzTqyznLu1zqGH5jrfTA1eAZXrjx7Vob",
|
||||
erasure: {
|
||||
totalChunks: 12,
|
||||
},
|
||||
por: {
|
||||
u: Array.from(randomBytes(480)),
|
||||
publicKey: Array.from(randomBytes(96)),
|
||||
name: Array.from(randomBytes(512)),
|
||||
},
|
||||
},
|
||||
},
|
||||
expiry: now() + hours(1),
|
||||
nonce: hexlify(randomBytes(32)),
|
||||
})
|
||||
|
||||
const exampleLock = () => ({
|
||||
id: hexlify(randomBytes(32)),
|
||||
expiry: now() + hours(1),
|
||||
})
|
||||
expiry: now + hours(1),
|
||||
nonce: hexlify(randomBytes(32)),
|
||||
}
|
||||
}
|
||||
const exampleLock = async () => {
|
||||
const now = await currentTime()
|
||||
return {
|
||||
id: hexlify(randomBytes(32)),
|
||||
expiry: now + hours(1),
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = { exampleRequest, exampleLock }
|
||||
|
|
|
@ -25,9 +25,18 @@ async function waitUntilFailed(contract, slot, maxSlotLoss) {
|
|||
}
|
||||
}
|
||||
|
||||
const RequestState = {
|
||||
New: 0,
|
||||
Started: 1,
|
||||
Cancelled: 2,
|
||||
Finished: 3,
|
||||
Failed: 4,
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
waitUntilCancelled,
|
||||
waitUntilStarted,
|
||||
waitUntilFinished,
|
||||
waitUntilFailed,
|
||||
RequestState,
|
||||
}
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
const now = () => Math.round(Date.now() / 1000)
|
||||
const hours = (amount) => amount * minutes(60)
|
||||
const minutes = (amount) => amount * seconds(60)
|
||||
const seconds = (amount) => amount
|
||||
|
@ -9,4 +8,4 @@ const periodic = (length) => ({
|
|||
periodEnd: (period) => (period + 1) * length,
|
||||
})
|
||||
|
||||
module.exports = { now, hours, minutes, seconds, periodic }
|
||||
module.exports = { hours, minutes, seconds, periodic }
|
||||
|
|
Loading…
Reference in New Issue