proof-of-portfolio 0.0.80__py3-none-any.whl → 0.0.82__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,2 +1,2 @@
1
1
  # This file is auto-generated during build
2
- __version__ = "0.0.80"
2
+ __version__ = "0.0.82"
@@ -6,37 +6,38 @@ import time
6
6
  import json
7
7
  import bittensor as bt
8
8
 
9
- # Constants for the circuit
10
9
  MAX_DAYS = 120
11
10
  MAX_SIGNALS = 256
12
11
  MERKLE_DEPTH = 8
13
- ARRAY_SIZE = 256
14
12
  SCALING_FACTOR = 10**7
13
+ RATIO_SCALE_FACTOR = 1_000_000
14
+ PRIME = 21888242871839275222246405745257275088548364400416034343698204186575808495617
15
15
 
16
16
 
17
- def run_command(command, cwd, verbose=True):
18
- """Executes a command in a given directory and returns the output."""
17
+ def log_verbose(verbose, level, message):
18
+ if verbose:
19
+ getattr(bt.logging, level)(message)
20
+
21
+
22
+ def get_attr(obj, attr):
23
+ """Get attribute from object or dictionary"""
24
+ return getattr(obj, attr) if hasattr(obj, attr) else obj[attr]
25
+
26
+
27
+ def run_command(command, cwd):
19
28
  result = subprocess.run(command, capture_output=True, text=True, cwd=cwd)
20
29
  if result.returncode != 0:
21
- if verbose:
22
- bt.logging.error("Error:")
23
- bt.logging.error(result.stdout)
24
- bt.logging.error(result.stderr)
30
+ bt.logging.error(f"Command failed: {' '.join(command)}")
31
+ bt.logging.error(f"stdout: {result.stdout}")
32
+ bt.logging.error(f"stderr: {result.stderr}")
25
33
  raise RuntimeError(
26
34
  f"Command {' '.join(command)} failed with exit code {result.returncode}"
27
35
  )
28
36
  return result.stdout
29
37
 
30
38
 
31
- def parse_nargo_struct_output(output):
32
- """
33
- Parses the raw output of a nargo execute command that returns a struct.
34
- """
35
- if (
36
- "[" in output
37
- and "]" in output
38
- and not ("MerkleTree" in output or "ReturnsData" in output)
39
- ):
39
+ def parse_circuit_output(output):
40
+ if "[" in output and "]" in output and "MerkleTree" not in output:
40
41
  array_matches = re.findall(r"\[([^\]]+)\]", output)
41
42
  if array_matches:
42
43
  array_content = array_matches[-1]
@@ -63,59 +64,37 @@ def parse_nargo_struct_output(output):
63
64
 
64
65
  if "MerkleTree" in output:
65
66
  tree = {}
66
- try:
67
- # Parse leaf_hashes
68
- if "leaf_hashes:" in struct_content:
69
- start = struct_content.find("leaf_hashes:") + len("leaf_hashes:")
70
- end = struct_content.find(", path_elements:")
71
- leaf_section = struct_content[start:end].strip()
72
- if leaf_section.startswith("[") and leaf_section.endswith("]"):
73
- leaf_content = leaf_section[1:-1]
74
- tree["leaf_hashes"] = [
75
- x.strip() for x in leaf_content.split(",") if x.strip()
76
- ]
77
-
78
- # Parse path_elements
79
- if "path_elements:" in struct_content:
80
- start = struct_content.find("path_elements:") + len("path_elements:")
81
- end = struct_content.find(", path_indices:")
82
- path_elem_section = struct_content[start:end].strip()
83
- tree["path_elements"] = parse_nested_arrays(path_elem_section)
84
-
85
- # Parse path_indices
86
- if "path_indices:" in struct_content:
87
- start = struct_content.find("path_indices:") + len("path_indices:")
88
- end = struct_content.find(", root:")
89
- path_idx_section = struct_content[start:end].strip()
90
- tree["path_indices"] = parse_nested_arrays(path_idx_section)
91
-
92
- # Parse root
93
- if "root:" in struct_content:
94
- start = struct_content.find("root:") + len("root:")
95
- root_section = struct_content[start:].strip().rstrip("}")
96
- tree["root"] = root_section.strip()
97
-
98
- return tree
99
- except Exception:
100
- pass
67
+ if "path_elements:" in struct_content:
68
+ start = struct_content.find("path_elements:") + len("path_elements:")
69
+ end = struct_content.find(", path_indices:")
70
+ path_elem_section = struct_content[start:end].strip()
71
+ tree["path_elements"] = parse_nested_arrays(path_elem_section)
101
72
 
102
- values = []
73
+ if "path_indices:" in struct_content:
74
+ start = struct_content.find("path_indices:") + len("path_indices:")
75
+ end = struct_content.find(", root:")
76
+ path_idx_section = struct_content[start:end].strip()
77
+ tree["path_indices"] = parse_nested_arrays(path_idx_section)
78
+
79
+ if "root:" in struct_content:
80
+ start = struct_content.find("root:") + len("root:")
81
+ root_section = struct_content[start:].strip().rstrip("}")
82
+ tree["root"] = root_section.strip()
83
+
84
+ return tree
103
85
 
86
+ values = []
104
87
  parts = re.split(r"[,\s]+", struct_content)
105
88
  for part in parts:
106
89
  part = part.strip("{}[](), \t\n\r")
107
90
  if not part:
108
91
  continue
109
-
110
- # Check if it's a hex value
111
92
  if part.startswith("0x") and len(part) > 2:
112
93
  try:
113
94
  values.append(str(int(part, 16)))
114
95
  continue
115
96
  except ValueError:
116
97
  pass
117
-
118
- # Check if it's a negative number
119
98
  if part.lstrip("-").isdigit():
120
99
  values.append(part)
121
100
 
@@ -123,7 +102,6 @@ def parse_nargo_struct_output(output):
123
102
 
124
103
 
125
104
  def parse_nested_arrays(section):
126
- """Helper function to parse nested array structures like [[...], [...]]"""
127
105
  if not section.strip().startswith("["):
128
106
  return []
129
107
 
@@ -134,116 +112,66 @@ def parse_nested_arrays(section):
134
112
  for char in section:
135
113
  if char == "[":
136
114
  depth += 1
137
- if depth == 2: # Start of inner array
115
+ if depth == 2:
138
116
  current_array = ""
139
- elif depth == 1: # Start of outer array
117
+ elif depth == 1:
140
118
  continue
141
119
  elif char == "]":
142
120
  depth -= 1
143
- if depth == 1: # End of inner array
121
+ if depth == 1:
144
122
  if current_array.strip():
145
123
  arrays.append(
146
124
  [x.strip() for x in current_array.split(",") if x.strip()]
147
125
  )
148
126
  current_array = ""
149
- elif depth == 0: # End of outer array
127
+ elif depth == 0:
150
128
  break
151
- elif depth == 2: # Inside inner array
129
+ elif depth == 2:
152
130
  current_array += char
153
131
 
154
132
  return arrays
155
133
 
156
134
 
157
- def parse_single_field_output(output):
158
- """
159
- Parses nargo output that contains a single field value.
160
- Handles both new hex format (0x...) and old Field() format.
161
- Returns the integer value, or None if no field found.
162
- """
163
- if "0x" in output:
164
- hex_match = output.split("0x")[1].split()[0]
165
- return int(hex_match, 16)
166
-
167
- if "Field(" in output:
168
- return int(output.split("Field(")[1].split(")")[0])
169
-
170
- return None
171
-
172
-
173
135
  def field_to_toml_value(f):
174
- """Converts a negative integer field to a proper field element string."""
175
- PRIME = (
176
- 21888242871839275222246405745257275088548364400416034343698204186575808495617
177
- )
178
- if f < 0:
179
- return str(f + PRIME)
180
- return str(f)
136
+ return str(f + PRIME) if f < 0 else str(f)
181
137
 
182
138
 
183
- def run_bb_prove(circuit_dir):
184
- """
185
- Runs barretenberg proving.
186
- Returns proof generation time and status.
187
- """
188
- print("\n--- Running Barretenberg Proof Generation ---")
139
+ def field_to_signed_int(field_str):
140
+ val = int(field_str, 16) if field_str.startswith("0x") else int(field_str)
141
+ return val - 2**64 if val >= 2**63 else val
189
142
 
143
+
144
+ def generate_bb_proof(circuit_dir):
190
145
  try:
191
146
  subprocess.run(["bb", "--version"], capture_output=True, check=True)
192
147
  except (subprocess.CalledProcessError, FileNotFoundError):
193
- print(
194
- "Error: bb (Barretenberg) not found. Please install it using \n`curl -L https://raw.githubusercontent.com/AztecProtocol/aztec-packages/master/barretenberg/cpp/installation/install | bash`"
148
+ bt.logging.error(
149
+ "bb (Barretenberg) not found. Install with: curl -L https://raw.githubusercontent.com/AztecProtocol/aztec-packages/master/barretenberg/cpp/installation/install | bash"
195
150
  )
196
151
  return None, False
197
152
 
198
- try:
199
- target_dir = os.path.join(circuit_dir, "target")
200
- proof_dir = os.path.join(circuit_dir, "proof")
201
- vk_dir = os.path.join(circuit_dir, "vk")
153
+ target_dir = os.path.join(circuit_dir, "target")
154
+ proof_dir = os.path.join(circuit_dir, "proof")
155
+ os.makedirs(proof_dir, exist_ok=True)
202
156
 
203
- os.makedirs(proof_dir, exist_ok=True)
204
- os.makedirs(vk_dir, exist_ok=True)
157
+ witness_file = os.path.join(target_dir, "witness.gz")
158
+ circuit_file = os.path.join(target_dir, "circuits.json")
205
159
 
206
- witness_file = os.path.join(target_dir, "witness.gz")
207
- circuit_file = os.path.join(target_dir, "circuits.json")
208
-
209
- proof_file = proof_dir
210
-
211
- prove_start = time.time()
212
- prove_result = subprocess.run(
213
- ["bb", "prove", "-b", circuit_file, "-w", witness_file, "-o", proof_file],
214
- capture_output=True,
215
- text=True,
216
- cwd=circuit_dir,
217
- )
218
- prove_time = time.time() - prove_start
219
-
220
- if prove_result.returncode != 0:
221
- print("bb prove failed:")
222
- print(
223
- " ".join(
224
- [
225
- "bb",
226
- "prove",
227
- "-b",
228
- circuit_file,
229
- "-w",
230
- witness_file,
231
- "-o",
232
- proof_file,
233
- ]
234
- )
235
- )
236
- print(prove_result.stdout)
237
- print(prove_result.stderr)
238
- return None, False
239
-
240
- print(f"Proof generated in {prove_time:.3f}s")
241
- return prove_time, True
160
+ prove_start = time.time()
161
+ prove_result = subprocess.run(
162
+ ["bb", "prove", "-b", circuit_file, "-w", witness_file, "-o", proof_dir],
163
+ capture_output=True,
164
+ text=True,
165
+ cwd=circuit_dir,
166
+ )
167
+ prove_time = time.time() - prove_start
242
168
 
243
- except Exception as e:
244
- print(f"Error during proof generation/verification: {e}")
169
+ if prove_result.returncode != 0:
170
+ bt.logging.error(f"bb prove failed: {prove_result.stderr}")
245
171
  return None, False
246
172
 
173
+ return prove_time, True
174
+
247
175
 
248
176
  def generate_proof(
249
177
  data=None,
@@ -256,43 +184,26 @@ def generate_proof(
256
184
  witness_only=False,
257
185
  account_size=None,
258
186
  ):
259
- """
260
- Core proof generation logic.
261
-
262
- Args:
263
- data: Optional dictionary containing perf_ledgers and positions.
264
- If None, will read from validator_checkpoint.json
265
- miner_hotkey: The hotkey of the miner to generate proof for.
266
- If None and reading from file, uses first available hotkey
267
- verbose: Optional boolean to control logging verbosity.
268
- If None, auto-detects (demo mode = verbose, production = minimal)
269
- annual_risk_free_percentage: Annual risk-free rate percentage (default 4.19)
270
- use_weighting: Whether to use weighted calculations (default False)
271
- bypass_confidence: Whether to bypass confidence thresholds (default False)
272
- daily_checkpoints: Number of checkpoints expected per day (default 2)
273
- witness_only: If True, skip barretenberg proof generation for faster testing (default False)
274
-
275
- Returns:
276
- Dictionary with proof results including status, portfolio_metrics, etc.
277
- """
278
- bt.logging.info(
279
- f"generate_proof called with verbose={verbose}, miner_hotkey={miner_hotkey[:8] if miner_hotkey else None}"
280
- )
281
-
282
- # Auto-detect mode: demo mode if reading from file, production if data provided
283
187
  is_demo_mode = data is None
284
188
  if verbose is None:
285
189
  verbose = is_demo_mode
286
190
 
287
- bt.logging.info(
288
- f"After auto-detect: verbose={verbose}, is_demo_mode={is_demo_mode}"
191
+ log_verbose(
192
+ verbose,
193
+ "info",
194
+ f"generate_proof called with miner_hotkey={miner_hotkey[:8] if miner_hotkey else None}",
195
+ )
196
+ log_verbose(
197
+ verbose,
198
+ "info",
199
+ f"Mode: {'Demo' if is_demo_mode else 'Production'}, verbose={verbose}",
289
200
  )
290
201
 
291
202
  try:
292
203
  if data is None:
293
- if verbose:
294
- bt.logging.info("Loading data from validator_checkpoint.json...")
295
-
204
+ log_verbose(
205
+ verbose, "info", "Loading data from validator_checkpoint.json..."
206
+ )
296
207
  with open("validator_checkpoint.json", "r") as f:
297
208
  data = json.load(f)
298
209
  except Exception as e:
@@ -300,13 +211,13 @@ def generate_proof(
300
211
 
301
212
  if miner_hotkey is None:
302
213
  miner_hotkey = list(data["perf_ledgers"].keys())[0]
303
- if verbose:
304
- bt.logging.info(
305
- f"No hotkey specified, using first available: {miner_hotkey}"
306
- )
214
+ log_verbose(
215
+ verbose,
216
+ "info",
217
+ f"No hotkey specified, using first available: {miner_hotkey}",
218
+ )
307
219
  else:
308
- if verbose:
309
- bt.logging.info(f"Using specified hotkey: {miner_hotkey}")
220
+ log_verbose(verbose, "info", f"Using specified hotkey: {miner_hotkey}")
310
221
 
311
222
  if miner_hotkey not in data["perf_ledgers"]:
312
223
  raise ValueError(
@@ -314,18 +225,18 @@ def generate_proof(
314
225
  )
315
226
 
316
227
  positions = data["positions"][miner_hotkey]["positions"]
317
- if verbose:
318
- bt.logging.info("Preparing circuit inputs...")
228
+ log_verbose(verbose, "info", "Preparing circuit inputs...")
319
229
 
320
230
  # Use daily returns calculated by PTN
321
231
  daily_log_returns = data.get("daily_returns", [])
322
232
  n_returns = len(daily_log_returns)
323
233
 
324
234
  if n_returns > MAX_DAYS:
325
- if verbose:
326
- bt.logging.warning(
327
- f"Warning: Miner has {n_returns} daily returns, but circuit only supports {MAX_DAYS}. Truncating."
328
- )
235
+ log_verbose(
236
+ verbose,
237
+ "warning",
238
+ f"Truncating {n_returns} daily returns to {MAX_DAYS} (circuit limit)",
239
+ )
329
240
  daily_log_returns = daily_log_returns[:MAX_DAYS]
330
241
  n_returns = MAX_DAYS
331
242
 
@@ -335,19 +246,19 @@ def generate_proof(
335
246
  # Pad to MAX_DAYS
336
247
  scaled_log_returns += [0] * (MAX_DAYS - len(scaled_log_returns))
337
248
 
338
- if verbose:
339
- bt.logging.info(f"Using {n_returns} daily returns from PTN")
249
+ log_verbose(verbose, "info", f"Using {n_returns} daily returns from PTN")
340
250
 
341
251
  all_orders = []
342
252
  for pos in positions:
343
- all_orders.extend(pos["orders"])
253
+ all_orders.extend(get_attr(pos, "orders"))
344
254
 
345
255
  signals_count = len(all_orders)
346
256
  if signals_count > MAX_SIGNALS:
347
- if verbose:
348
- bt.logging.warning(
349
- f"Warning: Miner has {signals_count} signals, but circuit only supports {MAX_SIGNALS}. Truncating."
350
- )
257
+ log_verbose(
258
+ verbose,
259
+ "warning",
260
+ f"Truncating {signals_count} signals to {MAX_SIGNALS} (circuit limit)",
261
+ )
351
262
  all_orders = all_orders[:MAX_SIGNALS]
352
263
  signals_count = MAX_SIGNALS
353
264
 
@@ -356,24 +267,34 @@ def generate_proof(
356
267
 
357
268
  signals = []
358
269
  for order in all_orders:
359
- trade_pair_str = order.get("trade_pair", ["UNKNOWN"])[0]
270
+ trade_pair = get_attr(order, "trade_pair")
271
+ trade_pair_str = (
272
+ str(trade_pair).split(".")[1]
273
+ if hasattr(trade_pair, "name")
274
+ else str(trade_pair)
275
+ )
360
276
  if trade_pair_str not in trade_pair_map:
361
277
  trade_pair_map[trade_pair_str] = trade_pair_counter
362
278
  trade_pair_counter += 1
363
279
 
364
- order_type_str = order["order_type"]
280
+ order_type = get_attr(order, "order_type")
281
+ order_type_str = (
282
+ str(order_type).split(".")[1]
283
+ if hasattr(order_type, "name")
284
+ else str(order_type)
285
+ )
365
286
  order_type_map = {"SHORT": 2, "LONG": 1, "FLAT": 0}
366
- price = int(order.get("price", 0) * SCALING_FACTOR)
367
- order_uuid = order.get("order_uuid", "0")
368
- bid = int(order.get("bid", 0) * SCALING_FACTOR)
369
- ask = int(order.get("ask", 0) * SCALING_FACTOR)
370
- processed_ms = order.get("processed_ms", 0)
287
+ price = int(get_attr(order, "price") * SCALING_FACTOR)
288
+ order_uuid = get_attr(order, "order_uuid")
289
+ bid = int(get_attr(order, "bid") * SCALING_FACTOR)
290
+ ask = int(get_attr(order, "ask") * SCALING_FACTOR)
291
+ processed_ms = get_attr(order, "processed_ms")
371
292
 
372
293
  signals.append(
373
294
  {
374
295
  "trade_pair": str(trade_pair_map[trade_pair_str]),
375
296
  "order_type": str(order_type_map.get(order_type_str, 0)),
376
- "leverage": str(int(abs(order.get("leverage", 0)) * SCALING_FACTOR)),
297
+ "leverage": str(int(abs(order.leverage) * SCALING_FACTOR)),
377
298
  "price": str(price),
378
299
  "processed_ms": str(processed_ms),
379
300
  "order_uuid": f"0x{order_uuid.replace('-', '')}",
@@ -396,39 +317,26 @@ def generate_proof(
396
317
  }
397
318
  ] * (MAX_SIGNALS - len(signals))
398
319
 
399
- if verbose:
400
- bt.logging.info(
401
- f"Prepared {n_returns} daily returns and {signals_count} signals for circuit."
402
- )
320
+ log_verbose(
321
+ verbose,
322
+ "info",
323
+ f"Prepared {n_returns} daily returns and {signals_count} signals for circuit",
324
+ )
403
325
 
326
+ if verbose:
404
327
  bt.logging.info(f"Circuit daily returns count: {n_returns}")
405
- bt.logging.info("Circuit First 10 daily returns:")
406
- for i in range(min(10, n_returns)):
328
+ bt.logging.info("Sample daily returns:")
329
+ for i in range(min(5, n_returns)):
407
330
  bt.logging.info(
408
331
  f" [{i}] return={daily_log_returns[i]:.6f} (scaled={scaled_log_returns[i]})"
409
332
  )
410
-
411
- if n_returns > 10:
412
- bt.logging.info("Circuit Last 5 daily returns:")
413
- for i in range(n_returns - 5, n_returns):
414
- if i >= 0:
415
- bt.logging.info(
416
- f" [{i}] return={daily_log_returns[i]:.6f} (scaled={scaled_log_returns[i]})"
417
- )
418
-
419
333
  if daily_log_returns:
420
334
  mean_return = sum(daily_log_returns) / len(daily_log_returns)
421
- bt.logging.info(
422
- f"Circuit daily returns stats: mean={mean_return:.6f}, count={n_returns}"
423
- )
424
-
425
- bt.logging.info(f"Daily returns from PTN: {n_returns}")
335
+ bt.logging.info(f"Mean daily return: {mean_return:.6f}, count={n_returns}")
426
336
  bt.logging.info(f"Circuit Config: MAX_DAYS={MAX_DAYS}, DAILY_CHECKPOINTS=2")
427
337
 
428
- if verbose:
429
- bt.logging.info("Running tree_generator circuit...")
430
- else:
431
- bt.logging.info(f"Generating tree for hotkey {miner_hotkey}...")
338
+ log_verbose(verbose, "info", "Running tree_generator circuit...")
339
+ bt.logging.info(f"Generating tree for hotkey {miner_hotkey[:8]}...")
432
340
  current_dir = os.path.dirname(os.path.abspath(__file__))
433
341
  tree_generator_dir = os.path.join(current_dir, "tree_generator")
434
342
 
@@ -438,12 +346,11 @@ def generate_proof(
438
346
  toml.dump(tree_prover_input, f)
439
347
 
440
348
  output = run_command(
441
- ["nargo", "execute", "--silence-warnings" if not verbose else ""],
349
+ ["nargo", "execute", "--silence-warnings"],
442
350
  tree_generator_dir,
443
- verbose,
444
351
  )
445
352
 
446
- tree = parse_nargo_struct_output(output)
353
+ tree = parse_circuit_output(output)
447
354
  try:
448
355
  path_elements = tree["path_elements"]
449
356
  path_indices = tree["path_indices"]
@@ -453,23 +360,15 @@ def generate_proof(
453
360
  "Unexpected tree_generator output structure, expected MerkleTree dict with leaf_hashes, path_elements, path_indices, and root"
454
361
  )
455
362
 
456
- if verbose:
457
- print(f"Generated signals Merkle root: {signals_merkle_root}")
458
- if isinstance(signals_merkle_root, str) and signals_merkle_root.startswith(
459
- "0x"
460
- ):
461
- print(f"Signals Merkle root (hex): {signals_merkle_root}")
462
- else:
463
- print(f"Signals Merkle root (int): {signals_merkle_root}")
464
-
465
- if verbose:
466
- print("Returns Merkle root will be calculated within the circuit")
467
- print(f"Number of daily returns: {n_returns}")
468
-
469
- if verbose:
470
- print("Running main proof of portfolio circuit...")
471
- else:
472
- print(f"Generating witness for hotkey {miner_hotkey}...")
363
+ log_verbose(
364
+ verbose, "info", f"Generated signals Merkle root: {signals_merkle_root}"
365
+ )
366
+ log_verbose(
367
+ verbose, "info", "Returns Merkle root will be calculated within circuit"
368
+ )
369
+ log_verbose(verbose, "info", f"Number of daily returns: {n_returns}")
370
+ log_verbose(verbose, "info", "Running main proof of portfolio circuit...")
371
+ bt.logging.info(f"Generating witness for hotkey {miner_hotkey[:8]}...")
473
372
  main_circuit_dir = os.path.join(current_dir, "circuits")
474
373
 
475
374
  # Pass annual risk-free rate (to match ann_excess_return usage)
@@ -513,17 +412,15 @@ def generate_proof(
513
412
  with open(os.path.join(main_circuit_dir, "Prover.toml"), "w") as f:
514
413
  toml.dump(main_prover_input, f)
515
414
 
516
- if verbose:
517
- print("Executing main circuit to generate witness...")
415
+ log_verbose(verbose, "info", "Executing main circuit to generate witness...")
518
416
  witness_start = time.time()
519
417
  output = run_command(
520
- ["nargo", "execute", "witness", "--silence-warnings"], main_circuit_dir, verbose
418
+ ["nargo", "execute", "witness", "--silence-warnings"], main_circuit_dir
521
419
  )
522
420
  witness_time = time.time() - witness_start
523
- if verbose:
524
- print(f"Witness generation completed in {witness_time:.3f}s")
421
+ log_verbose(verbose, "info", f"Witness generation completed in {witness_time:.3f}s")
525
422
 
526
- fields = parse_nargo_struct_output(output)
423
+ fields = parse_circuit_output(output)
527
424
  if len(fields) < 9:
528
425
  raise RuntimeError(
529
426
  f"Expected 9 output fields from main circuit, got {len(fields)}: {fields}"
@@ -585,53 +482,57 @@ def generate_proof(
585
482
 
586
483
  if witness_only:
587
484
  prove_time, proving_success = None, True
588
- if verbose:
589
- print("Skipping barretenberg proof generation (witness_only=True)")
485
+ log_verbose(
486
+ verbose,
487
+ "info",
488
+ "Skipping barretenberg proof generation (witness_only=True)",
489
+ )
590
490
  else:
591
491
  try:
592
- prove_time, proving_success = run_bb_prove(main_circuit_dir)
492
+ prove_time, proving_success = generate_bb_proof(main_circuit_dir)
593
493
  if prove_time is None:
594
- if verbose:
595
- print("Barretenberg proof generation failed")
494
+ bt.logging.error("Barretenberg proof generation failed")
596
495
  prove_time, proving_success = None, False
597
496
  except Exception as e:
598
- print(f"Exception during proof generation: {e}")
497
+ bt.logging.error(f"Exception during proof generation: {e}")
599
498
  prove_time, proving_success = None, False
600
499
 
601
500
  # Always print key production info: hotkey and verification status
602
- print(f"Hotkey: {miner_hotkey}")
603
- print(f"Orders processed: {signals_count}")
604
- print(f"Signals Merkle Root: {signals_merkle_root}")
605
- print(f"Returns Merkle Root: {returns_merkle_root}")
606
- print(f"Average Daily PnL: {avg_daily_pnl_scaled:.9f}")
607
- print(f"Sharpe Ratio: {sharpe_ratio_scaled:.9f}")
501
+ bt.logging.info(f"Hotkey: {miner_hotkey}")
502
+ bt.logging.info(f"Orders processed: {signals_count}")
503
+ bt.logging.info(f"Signals Merkle Root: {signals_merkle_root}")
504
+ bt.logging.info(f"Returns Merkle Root: {returns_merkle_root}")
505
+ bt.logging.info(f"Average Daily PnL: {avg_daily_pnl_scaled:.9f}")
506
+ bt.logging.info(f"Sharpe Ratio: {sharpe_ratio_scaled:.9f}")
608
507
  # Convert drawdown factor to percentage: drawdown% = (1 - factor) * 100
609
508
  drawdown_percentage = (1 - max_drawdown_scaled) * 100
610
- print(f"Max Drawdown: {max_drawdown_scaled:.9f} ({drawdown_percentage:.6f}%)")
611
- print(f"Calmar Ratio: {calmar_ratio_scaled:.9f}")
612
- print(f"Omega Ratio: {omega_ratio_scaled:.9f}")
613
- print(f"Sortino Ratio: {sortino_ratio_scaled:.9f}")
614
- print(f"Statistical Confidence: {stat_confidence_scaled:.9f}")
615
- print(f"PnL Score: {pnl_score_scaled:.9f}")
509
+ bt.logging.info(
510
+ f"Max Drawdown: {max_drawdown_scaled:.9f} ({drawdown_percentage:.6f}%)"
511
+ )
512
+ bt.logging.info(f"Calmar Ratio: {calmar_ratio_scaled:.9f}")
513
+ bt.logging.info(f"Omega Ratio: {omega_ratio_scaled:.9f}")
514
+ bt.logging.info(f"Sortino Ratio: {sortino_ratio_scaled:.9f}")
515
+ bt.logging.info(f"Statistical Confidence: {stat_confidence_scaled:.9f}")
516
+ bt.logging.info(f"PnL Score: {pnl_score_scaled:.9f}")
616
517
 
617
518
  if verbose:
618
- print("\n--- Proof Generation Complete ---")
619
- print("\n=== MERKLE ROOTS ===")
620
- print(f"Signals Merkle Root: {signals_merkle_root}")
621
- print(f"Returns Merkle Root: {returns_merkle_root}")
622
-
623
- print("\n=== DATA SUMMARY ===")
624
- print(f"Daily returns processed: {n_returns}")
625
- print(f"Trading signals processed: {signals_count}")
626
- print("PnL calculated from cumulative returns in circuit")
627
-
628
- print("\n=== PROOF GENERATION RESULTS ===")
629
- print(f"Witness generation time: {witness_time:.3f}s")
519
+ bt.logging.info("\n--- Proof Generation Complete ---")
520
+ bt.logging.info("\n=== MERKLE ROOTS ===")
521
+ bt.logging.info(f"Signals Merkle Root: {signals_merkle_root}")
522
+ bt.logging.info(f"Returns Merkle Root: {returns_merkle_root}")
523
+
524
+ bt.logging.info("\n=== DATA SUMMARY ===")
525
+ bt.logging.info(f"Daily returns processed: {n_returns}")
526
+ bt.logging.info(f"Trading signals processed: {signals_count}")
527
+ bt.logging.info("PnL calculated from cumulative returns in circuit")
528
+
529
+ bt.logging.info("\n=== PROOF GENERATION RESULTS ===")
530
+ bt.logging.info(f"Witness generation time: {witness_time:.3f}s")
630
531
  if not witness_only:
631
532
  if prove_time is not None:
632
- print(f"Proof generation time: {prove_time:.3f}s")
533
+ bt.logging.info(f"Proof generation time: {prove_time:.3f}s")
633
534
  else:
634
- print("Unable to prove due to an error.")
535
+ bt.logging.info("Unable to prove due to an error.")
635
536
 
636
537
  # Return structured results for programmatic access
637
538
  return {
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: proof-of-portfolio
3
- Version: 0.0.80
3
+ Version: 0.0.82
4
4
  Summary: Zero-Knowledge Proof framework for verifiable, private portfolio performance metrics
5
5
  Author-email: "Inference Labs, Inc." <info@inferencelabs.com>
6
6
  Requires-Python: >=3.10
@@ -1,12 +1,12 @@
1
1
  proof_of_portfolio/__init__.py,sha256=idt_3gH2rz8eP0NIwPgY6sYKWjoPWi01XfAuxmGPAkE,5052
2
- proof_of_portfolio/_version.py,sha256=yvp1Fs_2geNkQfVkX4P-WyMtEi9x8EJARqWCQ6tvOhs,66
2
+ proof_of_portfolio/_version.py,sha256=HHOQJkZCJaFupCOnXxM-rl_fCkgZHsjuumRYIpsHRjA,66
3
3
  proof_of_portfolio/analyze_data.py,sha256=t80ueFtBUzcWTrPiamiC1HXvw5Em-151zXJx0cCk8sQ,3709
4
4
  proof_of_portfolio/main.py,sha256=JbvdAK7B6hw2sQdjT0EVCiglCQZgN3urKphdeWcW43w,30994
5
5
  proof_of_portfolio/min_metrics.py,sha256=U16B7YRl0UbCterdJ1ksqFOxR5DiQeslUzMVGEWNyog,13211
6
6
  proof_of_portfolio/miner.py,sha256=eGXcPMRQVAepzXJj1ePbbDAf-72E9Yj9n-yfP7GohLw,17177
7
7
  proof_of_portfolio/parsing_utils.py,sha256=Hx61Sby5mEbC6uzhG9G69K7YPCLbjU6vK8fazpNBeLc,6463
8
8
  proof_of_portfolio/post_install.py,sha256=e-57Z_h-svQdjA8ibsM985MXmdV6-KLyymQm3Cgu8YM,5654
9
- proof_of_portfolio/proof_generator.py,sha256=lT6h9i83GIUedE5vFvH7U5bmr8eqxTXVkWG10QbsRpA,24389
9
+ proof_of_portfolio/proof_generator.py,sha256=fZ03w8VDM3PBtLFod098dB7g3659x-npkMND0QJsLuQ,20761
10
10
  proof_of_portfolio/signal_processor.py,sha256=JQjnkMJEbv_MWIgKNrjKjrBIcIT5pAkAlCneEOGsqT0,6702
11
11
  proof_of_portfolio/validator.py,sha256=kt3BeaXOffv-h52PZBKV1YHUWtiGsnPte16m3EJpITY,3839
12
12
  proof_of_portfolio/circuits/Nargo.toml,sha256=D6ycN7H3xiTcWHH5wz4qXYTXn7Ht0WgPr9w4B7d8ZGw,141
@@ -77,8 +77,8 @@ proof_of_portfolio/tree_generator/Nargo.toml,sha256=O6iSvb-EpV0XcETiDxNgSp7XKNiY
77
77
  proof_of_portfolio/tree_generator/target.gz,sha256=J55ZC5QuFy6vGC2dSJ-0rEWjUKzzxwXwKGDTDUGp06U,225314
78
78
  proof_of_portfolio/tree_generator/src/main.nr,sha256=5Jb46e5PyZ3kpmIJn4W1gVtN3AgHs-fCmTochVB7uOU,2427
79
79
  proof_of_portfolio/tree_generator/target/tree_generator.json,sha256=Uy9AFLrbsd2SayMFTPgmow91-BIs1DrqP3qGfxfZAa0,1540901
80
- proof_of_portfolio-0.0.80.dist-info/METADATA,sha256=kpFdXJWYXEFtGBVUWFFSW1HDM6_R9g68tWg_JvmemoM,7076
81
- proof_of_portfolio-0.0.80.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
82
- proof_of_portfolio-0.0.80.dist-info/entry_points.txt,sha256=KeLSJT_UJtr1WiLTkhlGqWQuPKbO_ylgj6OXOC2gJV4,53
83
- proof_of_portfolio-0.0.80.dist-info/top_level.txt,sha256=sY5xZnE6YuiISK1IuRHPfl71NV0vXO3N3YA2li_SPXU,19
84
- proof_of_portfolio-0.0.80.dist-info/RECORD,,
80
+ proof_of_portfolio-0.0.82.dist-info/METADATA,sha256=yT7cJG26SYJU3x-sDP8VgXl2mexohXhlw1r4d9VsRbc,7076
81
+ proof_of_portfolio-0.0.82.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
82
+ proof_of_portfolio-0.0.82.dist-info/entry_points.txt,sha256=KeLSJT_UJtr1WiLTkhlGqWQuPKbO_ylgj6OXOC2gJV4,53
83
+ proof_of_portfolio-0.0.82.dist-info/top_level.txt,sha256=sY5xZnE6YuiISK1IuRHPfl71NV0vXO3N3YA2li_SPXU,19
84
+ proof_of_portfolio-0.0.82.dist-info/RECORD,,