I wonder if there is an equivalent to bitcoind's getrawtransaction, i.e., a command to dump a raw transaction in hex format, given its hash id.
I am working preferably in geth.
There is eth.getRawTransaction(<txhash>)
now.
Edit:
Please check that you're using an up-to-date version of geth. It's part of the current release (v.1.8.6) and was introduced some time ago. You can also see it in the source code:
https://github.com/ethereum/go-ethereum/blob/ca64a122d33008c155c35a9d0e78cfbcafb1820a/internal/web3ext/web3ext.go (look for getRawTransaction
)
https://github.com/ethereum/go-ethereum/blob/ec8ee611caefb5c5ad5d796178e94c1919260df4/internal/ethapi/api.go (look for GetRawTransactionByHash
)
input: transaction hash
output: bytes of the corresponding transaction
eth.getRawTransaction()
. What are you talking about?
There is an "undocumented" method eth_getRawTransactionByHash
from JSON-RPC
curl -H "Content-Type: application/json" -X POST --data \
'{"jsonrpc":"2.0","method":"eth_getRawTransactionByHash","params":["<TX_HASH>"],"id":1}' http://localhost:8545
<TX_HASH> - transaction id
Have a look at getTransactionByHash() of the JSON-RPC API.
eth_getTransactionByHash
Returns the information about a transaction requested by transaction hash.
Parameters
DATA, 32 Bytes - hash of a transaction
params: [
"0xb903239f8543d04b5dc1ba6579132b143087c68db1b2168786408fcbce568238"
]
Returns
Object - A transaction object, or null when no transaction was found:
hash: DATA, 32 Bytes - hash of the transaction.
nonce: QUANTITY - the number of transactions made by the sender prior to this one.
blockHash: DATA, 32 Bytes - hash of the block where this transaction was in. null when its pending.
blockNumber: QUANTITY - block number where this transaction was in. null when its pending.
transactionIndex: QUANTITY - integer of the transactions index position in the block. null when its pending.
from: DATA, 20 Bytes - address of the sender.
to: DATA, 20 Bytes - address of the receiver. null when its a contract creation transaction.
value: QUANTITY - value transferred in Wei.
gasPrice: QUANTITY - gas price provided by the sender in Wei.
gas: QUANTITY - gas provided by the sender.
input: DATA - the data send along with the transact
You can also find the raw transaction hex on etherscan.io by going to a transaction, picking Tools & Utilities
and choosing Get Raw TxHash
. See for example:
https://etherscan.io/getRawTx?tx=0x248b16e4cb8a624ab4bb3125a3a2cf6bd6d21200b773e3d9c1f0738b1b09dd22
If you want to do this programatically with geth
, I present a solution for that here:
Can I get the raw transaction using Nethereum?
You can do it this way in Python:
import web3
from eth_account._utils.legacy_transactions import (
encode_transaction,
serializable_unsigned_transaction_from_dict,
)
w3 = web3.Web3(web3.HTTPProvider("https://eth-mainnet.alchemyapi.io/v2/XXXXXXXXXXXXXXXXXXXXXXXXXXX"))
hash = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
tx = w3.eth.getTransaction(hash)
def recover_raw_transaction(tx):
"""Recover raw transaction for replay.
Inspired by: https://github.com/ethereum/eth-account/blob/1d26f44f6075d6f283aeaeff879f4508c9a228dc/eth_account/_utils/signing.py#L28-L42
"""
transaction = {
"chainId": tx["chainId"],
"nonce": int(tx["nonce"], 16),
"maxPriorityFeePerGas": int(tx["maxPriorityFeePerGas"], 16),
"maxFeePerGas": int(tx["maxFeePerGas"], 16),
"gas": int(tx["gas"], 16),
"to": Web3.toChecksumAddress(tx["to"].lower()),
"value": int(tx["value"], 16),
"accessList": tx["accessList"],
}
if "data" in tx:
transaction["data"] = tx["data"]
if "input" in tx:
transaction["data"] = tx["input"]
v = int(tx["v"], 16)
r = int(tx["r"], 16)
s = int(tx["s"], 16)
unsigned_transaction = serializable_unsigned_transaction_from_dict(transaction)
return "0x" + encode_transaction(unsigned_transaction, vrs=(v, r, s)).hex()
raw_tx = recover_raw_transaction(tx)
If some basic fields like access_list
are missing when you retried the tx by hash, add them manually.
The node I'm consuming doesn't support eth_getTransactionByHash
So similarly to Nikolay answer, this is how I did it using ethers.js v5 (and TypeScript) instead of web3.py
import { Transaction } from "@ethersproject/transactions";
/**
* Serializes a transaction object into a raw transaction string.
* This function takes a Transaction object, ensures it is fully signed,
* constructs the unsigned transaction object, and then serializes it with the signature.
* It also verifies the serialization process by comparing the computed transaction hash
* with the original transaction hash.
*
* @param {Transaction} transaction - The transaction object from Ethers.js.
* @returns {string} The serialized raw transaction.
*/
const transactionToRawTransaction = (
transaction: TransactionResponse,
): string => {
const type0Fields = { gasPrice: transaction.gasPrice };
const type1Fields = { ...type0Fields, accessList: transaction.accessList };
const type2Fields = {
accessList: transaction.accessList,
maxFeePerGas: transaction.maxFeePerGas,
maxPriorityFeePerGas: transaction.maxPriorityFeePerGas,
};
const typeFileds = [type0Fields, type1Fields, type2Fields];
const extraFields = typeFileds[transaction.type ?? 0];
const unsignedTx = {
chainId: transaction.chainId,
data: transaction.data,
gasLimit: transaction.gasLimit,
nonce: transaction.nonce,
to: transaction.to,
type: transaction.type,
value: transaction.value,
...extraFields,
};
assert.ok(transaction.r);
const signature = {
r: transaction.r,
s: transaction.s,
v: transaction.v,
};
const serialized = ethers.utils.serializeTransaction(unsignedTx, signature);
// double check things went well
assert.strictEqual(ethers.utils.keccak256(serialized), transaction.hash);
return serialized;
};
/**
* Fetches a transaction from the blockchain using its hash and serializes it into a raw transaction string.
* This function retrieves the transaction details using the provided hash, ensuring the transaction exists,
* and then utilizes `transactionToRawTransaction` to serialize the transaction.
* This is useful if we want to replay a raw transaction in local or in the tests.
*
* @param {Provider} provider - The Ethers.js provider instance to interact with the blockchain.
* @param {string} hash - The hash of the transaction to fetch and serialize.
* @returns {Promise<string>} A promise that resolves to the serialized raw transaction string.
*/
const transactionHashToRawTransaction = async (
provider: Provider,
hash: string,
): Promise<string> => {
const transaction = await provider.getTransaction(hash);
const serialized = transactionToRawTransaction(transaction);
return serialized;
};
It's much easier with Ethers v6 is much easier since the ethers.Transaction
object has a serialized
attribute.
import { TransactionResponseParams } from "ethers";
const transactionToRawTransaction = (
transaction: TransactionResponseParams,
): string => {
const serialized = Transaction.from(transaction).serialized;
// double check things went well
assert.strictEqual(keccak256(serialized), transaction.hash);
return serialized;
};