133 lines
4.3 KiB
Python
Executable file
133 lines
4.3 KiB
Python
Executable file
#!/usr/bin/env python3
|
|
|
|
import sqlite3
|
|
import sys
|
|
import zstd
|
|
import click
|
|
from pathlib import Path
|
|
|
|
from typing import List
|
|
from time import time
|
|
|
|
|
|
from chia_rs import run_generator, MEMPOOL_MODE
|
|
|
|
from chia.types.full_block import FullBlock
|
|
from chia.types.blockchain_format.program import Program
|
|
from chia.consensus.default_constants import DEFAULT_CONSTANTS
|
|
from chia.wallet.puzzles.rom_bootstrap_generator import get_generator
|
|
from chia.util.ints import uint32
|
|
|
|
GENERATOR_ROM = bytes(get_generator())
|
|
|
|
|
|
# returns an optional error code and an optional PySpendBundleConditions (from chia_rs)
|
|
# exactly one of those will hold a value and the number of seconds it took to
|
|
# run
|
|
def run_gen(env_data: bytes, block_program_args: bytes, flags: uint32):
|
|
max_cost = DEFAULT_CONSTANTS.MAX_BLOCK_COST_CLVM
|
|
cost_per_byte = DEFAULT_CONSTANTS.COST_PER_BYTE
|
|
|
|
# we don't charge for the size of the generator ROM. However, we do charge
|
|
# cost for the operations it executes
|
|
max_cost -= len(env_data) * cost_per_byte
|
|
|
|
env_data = b"\xff" + env_data + b"\xff" + block_program_args + b"\x80"
|
|
|
|
try:
|
|
start_time = time()
|
|
err, result = run_generator(
|
|
GENERATOR_ROM,
|
|
env_data,
|
|
max_cost,
|
|
flags,
|
|
)
|
|
run_time = time() - start_time
|
|
return err, result, run_time
|
|
except Exception as e:
|
|
# GENERATOR_RUNTIME_ERROR
|
|
sys.stderr.write(f"Exception: {e}\n")
|
|
return 117, None, 0
|
|
|
|
|
|
@click.command()
|
|
@click.argument("file", type=click.Path(), required=True)
|
|
@click.option(
|
|
"--mempool-mode", default=False, is_flag=True, help="execute all block generators in the strict mempool mode"
|
|
)
|
|
def main(file: Path, mempool_mode: bool):
|
|
c = sqlite3.connect(file)
|
|
|
|
rows = c.execute("SELECT header_hash, height, block FROM full_blocks ORDER BY height")
|
|
|
|
height_to_hash: List[bytes] = []
|
|
|
|
for r in rows:
|
|
hh: bytes = r[0]
|
|
height = r[1]
|
|
block = FullBlock.from_bytes(zstd.decompress(r[2]))
|
|
|
|
if len(height_to_hash) <= height:
|
|
assert len(height_to_hash) == height
|
|
height_to_hash.append(hh)
|
|
else:
|
|
height_to_hash[height] = hh
|
|
|
|
if height > 0:
|
|
prev_hh = block.prev_header_hash
|
|
h = height - 1
|
|
while height_to_hash[h] != prev_hh:
|
|
height_to_hash[h] = prev_hh
|
|
ref = c.execute("SELECT block FROM full_blocks WHERE header_hash=?", (prev_hh,))
|
|
ref_block = FullBlock.from_bytes(zstd.decompress(ref.fetchone()[0]))
|
|
prev_hh = ref_block.prev_header_hash
|
|
h -= 1
|
|
if h < 0:
|
|
break
|
|
|
|
if block.transactions_generator is None:
|
|
sys.stderr.write(f" no-generator. block {height}\r")
|
|
continue
|
|
|
|
# add the block program arguments
|
|
block_program_args = bytearray(b"\xff")
|
|
|
|
num_refs = 0
|
|
start_time = time()
|
|
for h in block.transactions_generator_ref_list:
|
|
ref = c.execute("SELECT block FROM full_blocks WHERE header_hash=?", (height_to_hash[h],))
|
|
ref_block = FullBlock.from_bytes(zstd.decompress(ref.fetchone()[0]))
|
|
block_program_args += b"\xff"
|
|
block_program_args += Program.to(bytes(ref_block.transactions_generator)).as_bin()
|
|
num_refs += 1
|
|
ref.close()
|
|
ref_lookup_time = time() - start_time
|
|
|
|
block_program_args += b"\x80\x80"
|
|
|
|
if mempool_mode:
|
|
flags = MEMPOOL_MODE
|
|
else:
|
|
flags = 0
|
|
err, result, run_time = run_gen(bytes(block.transactions_generator), bytes(block_program_args), flags)
|
|
if err is not None:
|
|
sys.stderr.write(f"ERROR: {hh.hex()} {height} {err}\n")
|
|
break
|
|
|
|
num_removals = len(result.spends)
|
|
fees = result.reserve_fee
|
|
cost = result.cost
|
|
num_additions = 0
|
|
for spends in result.spends:
|
|
num_additions += len(spends.create_coin)
|
|
|
|
print(
|
|
f"{hh.hex()}\t{height}\t{cost}\t{run_time:0.3f}\t{num_refs}\t{ref_lookup_time:0.3f}\t{fees}\t"
|
|
f"{len(bytes(block.transactions_generator))}\t"
|
|
f"{num_removals}\t{num_additions}"
|
|
)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
# pylint: disable = no-value-for-parameter
|
|
main()
|