Skip to content
This repository has been archived by the owner on Sep 5, 2020. It is now read-only.

Commit

Permalink
Store profits by asset and scale
Browse files Browse the repository at this point in the history
  • Loading branch information
wilsonianb committed Oct 19, 2018
1 parent 34c745f commit 747e931
Show file tree
Hide file tree
Showing 7 changed files with 373 additions and 13 deletions.
52 changes: 52 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@
"@sharafian/cog": "0.0.5",
"@types/handlebars": "^4.0.38",
"@types/inert": "^5.1.1",
"@types/stream-to-promise": "^2.2.0",
"@types/vision": "^5.3.4",
"@types/ws": "^5.1.2",
"axios": "^0.18.0",
Expand All @@ -73,6 +74,7 @@
"multi-read-stream": "^2.0.0",
"reduct": "^3.2.0",
"riverpig": "^1.1.3",
"stream-to-promise": "^2.2.0",
"thirty-two": "^1.0.2",
"through2": "^2.0.3",
"vision": "^5.3.3",
Expand Down
18 changes: 14 additions & 4 deletions src/controllers/admin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import Config from '../services/Config'
import Ildcp from '../services/Ildcp'
import PodDatabase from '../services/PodDatabase'
import CodiusDB from '../util/CodiusDB'
import BigNumber from 'bignumber.js'
import { Injector } from 'reduct'
const Enjoi = require('enjoi')
const ConfigUpdate = require('../schemas/ConfigUpdate.json')
Expand Down Expand Up @@ -39,13 +40,22 @@ export default function (server: Hapi.Server, deps: Injector) {

async function getAllUptime (request: Hapi.Request, h: Hapi.ResponseToolkit) {
const uptime = podDatabase.getLifetimePodsUptime()
const profitRaw = await codiusdb.getProfit()
const profit = profitRaw.shiftedBy(-ildcp.getAssetScale())
const profitsRaw = await codiusdb.getProfits()
const profits = {}
profits[ildcp.getAssetCode()] = new BigNumber(0)

Object.keys(profitsRaw).forEach((assetCode: string) => {
profits[assetCode] = new BigNumber(0)
Object.keys(profitsRaw[assetCode]).forEach((assetScaleStr: string) => {
const assetScale = parseInt(assetScaleStr, 10)
const profit = profitsRaw[assetCode][assetScaleStr].shiftedBy(-assetScale)
profits[assetCode] = profits[assetCode].plus(profit)
})
profits[assetCode] = profits[assetCode].toString()
})
return {
aggregate_pod_uptime: uptime.toString(),
aggregate_earnings: profit.toString(),
currency: ildcp.getAssetCode()
aggregate_earnings: profits
}
}

Expand Down
4 changes: 2 additions & 2 deletions src/controllers/pods.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,10 +54,10 @@ export default function (server: Hapi.Server, deps: Injector) {

async function addProfit (amount: BigNumber.Value): Promise<void> {
if (profit === undefined) {
profit = await codiusdb.getProfit()
profit = await codiusdb.getProfit(ildcp.getAssetCode(), ildcp.getAssetScale())
}
profit = profit.plus(amount)
await codiusdb.setProfit(profit)
await codiusdb.setProfit(ildcp.getAssetCode(), ildcp.getAssetScale(), profit)
}

async function chargeForDuration (request: any): Promise<string> {
Expand Down
89 changes: 82 additions & 7 deletions src/util/CodiusDB.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,52 @@ import encode from 'encoding-down'
import { Injector } from 'reduct'
import BigNumber from 'bignumber.js'
import Config from '../services/Config'
import streamToPromise = require('stream-to-promise')

const PEERS_KEY = 'codiusPeers'
const PODS_KEY = 'codiusPods'
const MANIFEST_KEY = 'codiusManifests'
const PROFIT_KEY = 'codiusProfit'

interface StreamData {
key: string
value: string
}

interface Asset {
code: string
scale: number
}

const legacyDefaultAsset = {
code: 'XRP',
scale: 6
}

function profitKey (assetCode: string, assetScale: number): string {
if (assetCode === legacyDefaultAsset.code && assetScale === legacyDefaultAsset.scale) {
return PROFIT_KEY
}
return PROFIT_KEY + ':' + assetCode + ':' + assetScale
}

function parseProfitKey (key: string): Asset {
const keyParts = key.split(':')
if (keyParts[0] !== PROFIT_KEY) {
throw new Error('parseProfitKey invalid profit key for key=' + key)
}
if (keyParts.length === 1) {
return legacyDefaultAsset
} else if (keyParts.length !== 3) {
throw new Error('parseProfitKey invalid profit key for key=' + key)
} else {
return {
code: keyParts[1],
scale: parseInt(keyParts[2], 10)
}
}
}

export default class CodiusDB {
private config: Config
private db: LevelUp
Expand All @@ -30,7 +70,7 @@ export default class CodiusDB {
this.db = levelup(encode(backend, { valueEncoding: 'json' }))
}

// Manifest Methds
// Manifest Methods
async getManifest (hash: string): Promise<Manifest | void> {
return this.get(MANIFEST_KEY + ':' + hash)
}
Expand Down Expand Up @@ -69,18 +109,47 @@ export default class CodiusDB {
await this.delete(PEERS_KEY)
}

async getProfit (): Promise<BigNumber> {
const profit = await this.loadValue(PROFIT_KEY, new BigNumber(0))
async getProfit (assetCode: string, assetScale: number): Promise<BigNumber> {
const profit = await this.loadValue(profitKey(assetCode, assetScale), '0')
return new BigNumber(profit)
}

async setProfit (_profit: BigNumber.Value): Promise<void> {
async getProfits (): Promise<Object> {
const profits = {}
await this.createReadStream({
gte: PROFIT_KEY,
lt: PROFIT_KEY + ':~'
}, function (data: StreamData) {
const asset = parseProfitKey(data.key)
if (!profits[asset.code]) {
profits[asset.code] = {}
}
profits[asset.code][asset.scale.toString()] = new BigNumber(data.value)
})
return profits
}

async setProfit (assetCode: string, assetScale: number, _profit: BigNumber.Value): Promise<void> {
const profit = new BigNumber(_profit)
await this.saveValue(PROFIT_KEY, profit.toString())
await this.saveValue(profitKey(assetCode, assetScale), profit.toString())
}

async deleteProfit (): Promise<void> {
await this.delete(PROFIT_KEY)
async deleteProfit (assetCode: string, assetScale: number): Promise<void> {
await this.delete(profitKey(assetCode, assetScale))
}

async deleteProfits (): Promise<void> {
const keys: string[] = []
await this.createReadStream({
gte: PROFIT_KEY,
lt: PROFIT_KEY + ':~',
values: false
}, function (key: string) {
keys.push(key)
})
for (let key of keys) {
await this.delete(key)
}
}

// Save and Load serialized values
Expand Down Expand Up @@ -122,4 +191,10 @@ export default class CodiusDB {
private async delete (key: string) {
await this.db.del(key)
}

private async createReadStream (options: {}, callback: (...args: any[]) => void): Promise<void> {
const stream = this.db.createReadStream(options)
stream.on('data', callback)
await streamToPromise(stream)
}
}
67 changes: 67 additions & 0 deletions test/adminServer.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import AdminServer from '../src/services/AdminServer'
import CodiusDB from '../src/util/CodiusDB'
import Ildcp from '../src/services/Ildcp'
import BigNumber from 'bignumber.js'
import chai = require('chai')
import * as reduct from 'reduct'
const assert = chai.assert

describe('AdminServer', () => {
let codiusdb: any
let ildcp: any
let server: any

beforeEach(async () => {
const deps = reduct()
ildcp = deps(Ildcp)
codiusdb = deps(CodiusDB)
server = deps(AdminServer).getServer()
await ildcp.init()
})

describe('/getAllUptime', () => {

it('should return earnings and pod uptime', async () => {
const request = {
method: 'GET',
url: '/getAllUptime'
}
const response = await server.inject(request)
const res = JSON.parse(response.payload)
assert.isOk(res, 'Returns object')
assert.hasAllKeys(res, ['aggregate_pod_uptime', 'aggregate_earnings'])
assert.strictEqual(res.aggregate_pod_uptime, '0')
assert.isOk(res.aggregate_earnings)
})

it('should return zero for no profits', async () => {
const request = {
method: 'GET',
url: '/getAllUptime'
}
const response = await server.inject(request)
const res = JSON.parse(response.payload)
const expectedEarnings = {}
expectedEarnings[ildcp.getAssetCode()] = '0'
assert.deepEqual(res.aggregate_earnings, expectedEarnings)
})

it('should return profits', async () => {
await codiusdb.setProfit('USD', 2, new BigNumber(100))
await codiusdb.setProfit('XRP', 6, new BigNumber(2000000))
await codiusdb.setProfit('XRP', 9, new BigNumber(3000000000))
const request = {
method: 'GET',
url: '/getAllUptime'
}
const response = await server.inject(request)
const res = JSON.parse(response.payload)
const expectedEarnings = {
USD: '1',
XRP: '5'
}
expectedEarnings[ildcp.getAssetCode()] = '0'
assert.deepEqual(res.aggregate_earnings, expectedEarnings)
})
})
})
Loading

0 comments on commit 747e931

Please sign in to comment.