11import { useQuery } from "@tanstack/react-query" ;
2-
32import { useGraphqlBatcher } from "context/GraphqlBatcher" ;
43import { isUndefined } from "utils/index" ;
5-
64import { graphql } from "src/graphql" ;
75import { HomePageBlockQuery } from "src/graphql/graphql" ;
8- import useGenesisBlock from "../useGenesisBlock" ;
9- export type { HomePageBlockQuery } ;
106
117const homePageBlockQuery = graphql ( `
12- query HomePageBlock($blockNumber: Int ) {
13- presentCourts: courts(orderBy: id, orderDirection: asc) {
8+ query HomePageBlock($pastTimestamp: BigInt ) {
9+ presentCourts: courts(orderBy: id, orderDirection: asc, first: 1000 ) {
1410 id
1511 parent {
1612 id
@@ -21,21 +17,25 @@ const homePageBlockQuery = graphql(`
2117 feeForJuror
2218 effectiveStake
2319 }
24- pastCourts: courts(orderBy: id, orderDirection: asc, block: { number: $blockNumber }) {
25- id
26- parent {
20+ pastCourts: courtCounters(
21+ where: { timestamp_lte: $pastTimestamp }
22+ orderBy: timestamp
23+ orderDirection: desc
24+ first: 1000
25+ ) {
26+ court {
2727 id
2828 }
29- name
3029 numberDisputes
3130 numberVotes
32- feeForJuror
3331 effectiveStake
32+ timestamp
3433 }
3534 }
3635` ) ;
3736
3837type Court = HomePageBlockQuery [ "presentCourts" ] [ number ] ;
38+ type CourtCounter = HomePageBlockQuery [ "pastCourts" ] [ number ] ;
3939type CourtWithTree = Court & {
4040 numberDisputes : number ;
4141 numberVotes : number ;
@@ -58,66 +58,62 @@ export type HomePageBlockStats = {
5858 courts : CourtWithTree [ ] ;
5959} ;
6060
61- export const useHomePageBlockQuery = ( blockNumber : number | undefined , allTime : boolean ) => {
62- const genesisBlock = useGenesisBlock ( ) ;
63- const isEnabled = ! isUndefined ( blockNumber ) || allTime || ! isUndefined ( genesisBlock ) ;
64- const { graphqlBatcher } = useGraphqlBatcher ( ) ;
65-
66- return useQuery < HomePageBlockStats > ( {
67- queryKey : [ `homePageBlockQuery${ blockNumber } -${ allTime } ` ] ,
68- enabled : isEnabled ,
69- staleTime : Infinity ,
70- queryFn : async ( ) => {
71- const targetBlock = Math . max ( blockNumber ! , genesisBlock ! ) ;
72- const data = await graphqlBatcher . fetch ( {
73- id : crypto . randomUUID ( ) ,
74- document : homePageBlockQuery ,
75- variables : { blockNumber : targetBlock } ,
76- } ) ;
77-
78- return processData ( data , allTime ) ;
79- } ,
80- } ) ;
81- } ;
61+ const getCourtMostDisputes = ( courts : CourtWithTree [ ] ) =>
62+ courts . toSorted ( ( a , b ) => b . numberDisputes - a . numberDisputes ) [ 0 ] ;
63+ const getCourtBestDrawingChances = ( courts : CourtWithTree [ ] ) =>
64+ courts . toSorted ( ( a , b ) => b . treeVotesPerPnk - a . treeVotesPerPnk ) [ 0 ] ;
65+ const getBestExpectedRewardCourt = ( courts : CourtWithTree [ ] ) =>
66+ courts . toSorted ( ( a , b ) => b . treeExpectedRewardPerPnk - a . treeExpectedRewardPerPnk ) [ 0 ] ;
8267
8368const processData = ( data : HomePageBlockQuery , allTime : boolean ) => {
84- const presentCourts = data . presentCourts ;
69+ const presentCourts = [ ... data . presentCourts ] . sort ( ( a , b ) => Number ( a . id ) - Number ( b . id ) ) ;
8570 const pastCourts = data . pastCourts ;
86- const processedCourts : CourtWithTree [ ] = Array ( presentCourts . length ) ;
87- const processed = new Set ( ) ;
88-
89- const processCourt = ( id : number ) : CourtWithTree => {
90- if ( processed . has ( id ) ) return processedCourts [ id ] ;
91-
92- processed . add ( id ) ;
93- const court =
94- ! allTime && id < data . pastCourts . length
95- ? addTreeValuesWithDiff ( presentCourts [ id ] , pastCourts [ id ] )
96- : addTreeValues ( presentCourts [ id ] ) ;
97- const parentIndex = court . parent ? Number ( court . parent . id ) - 1 : 0 ;
98-
99- if ( id === parentIndex ) {
100- processedCourts [ id ] = court ;
101- return court ;
71+
72+ const presentCourtsMap = new Map ( presentCourts . map ( ( c ) => [ c . id , c ] ) ) ;
73+ const pastCourtsMap = new Map < string , CourtCounter > ( ) ;
74+ if ( ! allTime ) {
75+ for ( const pastCourt of pastCourts ) {
76+ const courtId = pastCourt . court . id ;
77+ if ( ! pastCourtsMap . has ( courtId ) ) {
78+ pastCourtsMap . set ( courtId , pastCourt ) ;
79+ }
80+ }
81+ }
82+
83+ const processedCourtsMap = new Map < string , CourtWithTree > ( ) ;
84+ const processCourt = ( courtId : string ) : CourtWithTree => {
85+ if ( processedCourtsMap . has ( courtId ) ) return processedCourtsMap . get ( courtId ) ! ;
86+
87+ const court = presentCourtsMap . get ( courtId ) ! ;
88+ const pastCourt = pastCourtsMap . get ( courtId ) ;
89+
90+ const courtWithTree = ! allTime && pastCourt ? addTreeValuesWithDiff ( court , pastCourt ) : addTreeValues ( court ) ;
91+
92+ const parentId = court . parent ?. id ;
93+ if ( ! parentId || courtId === parentId ) {
94+ processedCourtsMap . set ( courtId , courtWithTree ) ;
95+ return courtWithTree ;
10296 }
10397
104- processedCourts [ id ] = {
105- ...court ,
106- treeNumberDisputes : court . treeNumberDisputes + processCourt ( parentIndex ) . treeNumberDisputes ,
107- treeNumberVotes : court . treeNumberVotes + processCourt ( parentIndex ) . treeNumberVotes ,
108- treeVotesPerPnk : court . treeVotesPerPnk + processCourt ( parentIndex ) . treeVotesPerPnk ,
109- treeDisputesPerPnk : court . treeDisputesPerPnk + processCourt ( parentIndex ) . treeDisputesPerPnk ,
110- treeExpectedRewardPerPnk : court . treeExpectedRewardPerPnk + processCourt ( parentIndex ) . treeExpectedRewardPerPnk ,
98+ const parentCourt = processCourt ( parentId ) ;
99+ const fullTreeCourt : CourtWithTree = {
100+ ...courtWithTree ,
101+ treeNumberDisputes : courtWithTree . treeNumberDisputes + parentCourt . treeNumberDisputes ,
102+ treeNumberVotes : courtWithTree . treeNumberVotes + parentCourt . treeNumberVotes ,
103+ treeVotesPerPnk : courtWithTree . treeVotesPerPnk + parentCourt . treeVotesPerPnk ,
104+ treeDisputesPerPnk : courtWithTree . treeDisputesPerPnk + parentCourt . treeDisputesPerPnk ,
105+ treeExpectedRewardPerPnk : courtWithTree . treeExpectedRewardPerPnk + parentCourt . treeExpectedRewardPerPnk ,
111106 } ;
112107
113- return processedCourts [ id ] ;
108+ processedCourtsMap . set ( courtId , fullTreeCourt ) ;
109+ return fullTreeCourt ;
114110 } ;
115111
116112 for ( const court of presentCourts . toReversed ( ) ) {
117- processCourt ( Number ( court . id ) - 1 ) ;
113+ processCourt ( court . id ) ;
118114 }
119115
120- processedCourts . reverse ( ) ;
116+ const processedCourts = [ ... processedCourtsMap . values ( ) ] . sort ( ( a , b ) => Number ( a . id ) - Number ( b . id ) ) ;
121117
122118 return {
123119 mostDisputedCourt : getCourtMostDisputes ( processedCourts ) ,
@@ -148,21 +144,41 @@ const addTreeValues = (court: Court): CourtWithTree => {
148144 } ;
149145} ;
150146
151- const addTreeValuesWithDiff = ( presentCourt : Court , pastCourt : Court ) : CourtWithTree => {
147+ const addTreeValuesWithDiff = ( presentCourt : Court , pastCourt : CourtCounter | undefined ) : CourtWithTree => {
152148 const presentCourtWithTree = addTreeValues ( presentCourt ) ;
153- const pastCourtWithTree = addTreeValues ( pastCourt ) ;
154- const diffNumberVotes = presentCourtWithTree . numberVotes - pastCourtWithTree . numberVotes ;
155- const diffNumberDisputes = presentCourtWithTree . numberDisputes - pastCourtWithTree . numberDisputes ;
156- const avgEffectiveStake = ( presentCourtWithTree . effectiveStake + pastCourtWithTree . effectiveStake ) / 2n ;
149+
150+ if ( ! pastCourt ) {
151+ console . warn ( `Missing snapshot for court ${ presentCourt . id } , falling back to live` ) ;
152+ return presentCourtWithTree ;
153+ }
154+
155+ const pastNumberVotes = Number ( pastCourt . numberVotes ) ;
156+ const pastNumberDisputes = Number ( pastCourt . numberDisputes ) ;
157+ const pastEffectiveStake = BigInt ( pastCourt . effectiveStake ) ;
158+
159+ const diffNumberVotes = presentCourtWithTree . numberVotes - pastNumberVotes ;
160+ const diffNumberDisputes = presentCourtWithTree . numberDisputes - pastNumberDisputes ;
161+
162+ const hasLiveActivity = presentCourtWithTree . numberDisputes > 0 || presentCourtWithTree . numberVotes > 0 ;
163+ const hasSnapshotActivity = diffNumberDisputes > 0 || diffNumberVotes > 0 ;
164+
165+ if ( ! hasSnapshotActivity && hasLiveActivity ) {
166+ console . warn ( `Snapshot shows no delta for court ${ presentCourt . id } , using live` ) ;
167+ return presentCourtWithTree ;
168+ }
169+
170+ const avgEffectiveStake = ( presentCourtWithTree . effectiveStake + pastEffectiveStake ) / 2n ;
157171 const votesPerPnk = diffNumberVotes / ( Number ( avgEffectiveStake ) / 1e18 ) || 0 ;
158172 const disputesPerPnk = diffNumberDisputes / ( Number ( avgEffectiveStake ) / 1e18 ) || 0 ;
159173 const expectedRewardPerPnk = votesPerPnk * ( Number ( presentCourt . feeForJuror ) / 1e18 ) ;
174+
160175 return {
161176 ...presentCourt ,
162- numberDisputes : presentCourtWithTree . numberDisputes - pastCourtWithTree . numberDisputes ,
163- treeNumberDisputes : presentCourtWithTree . treeNumberDisputes - pastCourtWithTree . treeNumberDisputes ,
177+ numberDisputes : diffNumberDisputes ,
178+ treeNumberDisputes : diffNumberDisputes ,
164179 numberVotes : diffNumberVotes ,
165- treeNumberVotes : presentCourtWithTree . treeNumberVotes - pastCourtWithTree . treeNumberVotes ,
180+ treeNumberVotes : diffNumberVotes ,
181+ feeForJuror : presentCourtWithTree . feeForJuror ,
166182 effectiveStake : avgEffectiveStake ,
167183 votesPerPnk,
168184 treeVotesPerPnk : votesPerPnk ,
@@ -173,9 +189,21 @@ const addTreeValuesWithDiff = (presentCourt: Court, pastCourt: Court): CourtWith
173189 } ;
174190} ;
175191
176- const getCourtMostDisputes = ( courts : CourtWithTree [ ] ) =>
177- courts . toSorted ( ( a : CourtWithTree , b : CourtWithTree ) => b . numberDisputes - a . numberDisputes ) [ 0 ] ;
178- const getCourtBestDrawingChances = ( courts : CourtWithTree [ ] ) =>
179- courts . toSorted ( ( a , b ) => b . treeVotesPerPnk - a . treeVotesPerPnk ) [ 0 ] ;
180- const getBestExpectedRewardCourt = ( courts : CourtWithTree [ ] ) =>
181- courts . toSorted ( ( a , b ) => b . treeExpectedRewardPerPnk - a . treeExpectedRewardPerPnk ) [ 0 ] ;
192+ export const useHomePageBlockQuery = ( pastTimestamp : bigint | undefined , allTime : boolean ) => {
193+ const { graphqlBatcher } = useGraphqlBatcher ( ) ;
194+ const isEnabled = ! isUndefined ( pastTimestamp ) || allTime ;
195+
196+ return useQuery < HomePageBlockStats > ( {
197+ queryKey : [ `homePageBlockQuery${ pastTimestamp ?. toString ( ) } -${ allTime } ` ] ,
198+ enabled : isEnabled ,
199+ staleTime : Infinity ,
200+ queryFn : async ( ) => {
201+ const data = await graphqlBatcher . fetch ( {
202+ id : crypto . randomUUID ( ) ,
203+ document : homePageBlockQuery ,
204+ variables : { pastTimestamp : allTime ? "0" : pastTimestamp ?. toString ( ) } ,
205+ } ) ;
206+ return processData ( data , allTime ) ;
207+ } ,
208+ } ) ;
209+ } ;
0 commit comments