Skip to content

Commit

Permalink
feat: optimizesummary with json output
Browse files Browse the repository at this point in the history
  • Loading branch information
hopeyen committed Aug 23, 2022
1 parent 61c9169 commit 1e2a62f
Show file tree
Hide file tree
Showing 9 changed files with 195 additions and 128 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
.vscode/
opts.json
1 change: 1 addition & 0 deletions Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ Debugger = "31a5f54b-26ea-5ae9-a837-f05ce5417438"
Distributed = "8ba89e20-285c-5b6f-9357-94700520ee1b"
Formatting = "59287772-0a20-5a39-b81b-1366585eb4c0"
GraphQLClient = "09d831e3-9c21-47a9-bfd8-076871817219"
JSON = "682c06a0-de6a-54ab-a142-c8b1cf79cde6"
JuliaFormatter = "98e50ef6-434e-11e9-1051-2b60c6c9e899"
LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"
ProgressMeter = "92933f4c-e287-5a05-a399-4b506db050ca"
Expand Down
8 changes: 4 additions & 4 deletions scripts/allocationopt
Original file line number Diff line number Diff line change
Expand Up @@ -61,10 +61,10 @@ Optimise an indexer's allocations, json output, and log profit summary
- `allocation_lifetime`: The number of epochs for which these allocations would be open. An allocation earns indexing rewards upto 28 epochs.
- `maximum_new_allocations`: The maximum number of new allocations you would like the optimizer to open.
- `τ`: Interval [0,1]. As τ gets closer to 0, the optimiser selects greedy allocations that maximise your short-term, expected rewards, but network dynamics will affect you more. The opposite occurs as τ approaches 1.
- `management_server_url`: The URL that exposes the indexer managment server, including the port. Must begin with http. Example: http://localhost:18000.
- `indexer_service_network_url`: The URL that exposes the indexer service's network endpoint. Must begin with http. Example: http://localhost:7600/network.
- `output_filepath`: A path to write a JSON write that contains optimization results with gross estimation of profit over lifetime and APR.
"""
@cast function optimizesummary(id, network_id, filepath, grtgas, allocation_lifetime, maximum_new_allocations, τ, indexer_service_network_url)
@cast function optimizesummary(id, network_id, filepath, grtgas, allocation_lifetime, maximum_new_allocations, τ, indexer_service_network_url, output_filepath)
# Read subgraph lists defined in the file
cols = read_filterlists(filepath)
pinnedlist = cols[3]
Expand All @@ -76,13 +76,13 @@ Optimise an indexer's allocations, json output, and log profit summary
# Pull full network state from indexer service network endpoint
fullrepo, _, _ = network_state(id, parse(Int, network_id), String[], String[], String[], String[], indexer_service_network_url)

filter_fn = (ω, ψ, Ω) -> apply_preferences(network, parse(Float64, grtgas), parse(Int, allocation_lifetime), ω, ψ, Ω, map(s->s.ipfshash,repo.subgraphs))
filter_fn = (ω, ψ, Ω) -> apply_preferences(network, parse(Float64, grtgas), parse(Int, allocation_lifetime), ω, ψ, Ω, ipfshash.(repo.subgraphs), indexer.allocations, output_filepath)

# Optimize for the indexer
println("Beginning optimisation.")
ω = optimize_indexer(indexer, repo, fullrepo, parse(Int64, maximum_new_allocations), parse(Float64, τ), filter_fn, pinnedlist)

println("Done! Printed top plans with indexing rewards and APR for the allocation lifetime duration, assuming constant network and gas")
println("Done! Printed top plans, assuming constant network and gas, currently read key as number of nonzero allocations in the plan, values as (estimated total profit, APR, Allocation[amounts, profit, apr]). 0 is as if we repeat the same allocations")

return nothing
end
Expand Down
55 changes: 40 additions & 15 deletions src/AllocationOpt.jl
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
module AllocationOpt

using CSV
using JSON
using GraphQLClient

export network_state, optimize_indexer, read_filterlists
export network_state,
optimize_indexer, read_filterlists, write_results, allocated_stake, ipfshash
export push_allocations!, create_rules!, apply_preferences

include("exceptions.jl")
Expand Down Expand Up @@ -109,6 +111,9 @@ function apply_preferences(network::GraphNetworkParameters, gas::Real, allocatio
- `ω::Matrix{Real}`: A matrix of allocations in which the rows have different sparsities.
- `ψ::Vector{Real}`: A vector of subgraph signals.
- `Ω::Vector{Real}`: A vector of the allocations of other indexers.
- `ipfshashes::Vector{String}`: A vector of ipfs hashes on the repo
- `existing_allocations::Vector{Allocation}`: A vector of existing alloactions of the indexer
- `output_path::String`: filepath to write output results
"""
function apply_preferences(
network::GraphNetworkParameters,
Expand All @@ -118,11 +123,16 @@ function apply_preferences(
ψ::AbstractVector{T},
Ω::AbstractVector{T},
ipfshashes::Vector{String},
existing_allocations::Vector{Allocation},
output_path::String,
) where {T<:Real}
ω_curr = allocated_stake_onto_ipfs(ipfshashes, existing_allocations)
profit_sums = map(x -> profit(network, gas, allocation_lifetime, x, ψ, Ω), eachcol(ω))
profit_curr = profit(network, gas, allocation_lifetime, ω_curr, ψ, Ω)
principle_stake = sum(ω[:, 1])
best_i = argmax(profit_sums)

if all(profit_sums . 0)
if (profit_sums[best_i] 0)
throw(
ArgumentError(
"Solver was unable to find a solution with positive expected profit."
Expand All @@ -132,20 +142,22 @@ function apply_preferences(

top_three = partialsortperm(profit_sums, 1:min(3, size(ω, 2)); rev=true)

# APR and profit details for at most 3 top plans of allocations
summary = map(
(profit, x) -> (
profit,
annual_percentage_return(profit, principle_stake, allocation_lifetime),
apr(network, gas, allocation_lifetime, x, ψ, Ω, ipfshashes),
),
profit_sums[top_three],
eachcol(ω[:, top_three]),
summary_dict = Dict(
i => (
p,
annual_percentage_return(p, principle_stake, allocation_lifetime),
apr(network, gas, allocation_lifetime, v, ψ, Ω, ipfshashes),
) for (i, p, v) in zip(top_three, profit_sums[top_three], eachcol(ω[:, top_three]))
)
println("top plans:")
println.(summary)
i = argmax(profit_sums)
return ω[:, i]
# Current profit and returns at 0 allocations
summary_dict[0] = (
profit_curr,
annual_percentage_return(profit_curr, principle_stake, allocation_lifetime),
apr(network, gas, allocation_lifetime, ω_curr, ψ, Ω, ipfshashes),
)
write_results(output_path, summary_dict)

return ω[:, best_i]
end

"""
Expand Down Expand Up @@ -212,6 +224,19 @@ function read_filterlists(filepath::AbstractString)
return cols
end

"""
function write_results(filepath)
# Arguments
- `filepath::AbstractString`: A path to the json file to record optimized results with grossly estimated lifetime profit and APR.
"""
function write_results(filepath::AbstractString, results)
f = open(abspath(filepath), "w")
JSON.print(f, results)
flush(f)
end

"""
function push_allocations!(indexer_id, management_server_url, proposed_allocations, whitelist, blacklist, pinnedlist, frozenlist)
Expand Down
15 changes: 15 additions & 0 deletions src/domainmodel.jl
Original file line number Diff line number Diff line change
Expand Up @@ -154,3 +154,18 @@ stake(i::Indexer) = i.stake
function other_stake(repo::Repository, indexer::Indexer)
return sum(stake.(repo.indexers)) - stake(indexer)
end

function allocated_stake_onto_ipfs(ipfshashes::Vector{String}, allocs::Vector{Allocation})
# Dictionary might be cleaner but this shall work for now (strict ordering
stakes = zeros(length(ipfshashes))
existing_allocs_hashes = ipfshash.(allocs)
rearrange_allocs = Allocation[]
for hash in ipfshashes
if hash in existing_allocs_hashes
push!(rearrange_allocs, allocs[findfirst(a -> ipfshash(a) == hash, allocs)])
end
end
existing_ixs = findall(i -> i in existing_allocs_hashes, ipfshashes)
stakes[existing_ixs] .= allocated_stake.(rearrange_allocs)
return stakes
end
5 changes: 4 additions & 1 deletion src/service.jl
Original file line number Diff line number Diff line change
Expand Up @@ -274,6 +274,9 @@ function apr(
Φ = tokens_issued_over_lifetime(network, allocation_lifetime)

apr = aprᵢ.(ψ, Ω, ω, Φ, network.total_tokens_signalled, gas, allocation_lifetime)
allocation_aprs = Dict(k => (v, a) for (k, v, a) in zip(ipfshashes, ω, apr) if v > 0.0)
profit = profitᵢ(network, gas, allocation_lifetime, ω, ψ, Ω)
allocation_aprs = Dict(
k => (v, p, a) for (k, v, p, a) in zip(ipfshashes, ω, profit, apr) if v > 0.0
)
return allocation_aprs
end
Loading

0 comments on commit 1e2a62f

Please sign in to comment.