{"record":{"id":"63f930eba5699787","repo":"nautechsystems/nautilus_trader","slug":"verified-call-trace-child-has-an-invalid-caller-co","errorCode":null,"errorMessage":"Verified call trace child has an invalid caller context","messagePattern":"Verified call trace child has an invalid caller context","errorType":"validation","errorClass":"anyhow::Error","httpStatus":null,"severity":"critical","filePath":"crates/adapters/blockchain/src/execution/client.rs","lineNumber":4423,"sourceCode":"        trace.call_type == RpcCallType::Call\n            && trace.from == signed.signer\n            && trace.to == Some(signed.to)\n            && trace.value == signed.value\n            && trace.input_digest == keccak256(&signed.input)\n            && trace.success == receipt_success,\n        \"Verified call-trace root differs from the authenticated transaction\"\n    );\n    validate_internal_calls(&trace.calls, signed.to, purpose, manifest)\n}\n\nfn validate_internal_calls(\n    calls: &[VerifiedCallTrace],\n    caller_context: Address,\n    purpose: &str,\n    manifest: &BlockchainDeploymentManifest,\n) -> anyhow::Result<()> {\n    for call in calls {\n        anyhow::ensure!(\n            call.from == caller_context,\n            \"Verified call trace child has an invalid caller context\"\n        );\n        let target = call.to.ok_or_else(|| {\n            anyhow::anyhow!(\"Verified call trace contains an operation without a target\")\n        })?;\n        let call_type = match call.call_type {\n            RpcCallType::Call => \"call\",\n            RpcCallType::Callcode => \"callcode\",\n            RpcCallType::Delegatecall => \"delegatecall\",\n            RpcCallType::Staticcall => \"staticcall\",\n            RpcCallType::Create | RpcCallType::Create2 | RpcCallType::Selfdestruct => {\n                anyhow::bail!(\"Verified call trace contains a forbidden state-changing operation\")\n            }\n        };\n        let permitted = manifest.call_edges.iter().any(|edge| {\n            edge.purpose == purpose\n                && edge.call_type.eq_ignore_ascii_case(call_type)","sourceCodeStart":4405,"sourceCodeEnd":4441,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/adapters/blockchain/src/execution/client.rs#L4405-L4441","documentation":"This error comes from `validate_internal_calls`, which recursively walks the internal (child) calls of a verified transaction trace. Each child call's `from` must equal the `caller_context` passed in: the parent's target for `call`/`staticcall`, or the parent's caller for `callcode`/`delegatecall` (which preserve the caller context). A mismatch means the trace contains a frame whose sender does not follow EVM call semantics expected at that depth — i.e. the trace is malformed, was tampered with, or does not actually belong to this execution, so the check aborts.","triggerScenarios":"Fails for any child in `calls` where `call.from != caller_context`. E.g. a root-level internal call whose `from` is not the signed transaction's `to` contract (for CALL/STATICCALL), or a nested frame under a DELEGATECALL whose `from` is not the delegating contract's address. Triggered whenever the debug trace returns internal frames that violate standard EVM sender semantics for their position in the tree.","commonSituations":"The tracing node returns traces in a nonstandard or partially-populated shape (proxy nodes, custom tracers, or older geth/erigon versions with differing frame fields); traces are compared against the wrong transaction so the tree does not line up; a malicious or buggy tracer injects frames with fabricated `from` addresses; contract using unusual opcodes (callcode) confused a custom parser that misassigns caller context.","solutions":["Re-fetch the trace from a trusted node and dump the full call tree; check whether the offending frame's `from` actually equals the expected parent target (CALL) or parent caller (DELEGATECALL/CALLCODE).","Confirm the node's tracer type and version produce standard callTracer frames; upgrade or reconfigure the tracer (e.g. use geth's built-in callTracer) if frames are malformed.","Ensure the trace is for the same `tx_hash` being verified; a trace from a different transaction will not match the expected caller contexts.","Check that address casing/checksum handling in the tracer output is consistent (lowercase vs checksummed) so address comparison is not spuriously failing upstream.","If a specific contract legitimately produces unexpected frames, verify its bytecode/behavior (e.g. Metamorphic/proxy patterns) and update expectations rather than bypassing the check."],"exampleFix":"// before: trusting proxy node traces with nonstandard frames\nlet trace = proxy.debug_trace_transaction(tx_hash, tracer).await?;\nvalidate_internal_calls(&trace.root.calls, signed.to, purpose, manifest)?;\n\n// after: use a full node's standard callTracer and validate the root first\nlet trace = full_node.debug_trace_transaction(tx_hash, GethCallTracer).await?;\nvalidate_call_trace(&trace.root, &signed, receipt.status, purpose, manifest)?; // validates root, then children with correct contexts","handlingStrategy":"validation","validationCode":"// Sanity-check child frame senders before full verification.\nfn children_have_valid_contexts(calls: &[VerifiedCallTrace], ctx: Address) -> bool {\n    calls.iter().all(|c| c.from == ctx)\n}","typeGuard":"fn has_valid_caller_context(call: &VerifiedCallTrace, caller_context: Address) -> bool {\n    call.from == caller_context\n}","tryCatchPattern":"if let Err(e) = validate_internal_calls(&trace.calls, signed.to, purpose, manifest) {\n    if e.to_string().contains(\"invalid caller context\") {\n        dump_trace_tree(&trace); // capture malformed frames for node/tracer diagnosis\n        return Err(e.context(\"tracer produced frames violating EVM call semantics\"));\n    }\n    return Err(e);\n}","preventionTips":["Use a mainstream tracer (geth/erigon callTracer) rather than proxies or custom tracers that reshape frames.","Verify traces only from nodes whose version produces standard frame fields.","Always confirm the trace's transaction hash matches the tx being verified before walking children.","Keep address comparisons case-normalized upstream so failures reflect real semantic mismatches.","Log the offending frame's from/expected context on failure for fast root-cause analysis."],"tags":["blockchain","call-trace","evm","security","trace-validation"],"backgroundTag":"unexpected-response-shape","analyzedSha":"18893faf8b356be3320add8de2f861b0b647cf06","analyzedAt":"2026-09-08T20:49:34.690Z","contentChangedAt":"2026-09-08T20:49:34.690Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}