{"record":{"id":"e2d94f2096a23c4f","repo":"nautechsystems/nautilus_trader","slug":"finalized-swap-log-has-no-block-hash","errorCode":null,"errorMessage":"Finalized Swap log has no block hash","messagePattern":"Finalized Swap log has no block hash","errorType":"validation","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/adapters/blockchain/src/execution/client.rs","lineNumber":4747,"sourceCode":"            !log.removed\n                && log.topics.first().is_some_and(|topic| topic == &signature)\n                && Address::from_str(&log.address).ok() == Some(plan.pool_address)\n        })\n        .collect::<Vec<_>>();\n    anyhow::ensure!(\n        swap_logs.len() == 1,\n        \"Finalized transaction {} emitted {} Swap logs from expected pool {}; expected exactly one\",\n        included.tx_hash,\n        swap_logs.len(),\n        plan.pool_address\n    );\n    let log = swap_logs[0];\n    let log_transaction_hash = B256::from_str(&rpc_log::extract_transaction_hash(log)?)\n        .with_context(|| \"Invalid finalized Swap log transaction hash\")?;\n    let log_block_hash = log\n        .block_hash\n        .as_deref()\n        .ok_or_else(|| anyhow::anyhow!(\"Finalized Swap log has no block hash\"))?;\n    anyhow::ensure!(\n        log_transaction_hash == included.tx_hash\n            && rpc_log::extract_block_number(log)? == included.block_number\n            && u64::from(rpc_log::extract_transaction_index(log)?)\n                == included.receipt.transaction_index\n            && B256::from_str(log_block_hash)\n                .with_context(|| \"Invalid finalized Swap log block hash\")?\n                == included.receipt.block_hash,\n        \"Finalized Swap log position does not match transaction {}\",\n        included.tx_hash\n    );\n\n    let dex = crate::exchanges::get_dex_extended(plan.pool.chain.name, &plan.pool.dex.name)\n        .ok_or_else(|| {\n            anyhow::anyhow!(\n                \"No RPC Swap decoder for {}:{}\",\n                plan.pool.chain.name,\n                plan.pool.dex.name","sourceCodeStart":4729,"sourceCodeEnd":4765,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/adapters/blockchain/src/execution/client.rs#L4729-L4765","documentation":"The library extracts the block hash from the finalized Swap RPC log and requires it to be present before cross-checking the log against the transaction receipt. A missing block_hash field means the node returned an incomplete log object, so consistency verification cannot proceed.","triggerScenarios":"An RPC provider (eth_getLogs or receipt log entry) returning a log JSON without a blockHash field — common with some lightweight or non-standard providers, reorg-pruned responses, or hand-built/mocked log fixtures.","commonSituations":"Switching RPC providers where one omits blockHash on filtered logs; custom indexing middleware stripping fields; unit-test fixtures built with partial log structs; calling eth_getLogs on a node with partial trace support.","solutions":["Use a full-featured RPC provider that returns complete log objects including blockHash","Re-fetch the log via the transaction receipt (eth_getTransactionReceipt) which always includes blockHash","If using middleware/proxy that filters fields, disable field stripping","In test fixtures, populate block_hash before invoking verification"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"fn log_has_block_hash(log: &rpc_log::Log) -> bool { log.block_hash.as_deref().map(|h| h.len() == 66).unwrap_or(false) }\nif !log_has_block_hash(log) { return Err(anyhow!(\"provider returned log without blockHash\")); }","typeGuard":"fn has_block_hash(log: &rpc_log::Log) -> Option<&str> { log.block_hash.as_deref().filter(|h| B256::from_str(h).is_ok()) }","tryCatchPattern":"let log = fetch_complete_log(tx_hash).await\n    .map_err(|e| if is_incomplete_log(&e) { fetch_from_receipt(tx_hash).await? } else { e })?;","preventionTips":["Use RPC providers that return full log objects","Prefer eth_getTransactionReceipt over raw log polling for finality checks","Validate log completeness before verification","Populate all fields in test log fixtures"],"tags":["blockchain","rpc","missing-field","log"],"backgroundTag":"missing-required-argument","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"}