Check provider precise balance

This commit is contained in:
Arnaud 2025-07-03 18:56:51 +02:00
parent ff0de4d3e0
commit 8f415be2c3
No known key found for this signature in database
GPG Key ID: B8FBC178F10CA7AE

View File

@ -1,5 +1,4 @@
import std/times import std/times
import std/httpclient
import ../../examples import ../../examples
import ../../contracts/time import ../../contracts/time
import ../../contracts/deployment import ../../contracts/deployment
@ -72,8 +71,13 @@ marketplacesuite(name = "Marketplace"):
let availabilities = (await host.getAvailabilities()).get let availabilities = (await host.getAvailabilities()).get
check availabilities.len == 1 check availabilities.len == 1
let datasetSize = datasetSize(blocks, ecNodes, ecTolerance)
let newSize = availabilities[0].freeSize let newSize = availabilities[0].freeSize
check newSize > 0 and newSize < size check newSize > 0 and newSize + datasetSize == size
let reservations = (await host.getAvailabilityReservations(availability.id)).get
check reservations.len == 3
check reservations[0].requestId == purchase.requestId
let signer = ethProvider.getSigner(hostAccount) let signer = ethProvider.getSigner(hostAccount)
let marketplaceWithProviderSigner = marketplace.connect(signer) let marketplaceWithProviderSigner = marketplace.connect(signer)
@ -124,19 +128,17 @@ marketplacesuite(name = "Marketplace"):
let cid = (await client.upload(data)).get let cid = (await client.upload(data)).get
let pricePerSlotPerSecond = minPricePerBytePerSecond * slotSize let pricePerSlotPerSecond = minPricePerBytePerSecond * slotSize
var requestEnd = 0.SecondsSince1970 var providerRewardEvent = newAsyncEvent()
var hostRewardEvent = newAsyncEvent()
proc checkHostRewards() {.async.} =
var rewards = 0.u256
for filledAt in filledAtPerSlot:
rewards += (requestEnd.u256 - filledAt) * pricePerSlotPerSecond
proc checkProviderRewards() {.async.} =
let endBalanceHost = await token.balanceOf(hostAccount) let endBalanceHost = await token.balanceOf(hostAccount)
let requestEnd = await marketplace.requestEnd(requestId)
let rewards = filledAtPerSlot
.mapIt((requestEnd.u256 - it) * pricePerSlotPerSecond)
.foldl(a + b, 0.u256)
if rewards + startBalanceHost == endBalanceHost: if rewards + startBalanceHost == endBalanceHost:
hostRewardEvent.fire() providerRewardEvent.fire()
var clientFundsEvent = newAsyncEvent() var clientFundsEvent = newAsyncEvent()
@ -160,7 +162,7 @@ marketplacesuite(name = "Marketplace"):
let data = eventResult.get() let data = eventResult.get()
if data.receiver == hostAccount: if data.receiver == hostAccount:
asyncSpawn checkHostRewards() asyncSpawn checkProviderRewards()
if data.receiver == clientAccount: if data.receiver == clientAccount:
asyncSpawn checkHostFunds() asyncSpawn checkHostFunds()
@ -179,20 +181,19 @@ marketplacesuite(name = "Marketplace"):
discard await waitForRequestToStart() discard await waitForRequestToStart()
# Proving mechanism uses blockchain clock to do proving/collect/cleanup round stopOnRequestFailed:
# hence we must use `advanceTime` over `sleepAsync` as Hardhat does mine new blocks # Proving mechanism uses blockchain clock to do proving/collect/cleanup round
# only with new transaction # hence we must use `advanceTime` over `sleepAsync` as Hardhat does mine new blocks
await ethProvider.advanceTime(duration.u256) # only with new transaction
await ethProvider.advanceTime(duration.u256)
requestEnd = await marketplace.requestEnd(requestId) let tokenSubscription = await token.subscribe(Transfer, onTransfer)
let tokenSubscription = await token.subscribe(Transfer, onTransfer) await clientFundsEvent.wait().wait(timeout = chronos.seconds(60))
await providerRewardEvent.wait().wait(timeout = chronos.seconds(60))
await clientFundsEvent.wait().wait(timeout = chronos.seconds(60)) await tokenSubscription.unsubscribe()
await hostRewardEvent.wait().wait(timeout = chronos.seconds(60)) await filledSubscription.unsubscribe()
await tokenSubscription.unsubscribe()
await filledSubscription.unsubscribe()
test "SP are able to process slots after workers were busy with other slots and ignored them", test "SP are able to process slots after workers were busy with other slots and ignored them",
NodeConfigs( NodeConfigs(
@ -267,7 +268,14 @@ marketplacesuite(name = "Marketplace"):
discard await waitForRequestToStart() discard await waitForRequestToStart()
# Double check, verify that our second SP hosts the 3 slots # Double check, verify that our second SP hosts the 3 slots
check ((await provider1.client.getSlots()).get).len == 3 let signer = ethProvider.getSigner(hostAccount)
let marketplaceWithProviderSigner = marketplace.connect(signer)
let slots = await marketplaceWithProviderSigner.mySlots()
check slots.len == 3
for slotId in slots:
let slot = await marketplaceWithProviderSigner.getActiveSlot(slotId)
check slot.request.id == purchase.requestId
marketplacesuite(name = "Marketplace payouts"): marketplacesuite(name = "Marketplace payouts"):
const minPricePerBytePerSecond = 1.u256 const minPricePerBytePerSecond = 1.u256
@ -304,6 +312,8 @@ marketplacesuite(name = "Marketplace payouts"):
let providerApi = provider.client let providerApi = provider.client
let startBalanceProvider = await token.balanceOf(provider.ethAccount) let startBalanceProvider = await token.balanceOf(provider.ethAccount)
let startBalanceClient = await token.balanceOf(client.ethAccount) let startBalanceClient = await token.balanceOf(client.ethAccount)
let hostAccount = providers()[0].ethAccount
let clientAccount = clients()[0].ethAccount
# provider makes storage available # provider makes storage available
let datasetSize = datasetSize(blocks, ecNodes, ecTolerance) let datasetSize = datasetSize(blocks, ecNodes, ecTolerance)
@ -319,10 +329,20 @@ marketplacesuite(name = "Marketplace payouts"):
let cid = (await clientApi.upload(data)).get let cid = (await clientApi.upload(data)).get
var slotIdxFilled = none uint64 var filledAtPerSlot: seq[UInt256] = @[]
var slotIndex = 0.uint64
var slotFilledEvent = newAsyncEvent()
proc storeFilledAtTimestamps() {.async.} =
let filledAt = await ethProvider.blockTime(BlockTag.latest)
filledAtPerSlot.add(filledAt)
slotFilledEvent.fire()
proc onSlotFilled(eventResult: ?!SlotFilled) = proc onSlotFilled(eventResult: ?!SlotFilled) =
assert not eventResult.isErr assert not eventResult.isErr
slotIdxFilled = some (!eventResult).slotIndex let event = !eventResult
slotIndex = event.slotIndex
asyncSpawn storeFilledAtTimestamps()
let slotFilledSubscription = await marketplace.subscribe(SlotFilled, onSlotFilled) let slotFilledSubscription = await marketplace.subscribe(SlotFilled, onSlotFilled)
@ -344,18 +364,32 @@ marketplacesuite(name = "Marketplace payouts"):
nodes = ecNodes, nodes = ecNodes,
tolerance = ecTolerance, tolerance = ecTolerance,
) )
let requestId = (await clientApi.requestId(id)).get
# wait until one slot is filled # wait until one slot is filled
check eventually(slotIdxFilled.isSome, timeout = expiry.int * 1000) await slotFilledEvent.wait().wait(timeout = chronos.seconds(expiry.int))
let slotId = slotId(!(await clientApi.requestId(id)), !slotIdxFilled) let slotId = slotId(!(await clientApi.requestId(id)), slotIndex)
let slotSize = slotSize(blocks, ecNodes, ecTolerance)
let pricePerSlotPerSecond = minPricePerBytePerSecond * slotSize
var providerRewardEvent = newAsyncEvent()
proc checkProviderRewards() {.async.} =
let requestEnd = await marketplace.requestEnd(requestId)
let rewards = filledAtPerSlot
.mapIt((requestEnd.u256 - it) * pricePerSlotPerSecond)
.foldl(a + b, 0.u256)
let endBalanceHost = await token.balanceOf(hostAccount)
if rewards + startBalanceProvider == endBalanceHost:
providerRewardEvent.fire()
var counter = 0
var transferEvent = newAsyncEvent()
proc onTransfer(eventResult: ?!Transfer) = proc onTransfer(eventResult: ?!Transfer) =
assert not eventResult.isErr assert not eventResult.isErr
counter += 1
if counter == 3: let data = eventResult.get()
transferEvent.fire() if data.receiver == hostAccount:
asyncSpawn checkProviderRewards()
let tokenAddress = await marketplace.token() let tokenAddress = await marketplace.token()
let token = Erc20Token.new(tokenAddress, ethProvider.getSigner()) let token = Erc20Token.new(tokenAddress, ethProvider.getSigner())
@ -363,30 +397,23 @@ marketplacesuite(name = "Marketplace payouts"):
# wait until sale is cancelled # wait until sale is cancelled
await ethProvider.advanceTime(expiry.u256) await ethProvider.advanceTime(expiry.u256)
await requestCancelledEvent.wait().wait(timeout = chronos.seconds(5)) await requestCancelledEvent.wait().wait(timeout = chronos.seconds(5))
await advanceToNextPeriod() await advanceToNextPeriod()
await transferEvent.wait().wait(timeout = chronos.seconds(60)) await providerRewardEvent.wait().wait(timeout = chronos.seconds(60))
let slotSize = slotSize(blocks, ecNodes, ecTolerance) # Ensure that total rewards stay within the payout limit
let pricePerSlotPerSecond = minPricePerBytePerSecond * slotSize # determined by the expiry date.
let requestEnd = await marketplace.requestEnd(requestId)
let rewards = filledAtPerSlot
.mapIt((requestEnd.u256 - it) * pricePerSlotPerSecond)
.foldl(a + b, 0.u256)
check expiry.u256 * pricePerSlotPerSecond >= rewards
let endBalanceProvider = (await token.balanceOf(provider.ethAccount)) let endBalanceProvider = (await token.balanceOf(provider.ethAccount))
check (
endBalanceProvider > startBalanceProvider and
endBalanceProvider < startBalanceProvider + expiry.u256 * pricePerSlotPerSecond
)
let endBalanceClient = (await token.balanceOf(client.ethAccount)) let endBalanceClient = (await token.balanceOf(client.ethAccount))
check( check(
( startBalanceClient - endBalanceClient == endBalanceProvider - startBalanceProvider
(startBalanceClient - endBalanceClient) ==
(endBalanceProvider - startBalanceProvider)
)
) )
await slotFilledSubscription.unsubscribe() await slotFilledSubscription.unsubscribe()