Skip to content

fix(net): validate block transactions before propagation - #7066

Merged
lvs0075 merged 9 commits into
tronprotocol:release_v4.8.3from
xxo1shine:fix/block-prebroadcast-validation
Oct 27, 2026
Merged

lvs0075 merged 9 commits into
tronprotocol:release_v4.8.3from
xxo1shine:fix/block-prebroadcast-validation

Conversation

@xxo1shine

@xxo1shine xxo1shine commented Oct 27, 2026 •

Copy link
Copy Markdown
Collaborator

What does this PR do?

  • Reject blocks containing transactions with zero or multiple contracts, or transactions smaller than 80 bytes, before broadcasting or fast-forwarding them.
  • Apply shared transaction structure, size, Merkle root and witness signature validation to both advertised and sync blocks.
  • Keep future-timestamp validation at message ingress; remove the duplicate clock check from shared block validation.
  • Keep active-witness checks specific to advertised blocks so historical sync blocks remain valid.
  • Remove redundant Merkle root validation from Manager and the capsule validation cache.

Why are these changes required?

This PR has been tested by:

  • Unit Tests
  • Manual Testing

Follow up

Extra details

wb added 7 commits October 20, 2026 14:09
Track permission-update owners when blocks are rolled back so cached transaction verification is invalidated. Clear transaction results before caching relay messages and omit full hash lists when transaction inventory is rate limited.
Release the global sync request on every block processing failure so
another peer can supply the block without waiting for cache expiration.
Disconnect only the sender and preserve other peers' queued blocks and
sync progress.

Reject advertised blocks whose witness is outside the active set instead
of silently dropping them. Keep advertisement recovery on the sync path
and retain log-only handling for failures during advertised block application.

Unify block application errors as BAD_BLOCK while retaining their causes.
Log P2P failure details without a stack trace and keep stack traces for
unexpected sync failures.
Clear results only on the transaction copy cached for relay. Keep the original capsule unchanged so broadcasting cannot erase pending execution results or race with block assembly.
Reject transactions with a contract count other than one before relaying
received blocks. Apply shared timestamp, transaction structure, Merkle root
and witness signature checks to both advertised and sync blocks, while
keeping current active-witness checks specific to advertised blocks.

Validate Merkle roots at network admission and remove the redundant
Manager check and capsule validation cache. Keep the existing signature
failure types, messages and causes.
Merge upstream release_v4.8.3 through d7df62b. Preserve shared block prevalidation before propagation and sync processing while adopting the release inactive-witness relay guard and repeated-block disconnect policy.
@github-actions
github-actions Bot requested a review from 317787106 October 27, 2026 03:25
@halibobo1205 halibobo1205 added this to the GreatVoyage-v4.8.3 milestone Oct 27, 2026
@halibobo1205 halibobo1205 added the topic:net p2p net work, synchronization label Oct 27, 2026
"time:" + time + ",block time:" + block.getTimeStamp());
}
for (Transaction transaction : block.getInstance().getTransactionsList()) {
int contractCount = transaction.getRawData().getContractCount();

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[SHOULD] Please also check each transaction’s full serialized size here, rejecting transactions smaller than 65 bytes or larger than Constant.TRANSACTION_MAX_BYTE_SIZE before propagation.

Merkle leaves and internal nodes use the same hash function without domain separation. A 64-byte transaction can match the concatenation of two 32-byte child hashes, allowing different transaction lists to share the same Merkle root. Checking contract count alone does not rule this out.

Please add boundary tests and verify compatibility with historical blocks and shielded transactions.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Implemented in 9b3ab87. MIN_TRANSACTION_SIZE = 80 now rejects transactions whose full Transaction.getSerializedSize() is below 80 bytes, before Merkle validation for both advertised and sync blocks.

Tests cover 64/79-byte rejection, 80/81-byte acceptance, signatures and ret counting toward the full size, a synthetic shielded transaction without an outer signature, and rejection before broadcast, fast-forwarding, or sync processing. All 62 targeted tests, the build with tests excluded, and Checkstyle passed.

This change adds the lower bound only; upper-bound validation is unchanged. A full historical-chain replay has not been performed.

Check the full serialized transaction size before Merkle validation for advertised and sync blocks. Exclude short transaction encodings from the 64-byte internal-node hash input domain.

/**
* save a block.
* Save a block. Untrusted callers must first use network prevalidation to check its timestamp,

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[DISCUSS] Confirm the Merkle-validation boundary for future callers

This removes the Merkle-root check from pushBlock and makes network prevalidation a caller prerequisite. The current advertised and sync paths both call validBlock, so I did not find a current bypass; however, a future direct caller that misses this Javadoc contract would no longer get the previous defense-in-depth check.

Suggestion: Keep the prevalidation requirement explicit for all new entry points, and consider retaining a core Merkle check or introducing a validated-block abstraction if that caller contract cannot be enforced.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is an intentional change in validation responsibility: the advertised-block path calls validAdvBlock -> validBlock, and the sync path calls validBlock directly before entering pushBlock. The duplicate Merkle validation in the core layer was therefore removed.

I agree with the reminder about future callers. The Javadoc for pushBlock explicitly requires untrusted blocks to undergo prevalidation, and new entry points must respect that prerequisite as well. No further code changes are planned for this comment.

Rely on BlockMsgHandler to check timestamps for advertised and sync blocks. Remove the duplicate one-second wall-clock rejection from shared block validation.
@lvs0075
lvs0075 merged commit 0b59aca into tronprotocol:release_v4.8.3 Oct 27, 2026
12 of 13 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

topic:net p2p net work, synchronization

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants