Skip to content

Conversation

@Mustang98
Copy link
Contributor

Optimized compression of the MERKLE_UPDATE part of the block based on the efficient state usage. Leads to up to 50% decrease in the block size.

@github-actions
Copy link

@codex review

@chatgpt-codex-connector
Copy link

To use Codex here, create a Codex account and connect to github.

@github-actions
Copy link

@codex review

@chatgpt-codex-connector
Copy link

To use Codex here, create a Codex account and connect to github.

@github-actions
Copy link

@codex review

@chatgpt-codex-connector
Copy link

To use Codex here, create a Codex account and connect to github.

@github-actions
Copy link

@codex review

@chatgpt-codex-connector
Copy link

To use Codex here, create a Codex account and connect to github.

…n if we already checked them before state extraction.
@github-actions
Copy link

  • validator/full-node-serializer.cpp:196-222 and 299-317 – tonNode_blockBroadcastCompressedV2 and tonNode_dataFullCompressedV2 now carry the proof out-of-band (f.proof_) but the deserializers no longer enforce any size limit on it. Previously the max_decompressed_size cap applied to the combined proof+data inside the compressed blob; now an attacker can ship an arbitrarily large proof_ and we accept/move it without bounds, which can exhaust memory or blow up logging while still passing the size check on data_compressed_/block_compressed_.

  • validator/net/download-block-new.cpp:229-264 – when a peer sends dataFullCompressedV2 that requires state to decompress, we parse the unverified proof and immediately call wait_state_by_prev_blocks, which can trigger expensive state downloads/merges for attacker-chosen prev block IDs before any proof or signature validation. A malicious peer could spam crafted proofs to force repeated state fetches/merges and tie up resources.

@github-actions
Copy link

Findings

  • extract_prev_blocks_from_proof only handles full BlockProof (block::gen::BlockProof::Record) and fails on proof links, but shard block broadcasts/dataFull still carry proof links. All stateful-decompression paths call this helper (e.g. FullNodeShardImpl::obtain_state_for_decompression, FullNodeCustomOverlay::obtain_state_for_decompression, FullNodeFastSyncOverlay::obtain_state_for_decompression, DownloadBlockNew::got_data). For any shard block using the new state-based compressed V2 format, extract_prev_blocks_from_proof will return “invalid block proof” and the broadcast/download is dropped/aborted, making the new compression unusable for shard blocks. Ref: validator/full-node-serializer.cpp:133-159, validator/full-node-shard.cpp:864-882, validator/full-node-custom-overlays.cpp:68-86, validator/full-node-fast-sync-overlays.cpp:62-82, validator/net/download-block-new.cpp:229-264.

Notes

  • No other blocking issues spotted.

…lizer to distinguish validator_session and collator_node
@github-actions
Copy link

Two critical issues spotted in the new MERKLE_UPDATE compression handling:

  • validator/full-node-serializer.cpp still serializes broadcasts and full blocks in the old V2 layout (proof+data packed together and LZ4’d into compressed_; see serialize_block_broadcast around lines 20-67 and serialize_block_full around lines 120-156), but the TL schema now declares separate proof and data_compressed/block_compressed fields (tl/generate/scheme/ton_api.tl:433-466), and the new deserializers expect only one BOC root plus an external proof (validator/full-node-serializer.cpp:196-215, 250-277). Outbound messages won’t match the new schema, and the code will reject peers still speaking the old V2 (two-root) format. This is a protocol/compatibility blocker; serializers (and generated TL files) need to be updated to the new field layout and single-root compression.

  • In the block download path, shard state is now fetched before any cryptographic validation: validator/net/download-block-new.cpp:225-260 extracts prev blocks from the untrusted proof in a tonNode_dataFullCompressedV2 and calls wait_state_by_prev_blocks prior to verifying the proof/signatures. A malicious peer can respond with bogus dataFullCompressedV2 messages to force expensive state loads/merges and only fail later during decompression/validation. The state fetch should be gated on proof/signature verification (or at least minimal validation) to avoid this DoS vector.

No tests were added for these paths. If you want, I can draft the serializer changes for the new TL layout and add a guard in the download path to validate before fetching state.

