import Db from "./db" ; import ChainData from "./chaindata" ; import logger from "./logger" ; import { checkUnclaimed , OTV } from "./constraints" ; import Monitor from "./monitor" ; import { Subscan } from "./subscan" ; import { arrayBuffer } from "stream/consumers" ; import { Referendum , ReferendumVote } from "./types" ; export const monitorJob = async ( db , monitor ) => { const start = Date . now ( ) ; logger . info ( `(cron::Monitor::start) Running Monitor job` ) ; await monitor . getLatestTaggedRelease ( ) ; const end = Date . now ( ) ; logger . info ( `{cron::Monitor::ExecutionTime} started at ${ new Date ( start ) . toString ( ) } Done. Took ${ ( end - start ) / 1000 } seconds` ) ; } ; export const validityJob = async ( db , chaindata , allCandidates , constraints ) => { const start = Date . now ( ) ; logger . info ( `(cron::Validity::start) Running validity cron` ) ; for ( const candidate of allCandidates ) { await constraints . checkCandidate ( candidate ) ; } const end = Date . now ( ) ; logger . info ( `{cron::Validity::ExecutionTime} started at ${ new Date ( start ) . toString ( ) } Done. Took ${ ( end - start ) / 1000 } seconds` ) ; } ; export const scoreJob = async ( constraints ) => { const start = Date . now ( ) ; logger . info ( `(cron::Score::start) Running score cron` ) ; constraints . scoreAllCandidates ( ) ; const end = Date . now ( ) ; logger . info ( `{cron::Score::ExecutionTime} started at ${ new Date ( start ) . toString ( ) } Done. Took ${ ( end - start ) / 1000 } seconds` ) ; } ; export const eraStatsJob = async ( db , chaindata , allCandidates ) => { const start = Date . now ( ) ; logger . info ( `(cron::eraStats::start) Running era stats cron` ) ; const currentEra = await chaindata . getCurrentEra ( ) ; const valid = allCandidates . filter ( ( candidate ) => candidate . valid ) ; const active = allCandidates . filter ( ( candidate ) => candidate . active ) ; await db . setEraStats ( Number ( currentEra ) , allCandidates . length , valid . length , active . length ) ; const end = Date . now ( ) ; logger . info ( `{cron::eraStats::ExecutionTime} started at ${ new Date ( start ) . toString ( ) } Done. Took ${ ( end - start ) / 1000 } seconds` ) ; } ; export const eraPointsJob = async ( db , chaindata ) => { const start = Date . now ( ) ; logger . info ( `{cron::EraPointsJob} setting era info` ) ; const [ activeEra , err ] = await chaindata . getActiveEraIndex ( ) ; for ( let i = activeEra - 1 ; i > activeEra - 84 && i >= 0 ; i -- ) { const erapoints = await db . getTotalEraPoints ( i ) ; if ( ! ! erapoints && erapoints . totalEraPoints >= 70000 && erapoints . median ) { continue ; } else { logger . info ( `{cron::EraPointsJob} era ${ i } point data doesnt exist. Creating....` ) ; const { era , total , validators } = await chaindata . getTotalEraPoints ( i ) ; await db . setTotalEraPoints ( era , total , validators ) ; } } const { era , total , validators } = await chaindata . getTotalEraPoints ( activeEra ) ; await db . setTotalEraPoints ( era , total , validators ) ; const end = Date . now ( ) ; logger . info ( `{cron::EraPointsJob::ExecutionTime} started at ${ new Date ( start ) . toString ( ) } Done. Took ${ ( end - start ) / 1000 } seconds` ) ; } ; export const validatorPrefJob = async ( db , chaindata , candidates ) => { const start = Date . now ( ) ; for ( const candidate of candidates ) { const identity = await chaindata . getFormattedIdentity ( candidate . stash ) ; await db . setIdentity ( candidate . stash , identity ) ; const [ commission , err ] = await chaindata . getCommission ( candidate . stash ) ; const formattedCommission = commission == 0 ? 0 : commission / Math . pow ( 10 , 7 ) ; await db . setCommission ( candidate . stash , formattedCommission ) ; const controller = await chaindata . getControllerFromStash ( candidate . stash ) ; await db . setController ( candidate . stash , controller ) ; const rewardDestination = await chaindata . getRewardDestination ( candidate . stash ) ; await db . setRewardDestination ( candidate . stash , rewardDestination ) ; const [ bonded , err2 ] = await chaindata . getBondedAmount ( candidate . stash ) ; await db . setBonded ( candidate . stash , bonded ) ; } const end = Date . now ( ) ; logger . info ( `{cron::ValidatorPrefJob::ExecutionTime} started at ${ new Date ( start ) . toString ( ) } Done. Took ${ ( end - start ) / 1000 } seconds` ) ; } ; export const unclaimedErasJob = async ( db , chaindata , candidates , unclaimedEraThreshold ) => { const start = Date . now ( ) ; for ( const candidate of candidates ) { const unclaimedEras = await chaindata . getUnclaimedEras ( candidate . stash , db ) ; await db . setUnclaimedEras ( candidate . stash , unclaimedEras ) ; await checkUnclaimed ( db , chaindata , unclaimedEraThreshold , candidate ) ; } const end = Date . now ( ) ; logger . info ( `{cron::UnclaimedEraJob::ExecutionTime} started at ${ new Date ( start ) . toString ( ) } Done. Took ${ ( end - start ) / 1000 } seconds` ) ; } ; export const sessionKeyJob = async ( db , chaindata , candidates ) => { const start = Date . now ( ) ; const queuedKeys = await chaindata . getQueuedKeys ( ) ; for ( const candidate of candidates ) { for ( const key of queuedKeys ) { if ( key . address == candidate . stash ) { await db . setQueuedKeys ( candidate . stash , key . keys ) ; } } const nextKeys = await chaindata . getNextKeys ( candidate . stash ) ; await db . setNextKeys ( candidate . stash , nextKeys ) ; } const end = Date . now ( ) ; logger . info ( `{cron::SessionKeyJob::ExecutionTime} started at ${ new Date ( start ) . toString ( ) } Done. Took ${ ( end - start ) / 1000 } seconds` ) ; } ; export const inclusionJob = async ( db , chaindata , candidates ) => { const start = Date . now ( ) ; const [ activeEra , err ] = await chaindata . getActiveEraIndex ( ) ; for ( const candidate of candidates ) { const erasActive = await db . getHistoryDepthEraPoints ( candidate . stash , activeEra ) ; const filteredEras = erasActive . filter ( ( era ) => era . eraPoints > 0 ) ; const inclusion = Number ( filteredEras . length / 84 ) ; await db . setInclusion ( candidate . stash , inclusion ) ; const spanErasActive = await db . getSpanEraPoints ( candidate . stash , activeEra ) ; const filteredSpanEras = spanErasActive . filter ( ( era ) => era . eraPoints > 0 ) ; const spanInclusion = Number ( filteredSpanEras . length / 28 ) ; await db . setSpanInclusion ( candidate . stash , spanInclusion ) ; } const end = Date . now ( ) ; logger . info ( `{cron::InclusionJob::ExecutionTime} started at ${ new Date ( start ) . toString ( ) } Done. Took ${ ( end - start ) / 1000 } seconds` ) ; } ; export const activeValidatorJob = async ( db , chaindata , candidates ) => { const start = Date . now ( ) ; const activeValidators = await chaindata . currentValidators ( ) ; for ( const candidate of candidates ) { const active = activeValidators . includes ( candidate . stash ) ; await db . setActive ( candidate . stash , active ) ; } const end = Date . now ( ) ; logger . info ( `{cron::ActiveValidatorJob::ExecutionTime} started at ${ new Date ( start ) . toString ( ) } Done. Took ${ ( end - start ) / 1000 } seconds` ) ; } ; export const locationStatsJob = async ( db , chaindata , candidates ) => { const start = Date . now ( ) ; const session = await chaindata . getSession ( ) ; const locationMap = new Map ( ) ; const locationArr = [ ] ; for ( const candidate of candidates ) { const location = candidate . location || "No Location" ; const address = candidate . stash ; const locationCount = locationMap . get ( location ) ; if ( ! locationCount ) { locationMap . set ( location , 1 ) ; } else { locationMap . set ( location , locationCount + 1 ) ; } } for ( const location of locationMap . entries ( ) ) { const [ name , numberOfNodes ] = location ; locationArr . push ( { name , numberOfNodes } ) ; } await db . setLocationStats ( session , locationArr ) ; const end = Date . now ( ) ; logger . info ( `{cron::locationStatsJob::ExecutionTime} started at ${ new Date ( start ) . toString ( ) } Done. Took ${ ( end - start ) / 1000 } seconds` ) ; } ; export const councilJob = async ( db , chaindata , candidates ) => { const start = Date . now ( ) ; const session = await chaindata . getSession ( ) ; const candidateAddresses = candidates . map ( ( candidate ) => { return candidate . stash ; } ) ; const councilVoting = await chaindata . getCouncilVoting ( ) ; for ( const vote of councilVoting ) { const isCandidate = candidateAddresses . includes ( vote . who . toString ( ) ) ; if ( isCandidate ) { db . setCouncilBacking ( vote . who . toString ( ) , vote . stake , vote . votes ) ; } } const totalVoters = councilVoting . length ; const totalBonded = councilVoting . reduce ( ( a , b ) => a + b . stake , 0 ) ; const electionsInfo = await chaindata . getElectionsInfo ( ) ; const { candidacyBond , desiredSeats , termDuration } = electionsInfo ; const totalMembers = electionsInfo . members . length ; const totalRunnersUp = electionsInfo . runnersUp . length ; const totalCandidates = electionsInfo . candidates . length ; await db . setElectionStats ( termDuration . toNumber ( ) , candidacyBond , totalMembers , totalRunnersUp , totalCandidates , totalVoters , totalBonded , session ) ; if ( totalMembers ) { for ( const member of electionsInfo . members ) { const { address , totalBacking } = member ; await db . setCouncillor ( address . toString ( ) , "Member" , totalBacking ) ; } } if ( totalRunnersUp ) { for ( const member of electionsInfo . runnersUp ) { const { address , totalBacking } = member ; await db . setCouncillor ( address . toString ( ) , "Runner Up" , totalBacking ) ; } } if ( totalCandidates ) { for ( const member of electionsInfo . candidates ) { const { address , totalBacking } = member ; await db . setCouncillor ( address . toString ( ) , "Candidate" , totalBacking ) ; } } const end = Date . now ( ) ; logger . info ( `{cron::councilJob::ExecutionTime} started at ${ new Date ( start ) . toString ( ) } Done. Took ${ ( end - start ) / 1000 } seconds` ) ; } ; export const subscanJob = async ( db , subscan , candidates ) => { const start = Date . now ( ) ; const eraPaidEvents = await subscan . getEraPaid ( ) ; for ( const event of eraPaidEvents ) { if ( event ) { const { era , blockNumber , blockTimestamp , eventIndex , moduleId , eventId , totalValidatorsReward , totalRemainderReward , } = event ; await db . setEraPaidEvent ( era , blockNumber , blockTimestamp , eventIndex , moduleId , eventId , totalValidatorsReward , totalRemainderReward ) ; } else { logger . info ( `{cron::subscanJob::eraPaidEvent} event ${ event } is empty` ) ; } } for ( const candidate of candidates ) { const rewards = await subscan . getRewards ( candidate . stash ) ; let totalRewards = 0 ; let totalClaimTimestampDelta = 0 ; let totalClaimBlockDelta = 0 ; for ( const reward of rewards ) { const { era , stash , rewardDestination , validatorStash , amount , blockTimestamp , blockNumber , slashKTon , } = reward ; const unclaimedRewards = candidate . unclaimedEras ; const eraPaid = await db . getEraPaidEvent ( era ) ; const eraPaidBlockNumber = eraPaid ?. blockNumber ? eraPaid ?. blockNumber : 0 ; const eraPaidBlockTimestamp = eraPaid ?. blockTimesamp ? eraPaid ?. blockTimesamp : 0 ; const claimTimestampDelta = blockTimestamp != 0 ? eraPaidBlockTimestamp - blockTimestamp : 0 ; const claimBlockDelta = blockNumber != 0 ? eraPaidBlockNumber - blockNumber : 0 ; totalRewards = totalRewards + amount ; totalClaimTimestampDelta = totalClaimTimestampDelta + claimTimestampDelta ; totalClaimBlockDelta = totalClaimBlockDelta + claimBlockDelta ; await db . setEraReward ( era , stash , rewardDestination , validatorStash , amount , blockTimestamp , blockNumber , slashKTon , claimTimestampDelta ? claimTimestampDelta : 0 , claimBlockDelta ? claimBlockDelta : 0 ) ; } const avgClaimTimestampDelta = ! isNaN ( rewards . length ) && rewards . length > 0 ? totalClaimTimestampDelta / rewards . length : 0 ; const avgClaimBlockDelta = ! isNaN ( rewards . length ) && rewards . length > 0 ? totalClaimBlockDelta / rewards . length : 0 ; await db . setClaimDelta ( candidate . stash , avgClaimBlockDelta , avgClaimTimestampDelta ) ; await db . setTotalRewards ( candidate . stash , totalRewards ) ; } const end = Date . now ( ) ; logger . info ( `{cron::subscanJob::ExecutionTime} started at ${ new Date ( start ) . toString ( ) } Done. Took ${ ( end - start ) / 1000 } seconds` ) ; } ; export const democracyJob = async ( db , chaindata ) => { const start = Date . now ( ) ; const latestBlockNumber = await chaindata . getLatestBlock ( ) ; const latestBlockHash = await chaindata . getLatestBlockHash ( ) ; const denom = await chaindata . getDenom ( ) ; const referendaQuery = await chaindata . getDerivedReferenda ( ) ; for ( const r of referendaQuery ) { if ( ! r ) continue ; const { image : { at = 0 , balance = 0 , proposal , proposer = "0x" , } , imageHash , index , status : { end = 0 , proposalHash , threshold = "" , delay , tally : { ayes , nays , turnout , } , } , allAye , allNay , voteCount = 0 , voteCountAye = 0 , voteCountNay = 0 , votedAye = 0 , votedNay = 0 , votedTotal = 0 , isPassing , votes , } = r ; const referendum = { referendumIndex : index . toNumber ( ) , proposedAt : Number ( at ) , proposalEnd : Number ( end ) , proposalDelay : delay . toNumber ( ) , threshold : threshold . toString ( ) , deposit : parseFloat ( balance . toString ( ) ) / denom , proposer : proposer . toString ( ) , imageHash : imageHash . toString ( ) , voteCount : voteCount , voteCountAye : voteCountAye , voteCountNay : voteCountNay , voteAyeAmount : parseFloat ( votedAye . toString ( ) ) / denom , voteNayAmount : parseFloat ( votedNay . toString ( ) ) / denom , voteTotalAmount : parseFloat ( votedTotal . toString ( ) ) / denom , isPassing : isPassing , } ; await db . setReferendum ( referendum , latestBlockNumber , latestBlockHash ) ; for ( const v of votes ) { const { accountId , isDelegating , initialU8aLength , vote , balance } = v ; const { vote : voteDirection , conviction } = vote . toHuman ( ) ; const referendumVote = { referendumIndex : index . toNumber ( ) , accountId : accountId . toString ( ) , isDelegating : isDelegating , balance : parseFloat ( balance . toString ( ) ) / denom , voteDirection : voteDirection , conviction : conviction , } ; await db . setReferendumVote ( referendumVote , latestBlockNumber , latestBlockHash ) ; } } const endTime = Date . now ( ) ; logger . info ( `{cron::councilJob::ExecutionTime} started at ${ new Date ( start ) . toString ( ) } Done. Took ${ ( endTime - start ) / 1000 } seconds` ) ; } ;