> loading_
# Walkthrough: Understanding the eager copy fix in ProgramInvokeFactoryImpl
# This isn't a contract you deploy — it's a node-level change.
# But you can verify the behavioral difference with a test contract.
# --- TestCallDataIntegrity.sol ---
# Deploy this on RSK testnet to confirm call data immutability
# across nested invocations.
# pragma solidity ^0.8.0;
#
# contract Inner {
# // Returns the first 4 bytes of msg.data (the selector) and full calldata length
# function echo() external pure returns (bytes4 selector, uint256 len, bytes memory data) {
# selector = msg.sig;
# len = msg.data.length;
# data = msg.data;
# }
# }
#
# contract Outer {
# Inner public inner;
#
# constructor(address _inner) {
# inner = Inner(_inner);
# }
#
# // Calls Inner.echo() and then does additional memory operations
# // to stress-test whether call data bleeds across contexts
# function testCallDataIsolation(uint256 nonce) external view returns (
# bytes4 innerSelector,
# uint256 innerLen,
# bytes memory innerData,
# bytes4 outerSelector,
# uint256 outerLen
# ) {
# // Capture outer context first
# outerSelector = msg.sig;
# outerLen = msg.data.length;
#
# // Make the nested call
# (innerSelector, innerLen, innerData) = inner.echo();
#
# // After the nested call returns, outer's msg.data should be unchanged.
# // Pre-fix, shared references could theoretically cause outerSelector
# // or outerLen to reflect corrupted state in edge cases.
# assert(msg.sig == outerSelector); // must hold
# assert(msg.data.length == outerLen); // must hold
# }
# }
#
# --- How to test ---
# 1. Deploy Inner to RSK testnet
# 2. Deploy Outer, passing Inner's address to the constructor
# 3. Call Outer.testCallDataIsolation(42)
# 4. Verify: innerSelector == 0xc5d7802e (echo's selector),
# outerSelector == the selector for testCallDataIsolation,
# and both lengths are correct for their respective calldata
#
# If the assertions pass (and they should post-fix), call data isolation is intact.
# On a pre-fix node with pathological execution patterns, the shared reference
# could have allowed the inner call's context setup to interfere with the outer.
#
# For node operators: verify you're running the patched RSKj release by checking
# the git log for the RSKCORE-5466 commit in ProgramInvokeFactoryImpl.java:
# git log --oneline --all --grep="RSKCORE-5466"
# The fix is a single-line change from passing the byte array directly to:
# Arrays.copyOf(callData, callData.length)
# in the ProgramInvoke constructor call path.