…ip others because they aren't consistent with state.
@github-actions
Copy link

  • validator/full-node-serializer.cpp:133-152 assumes the broadcast proof is a BlockProof, but shard broadcasts/data responses carry a proof link. tlb::unpack_cell will fail for shard proofs, so extract_prev_blocks_from_proof returns an error and the new state-preload path drops shard blockBroadcastCompressedV2/dataFullCompressedV2 messages that require state (fast-sync/custom/public overlays and DownloadBlockNew). Shard blocks compressed with the new MU algorithm would never decompress. Needs to handle proof links too.
  • validator/full-node-serializer.cpp:188-191 builds a BlockBroadcast with static_cast<UnixTime>(f.catchain_seqno_); BlockBroadcast.catchain_seqno is CatchainSeqno (uint32). This braced init will narrowly convert a double and should not compile (and would store the wrong type if it did). Should construct with CatchainSeqno.

@github-actions
Copy link

  • validator/full-node-serializer.cpp:133 extract_prev_blocks_from_proof unpacks only BlockProof. Shard block broadcasts/dataFull carry a BlockProofLink (ValidateBroadcast uses create_proof_link for non-mc), so unpacking fails → wait_state_by_prev_blocks never runs and every V2 shard broadcast/data-full that requires state is dropped. The new Merkle-update compression therefore cannot be used for shard blocks. Handle proof links in this helper (or select the correct parser based on shard) before requesting state.

@github-actions
Copy link

No issues found.

@github-actions
Copy link

  • crypto/vm/boc-compression.cpp:727-758 – build_prunned_branch_from_state drops the highest set bit from the pruned-branch mask (base_mask instead of the full mask_value) before computing level_mask. As a result max_level/is_significant ignore the top level and no hash/depth is stored for it, so reconstructed pruned branches under MerkleUpdate will have missing hashes/depths and yield incorrect cells during decompression.

@github-actions
Copy link

  • validator/net/download-block-new.cpp: in got_data the new state-aware path requests shard state (wait_state_by_prev_blocks) immediately after parsing the TL object, before any proof/hash/signature validation. A malicious peer can now respond to a download request with a forged dataFullCompressedV2 that advertises the “state-required” algorithm and arbitrary prev IDs in the proof, forcing the node to fetch/merge those states (I/O/CPU) before the response is rejected. Consider validating the proof/block id (or otherwise rate-limiting) prior to issuing state fetches, or deferring state acquisition until after basic checks to avoid a DoS vector.

@github-actions
Copy link

No issues found.

…ompression of the nested Merkle Updates and corresponding Prunned Branches
@github-actions
Copy link

No issues found.

@github-actions
Copy link

  • validator/net/download-block-new.cpp:236-262 fetches/merges shard states (wait_state_by_prev_blocks) based solely on an unverified dataFullCompressedV2 proof, before any proof/signature validation. A malicious peer can send crafted proofs to force expensive state downloads/merges as a DoS. Validate the proof (or otherwise authenticate the response) before requesting state, or defer state acquisition until after proof verification.

@github-actions
Copy link

github-actions bot commented Jan 6, 2026

  • validator/net/download-block-new.cpp:229-264 – when a compressed V2 response claims it needs state, the code now extracts prev blocks from the unvalidated proof and immediately requests those states before checking that the block id matches the requested one or that the proof is genuine. A malicious peer can craft a fake compressed reply with arbitrary prev blocks and force the node to download/merge unrelated states (DoS). Validate the block/proof (or at least confirm block_id against the request and sanity-check the proof) before calling wait_state_by_prev_blocks.

@github-actions
Copy link

github-actions bot commented Jan 6, 2026

  • validator/net/download-block-new.cpp:225-259 – For tonNode_dataFullCompressedV2 the code requests state (and even merges prev states) before any proof/file-hash validation of the incoming data. A malicious peer can reply with a forged message that forces expensive state downloads/merges and only fails later during validation. Please validate the proof (or otherwise vet the message) before calling wait_state_by_prev_blocks, or defer the state fetch until after the proof is checked.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant