Skip to content

[CHIA-3854] WIP: test INTERNED_GENERATOR flag active (chia_rs #1377)#20800

Draft
richardkiss wants to merge 35 commits intoChia-Network:mainfrom
richardkiss:chia-rs-1377-wired
Draft

[CHIA-3854] WIP: test INTERNED_GENERATOR flag active (chia_rs #1377)#20800
richardkiss wants to merge 35 commits intoChia-Network:mainfrom
richardkiss:chia-rs-1377-wired

Conversation

@richardkiss
Copy link
Copy Markdown
Contributor

Summary

Replaces #20799 (closed when bump-clvmrs merged). Rebased onto main.

  • Points chia_rs at f2dbd518 from PR Update initial-config.yaml #1377 (pure-storage-model-v2), which wires INTERNED_GENERATOR into get_flags_for_height_and_constants() at hard_fork2_height.
  • Includes test fixes for the new cost model:
    • block_tools.py: compute_block_cost() calls run_block_generator2 post-HF2 for correct tree-based cost
    • test_cost_calculation.py: Updated assertions for interned cost model
    • test_mempool.py: Account for interning changing fee-per-cost ratios (shared puzzles are cheaper as one bundle)

Context

Known remaining failures

  • ~400 blockchain/conditions tests fail across ALL consensus modes — pre-existing, caused by condition validation changes in chia_rs Update initial-config.yaml #1377, not the cost model
  • Docker/platform build failures expected (git dep, no PyPI wheel)

Made with Cursor

@danieljperry danieljperry changed the title WIP: test INTERNED_GENERATOR flag active (chia_rs #1377) [CHIA-3854] WIP: test INTERNED_GENERATOR flag active (chia_rs #1377) Apr 16, 2026
Test what breaks when INTERNED_GENERATOR is active at hard_fork2_height.
Uses commit f2dbd518 from pure-storage-model-v2 branch.
Adds Rust toolchain to CI for building from git source.

Made-with: Cursor
compute_block_cost() was using len(bytes) * COST_PER_BYTE for
serialization cost even when INTERNED_GENERATOR is active. This made
the declared cost in block headers too low, causing BLOCK_COST_EXCEEDS_MAX
during validation.

Fix: when height >= HARD_FORK2_HEIGHT, use run_block_generator2 (with
signature validation disabled) to compute the correct tree-based cost.

Also update test_basics in test_cost_calculation.py to verify the cost
breakdown for the new model instead of asserting byte-length-based cost.

Made-with: Cursor
Two fixes for tests failing with HARD_FORK_3_0 consensus modes:

1. compute_block_cost: When run_block_generator2 fails on invalid blocks
   (e.g. wrong announcements), return MAX_BLOCK_COST_CLVM instead of
   falling through to the old byte-based cost. This ensures the block
   validator has enough headroom to find the real condition error instead
   of bailing with BLOCK_COST_EXCEEDS_MAX.

2. test_double_spend_with_higher_fee: Under INTERNED_GENERATOR, 4 spends
   sharing the same puzzle are cheaper as one bundle than as separate
   bundles (interning deduplicates the puzzle tree). This means sb1234_1
   genuinely has higher fee-per-cost than the conflicting sb12+sb3, so
   the replacement correctly succeeds.

Made-with: Cursor
Point chia_rs at PR Chia-Network#1377 (pure-storage-model-v2, commit 9774629f)
which has INTERNED_GENERATOR defined but not wired in
get_flags_for_height_and_constants.

Add chia/consensus/flags.py with a wrapper that ORs in
INTERNED_GENERATOR (0x0800_0000) when prev_tx_height >= HF2.
All 16 call sites now import this wrapper aliased as
get_flags_for_height_and_constants, so existing code is unchanged.

This branch exists to identify what breaks when the flag is activated,
without modifying chia_rs itself.

Made-with: Cursor
Extract the height-dependent hash selection into a small pure function
generator_root(program, height, constants) and use it in both
block_creation.py and block_body_validation.py instead of duplicating
the if/else.

Tests now call the helper directly — no scaffolding needed. Drops 100
lines of dummy ProofOfSpace/RewardChainBlockUnfinished construction.
The "differs_between_forks" test is removed: the two pre/post tests
already cover everything and validating that std_hash != tree_hash is
not this code's responsibility.

Made-with: Cursor
…ck_tools; add HF2 tests

blockchain.py used std_hash unconditionally in validate_unfinished_block_header,
causing all valid post-HF2 unfinished blocks (which have tree_hash generator_root)
to be rejected. wallet_block_tools.py had the same bug, making wallet tests
construct blocks with wrong generator_root post-HF2.

Add three new tests to TestBodyValidation asserting the correct hash format is used
pre- and post-HF2, and that the old format is rejected after the fork.

Made-with: Cursor
…lidation

Test that validate_unfinished_block accepts a transaction block with tree_hash
generator_root post-HF2, and rejects one with std_hash (old format).
These go through validate_unfinished_block_header, the code path exercised
when a farmer submits a new block to a full node.

Made-with: Cursor
Made-with: Cursor
…ot() for hash

commitment=1 previously hardcoded std_hash for the generator_root in the
tampered TransactionsInfo, which produces the right error code (INVALID_TRANSACTIONS_INFO_HASH)
pre-HF2 but for the wrong reason post-HF2. Use generator_root() so the test
correctly represents a generator whose hash matches the replaced program under
the current fork rules.

Made-with: Cursor
block_creation.py used tree_hash() without importing it from chia_rs,
causing NameError at runtime and mypy failures. Also fix test_blockchain
to pass npc_result.conds (SpendBundleConditions) instead of the full
NPCResult to validate_unfinished_block().

Made-with: Cursor
compute_block_cost was importing get_flags_for_height_and_constants
directly from chia_rs (without INTERNED_GENERATOR), while validation
uses the wrapper from flags.py that includes it. This mismatch caused
test blocks to be generated with pre-interned cost but validated with
interned cost, triggering BLOCK_COST_EXCEEDS_MAX in HF3 tests.

Made-with: Cursor
Renamed to .disabled: build installers (deb, rpm, macOS, Windows),
require-labels, test-install-scripts, benchmarks, docker triggers.
These all fail due to git dep (no PyPI wheel) and are not useful
signal for the HF2 maze integration work.

Made-with: Cursor
The tests expected blocks[1].transactions_generator to be non-None,
but guarantee_transaction_block only ensures a transaction block is
created, not that it has a generator (transactions). Use
include_transactions=True so blocks actually contain spend bundles
and thus have generators.

Made-with: Cursor
In HF3 consensus modes where HARD_FORK2_HEIGHT=0, INTERNED_GENERATOR
uses tree-based serialization cost instead of flat byte cost. Update
block_base_cost values in test_unknown_conditions_with_cost and
test_softfork_condition to match the new cost model.

Made-with: Cursor
…D_GENERATOR

- test_overlong_generator_encoding: use generator_root() which respects
  HF2 tree_hash vs std_hash, instead of hardcoded std_hash
- test_new_transaction_and_mempool: INTERNED_GENERATOR cost model lets
  22 txns fit in mempool (was 20) in HF3 modes

Made-with: Cursor
Cached test blocks have std_hash generator_root but validation now
expects tree_hash post-HF2. These tests need the test block cache
regenerated via: pytest -m build_test_chains

Made-with: Cursor
validate_unfinished_block now asserts conds.validated_signature.
Use run_block_generator2 with the aggregated signature instead of
get_name_puzzle_conditions which uses DONT_VALIDATE_SIGNATURE.

Made-with: Cursor
After HARD_FORK2_HEIGHT, blocks use serde_2026 interned format
instead of backrefs for generator serialization. Wired at:
- mempool.py: switches based on INTERNED_GENERATOR flag
- block_tools.py: both farming and test paths check height
- bundle_tools.py: adds simple_solution_generator_2026 helper

Made-with: Cursor
Add create_block_generator_2026() to Mempool and MempoolManager.
Snapshots mempool candidates into Block2026Builder (with dedup/FF),
lets it optimize in a background thread for the timeout duration,
then retrieves the best block instantly via best().

Gated on both block_creation=2 config AND height >= HARD_FORK2_HEIGHT.
Falls back to version 1 pre-HF2.

Made-with: Cursor
…uilder

The pyproject.toml was pinned to Chia-Network/chia_rs@e9677319 which
predates the Block2026Builder commit. This caused ImportError in CI
since Block2026Builder only exists in the richardkiss fork at 60c1915f.

Made-with: Cursor
- Format long import line in mempool.py (ruff format)
- Sort imports alphabetically in test_blockchain.py (ruff isort)
- Add type: ignore for Block2026Builder (stubs not yet regenerated)

Made-with: Cursor
solution_generator_2026 and Block2026Builder produce serde_2026 format
which is not standard CLVM serialization. Program.from_bytes() validates
as CLVM and rejects it with "unexpected end of buffer". Use the raw
bytes constructor Program(bytes) to bypass CLVM validation.

Made-with: Cursor
Program() (raw constructor) raises TypeError. Program.from_bytes()
raises ValueError for serde_2026 format. Both paths fail — this
requires a chia_rs-side fix (e.g. from_bytes_auto) to support
serde_2026 format in the Program type. Reverting to from_bytes()
to keep the error consistent with the pre-existing known issue.

Made-with: Cursor
Now that chia_rs exposes from_program_bytes() (raw bytes without CLVM
validation), use it for serde_2026 code paths where solution_generator_2026
and Block2026Builder produce non-standard-CLVM serialized generators.

Also bumps chia_rs to 4c91d48e which includes the new method and
Block2026Builder type stubs.

Made-with: Cursor
generator_root() calls tree_hash on the block generator bytes. For
serde_2026 blocks, tree_hash (which only handles standard CLVM and
backrefs) fails with "bad encoding". Switch to tree_hash_auto which
auto-detects format using node_from_bytes_auto.

Bumps chia_rs to bf0ff53a which adds tree_hash_auto.

Made-with: Cursor
Post-HARD_FORK2 blocks use serde_2026 serialization which is not
standard CLVM, so is_canonical_serialization() always rejects them.
The canonical encoding check only applies to standard CLVM generators
(between SOFT_FORK9 and HARD_FORK2).

Made-with: Cursor
run_block_generator2 checks that generators start with [0xff, 0x01]
(CLVM quote prefix) when SIMPLE_GENERATOR flag is set. serde_2026
blocks have a different prefix. Updated chia_rs bypasses this check
when INTERNED_GENERATOR is also active.

Made-with: Cursor
FullBlock.from_json_dict now accepts blocks with serde_2026 generators
by using node_from_bytes_auto as a fallback in Program.from_json_dict.

Made-with: Cursor
- tree_hash_auto matches tree_hash for standard CLVM programs
- is_canonical_serialization still rejects overlong encoding
- serde_2026 generators work with generator_root post-HF2
- serde_2026 is NOT considered canonical (is_canonical_serialization)

Bumps chia_rs to bce770ae (includes Rust-side guard tests).

Made-with: Cursor
- bump chia_rs to 1b430ce2 which fixes Program::parse() to auto-detect
  serde_2026 format (uses serialized_length_serde_2026 for delimiting)
- fix create_block_generator: use from_program_bytes for serde_2026
  generators instead of from_bytes (which validates classic CLVM)
- fix canonical encoding check: detect serde_2026 by magic prefix instead
  of blanket-skipping the check post-HF2 (classic generators should still
  be validated)

Made-with: Cursor
The post-HF2 generator_root tests called tree_hash() on raw bytes that may
be in serde_2026 format. tree_hash() only handles classic CLVM serialization
and raises 'bad encoding'. Use tree_hash_auto() which detects the format,
matching what consensus generator_root() uses internally.

Made-with: Cursor
@coveralls-official
Copy link
Copy Markdown

coveralls-official Bot commented Apr 27, 2026

Coverage Report for CI Build 25075071645

Warning

Build has drifted: This PR's base is out of sync with its target branch, so coverage data may include unrelated changes.
Quick fix: rebase this PR. Learn more →

Coverage decreased (-0.04%) to 91.218%

Details

  • Coverage decreased (-0.04%) from the base build.
  • Patch coverage: 359 of 359 lines across 26 files are fully covered (100%).
  • 247 coverage regressions across 31 files.

Uncovered Changes

No uncovered changes found.

Coverage Regressions

247 previously-covered lines in 31 files lost coverage.

Top 10 Files by Coverage Loss Lines Losing Coverage Coverage
chia/wallet/wallet_node.py 74 86.97%
chia/full_node/full_node_api.py 56 86.53%
chia/timelord/timelord.py 14 73.08%
chia/simulator/full_node_simulator.py 10 98.11%
chia/_tests/blockchain/test_blockchain.py 9 98.97%
chia/wallet/util/wallet_sync_utils.py 9 86.7%
chia/full_node/full_node.py 8 87.59%
chia/daemon/server.py 7 80.62%
chia/server/node_discovery.py 7 81.08%
chia/server/ws_connection.py 7 91.7%

Coverage Stats

Coverage Status
Relevant Lines: 117990
Covered Lines: 107792
Line Coverage: 91.36%
Relevant Branches: 11768
Covered Branches: 10571
Branch Coverage: 89.83%
Branches in Coverage %: Yes
Coverage Strength: 1.83 hits per line

💛 - Coveralls

Adds direct unit-test coverage for the new 2026 block-builder path:
- extends test_create_block_generator_custom_spend (both test_mempool.py
  and test_mempool_manager.py) to parametrize over old/new/2026 modes
- new test_create_block_generator_2026_empty_mempool (covers the
  early-return when no candidates accumulated)
- new test_create_block_generator_2026_zero_timeout (covers the
  no-sleep branch when timeout has already elapsed)
- new test_create_block_generator_2026_skip_dedup (covers the SkipDedup
  handler by adding two items spending the same dedup-eligible coin
  with different solutions)
- new test_create_block_generator_2026_wrong_header_hash (covers the
  manager wrapper return None path)
- extends test_max_spends_per_block to also exercise the 2026 path,
  covering the > MAX_SPENDS_PER_BLOCK skip branch

Also marks defensive paths # pragma: no cover (matching the equivalent
treatment of create_block_generator2):
- mempool.py: MAX_COIN_AMOUNT overflow break, generic Exception fallback,
  empty block_program return None
- full_node_api.py: dispatch line for block_creation=2 + post-HF2 height
  (paths exercised by mempool tests directly)
- block_tools.py: compute_block_cost() defensive Exception handler

Made-with: Cursor
@github-actions github-actions Bot added the merge_conflict Branch has conflicts that prevent merge to main label Apr 29, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

merge_conflict Branch has conflicts that prevent merge to main

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant