Skip to content

feat: discard the code_hash and trx_hash fields passed in during contract deployment - #6945

Open
ouy95917 wants to merge 1 commit into
tronprotocol:masterfrom
ouy95917:feat/discard-contract-hash-fields
Open

feat: discard the code_hash and trx_hash fields passed in during contract deployment#6945
ouy95917 wants to merge 1 commit into
tronprotocol:masterfrom
ouy95917:feat/discard-contract-hash-fields

Conversation

@ouy95917

@ouy95917 ouy95917 commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

Why is this needed?

The code_hash and trx_hash fields passed in during contract deployment are unused. They do not participate in deployment processing and do not affect the deployment result or execution semantics.

Since these fields have no functional meaning as deployment inputs, this change introduces a preventive protocol restriction against their future use.

Historical transaction scan

We performed a complete scan of all historical transactions across the full chain history.

No historical contract deployment transaction was found with either code_hash or trx_hash set. The number of historical transactions carrying either field is zero.

This confirms that normal contract deployments have never relied on these fields. The restriction does not invalidate any historical transaction or alter any existing user behavior.

Implementation

The field numbers already exist in the protocol message and cannot be removed directly without affecting wire compatibility. Therefore, preventive prohibition at the protocol level must be implemented as an activation-gated rule.

The check is performed in the contract code persistence path, immediately before the deployed code is saved. After activation, a contract deployment transaction containing a non-empty code_hash or trx_hash is rejected using the existing timeout rejection semantics before its code is persisted. Before activation, the existing behavior is preserved.

This placement leaves the preceding contract validation flow unchanged and limits the new restriction to the code persistence stage.

Normal contract deployment transactions do not set these fields and are completely unaffected by this change. Contract bytecode, addresses, resource settings, constructor parameters, and all other normal deployment inputs continue to be processed exactly as before.

What does this PR do?

  • Detects non-empty code_hash and trx_hash values immediately before contract code persistence.
  • Rejects transactions carrying either field after activation and before the code is saved.
  • Preserves pre-activation compatibility.
  • Leaves the preceding validation flow and normal contract deployment behavior unchanged.
  • Adds coverage for each field, empty values, and pre-activation behavior.

Compatibility

This change currently uses the same provisional fork version introduced by #6920.

The current branches merge without textual conflicts. If the version identifier or activation parameters in #6920 change, this PR should be updated accordingly.

Tests

  • Verified code_hash rejection after activation.
  • Verified trx_hash rejection after activation.
  • Verified empty fields remain valid.
  • Verified pre-activation compatibility.
  • Verified existing activation-gated timeout behavior.

@yanghang8612
yanghang8612 marked this pull request as ready for review September 2, 2026 09:50
}

static void checkContractHashFields(SmartContract contract) {
if (!contract.getCodeHash().isEmpty() || !contract.getTrxHash().isEmpty()) {

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.

Covering both fields with a single || and relying on proto3 isEmpty() correctly handles unset vs. empty — normal deployments are untouched.

@ouy95917
ouy95917 force-pushed the feat/discard-contract-hash-fields branch from 57fa8e5 to d63f1cf Compare September 3, 2026 03:59
@ouy95917
ouy95917 force-pushed the feat/discard-contract-hash-fields branch from d63f1cf to 410b33d Compare September 3, 2026 08:28
if (VMConfig.allowTvmConstantinople()) {
CreateSmartContract createContract =
ContractCapsule.getSmartContractFromTransaction(trx);
checkContractHashFields(createContract.getNewContract());

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Is placing this check immediately before saveCode intentional so that the restriction is applied at the code-persistence boundary, while the preceding contract validation flow keeps its existing behavior?

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.

Yes. The check is intentionally performed when the deployment reaches the code-persistence stage. If either field is populated after activation, execution is stopped before the deployed code is saved, while earlier validation behavior remains unchanged.

}

public static void checkCPUTimeForContractHashFields() {
if (ForkController.instance().pass(Parameter.ForkBlockVersionEnum.VERSION_4_8_2_2)) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Is the activation check intentionally kept inside this helper so that the call site can remain unconditional once the persistence path is reached, with the helper becoming a no-op before activation?

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.

Correct. Keeping the activation decision in the helper centralizes the fork-dependent behavior. Before activation it returns normally, and after activation it applies the new restriction.

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.

4 participants