* Add Bugbot consensus review context Document the validation-state and sub-epoch-summary invariant so automated PR review has the same consensus context as local agents. * Route Bugbot to repository context docs Keep Bugbot guidance focused on subsystem context routing so automated reviews use the same module map as local agents. * Add generated repository context docs Include the expanded module context map and route Bugbot to the same subsystem docs used by local agents. * Add EDC agent context pointer Include the generated EDC agent guidance alongside the Cursor agent context docs. * Fold EDC guidance into AGENTS Keep agent context entrypoints consolidated in AGENTS.md and remove the separate EDC pointer. * Remove generator name from agent guidance Keep AGENTS.md focused on repository context locations rather than the tooling used to produce them. * Consolidate context corpus into one source-verified canonical set - Normalize all subsystem docs to canonical names without chia- prefix, removing the split between old and new-dominant corpora. - Merge new-dominant content into consensus.md, full-node.md, wallet.md; split networking.md into server.md, protocols.md, apis.md; add types.md. - Rename 15 genuinely-new subsystem docs; fold chia-root.md into architecture-overview.md. - Remove filter-branch leakage (filter_challenge, predictable filter, protocol 0.0.38) from types.md, protocols.md, harvester.md. - Correct factual inaccuracies: /push_tx vs wallet queue semantics, Err sign/ban policy, protocol import-time coverage, server peer-serving, address-manager mutation rule, wallet tx-store rollback, ValidationState speculative advancement, block-creation default, MempoolItem fallback. - Replace unreachable verification SHA with PR-head commit. - Consolidate test guidance into one small router plus 12 on-demand testing/ docs; remove duplicate auto-attached test guides. - Make INDEX.md the authoritative routing manifest; update BUGBOT.md, AGENTS.md, and context-routing.mdc to reference one canonical corpus. - Replace context-chia-*.mdc rules with canonical narrow rules; remove recursive .cursor/** rule and consolidate duplicate tooling rules. - Tighten clvm-execution.md: remove stale cost_calculator.py reference, fix block-creation default, replace opcode catalogue with pointer. * Trim redundant context and testing docs after value audit - Trim benchmarks.md: remove per-script Workload Groups narration that is obvious from opening each script; keep fidelity, coupling, and fragility sections. - Trim testing/patterns.md: slim to the module-by-module setup map and layered-assertion list; remove block/tx/assertion how-to that duplicates per-area testing docs. - Trim testing/full-node.md: slim to starter template and sync-convergence tip; remove fixture list and assertion patterns duplicated by patterns.md and architecture.md. - Fold testing/service-wiring.md per-cluster correlation details into testing/architecture.md; delete service-wiring.md (high overlap with architecture.md). - Fix protocols.md: correct NewSignagePointHarvester2 message-ID wording (ID reassigned to 66, not literally the same ID). - Update INDEX.md and testing-guide.mdc router to reflect service-wiring.md removal. * Fix verification SHA to reference the main source baseline The docs were verified against source at PR base24db9ad390(origin/main), nota5647a9327(the original PR head, which only adds context docs and is not a meaningful source baseline). The chia/ source tree is identical across both commits since the PR changes no production code. * Fix remaining V2 filter-branch leakage in harvester.md and types.md - harvester.md: replace calculate_effective_plot_filter_bits() and calculate_min_plot_strength() (filter-branch-only) with the actual main source path: calculate_prefix_bits() with NUMBER_ZERO_BITS_PLOT_FILTER_V2 and height adjustments, then passes_plot_filter(); strength bounds checked by check_plot_param() against MIN_PLOT_STRENGTH/MAX_PLOT_STRENGTH. - harvester.md: use meta_group (actual PartialProofsData field name) instead of "meta group". - types.md: correct that candidate height feeds prefix-bit reductions for both V1 and V2, not just V1; calculate_prefix_bits() branches on V1/V2 constants and height thresholds.
14 KiB
chia-simulator
Verified: 2026-07-12 against 24db9ad390. If source contradicts this doc, trust source and update the doc.
Scope: chia/simulator/. This is distilled architectural context for future audit or implementation agents. It intentionally omits generated SSL collateral and obvious helper inventories.
When To Read This
Read this for simulator block farming, reorg/revert helpers, simulator-only RPC routes, BlockTools, service test harnesses, deterministic plots/keys, wallet transaction helpers, and local simulator startup. For production full-node behavior, read full-node.md; for consensus acceptance rules, read consensus.md.
Implementation Authority
chia.simulator is the deterministic test and local-dev control plane for Chia services. It does not implement an alternate blockchain. Instead, it fabricates blocks, plots, VDFs, keys, config roots, and RPC affordances so tests and simulator users can drive the real FullNode, Blockchain, MempoolManager, wallet sync, and service stack quickly.
The two central surfaces are:
BlockTools: constructs consensus-shaped objects, test plots, keys, block generators, VDF proofs, signage points, sub-slots, and block sequences.FullNodeSimulator: subclassesFullNodeAPIand wraps a realFullNodewith high-level farming, reorg, revert, mempool-processing, and wallet-sync helpers.
The main architectural rule is: simulator conveniences may shortcut environment setup and block production, but accepted chain state must still flow through normal full-node validation/commit paths unless the function explicitly documents a destructive test-only state edit.
Why This Is Tricky
Public simulator docs describe complete control of a private chain: farm blocks, reorg, revert, inspect state, and toggle autofarming. In source, that control is intentionally split between safe helpers that still pass through real full-node validation and destructive helpers that directly edit local stores for test convenience. Simulator code is useful because it is close to production paths; making shortcuts broader can create tests that pass against states a real node could never reach.
Wrong Assumptions To Avoid
- Do not treat simulator block creation as consensus acceptance; generated blocks still need full-node/consensus commit unless a helper explicitly bypasses it.
- Do not use destructive revert helpers as a model for production reorg behavior.
- Do not assume simulator config/key/plot shortcuts are valid outside isolated test roots.
- Do not treat simulator RPC routes as normal full-node RPC behavior; they extend the full-node API for local private-chain control.
Core Simulator Contracts
BlockTools.get_consecutive_blocks()is a block factory, not a chain authority. It can create blocks with specific timing, overflow, references, transaction generators, reward targets, and seeds; the authoritative decision happens whenFullNode.add_block(),FullNode.add_block_batch(), orBlockchain.add_block()accepts those blocks.FullNodeSimulator.farm_new_block()andfarm_new_transaction_block()acquire the full node blockchain mutex, derive the next block from current persisted chain state, release the lock, then callfull_node.add_block(). They rely on the same post-processing path as ordinary full-node operation.add_blocks_in_batches()intentionally mirrors batch sync: it buildsForkInfo,ValidationState, andAugmentedBlockchain, callsFullNode.add_block_batch()in chunks, then runs peak post-processing and_finish_sync(). It is the right path for large simulator-generated chains and reorg tails.revert_block_height()is the exception: it directly rollscoin_storeandblock_store, sets the block-store peak, mutatesblockchain._peak_height, and refreshes the mempool. It does not broadcast and explicitly expects wallets to be wiped. Treat it as destructive local state surgery, not a reorg model.
Block Generation Model
BlockTools lowers mainnet constants for tests (test_constants) and creates enough deterministic plots to find proofs quickly. The defaults reduce plot sizes, difficulty, VDF discriminant size, proof filter bits, weight-proof windows, and timing while preserving the consensus shape that validation expects.
get_consecutive_blocks() is the heart of the module. It:
- continues from an optional block list or creates genesis;
- computes signage points and end-of-sub-slot bundles;
- scans local test plots for qualified V1/V2 proofs;
- computes required iterations, overflow status, pool/farmer targets, VDF proofs, and MMR/header commitments;
- optionally injects a
SpendBundleas transaction data or synthesizes spends from farmer reward coins; - updates local block-record, height-to-hash, difficulty, sub-slot-iterations, MMR, pending-reward, and generator-reference state as it appends blocks.
The factory deliberately exposes consensus edge knobs: force_overflow, skip_slots, guarantee_transaction_block, keep_going_until_tx_block, dummy_block_references, block_refs, normalized VDF proof flags, current_time, genesis_timestamp, force_plot_id, skip_overflow, min_signage_point, and deterministic seed.
Important coupling: block construction must stay aligned with consensus validation around pre_sp_tx_block_height, hard-fork gates, V1 phase-out, V2 plot activation/strength, generator reference bans, transaction-block reward maturity, and post-HF2 MMR commitments. A generated block that looks locally coherent can still be rejected by full-node validation if these gates diverge.
Plot, Key, And Signature State
BlockTools owns an ephemeral root path, config, keychain, plot directory, PlotManager, expected plot IDs, and local key caches. In automated tests it creates config and SSL under temp roots, forces the test network, normalizes localhost to loopback, assigns free daemon/RPC/service ports, and uses pre-generated cert pools to avoid expensive cert generation.
Plot setup creates deterministic V1 and V2 plots with stable filenames and test private keys. expected_plots is the invariant checked after refresh; refresh callbacks assert batch accounting and duration. Deleted or excluded plots must update this set or refresh assertions will fail.
Signatures are produced from plot memo-derived local keys plus farmer/pool keys:
- plot signatures aggregate local, farmer, and optional taproot shares;
- pool signatures are only returned for pool public-key plots;
setup_keys()can use simulator config fingerprint/reward address or synthesize farmer/pool keys in a local keychain.
Because locked-memory key material is expensive, plot local keys are cached by plot ID. Changes around parse_plot_info(), V1/V2 plot metadata, or keychain patching can break both block farming and harvester/farmer integration tests.
Transaction And Wallet Helpers
There are two transaction paths:
- Low-level block inclusion: pass
transaction_datatoBlockTools.get_consecutive_blocks()or useWalletToolto build simple signed spends for fabricated chain tests. - Full-node/mempool path: use wallet action scopes or spend bundles, wait for mempool inclusion through
FullNodeSimulator, then farm a guaranteed transaction block.
FullNodeSimulator helpers are behavior-level conveniences:
wait_transaction_records_entered_mempool()polls the full node mempool and can fail fast if a wallet transaction is marked invalid after retries.process_transaction_records(),process_spend_bundles(), andprocess_coin_spends()farm transaction blocks until expected additions exist in the coin store.farm_blocks_to_wallet()intentionally farms extra transaction blocks because block rewards are only claimable by later transaction blocks. It verifies the exact expected coinbase coin count before waiting for wallet spendability.create_coins_with_amounts()groups wallet-generated outputs, avoids duplicate puzzle-hash/amount pairs when necessary, farms one transaction block, filters change, and waits for wallet visibility.
Wallet sync checks require three states to converge: the simulator's full node reports synced, the wallet state manager reports synced, and retry-store states are exhausted. Height equality alone is not sufficient.
RPC Surface
SimulatorFullNodeRpcApi extends FullNodeRpcApi with simulator-only endpoints:
/farm_block/set_auto_farming/get_auto_farming/get_farming_ph/get_all_blocks/get_all_coins/get_all_puzzle_hashes/revert_blocks/reorg_blocks
The client wrapper converts these to typed Python calls and reuses the normal full-node RPC transport. Address inputs are decoded as testnet addresses; farm_block() returns a computed new peak height, while the actual block acceptance still happens through simulator/full-node methods.
Autofarm is implemented by installing FullNode.simulator_transaction_callback = FullNodeSimulator.autofarm_transaction. When enabled, accepted mempool transactions trigger a transaction-block farm to the simulator farming puzzle hash. The setting is persisted back into config.yaml.
Service Harness
setup_services.py is the service-factory layer used by tests. It creates real Service[...] instances for full nodes, simulator nodes, wallets, farmer, harvester, timelord, introducer, crawler, seeder, daemon, and solver with test config mutations.
Key setup contracts:
setup_full_node(..., simulator=True)returns aSimulatorFullNodeService; otherwise it creates a normalFullNodeService.- Most service ports are set to request ephemeral binding or assigned via
find_available_listen_port()to avoid collisions. The helper only reserves recently returned ports inside the current process; it is not a cross-process lock. - In-memory DB URIs are used unless
reuse_db=True; DB version tables may be pre-created for migration tests. - Test full nodes disable introducers/DNS by default, reduce peer connect churn, reserve all but one logical core, and force simulator autofarm/current-time off for deterministic tests.
- Capability overrides preserve
BASE, allow explicit disables, and then force important modern capabilities (HARD_FORK_2,RATE_LIMITS_V3) on in test setup.
chia/_tests/util/setup_nodes.py builds higher-level pytest environments on top of this module. setup_simulators_and_wallets*() creates one BlockTools per simulator and additional BlockTools if wallets outnumber simulators, then returns FullNodeEnvironment/WalletEnvironment wrappers plus the first BlockTools.
Local Simulator Startup
start_simulator.async_main() is the user-facing simulator startup path. It loads config, extracts simulator fingerprint, farming address, and plot directory, forces simulator.use_current_time=True, creates BlockTools, sets up keys and a small plot set, initializes logging, and returns/runs a full-node service whose peer API is FullNodeSimulator and whose RPC API is SimulatorFullNodeRpcApi.
This path is intentionally close to a normal full-node service after BlockTools setup. If a change only belongs to the CLI/local simulator experience, keep it out of test fixtures unless deterministic tests also need it.
Small Support Modules
WalletToolis a minimal standard-puzzle wallet for test spend creation. It derives child keys, tracks puzzle-hash-to-key mappings, creates announcement-linked multi-coin spends, computes change, and signs all relevant aggregate-signature opcodes. It is not wallet state management.vdf_prover.get_vdf_info_and_proof()callschiavdf.prove()directly and wraps the output asVDFInfo/VDFProof. Simulator block creation depends on this being structurally identical to validation expectations, even with tiny test discriminants.TempKeyringpatchesKeyringWrapperandsupports_os_passphrase_storage()so tests use isolated file keyrings. Cleanup restores the old shared keyring root when needed.ssl_certs*.pyare pre-generated test collateral.ssl_certs.pycycles through ten CA/node-cert sets and warns if a set is reused while still marked in use.
Fragility Hotspots
- Do not bypass full-node validation for convenience unless the API is explicitly destructive test state manipulation. Most simulator bugs become false-positive tests.
get_consecutive_blocks()has many consensus mirror points. Edits around overflow, sub-epoch summaries, MMR,pre_sp_tx_block_height, V1/V2 plot eligibility, transaction-generator cost, or reward maturity need consensus tests across hard-fork modes.BlockToolscaches block records and MMR state between calls when the input tip matches. Cache invalidation is by header hash; mutating a passed block list or reusing staleBlockToolsstate can produce surprising chains.WalletToolhas mutable class attributes noted by a TODO. Tests that share instances or assume pristine address/key lookup state should be treated carefully.revert_block_height()intentionally leaves network peers and wallets uninformed. Use reorg helpers for wallet/full-node behavior and revert only for local chain reset scenarios.- Test setup mutates nested config dicts in place before saving. Passing shared config objects across services can leak simulator-specific settings unless callers copy or isolate roots.
Source Pointers
- Block generation and deterministic plot/key setup:
chia/simulator/block_tools.py. - Simulator full-node API and RPC routes:
chia/simulator/full_node_simulator.py,chia/simulator/simulator_full_node_rpc_api.py,chia/simulator/simulator_full_node_rpc_client.py. - Local simulator startup:
chia/simulator/start_simulator.py. - Test service factories:
chia/simulator/setup_services.py,chia/_tests/util/setup_nodes.py. - Minimal wallet spend helper:
chia/simulator/wallet_tools.py.