eth_getRawTransactionByHash returns a transaction as hex-encoded raw bytes: bare RLP for legacy transactions or a typed envelope for EIP-2718 transactions. The decoded object from eth_getTransactionByHash is the node's interpretation of those same bytes, so the two must agree. You can verify the raw bytes by computing keccak256 over them and comparing the result to the requested transaction hash and the node's transactionHash field. Re-broadcasting the same raw bytes through eth_sendRawTransaction preserves the nonce and signature, which is useful when a transaction was dropped from the mempool. This guide covers the method, the envelope layout, runnable Node.js verification, and the limitations that vary by client and provider.
Raw Transaction Bytes and the Decoded Transaction Object
The Ethereum JSON-RPC specification defines eth_getRawTransactionByHash as a method that returns the raw bytes of a transaction given its hash. The result is a hex string beginning with 0x, not a JSON object with named fields. For a legacy transaction those bytes are the RLP encoding of the signed transaction; for an EIP-2718 transaction they are a type byte followed by an opaque payload. The authoritative reference is the Ethereum JSON-RPC eth_getRawTransactionByHash documentation.
By contrast, eth_getTransactionByHash returns a decoded object with fields such as nonce, gasPrice or maxFeePerGas, input, v, r, and s. That object is the node's interpretation of the raw bytes. The raw bytes are the canonical artifact: they are what was signed, what propagates through the peer-to-peer network, and what is included in a block. When you need to re-broadcast, audit, or independently verify a transaction, the decoded object alone is not sufficient because it may omit or normalize details.
The two representations must agree. If you hash the raw bytes with keccak256, you should get the transaction hash you requested. If you decode the raw bytes, you should recover the same nonce, type, and signature values that eth_getTransactionByHash reports. A mismatch is a signal that the endpoint is proxying, caching, or returning data from a different chain or state.
- eth_getRawTransactionByHash returns hex-encoded bytes, not a JSON object.
- eth_getTransactionByHash returns the decoded interpretation of those bytes.
- The raw bytes are the signed artifact; the decoded object is a view.
- Hash agreement between the two is the primary consistency check.
EIP-2718 Typed Envelope Layout and Parser Pitfalls
EIP-2718 introduced a typed transaction envelope: a single type byte followed by an opaque payload. The EIP-2718 specification defines this as TransactionType || TransactionPayload. Legacy transactions are the special case where the entire byte string is bare RLP with no leading type byte. This means a parser that assumes every raw transaction is RLP will misread typed transactions, because the first byte is a type identifier rather than an RLP list prefix.
Common type bytes include 0x01 for access-list transactions (EIP-2930), 0x02 for dynamic-fee transactions (EIP-1559), and 0x03 for blob transactions (EIP-4844). The payload after the type byte is itself RLP-encoded for these types, but the outer framing is not a single RLP list. For a deeper look at the type-3 envelope and blob-specific fields, see Ethereum blob transactions and EIP-4844.
A robust decoder should inspect the first byte. If it is 0x01, 0x02, or 0x03, treat the remainder as a typed payload and decode accordingly. If it is an RLP list prefix such as 0xf8 or 0xf9, treat the whole byte string as legacy RLP. This branching is the difference between a correct decoder and one that silently produces garbage fields.
- Legacy: bare RLP, no type byte.
- Type 0x01: access list (EIP-2930).
- Type 0x02: dynamic fee (EIP-1559).
- Type 0x03: blob (EIP-4844).
- Always branch on the leading byte before decoding.
Verifying Raw Bytes Against the Transaction Hash
The transaction hash is defined as keccak256 of the raw transaction bytes. This is true for both legacy and typed transactions: the type byte is included in the hash preimage. Therefore, the most direct verification is to compute keccak256 over the bytes returned by eth_getRawTransactionByHash and compare the result to the hash you requested. If they differ, the endpoint returned bytes for a different transaction or a different chain.
A second check is to compare against eth_getTransactionByHash. The decoded object should report the same transactionHash, the same type, and the same nonce. If the raw bytes decode to a type 0x02 transaction but the decoded object says type 0x00, something is inconsistent. This can happen with misconfigured proxies or endpoints that serve stale data.
For a broader view of how transaction data is organized across blocks and receipts, see eth_getBlockReceipts bulk receipts. Receipts confirm inclusion, while raw bytes confirm the exact signed payload.
- keccak256(rawBytes) must equal the requested transaction hash.
- The decoded object's transactionHash must match the same value.
- Type and nonce from the decoded object should match the raw bytes.
- Mismatches indicate a proxied, stale, or wrong-chain endpoint.
Runnable Node.js Example: Fetch, Detect Type, and Verify Hash
The following Node.js script uses the built-in fetch API and the ethers library for keccak256 and RLP decoding. It fetches the raw bytes, detects the transaction type from the leading byte, computes the keccak256 hash, and compares it to the requested hash. It also fetches the decoded object for a second-source check.
Replace the RPC_URL with your provider endpoint. OnFinality's Ethereum network page lists supported endpoints, and the Ethereum RPC node guide covers connection basics. The script is intentionally minimal so you can adapt it to your own verification workflow.
const { keccak256 } = require('ethers/lib/utils');
const RPC_URL = process.env.RPC_URL || 'https://api.onfinality.io/public/eth';
const TX_HASH = process.env.TX_HASH;
async function rpc(method, params) {
const res = await fetch(RPC_URL, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ jsonrpc: '2.0', id: 1, method, params })
});
const json = await res.json();
if (json.error) throw new Error(JSON.stringify(json.error));
return json.result;
}
function detectType(rawHex) {
const first = parseInt(rawHex.slice(2, 4), 16);
if (first === 0x01) return '0x01 access list (EIP-2930)';
if (first === 0x02) return '0x02 dynamic fee (EIP-1559)';
if (first === 0x03) return '0x03 blob (EIP-4844)';
return 'legacy RLP';
}
(async () => {
const raw = await rpc('eth_getRawTransactionByHash', [TX_HASH]);
if (!raw) throw new Error('raw transaction not found');
const type = detectType(raw);
const computed = keccak256(raw);
const decoded = await rpc('eth_getTransactionByHash', [TX_HASH]);
console.log('requested hash:', TX_HASH);
console.log('computed hash :', computed);
console.log('hash match :', computed.toLowerCase() === TX_HASH.toLowerCase());
console.log('detected type :', type);
console.log('decoded type :', decoded ? decoded.type : 'n/a');
console.log('decoded nonce :', decoded ? decoded.nonce : 'n/a');
console.log('decoded hash :', decoded ? decoded.hash : 'n/a');
})();Re-Broadcasting Raw Bytes Without Re-Signing
When a transaction is dropped from the mempool, the signed raw bytes remain valid until the nonce is consumed. You can re-broadcast the exact same bytes with eth_sendRawTransaction. Because the bytes already contain the signature, the nonce, and the gas parameters, re-broadcasting preserves all of them. This is safer than re-signing, which could produce a different hash and create a competing transaction.
The Ethereum transaction pool and mempool namespace explains how pending transactions are tracked. A pending raw transaction may be available via eth_getRawTransactionByHash before a receipt exists, because it is in the pool rather than in a block. Once mined, the same raw bytes are part of the block and the receipt becomes available.
For MEV-related workflows, raw bytes are also the input to bundle submission. See Ethereum MEV bundles and eth_sendBundle for how bundles carry signed transactions. The same principle applies: the raw bytes are the unit of propagation.
- Re-broadcast the same raw bytes to preserve nonce and signature.
- Do not re-sign unless you intend to replace the transaction.
- Pending raw bytes may be available before a receipt.
- Mined raw bytes are part of the block; receipts confirm inclusion.
Runnable curl Example: Fetch Raw Bytes and Compare Endpoints
A quick curl check helps you confirm whether an endpoint supports eth_getRawTransactionByHash and whether two endpoints agree. The following example sends the same request to two RPC URLs and prints the raw bytes. If one endpoint returns an error or a different byte string, you have a provider or configuration issue.
This is also a useful way to test whether a provider gates the method behind a namespace or flag. Some clients disable raw transaction retrieval by default. The API service page describes how OnFinality exposes JSON-RPC endpoints, and RPC pricing covers plan-level access.
TX_HASH=0xYOUR_TRANSACTION_HASH
for URL in https://api.onfinality.io/public/eth https://your-other-rpc.example/eth; do
echo "== $URL =="
curl -s -X POST "$URL" \
-H 'Content-Type: application/json' \
-d '{"jsonrpc":"2.0","id":1,"method":"eth_getRawTransactionByHash","params":["'"$TX_HASH"'"]}' \
| head -c 400
echo
doneResults Table: Measuring Raw Transaction Retrieval on Your Endpoint
Because provider behavior and client support vary, the most reliable approach is to measure against your own endpoint. Use the table below to record what you observe. Do not rely on published numbers from other environments; your results depend on your client, your provider, and your network conditions.
Run the Node.js or curl example against your endpoint and fill in each row. The goal is to document whether the method is available, whether the hash verifies, and whether the decoded object agrees. This turns an ambiguous 'it works' into a reproducible check.
- Endpoint URL: the exact RPC URL you tested.
- Method available: yes/no, or error code if gated.
- Raw bytes returned: first 20 hex characters for reference.
- Detected type: legacy, 0x01, 0x02, or 0x03.
- keccak256 match: true/false against requested hash.
- Decoded object match: type, nonce, and hash agree true/false.
- Notes: any provider-specific flags or namespace requirements.
Troubleshooting Mismatches, Missing Bytes, and Rejected Re-Broadcasts
If eth_getRawTransactionByHash returns null, the transaction may not be known to that node. This can happen if the node is not fully synced, if the transaction is on a different chain, or if the hash is incorrect. Check the hash length and prefix first, then confirm the node's chain ID and sync status.
If the method returns an error such as 'method not found' or 'method not enabled', the client may gate raw transaction retrieval behind a flag or namespace. This is documented behavior that varies by client. Some clients expose it only when the transaction is in the pool or only for recent blocks. Consult your client's documentation and your provider's supported methods.
If keccak256 of the raw bytes does not match the requested hash, the endpoint may be proxying to a different chain or returning cached data. Compare against a second endpoint. If eth_sendRawTransaction rejects a re-broadcast with a nonce error, that is a correct rejection: the nonce was already consumed, meaning the original transaction was mined or replaced. Do not treat it as a bug.
- null result: check hash, chain ID, and sync status.
- Method not found: client may gate the method behind a flag.
- Hash mismatch: suspect proxying, caching, or wrong chain.
- Nonce rejection on re-broadcast: the nonce is already consumed.
- Raw bytes include the signature; they are not the message body alone.
Limitations and Tradeoffs of Raw Transaction Retrieval
Not every client enables eth_getRawTransactionByHash by default. Some require a flag, some expose it only under a specific namespace, and some providers do not route it at all. This is documented behavior that varies by client and provider, so you should verify support before building a workflow that depends on it.
The raw bytes are the full signed transaction, including the signature. They are not the unsigned message body. If you need to verify a signature, you must decode the bytes and extract v, r, and s, then recover the signer. The raw bytes alone do not tell you who signed without that step.
Re-broadcasting is not a guarantee of inclusion. If the nonce was already consumed, the network will reject the transaction. If gas prices have moved, the transaction may remain pending. Raw bytes preserve the original parameters, which is both their strength and their limitation: you cannot adjust fees without re-signing.
- Client support varies; some gate the method behind a flag.
- Raw bytes include the signature, not just the message body.
- Re-broadcast preserves nonce and signature but not inclusion.
- Fee changes require re-signing and produce a new hash.
Next Steps: Integrating Raw Bytes into Your Workflow
Start by adding a verification step to your transaction monitoring. Whenever you fetch a transaction, also fetch its raw bytes and confirm the keccak256 hash. This catches endpoint inconsistencies early. The OnFinality Learn hub has related guides on transaction pools, receipts, and blob transactions.
For production systems, consider caching raw bytes alongside the decoded object. This lets you re-broadcast without another RPC call and gives you an audit trail of the exact signed payload. If you use multiple providers, run the results table against each one to document support and behavior.
Finally, review your provider's method support and plan limits. The Ethereum network page and RPC pricing pages describe available endpoints and access tiers. Combine raw transaction retrieval with receipt checks and mempool monitoring for a complete view of transaction lifecycle.
- Add keccak256 verification to transaction monitoring.
- Cache raw bytes for re-broadcast and audit.
- Test each provider with the results table.
- Combine with receipts and mempool monitoring.