Skip to main content

Quickstart guide

This guide will walk you through building, running, and using reth-private-transaction to send your first private transaction.

Prerequisites

Before you begin, ensure you have:
  • Rust toolchain (1.75 or later)
  • Git
  • At least 2TB of free disk space for a full Ethereum node
  • A synced execution client (or prepare to sync one)
Running a Reth node requires significant disk space and bandwidth. Make sure you have adequate resources before proceeding.

Installation

1

Clone the repository

Clone the reth-private-transaction repository to your local machine:
git clone https://github.com/Quertyy/reth-private-transaction.git
cd reth-private-transaction
2

Build the binary

Compile the project in release mode for optimal performance:
cargo build --release
This will create an optimized binary at ./target/release/reth-private-transaction.
The first build may take 10-20 minutes depending on your system. Subsequent builds will be faster.
3

Prepare your JWT secret

Create a JWT secret for authenticated communication between execution and consensus clients:
mkdir -p /data/mainnet/secrets
openssl rand -hex 32 > /data/mainnet/secrets/jwt.hex
4

Start the node

Launch your Reth node with the private transaction extension enabled:
./target/release/reth-private-transaction node \
  --datadir /data/mainnet/ \
  --authrpc.jwtsecret /data/mainnet/secrets/jwt.hex \
  --http --ws \
  --http.addr 0.0.0.0 --ws.addr 0.0.0.0 \
  --http.api txpool,web3,eth,debug,trace \
  --ws.api txpool,web3,eth,debug,trace
The RPC method eth_sendPrivateRawTransaction will be automatically registered under the eth namespace.
Look for the log message: Private transaction method added to confirm successful registration.

Send your first private transaction

Once your node is running, you can send private transactions using the new RPC method.

Using curl

1

Sign your transaction

First, create and sign a transaction using your preferred method (web3.js, ethers.js, etc.). You’ll need the raw signed transaction as a hex string.Example using ethers.js:
const { Wallet, parseEther } = require('ethers');

const wallet = new Wallet('YOUR_PRIVATE_KEY');
const tx = await wallet.signTransaction({
  to: '0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb',
  value: parseEther('0.01'),
  gasLimit: 21000,
  gasPrice: parseEther('0.00000002'), // 20 gwei
  nonce: await wallet.getNonce(),
  chainId: 1
});

console.log('Signed transaction:', tx);
2

Submit via RPC

Send the signed transaction to your Reth node using the private RPC method:
curl -X POST http://localhost:8545 \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_sendPrivateRawTransaction",
    "params": ["0x..."],
    "id": 1
  }'
Replace 0x... with your actual signed transaction hex.
3

Get your transaction hash

If at least one builder accepts your transaction, you’ll receive a response with your transaction hash:
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef"
}
Use this hash to track your transaction on Etherscan or via eth_getTransactionReceipt.

Using ethers.js

You can also integrate the private transaction method directly into your JavaScript application:
const { JsonRpcProvider, Wallet, parseEther } = require('ethers');

const provider = new JsonRpcProvider('http://localhost:8545');
const wallet = new Wallet('YOUR_PRIVATE_KEY', provider);

async function sendPrivateTransaction() {
  // Create and sign the transaction
  const tx = await wallet.signTransaction({
    to: '0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb',
    value: parseEther('0.01'),
    gasLimit: 21000,
    gasPrice: parseEther('0.00000002'),
    nonce: await wallet.getNonce(),
    chainId: 1
  });
  
  // Send via private RPC method
  const txHash = await provider.send('eth_sendPrivateRawTransaction', [tx]);
  console.log('Transaction hash:', txHash);
  
  // Wait for confirmation
  const receipt = await provider.waitForTransaction(txHash);
  console.log('Transaction confirmed in block:', receipt.blockNumber);
}

sendPrivateTransaction();

Understanding the response

Success response

When your transaction is successfully accepted by at least one builder:
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef"
}
The result field contains your transaction hash. Your transaction is now privately queued with one or more builders.

Error responses

All builders failed
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32001,
    "message": "All builders failed to send tx"
  }
}
This means none of the builders accepted your transaction. Common causes:
  • Invalid transaction signature
  • Insufficient gas price
  • Nonce issues
  • Network connectivity problems
No builders available
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "No builders available"
  }
}
The node couldn’t initialize connections to any builders. Check your network connectivity.

Behind the scenes

When you call eth_sendPrivateRawTransaction, here’s what happens:
  1. Transaction validation: Your raw transaction is decoded and validated (src/main.rs:103)
  2. Builder initialization: The node creates HTTP clients for all supported builders (src/lib.rs:52-63)
  3. Concurrent submission: Your transaction is sent to all builders in parallel (src/main.rs:86)
  4. Response handling: If at least one builder succeeds, your transaction hash is returned (src/main.rs:88-92)
The implementation uses Rust’s async runtime to send to multiple builders simultaneously:
async fn send_tx_to_builders(&self, tx: Bytes, builders: Vec<Builder>) -> RpcResult<()> {
    let results = join_all(builders.iter().map(|builder| builder.send_tx(tx.clone()))).await;

    if results.iter().all(|r| r.is_err()) {
        return Err(PrivateTransactionError::AllBuildersFailed.into());
    }

    Ok(())
}
This ensures maximum redundancy and speed.

Next steps

Now that you’ve sent your first private transaction, you can:
  • Monitor builder logs to see which builders accepted your transactions
  • Integrate the RPC method into your dApp or trading bot
  • Configure custom builder endpoints if needed
  • Set up monitoring and alerting for your Reth node
Remember that private transactions still require competitive gas prices to be included by builders. Privacy doesn’t guarantee inclusion - it only guarantees protection from public mempool MEV.

Build docs developers (and LLMs) love