[node] Store datasets locally when sales asks for it
This commit is contained in:
parent
7bc5280596
commit
adcb91a5d5
|
@ -168,6 +168,39 @@ proc store*(
|
||||||
|
|
||||||
return manifest.cid.success
|
return manifest.cid.success
|
||||||
|
|
||||||
|
proc store(node: CodexNodeRef, cid: Cid): Future[?!void] {.async.}
|
||||||
|
|
||||||
|
proc store(node: CodexNodeRef, cids: seq[Cid]): Future[?!void] {.async.} =
|
||||||
|
## Retrieves multiple datasets from the network, and stores them locally
|
||||||
|
|
||||||
|
let batches = max(1, cids.len div FetchBatch)
|
||||||
|
for batch in cids.distribute(batches, true):
|
||||||
|
let results = await allFinished(cids.mapIt(node.store(it)))
|
||||||
|
for future in results:
|
||||||
|
let res = await future
|
||||||
|
if res.isFailure:
|
||||||
|
return failure res.error
|
||||||
|
|
||||||
|
return success()
|
||||||
|
|
||||||
|
proc store(node: CodexNodeRef, cid: Cid): Future[?!void] {.async.} =
|
||||||
|
## Retrieves dataset from the network, and stores it locally
|
||||||
|
|
||||||
|
if node.blockstore.hasBlock(cid):
|
||||||
|
return success()
|
||||||
|
|
||||||
|
without blk =? await node.blockstore.getBlock(cid):
|
||||||
|
return failure newException(CodexError, "Unable to retrieve block " & $cid)
|
||||||
|
|
||||||
|
if not (await node.blockstore.putBlock(blk)):
|
||||||
|
return failure newException(CodexError, "Unable to store block " & $cid)
|
||||||
|
|
||||||
|
if manifest =? Manifest.decode(blk.data, blk.cid):
|
||||||
|
|
||||||
|
let res = await node.store(manifest.blocks)
|
||||||
|
if res.isFailure:
|
||||||
|
return failure res.error
|
||||||
|
|
||||||
proc requestStorage*(self: CodexNodeRef,
|
proc requestStorage*(self: CodexNodeRef,
|
||||||
cid: Cid,
|
cid: Cid,
|
||||||
duration: UInt256,
|
duration: UInt256,
|
||||||
|
@ -279,11 +312,8 @@ proc start*(node: CodexNodeRef) {.async.} =
|
||||||
await node.discovery.start()
|
await node.discovery.start()
|
||||||
|
|
||||||
if contracts =? node.contracts:
|
if contracts =? node.contracts:
|
||||||
contracts.sales.retrieve = proc(cid: string) {.async.} =
|
contracts.sales.store = proc(cid: string) {.async.} =
|
||||||
let stream = (await node.retrieve(Cid.init(cid).tryGet())).tryGet()
|
(await node.store(Cid.init(cid).tryGet())).tryGet()
|
||||||
while not stream.atEof():
|
|
||||||
var buffer: array[4096, byte]
|
|
||||||
discard await readOnce(stream, addr buffer[0], buffer.len)
|
|
||||||
contracts.sales.prove = proc(cid: string): Future[seq[byte]] {.async.} =
|
contracts.sales.prove = proc(cid: string): Future[seq[byte]] {.async.} =
|
||||||
return @[42'u8] # TODO: generate actual proof
|
return @[42'u8] # TODO: generate actual proof
|
||||||
await contracts.start()
|
await contracts.start()
|
||||||
|
|
|
@ -15,7 +15,7 @@ type
|
||||||
clock: Clock
|
clock: Clock
|
||||||
subscription: ?Subscription
|
subscription: ?Subscription
|
||||||
available*: seq[Availability]
|
available*: seq[Availability]
|
||||||
retrieve: ?Retrieve
|
store: ?Store
|
||||||
prove: ?Prove
|
prove: ?Prove
|
||||||
onSale: ?OnSale
|
onSale: ?OnSale
|
||||||
Availability* = object
|
Availability* = object
|
||||||
|
@ -33,7 +33,7 @@ type
|
||||||
running: ?Future[void]
|
running: ?Future[void]
|
||||||
waiting: ?Future[void]
|
waiting: ?Future[void]
|
||||||
finished: bool
|
finished: bool
|
||||||
Retrieve = proc(cid: string): Future[void] {.gcsafe, upraises: [].}
|
Store = proc(cid: string): Future[void] {.gcsafe, upraises: [].}
|
||||||
Prove = proc(cid: string): Future[seq[byte]] {.gcsafe, upraises: [].}
|
Prove = proc(cid: string): Future[seq[byte]] {.gcsafe, upraises: [].}
|
||||||
OnSale = proc(availability: Availability, request: StorageRequest) {.gcsafe, upraises: [].}
|
OnSale = proc(availability: Availability, request: StorageRequest) {.gcsafe, upraises: [].}
|
||||||
|
|
||||||
|
@ -51,8 +51,8 @@ proc init*(_: type Availability,
|
||||||
doAssert randomBytes(id) == 32
|
doAssert randomBytes(id) == 32
|
||||||
Availability(id: id, size: size, duration: duration, minPrice: minPrice)
|
Availability(id: id, size: size, duration: duration, minPrice: minPrice)
|
||||||
|
|
||||||
proc `retrieve=`*(sales: Sales, retrieve: Retrieve) =
|
proc `store=`*(sales: Sales, store: Store) =
|
||||||
sales.retrieve = some retrieve
|
sales.store = some store
|
||||||
|
|
||||||
proc `prove=`*(sales: Sales, prove: Prove) =
|
proc `prove=`*(sales: Sales, prove: Prove) =
|
||||||
sales.prove = some prove
|
sales.prove = some prove
|
||||||
|
@ -122,8 +122,8 @@ proc start(agent: SalesAgent) {.async.} =
|
||||||
let market = sales.market
|
let market = sales.market
|
||||||
let availability = agent.availability
|
let availability = agent.availability
|
||||||
|
|
||||||
without retrieve =? sales.retrieve:
|
without store =? sales.store:
|
||||||
raiseAssert "retrieve proc not set"
|
raiseAssert "store proc not set"
|
||||||
|
|
||||||
without prove =? sales.prove:
|
without prove =? sales.prove:
|
||||||
raiseAssert "prove proc not set"
|
raiseAssert "prove proc not set"
|
||||||
|
@ -139,7 +139,7 @@ proc start(agent: SalesAgent) {.async.} =
|
||||||
|
|
||||||
agent.waiting = some agent.waitForExpiry()
|
agent.waiting = some agent.waitForExpiry()
|
||||||
|
|
||||||
await retrieve(request.content.cid)
|
await store(request.content.cid)
|
||||||
let proof = await prove(request.content.cid)
|
let proof = await prove(request.content.cid)
|
||||||
await market.fulfillRequest(request.id, proof)
|
await market.fulfillRequest(request.id, proof)
|
||||||
except CancelledError:
|
except CancelledError:
|
||||||
|
|
|
@ -32,7 +32,7 @@ suite "Sales":
|
||||||
market = MockMarket.new()
|
market = MockMarket.new()
|
||||||
clock = MockClock.new()
|
clock = MockClock.new()
|
||||||
sales = Sales.new(market, clock)
|
sales = Sales.new(market, clock)
|
||||||
sales.retrieve = proc(_: string) {.async.} = discard
|
sales.store = proc(_: string) {.async.} = discard
|
||||||
sales.prove = proc(_: string): Future[seq[byte]] {.async.} = return proof
|
sales.prove = proc(_: string): Future[seq[byte]] {.async.} = return proof
|
||||||
await sales.start()
|
await sales.start()
|
||||||
request.expiry = (clock.now() + 42).u256
|
request.expiry = (clock.now() + 42).u256
|
||||||
|
@ -74,16 +74,16 @@ suite "Sales":
|
||||||
discard await market.requestStorage(tooBig)
|
discard await market.requestStorage(tooBig)
|
||||||
check sales.available == @[availability]
|
check sales.available == @[availability]
|
||||||
|
|
||||||
test "retrieves data":
|
test "retrieves and stores data locally":
|
||||||
var retrievingCid: string
|
var storingCid: string
|
||||||
sales.retrieve = proc(cid: string) {.async.} = retrievingCid = cid
|
sales.store = proc(cid: string) {.async.} = storingCid = cid
|
||||||
sales.add(availability)
|
sales.add(availability)
|
||||||
discard await market.requestStorage(request)
|
discard await market.requestStorage(request)
|
||||||
check retrievingCid == request.content.cid
|
check storingCid == request.content.cid
|
||||||
|
|
||||||
test "makes storage available again when data retrieval fails":
|
test "makes storage available again when data retrieval fails":
|
||||||
let error = newException(IOError, "data retrieval failed")
|
let error = newException(IOError, "data retrieval failed")
|
||||||
sales.retrieve = proc(cid: string) {.async.} = raise error
|
sales.store = proc(cid: string) {.async.} = raise error
|
||||||
sales.add(availability)
|
sales.add(availability)
|
||||||
discard await market.requestStorage(request)
|
discard await market.requestStorage(request)
|
||||||
check sales.available == @[availability]
|
check sales.available == @[availability]
|
||||||
|
@ -116,14 +116,14 @@ suite "Sales":
|
||||||
|
|
||||||
test "makes storage available again when other host fulfills request":
|
test "makes storage available again when other host fulfills request":
|
||||||
let otherHost = Address.example
|
let otherHost = Address.example
|
||||||
sales.retrieve = proc(_: string) {.async.} = await sleepAsync(1.hours)
|
sales.store = proc(_: string) {.async.} = await sleepAsync(1.hours)
|
||||||
sales.add(availability)
|
sales.add(availability)
|
||||||
discard await market.requestStorage(request)
|
discard await market.requestStorage(request)
|
||||||
market.fulfillRequest(request.id, proof, otherHost)
|
market.fulfillRequest(request.id, proof, otherHost)
|
||||||
check sales.available == @[availability]
|
check sales.available == @[availability]
|
||||||
|
|
||||||
test "makes storage available again when request expires":
|
test "makes storage available again when request expires":
|
||||||
sales.retrieve = proc(_: string) {.async.} = await sleepAsync(1.hours)
|
sales.store = proc(_: string) {.async.} = await sleepAsync(1.hours)
|
||||||
sales.add(availability)
|
sales.add(availability)
|
||||||
discard await market.requestStorage(request)
|
discard await market.requestStorage(request)
|
||||||
clock.set(request.expiry.truncate(int64))
|
clock.set(request.expiry.truncate(int64))
|
||||||
|
|
Loading…
Reference in New Issue