2024-09-23 14:37:17 +00:00
|
|
|
import std/os
|
|
|
|
import std/streams
|
|
|
|
import pkg/chronicles
|
|
|
|
import pkg/chronos
|
|
|
|
import pkg/ethers
|
|
|
|
import pkg/questionable
|
|
|
|
import pkg/questionable/results
|
|
|
|
import pkg/zippy/tarballs
|
|
|
|
import pkg/chronos/apps/http/httpclient
|
|
|
|
import ../../codex/contracts/marketplace
|
|
|
|
|
|
|
|
proc consoleLog(logLevel: LogLevel, msg: LogOutputStr) {.gcsafe.} =
|
|
|
|
try:
|
|
|
|
stdout.write(msg)
|
|
|
|
stdout.flushFile()
|
|
|
|
except IOError as err:
|
|
|
|
logLoggingFailure(cstring(msg), err)
|
|
|
|
|
|
|
|
proc noOutput(logLevel: LogLevel, msg: LogOutputStr) = discard
|
|
|
|
|
|
|
|
defaultChroniclesStream.outputs[0].writer = consoleLog
|
|
|
|
defaultChroniclesStream.outputs[1].writer = noOutput
|
|
|
|
defaultChroniclesStream.outputs[2].writer = noOutput
|
|
|
|
|
|
|
|
proc printHelp() =
|
|
|
|
info "Usage: ./cirdl [circuitPath] [rpcEndpoint] [marketplaceAddress]"
|
|
|
|
info " circuitPath: path where circuit files will be placed."
|
|
|
|
info " rpcEndpoint: URL of web3 RPC endpoint."
|
|
|
|
info " marketplaceAddress: Address of deployed Codex marketplace contracts."
|
|
|
|
|
|
|
|
proc getCircuitHash(rpcEndpoint: string, marketplaceAddress: string): Future[?!string] {.async.} =
|
|
|
|
let provider = JsonRpcProvider.new(rpcEndpoint)
|
|
|
|
without address =? Address.init(marketplaceAddress):
|
|
|
|
return failure("Invalid address: " & marketplaceAddress)
|
|
|
|
|
|
|
|
let marketplace = Marketplace.new(address, provider)
|
2024-10-28 23:13:18 +00:00
|
|
|
let config = await marketplace.configuration()
|
2024-09-23 14:37:17 +00:00
|
|
|
return success config.proofs.zkeyHash
|
|
|
|
|
|
|
|
proc formatUrl(hash: string): string =
|
|
|
|
"https://circuit.codex.storage/proving-key/" & hash
|
|
|
|
|
|
|
|
proc retrieveUrl(uri: string): Future[seq[byte]] {.async.} =
|
|
|
|
let httpSession = HttpSessionRef.new()
|
|
|
|
try:
|
|
|
|
let resp = await httpSession.fetch(parseUri(uri))
|
|
|
|
return resp.data
|
|
|
|
finally:
|
|
|
|
await noCancel(httpSession.closeWait())
|
|
|
|
|
|
|
|
proc downloadZipfile(url: string, filepath: string): Future[?!void] {.async.} =
|
|
|
|
try:
|
|
|
|
let file = await retrieveUrl(url)
|
|
|
|
var s = newFileStream(filepath, fmWrite)
|
|
|
|
for b in file:
|
|
|
|
s.write(b)
|
|
|
|
s.close()
|
|
|
|
except Exception as exc:
|
|
|
|
return failure(exc.msg)
|
|
|
|
success()
|
|
|
|
|
|
|
|
proc unzip(zipfile: string, targetPath: string): ?!void =
|
|
|
|
try:
|
|
|
|
extractAll(zipfile, targetPath)
|
|
|
|
except Exception as exc:
|
|
|
|
return failure(exc.msg)
|
|
|
|
success()
|
|
|
|
|
|
|
|
proc copyFiles(unpackDir: string, circuitPath: string): ?!void =
|
|
|
|
try:
|
|
|
|
for file in walkDir(unpackDir):
|
|
|
|
copyFileToDir(file.path, circuitPath)
|
|
|
|
except Exception as exc:
|
|
|
|
return failure(exc.msg)
|
|
|
|
success()
|
|
|
|
|
|
|
|
proc main() {.async.} =
|
|
|
|
info "Codex Circuit Downloader, Aww yeah!"
|
|
|
|
let args = os.commandLineParams()
|
|
|
|
if args.len != 3:
|
|
|
|
printHelp()
|
|
|
|
return
|
|
|
|
|
|
|
|
let
|
|
|
|
circuitPath = args[0]
|
|
|
|
rpcEndpoint = args[1]
|
|
|
|
marketplaceAddress = args[2]
|
|
|
|
zipfile = "circuit.tar.gz"
|
|
|
|
unpackFolder = "." / "tempunpackfolder"
|
|
|
|
|
|
|
|
debug "Starting", circuitPath, rpcEndpoint, marketplaceAddress
|
|
|
|
|
|
|
|
if (dirExists(unpackFolder)):
|
|
|
|
removeDir(unpackFolder)
|
|
|
|
|
|
|
|
without circuitHash =? (await getCircuitHash(rpcEndpoint, marketplaceAddress)), err:
|
|
|
|
error "Failed to get circuit hash", msg = err.msg
|
|
|
|
return
|
|
|
|
debug "Got circuithash", circuitHash
|
|
|
|
|
|
|
|
let url = formatUrl(circuitHash)
|
2024-10-10 12:05:03 +00:00
|
|
|
info "Download URL", url
|
2024-09-23 14:37:17 +00:00
|
|
|
if dlErr =? (await downloadZipfile(url, zipfile)).errorOption:
|
|
|
|
error "Failed to download circuit file", msg = dlErr.msg
|
|
|
|
return
|
|
|
|
debug "Download completed"
|
|
|
|
|
|
|
|
if err =? unzip(zipfile, unpackFolder).errorOption:
|
|
|
|
error "Failed to unzip file", msg = err.msg
|
|
|
|
return
|
|
|
|
debug "Unzip completed"
|
|
|
|
|
|
|
|
# Unpack library cannot unpack into existing directory. We also cannot
|
|
|
|
# delete the targer directory and have the library recreate it because
|
|
|
|
# Codex has likely created it and set correct permissions.
|
|
|
|
# So, we unpack to a temp folder and move the files.
|
|
|
|
if err =? copyFiles(unpackFolder, circuitPath).errorOption:
|
|
|
|
error "Failed to copy files", msg = err.msg
|
|
|
|
return
|
|
|
|
debug "Files copied"
|
|
|
|
|
|
|
|
removeFile(zipfile)
|
|
|
|
removeDir(unpackFolder)
|
|
|
|
|
|
|
|
debug "file and unpack folder removed"
|
|
|
|
|
|
|
|
when isMainModule:
|
|
|
|
waitFor main()
|
|
|
|
info "Done!"
|