Skip to content

Commit

Permalink
WIP
Browse files Browse the repository at this point in the history
Co-authored-by: Max <[email protected]>
  • Loading branch information
Albermonte and onmax committed May 23, 2024
1 parent 4871557 commit 96dacf8
Show file tree
Hide file tree
Showing 8 changed files with 286 additions and 72 deletions.
6 changes: 4 additions & 2 deletions packages/nimiq-vts/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,11 +39,13 @@
"prepublishOnly": "nr build",
"release": "bumpp && npm publish",
"start": "esno src/index.ts",
"typecheck": "tsc --noEmit"
"typecheck": "tsc --noEmit",
"test": "vitest"
},
"dependencies": {
"defu": "^6.1.4",
"nimiq-rpc-client-ts": "^0.3.0"
"nimiq-rpc-client-ts": "^0.3.0",
"vitest": "^1.6.0"
},
"devDependencies": {
"@antfu/ni": "^0.21.12",
Expand Down
15 changes: 15 additions & 0 deletions packages/nimiq-vts/src/score.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { describe, expect, it, beforeEach } from 'vitest'
import { getLiveness } from './score'

describe('should compute livenes correctly', () => {
const fromEpoch = 3075210
const toEpoch = 5062410
const blocksPerEpoch = 43200
const activeEpochBlockNumbers = Array.from({ length: Math.floor((toEpoch - fromEpoch) / blocksPerEpoch) }, (_, i) => fromEpoch + i * blocksPerEpoch)
const weightFactor = 0.5

it('exported', () => {
const liveness = getLiveness({fromEpoch, toEpoch, weightFactor, activeEpochBlockNumbers, blocksPerEpoch })
expect(liveness).toBeGreaterThan(0.5)
})
})
34 changes: 20 additions & 14 deletions packages/nimiq-vts/src/score.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,28 +9,34 @@ export function getSize({ balance, threshold, steepness, totalBalance }: ScorePa
return s
}

// TODO: active epoch numbers convert to binary array
export function getLiveness({ activeEpochBlockNumbers, blocksPerEpoch, fromEpoch, toEpoch, weightFactor }: ScoreParams['liveness']) {
if (!activeEpochBlockNumbers || !fromEpoch || !toEpoch || !weightFactor || !blocksPerEpoch)
throw new Error("Active epoch block numbers, from epoch, to epoch, blocks per epoch, or weight factor is not set")
throw new Error(`Invalid params: ${JSON.stringify({ activeEpochBlockNumbers, blocksPerEpoch, fromEpoch, toEpoch, weightFactor })}`)
if (fromEpoch === -1 || toEpoch === -1 || activeEpochBlockNumbers.length === 0)
throw new Error(`fromEpoch, toEpoch, or activeEpochBlockNumbers is not set: ${fromEpoch}, ${toEpoch}, ${activeEpochBlockNumbers}`)
if (toEpoch - fromEpoch + 1 <= 0)
throw new Error(`Invalid epoch range. fromEpoch: ${fromEpoch}, toEpoch: ${toEpoch}`)

const n = toEpoch - fromEpoch + 1; // Total number of epochs in the window
if (n <= 0) throw new Error('Invalid epoch range');
let weightedSum = 0
let weightTotal = 0

let weightedSum = 0;
let weightTotal = 0;

for (let i = toEpoch; i >= fromEpoch; i--) {
const isActive = activeEpochBlockNumbers.includes(i) ? 1 : 0;
const weight = 1 - weightFactor * (i - fromEpoch) / (toEpoch - fromEpoch);
weightedSum += weight * isActive;
weightTotal += weight;
const n = toEpoch - fromEpoch // Total number of epochs in the window
const indexToBlockNumber = (i: number) => fromEpoch + i * blocksPerEpoch
console.log({ fromEpoch, toEpoch, weightFactor, n })
for (let i = 0; i <= n; i++) {
const index = indexToBlockNumber(i)
const isActive = activeEpochBlockNumbers.indexOf(index) ? 1 : 0
const weight = 1 - weightFactor * index / n
weightedSum += weight * isActive
weightTotal += weight
if(i < 20)
console.log(JSON.stringify({ i, isActive, weight, weightedSum, weightTotal, x: weightFactor * i / n },null, 2))
}
if (weightTotal === 0) throw new Error('Weight total is zero, cannot divide by zero');
if (weightTotal === 0) throw new Error('Weight total is zero, cannot divide by zero')

const movingAverage = weightedSum / weightTotal;
const liveness = -Math.pow(movingAverage, 2) + 2 * movingAverage;
const movingAverage = weightedSum / weightTotal
const liveness = -Math.pow(movingAverage, 2) + 2 * movingAverage

return liveness
}
Expand Down
1 change: 1 addition & 0 deletions packages/nimiq-vts/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ export type ScoreParams = {
reliability?: {}
}
export type ActivityEpoch = { validator: string, assigned: number, missed: number }[]
// TODO: rename ValidatorActivity to be more descriptive
export type ValidatorActivity = Record<string /* address */, { activeEpochBlockNumbers: number[], validatorId: number, balance: number }>
export type EpochActivity = Record<number /* Election block number */, ActivityEpoch>
export type ScoreValues = { liveness: number, reliability: number, size: number, total: number }
Expand Down
1 change: 1 addition & 0 deletions packages/nimiq-vts/src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ export async function getRange(client: Client, options?: GetRangeOptions): Promi
if (errorCurrentEpoch || !currentEpoch) throw new Error(errorCurrentEpoch?.message || 'No current epoch')
toEpochIndex = currentEpoch - 1
}
// Don't go back more than the block after the genesis block
const fromEpochIndex = Math.max(1, toEpochIndex - epochsCount)

// Convert indexes to election blocks
Expand Down
Loading

0 comments on commit 96dacf8

Please sign in to comment.