"""Reproduce key statistics using three frozen CSV downloads from one weekly report. Usage: python reproduce-weekly.py observations.csv blocks.csv runs.csv YYYY-MM-DD Python 3 standard library only. The date must be the report's UTC Monday. """ import csv,datetime,json,math,sys def rows(path): with open(path,encoding='utf-8',newline='') as f:return list(csv.DictReader(f)) def quantile(values,q): values=sorted(values) if not values:return None i=(len(values)-1)*q;a=math.floor(i);b=math.ceil(i) return values[a]+(values[b]-values[a])*(i-a) obs,blocks,runs=map(rows,sys.argv[1:4]);start=int(datetime.datetime.strptime(sys.argv[4],'%Y-%m-%d').replace(tzinfo=datetime.timezone.utc).timestamp());end=start+604800 blocks.sort(key=lambda x:int(x['height']));intervals=[];negative=0;missing=0 for a,b in zip(blocks,blocks[1:]): heights=int(b['height'])-int(a['height']);delta=int(b['block_time'])-int(a['block_time']) if heights==1: if delta<0:negative+=1 else:intervals.append(delta) else:missing+=heights-1 slots={int(r['started_at'])//900 for r in runs if int(r['snapshot_ok']) and int(r['blocks_ok'])} times=sorted([start,end]+[int(r['fetched_at']) for r in obs]) print(json.dumps({'snapshots':len(obs),'blocks':len(blocks),'blockIntervals':len(intervals),'negativeIntervals':negative,'missingHeights':missing,'intervalMedianSeconds':quantile(intervals,.5),'intervalP90Seconds':quantile(intervals,.9),'mempoolMedian':quantile([float(r['mempool']) for r in obs if r['mempool']],.5),'successfulSlots':len(slots),'expectedSlots':672,'largestSnapshotGapSeconds':max(b-a for a,b in zip(times,times[1:]))},indent=2))