Complete reference for the shell-chain JSON-RPC API. All methods follow the JSON-RPC 2.0 specification.
See also: Quickstart Guide · Testnet Operator Guide · Post-Quantum Cryptography Guide · Native Account Abstraction Guide · System Contracts · Prover Guide
- Connection
- CORS Configuration
- API Namespace Whitelist
- Rate Limiting
- WebSocket Support
- eth_ Namespace
- net_ Namespace
- web3_ Namespace
- shell_ Namespace
- debug_ Namespace
- trace_ Namespace
HTTP endpoint (default):
http://127.0.0.1:8545
WebSocket endpoint (when --ws is enabled):
ws://127.0.0.1:8546
All requests use POST with Content-Type: application/json.
Address note: RPC input and output addresses use canonical 32-byte 0x + 64 lowercase hex throughout the current codebase.
Control cross-origin access with --rpc-cors:
# Allow all origins
shell-node run --rpc-cors "*"
# Allow specific origins (comma-separated)
shell-node run --rpc-cors "http://localhost:3000,https://app.example.com"Or in TOML config:
[rpc]
cors_origins = ["http://localhost:3000", "https://app.example.com"]Control which API namespaces are exposed with --rpc-api:
# Validators (minimal surface)
shell-node run --rpc-api eth,net,web3,shell
# RPC nodes (full API)
shell-node run --rpc-api eth,net,web3,shell,debug,traceAvailable namespaces: eth, net, web3, shell, debug, trace
If --rpc-api is not specified, all namespaces registered by the node are available.
RPC rate limiting is available via --rpc-rate-limit:
shell-node run --rpc-rate-limit 100 # 100 requests/sec per bearer token/public bucketOr in TOML config:
[rpc]
rate_limit = 100When an API key is configured, authentication is evaluated before rate limiting, so bad unauthenticated requests do not consume the authenticated bucket. Valid Bearer tokens get independent buckets; no-token public requests share a public bucket. When the limit is exceeded, the server returns an HTTP 429 response.
Enable the WebSocket server with --ws:
shell-node run --ws --ws-port 8546The WebSocket endpoint supports all the same JSON-RPC methods as HTTP, plus real-time PubSub subscriptions and filter-based polling via eth_newFilter, eth_newBlockFilter, and eth_getFilterChanges.
Subscribe to live events. Returns a subscription ID.
Subscription types:
| Type | Description |
|---|---|
newHeads |
Pushes new block headers when blocks are produced or imported |
logs |
Pushes matching log events; reorged logs are replayed with removed: true before replacement-chain logs |
newPendingTransactions |
Pushes transaction hashes as they enter the mempool |
syncing |
Pushes sync status changes (syncing/not syncing) |
Example — newHeads:
wscat -c ws://127.0.0.1:8546
> {"jsonrpc":"2.0","id":1,"method":"eth_subscribe","params":["newHeads"]}
< {"jsonrpc":"2.0","id":1,"result":"0x1"}
< {"jsonrpc":"2.0","method":"eth_subscription","params":{"subscription":"0x1","result":{"number":"0xa","hash":"0x...","parentHash":"0x...","timestamp":"0x..."}}}Example — logs with filter:
> {"jsonrpc":"2.0","id":2,"method":"eth_subscribe","params":["logs",{"address":"0x...","topics":["0xddf2..."]}]}
< {"jsonrpc":"2.0","id":2,"result":"0x2"}logs filters reject invalid address or topics values. Addresses must use
the canonical 0x-prefixed 64-hex-character Shell address form. Topic entries
must be null, a 0x-prefixed 32-byte hash, or an array of 0x-prefixed
32-byte hashes. The topics array can contain at most four positional entries.
Within topics, null is a wildcard for that position; an empty alternatives
array ([]) matches no logs at that position.
Only address and topics are supported for live log subscriptions; other
filter fields are rejected as invalid parameters rather than ignored.
Example — newPendingTransactions:
> {"jsonrpc":"2.0","id":3,"method":"eth_subscribe","params":["newPendingTransactions"]}
< {"jsonrpc":"2.0","id":3,"result":"0x3"}
< {"jsonrpc":"2.0","method":"eth_subscription","params":{"subscription":"0x3","result":"0xabc123..."}}newPendingTransactions currently returns hashes only. Requests with
includeTransactions: true are rejected because full transaction objects are
not supported. Option objects may contain only includeTransactions; unknown
fields are rejected as invalid parameters.
Cancel an active subscription.
> {"jsonrpc":"2.0","id":4,"method":"eth_unsubscribe","params":["0x1"]}
< {"jsonrpc":"2.0","id":4,"result":true}Limits: Maximum 1024 global subscriptions, 16 per connection. Connections are auto-disconnected after repeated lag events.
Standard Ethereum-compatible JSON-RPC methods.
Returns the current block height.
Parameters: None
Returns: String — Hex-encoded block number.
curl -s http://localhost:8545 \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","method":"eth_blockNumber","params":[],"id":1}'{"jsonrpc":"2.0","id":1,"result":"0x1a"}Returns the chain ID.
Parameters: None
Returns: String — Hex-encoded chain ID.
curl -s http://localhost:8545 \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","method":"eth_chainId","params":[],"id":1}'{"jsonrpc":"2.0","id":1,"result":"0x539"}Returns sync status. A node may temporarily report syncing while block range catch-up is in flight; otherwise it returns false.
Parameters: None
Returns: Boolean | Object — false when not syncing, or a sync progress object when the node is catching up.
curl -s http://localhost:8545 \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","method":"eth_syncing","params":[],"id":1}'{"jsonrpc":"2.0","id":1,"result":false}Returns whether the node is producing blocks.
Parameters: None
Returns: Boolean — true if the node has a validator keystore loaded.
curl -s http://localhost:8545 \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","method":"eth_mining","params":[],"id":1}'{"jsonrpc":"2.0","id":1,"result":true}Returns mining hashrate. Always "0x0" (PoA consensus, no mining).
Parameters: None
Returns: String — Always "0x0".
Returns managed accounts. Always empty — the node does not hold user private keys.
Parameters: None
Returns: Array — Always [].
Returns the protocol version.
Parameters: None
Returns: String — "0x45" (Cancun-compatible).
Returns the current base fee.
Parameters: None
Returns: String — Hex-encoded base fee in wei for the latest chain state.
The exact value changes over time as blocks are produced.
curl -s http://localhost:8545 \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","method":"eth_gasPrice","params":[],"id":1}'{"jsonrpc":"2.0","id":1,"result":"0x5f7609"}Returns the suggested priority fee. Always "0x0" on this PoA chain.
Parameters: None
Returns: String — "0x0".
Returns historical base fee and gas usage data.
Parameters:
| # | Type | Required | Description |
|---|---|---|---|
| 1 | String |
Yes | Block count (hex) — 1 to 1024 |
| 2 | String |
Yes | Newest block (block tag or hex number) |
| 3 | Array<Number> |
No | Reward percentiles, 0 to 100 in non-decreasing order |
Returns: Object with oldestBlock, baseFeePerGas, gasUsedRatio, reward.
Unreleased node source computes reward as effective priority fees, sorted by
fee and weighted by actual receipt gas consumed. Fee caps limit the effective
tip; failed transactions still contribute their charged gas. Empty blocks or
zero-tip transactions yield zero rewards. Omitting percentiles or passing []
keeps reward: [].
Fee inputs remain available after body pruning for blocks stored by this implementation. Legacy intact bodies also remain queryable and preserve their fee inputs when subsequently pruned. Already-pruned legacy blocks with missing fee metadata cannot supply reward percentiles: the query returns an error, while queries without percentiles can still return header base fees and gas usage. Positive-tip percentile results on published node versions remain to be verified.
curl -s http://localhost:8545 \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","method":"eth_feeHistory","params":["0x5","latest",[]],"id":1}'{
"jsonrpc": "2.0",
"id": 1,
"result": {
"oldestBlock": "0x15",
"baseFeePerGas": ["0x8e4f6f","0x7c4681","0x6c1761","0x5f7609","0x53a8d3","0x48c470"],
"gasUsedRatio": [0.0, 0.0, 0.0, 0.0, 0.0],
"reward": []
}
}Unreleased node source supports eth_getBalance, eth_getTransactionCount,
eth_getCode, eth_getStorageAt, eth_call, and eth_createAccessList against
retained canonical state using "earliest", "safe", "finalized", or a numeric
block. Historical reads use the selected header's committed state root even
when the block body has been pruned. Missing blocks, retained state, or historical
contract bytecode return an error rather than current-state data or an empty
contract. Queries do not write chain state; simulations discard all writes.
"latest" and "pending" state reads retain their live-state behavior.
eth_getTransactionCount with "pending" also includes contiguous queued
transactions from the sender; historical nonce queries never include the pool.
"safe" and "finalized" select the finalized cursor, while "earliest" selects
genesis. Published binaries may still accept only "latest" and "pending";
verify the running version before using historical state reads.
From a source checkout, run the isolated HTTP snapshot regression and the signed execution, independent import, pruning and fresh-process recovery regression:
cargo test -p shell-rpc historical_state_reads_http -- --nocapture
cargo test -p shell-node --features rocksdb fee_history_rewards -- --nocaptureBlock, receipt, log, and fee-history methods keep their documented historical block support.
Returns the balance of an address.
Parameters:
| # | Type | Required | Description |
|---|---|---|---|
| 1 | String |
Yes | Address (0x... canonical) |
| 2 | String |
No | State block tag ("latest" or "pending" only) |
Returns: String — Hex-encoded balance in wei.
curl -s http://localhost:8545 \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","method":"eth_getBalance","params":["0xYOUR_ADDRESS_HERE","latest"],"id":1}'{"jsonrpc":"2.0","id":1,"result":"0x3635c9adc5dea00000"}Returns the nonce (transaction count) for an address.
Parameters:
| # | Type | Required | Description |
|---|---|---|---|
| 1 | String |
Yes | Address (0x... canonical) |
| 2 | String |
No | State block tag ("latest" or "pending" only) |
Returns: String — Hex-encoded nonce.
curl -s http://localhost:8545 \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","method":"eth_getTransactionCount","params":["0xYOUR_ADDRESS_HERE","latest"],"id":1}'{"jsonrpc":"2.0","id":1,"result":"0x0"}Returns a block by number.
Parameters:
| # | Type | Required | Description |
|---|---|---|---|
| 1 | String |
Yes | Block tag or hex number |
| 2 | Boolean |
Yes | true for full transaction objects, false for hashes only |
Supported block tags: "latest", "earliest", "pending", "safe", "finalized".
When "pending" is requested, a pseudo-block is constructed from the current mempool.
Returns: Object|null — Block object or null if not found.
curl -s http://localhost:8545 \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","method":"eth_getBlockByNumber","params":["latest",false],"id":1}'{
"jsonrpc": "2.0",
"id": 1,
"result": {
"number": "0x1a",
"hash": "0xabc...",
"parentHash": "0xdef...",
"timestamp": "0x65a5f200",
"gasLimit": "0x1c9c380",
"gasUsed": "0x0",
"compressionLayer": 1,
"pruningStatus": "pruned",
"transactions": []
}
}Shell block responses include STARK storage metadata in addition to Ethereum
compatibility fields. compressionLayer is the highest accepted compression
layer currently known for the block, including pointer blocks in a contiguous
range. pruningStatus reports the local witness state (unpruned,
compressedWitnessRetained, pruned, notWitnessed, pending, or unknown).
STARK proof bytes are no longer carried in block header extraData; canonical
settlements use a StarkReward system transaction whose input contains the
proof payload, while source blocks expose full-proof or pointer metadata.
Returns a block by hash.
Parameters:
| # | Type | Required | Description |
|---|---|---|---|
| 1 | String |
Yes | Block hash (0x-prefixed, 32 bytes) |
| 2 | Boolean |
Yes | true for full tx objects, false for hashes |
Returns: Object|null — Block object or null.
Returns a transaction by hash. Checks the mempool first, then on-chain storage. Shell reward records are first-class system transactions, so block gas rewards and STARK rewards are also discoverable by deterministic transaction hash.
Parameters:
| # | Type | Required | Description |
|---|---|---|---|
| 1 | String |
Yes | Transaction hash (0x-prefixed, 32 bytes) |
Returns: Object|null — Transaction object or null.
Shell-specific transaction metadata:
| Field | Description |
|---|---|
shellType |
Product-readable type: transfer, contractCreate, contractCall, aaBatch, blockGasReward, or starkReward |
rewardKind |
Present for reward system transactions: blockGasReward or starkReward |
rewardLayer |
STARK layer for prover rewards, hex encoded |
rewardSourceHash |
Parent block, source range, or artifact hash used to derive the reward |
originalSize / compressedSize |
STARK compression accounting, hex byte counts |
curl -s http://localhost:8545 \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","method":"eth_getTransactionByHash","params":["0xabc123..."],"id":1}'Returns the receipt of a mined transaction.
Parameters:
| # | Type | Required | Description |
|---|---|---|---|
| 1 | String |
Yes | Transaction hash |
Returns: Object|null — Receipt object (includes status, gasUsed, logs, blockNumber, shellType, rewardKind, etc.) or null if not yet mined.
Submits a signed transaction. Accepts RLP-encoded or JSON-encoded transaction bytes.
Parameters:
| # | Type | Required | Description |
|---|---|---|---|
| 1 | String |
Yes | Hex-encoded signed transaction data |
Returns: String — Transaction hash.
Validation: The transaction's max_fee_per_gas must be ≥ the current base fee.
curl -s http://localhost:8545 \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","method":"eth_sendRawTransaction","params":["0x...signed_tx_bytes..."],"id":1}'{"jsonrpc":"2.0","id":1,"result":"0xabc123..."}Executes a read-only call against the EVM (no state changes).
Parameters:
| # | Type | Required | Description |
|---|---|---|---|
| 1 | Object |
Yes | Call request: {from?, to, data?, value?, gas?} |
| 2 | String |
No | State block tag; historical calls require the unreleased source and retained canonical state described above |
Returns: String — Hex-encoded return data.
curl -s http://localhost:8545 \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","method":"eth_call","params":[{"to":"0xCONTRACT_ADDRESS","data":"0x..."},"latest"],"id":1}'Estimates gas for a transaction. Returns gas_used × 1.2 with a minimum of 21,000.
Parameters:
| # | Type | Required | Description |
|---|---|---|---|
| 1 | Object |
Yes | Call request: {from?, to?, data?, value?} |
Returns: String — Hex-encoded gas estimate.
curl -s http://localhost:8545 \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","method":"eth_estimateGas","params":[{"to":"0xRECIPIENT_ADDRESS","value":"0xde0b6b3a7640000"}],"id":1}'{"jsonrpc":"2.0","id":1,"result":"0x5208"}Creates an EIP-2930 access list for a transaction.
Parameters:
| # | Type | Required | Description |
|---|---|---|---|
| 1 | Object |
Yes | Call request |
| 2 | String |
No | Block tag or canonical hex block number (retained state required) |
Returns: Object with accessList and gasUsed.
Unreleased node source discovers accessed accounts and storage keys by executing
on isolated state. Supplied entries are merged and deduplicated; accesses in
reverted child calls are retained. gasUsed reflects execution with the final
returned list, including its intrinsic gas. Discovery passes use one captured
header and state root; historical queries require retained canonical state and
never substitute current state. Existing execution-profile restrictions apply.
Generated lists are bounded by transaction limits: 256 addresses and 512 keys per address. A call that exceeds these limits or does not converge within eight simulations returns an error. Published node versions must be verified before relying on discovery or historical support.
From a source checkout, run the self-contained acceptance regression:
cargo test -p shell-rpc create_access_list -- --nocaptureThe regression uses temporary contracts and checks real HTTP history, returned list usability, gas-dependent discovery, reverted child accesses and state isolation. It does not enable the development execution profile on a network.
Returns the bytecode at an address.
Parameters:
| # | Type | Required | Description |
|---|---|---|---|
| 1 | String |
Yes | Address |
| 2 | String |
No | State block tag ("latest" or "pending" only) |
Returns: String — Hex-encoded bytecode, or "0x" for accounts without
runtime code.
Returns a storage slot value.
Parameters:
| # | Type | Required | Description |
|---|---|---|---|
| 1 | String |
Yes | Address |
| 2 | String |
Yes | Storage position (hex-encoded, 32-byte key) |
| 3 | String |
No | State block tag ("latest" or "pending" only) |
Returns: String — Zero-padded 32-byte hex value.
Returns logs matching a filter.
Parameters:
| # | Type | Required | Description |
|---|---|---|---|
| 1 | Object |
Yes | Filter: {address?, topics?, fromBlock?, toBlock?}. Addresses use the canonical 0x-prefixed 64-hex-character Shell address form; topics can contain at most four positional entries. Topic entries are null, a 0x-prefixed 32-byte hash, or an array of 0x-prefixed 32-byte hashes. null is a positional wildcard; an empty alternatives array ([]) matches no logs at that position. |
Unsupported filter fields are rejected as invalid parameters rather than ignored.
Returns: Array — Log objects with address, topics, data, blockNumber, blockHash, transactionHash, transactionIndex, logIndex, removed.
Uses bloom filters for fast block-level filtering. The block range is capped at MAX_BLOCK_RANGE to prevent DoS.
curl -s http://localhost:8545 \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","method":"eth_getLogs","params":[{"fromBlock":"0x0","toBlock":"latest"}],"id":1}'Creates a poll-based log filter.
Parameters:
| # | Type | Required | Description |
|---|---|---|---|
| 1 | Object |
Yes | Filter: {address?, topics?, fromBlock?, toBlock?}. Addresses use the canonical 0x-prefixed 64-hex-character Shell address form; topics can contain at most four positional entries. Topic entries are null, a 0x-prefixed 32-byte hash, or an array of 0x-prefixed 32-byte hashes. null is a positional wildcard; an empty alternatives array ([]) matches no logs at that position. |
Unsupported filter fields are rejected as invalid parameters rather than ignored.
Returns: String — Filter ID.
Creates a poll-based block filter.
Parameters: None
Returns: String — Filter ID.
Returns changes since last poll for a filter. If the canonical chain is
reorganized, log filters first return matching orphaned logs with
removed: true, followed by matching logs from the replacement chain. Block
filters return the canonical replacement block hashes.
Parameters:
| # | Type | Required | Description |
|---|---|---|---|
| 1 | String |
Yes | Filter ID |
Returns: Array — Logs (for log filters) or block hashes (for block
filters). Logs from orphaned blocks have removed: true.
Re-queries all logs matching a filter's criteria.
Parameters:
| # | Type | Required | Description |
|---|---|---|---|
| 1 | String |
Yes | Filter ID |
Returns: Array — Log objects.
Removes a filter.
Parameters:
| # | Type | Required | Description |
|---|---|---|---|
| 1 | String |
Yes | Filter ID |
Returns: Boolean — true if the filter was removed.
Returns the current blob gas price (EIP-4844).
Parameters: None
Returns: String — Hex-encoded blob gas price, calculated from excess_blob_gas.
Returns error code -32601. The node does not hold private keys — sign transactions client-side with the CLI or SDK.
Returns error code -32601. Same reason as eth_sign.
Returns []. This legacy Ethereum method is retained for compatibility.
Returns the network/chain ID as a decimal string.
Parameters: None
Returns: String — Chain ID (e.g., "1337").
curl -s http://localhost:8545 \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","method":"net_version","params":[],"id":1}'{"jsonrpc":"2.0","id":1,"result":"1337"}Returns whether the node is accepting connections. Always true.
Parameters: None
Returns: Boolean — true.
Returns the number of connected peers.
Parameters: None
Returns: String — Hex-encoded peer count (e.g., "0x3").
curl -s http://localhost:8545 \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","method":"net_peerCount","params":[],"id":1}'Returns the client identifier string.
Parameters: None
Returns: String — "shell-chain/0.27.4".
curl -s http://localhost:8545 \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","method":"web3_clientVersion","params":[],"id":1}'{"jsonrpc":"2.0","id":1,"result":"shell-chain/0.27.4"}Returns the Keccak-256 hash of the given data.
Parameters:
| # | Type | Required | Description |
|---|---|---|---|
| 1 | String |
Yes | Hex-encoded data (max 32 KB) |
Returns: String — Hex-encoded Keccak-256 hash.
curl -s http://localhost:8545 \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","method":"web3_sha3","params":["0x68656c6c6f"],"id":1}'{"jsonrpc":"2.0","id":1,"result":"0x1c8aff950685c2ed4bc3174f3472287b56d9517b9c948127319a09a7a36deac8"}Shell-chain custom extensions for post-quantum features, validator governance, and node information.
Returns the post-quantum public key associated with an address.
Parameters:
| # | Type | Required | Description |
|---|---|---|---|
| 1 | String |
Yes | Address (0x... canonical) |
Returns: String|null — Hex-encoded PQ public key, or null if not found.
curl -s http://localhost:8545 \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","method":"shell_getPqPubkey","params":["0xYOUR_ADDRESS_HERE"],"id":1}'Returns the number of pending transactions in the mempool.
Parameters: None
Returns: String — Hex-encoded count.
curl -s http://localhost:8545 \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","method":"shell_pendingCount","params":[],"id":1}'{"jsonrpc":"2.0","id":1,"result":"0x0"}Submits a pre-signed shell-chain transaction.
Parameters:
| # | Type | Required | Description |
|---|---|---|---|
| 1 | Object |
Yes | Signed transaction object |
Returns: String — Transaction hash.
Returns the current validator set.
Parameters: None
Returns: Array<String> — List of validator addresses.
curl -s http://localhost:8545 \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","method":"shell_getValidators","params":[],"id":1}'{
"jsonrpc": "2.0",
"id": 1,
"result": [
"0x0000000000000000000000000000000000000000000000000000000000000001",
"0x0000000000000000000000000000000000000000000000000000000000000002"
]
}Returns whether an address is a validator.
Parameters:
| # | Type | Required | Description |
|---|---|---|---|
| 1 | String |
Yes | Address |
Returns: Object:
{
"address": "0x...",
"isValidator": true
}Submits a governance transaction to add a validator (requires the node to have a proposer keystore).
On non-loopback RPC listeners, this signer-backed method is registered only
when --rpc-api-key is configured.
Parameters:
| # | Type | Required | Description |
|---|---|---|---|
| 1 | String |
Yes | Address to add |
Returns: String — Transaction hash.
Submits a governance transaction to remove a validator.
On non-loopback RPC listeners, this signer-backed method is registered only
when --rpc-api-key is configured.
Parameters:
| # | Type | Required | Description |
|---|---|---|---|
| 1 | String |
Yes | Address to remove |
Returns: String — Transaction hash.
Generates calldata for the validator management system contract (does not submit a transaction).
Parameters:
| # | Type | Required | Description |
|---|---|---|---|
| 1 | String |
Yes | Address to add |
Returns: String — Hex-encoded calldata.
Generates calldata for validator removal.
Parameters:
| # | Type | Required | Description |
|---|---|---|---|
| 1 | String |
Yes | Address to remove |
Returns: String — Hex-encoded calldata.
Estimates gas for a governance operation.
Parameters:
| # | Type | Required | Description |
|---|---|---|---|
| 1 | String |
Yes | Operation: "addValidator", "removeValidator", "getValidators", or "isValidator" |
Returns: String — Hex-encoded gas estimate.
Returns governance configuration.
Parameters: None
Returns:
{
"validatorCount": 3,
"validators": ["0x...", "0x...", "0x..."],
"systemContractAddress": "0x0000000000000000000000000000000000000001",
"proposalGasLimit": 100000
}Returns node status information.
Parameters: None
Returns:
{
"version": "ShellChain/v0.27.4/rust",
"chainId": 1337,
"blockHeight": 42,
"peerCount": 0,
"txPoolSize": 5,
"isMining": true,
"uptime": 3600,
"baseFee": "0x5f7609"
}curl -s http://localhost:8545 \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","method":"shell_getNodeInfo","params":[],"id":1}'Returns live P2P network statistics. peerCount uses the same connected-peer
counter as net_peerCount. listeningAddress is an actual bound multiaddr:
when several listeners are available, the first address in sorted order is
returned. A configured port of zero is replaced by the assigned port. This
local address does not establish reachability from another network.
protocols lists enabled gossipsub, Kademlia and mDNS behaviours; disabled
behaviours are omitted.
Parameters: None
Example result (address, peer count and protocols depend on the running node):
{
"peerCount": 1,
"protocolVersion": "shell/1.0.0",
"listeningAddress": "/ip4/127.0.0.1/tcp/40123",
"protocols": ["gossipsub", "kademlia"]
}No bound listener yields an empty listeningAddress. With P2P disabled or its
transport stopped, protocols is empty as well. Local transport metadata is
rebuilt on startup rather than persisted; shell_getNodeInfo.peer_id and
admin_nodeInfo.id read the same live identity.
Version: This correction is in unreleased node source. Older binaries may return the fixed default address and protocol list; verify the installed version before using this response to diagnose connectivity.
Local acceptance: From the node repository, build with the libp2p feature and run the existing Python 3 regression (standard library only):
cargo build -p shell-cli --features libp2p
python3 tests/e2e/operator-p2p-monitoring.py --network-statsThe script creates fresh test keys and isolated RocksDB nodes, connects a follower to a 16-block backlog, compares canonical block hashes and live RPC listeners, then restarts the follower with P2P enabled and disabled. Results and isolated data are retained at the printed temporary directory. This checks local connectivity and restart behaviour; the default script mode separately checks transient catch-up monitoring.
Returns aggregate chain statistics. totalTransactions and gasUsedTotal
cover the canonical chain from block 0 through the current head; avgBlockTime
is computed from the most recent block-time window.
Parameters: None
Returns:
{
"blockHeight": 1500,
"totalTransactions": 3200,
"avgBlockTime": 2.01,
"gasUsedTotal": "0x...",
"latestBaseFee": "0x5f7609"
}Returns finality status for the connected node.
Parameters: None
Returns:
{
"currentHead": "0x1a",
"finalityLag": 2,
"lastFinalizedBlock": "0x18",
"lastFinalizedHash": "0xabc...",
"pendingAttestations": 2
}Returns a wrapper object for a finalized block hash. The certificate field
maps validator addresses to post-quantum signatures and is null when the
local node has no certificate for the requested hash.
Parameters:
| # | Type | Required | Description |
|---|---|---|---|
| 1 | String |
Yes | Block hash |
Returns:
{
"blockHash": "0xabc...",
"certificate": {
"0x...": {
"sig_type": "Dilithium3",
"data": [1, 2, 3]
}
}
}Returns the post-quantum signature details for validators who signed a specific block.
Unreleased node source implements this method using authenticated proposer and
quorum signing evidence. It retains the signing public keys and signatures
separately from the header, so block hashes and consensus messages are unchanged.
Retained evidence remains queryable after body pruning and changes to the live
key lookup. signatureValid checks the actual signature against the captured
block hash and the native signer identity; it reports historical cryptographic
validity, independent of whether that algorithm may accept new transactions now.
Legacy intact blocks and certificates remain queryable when the matching identity-bound key is available. Missing historical keys or proposer evidence return an error; current rotated keys are never substituted. Genesis without signatures returns an empty signer list. Invalid block tags and missing blocks are rejected. The query does not change chain state. Published node versions must be verified before relying on this method.
From a source checkout, run the self-contained production, import, HTTP, pruning and fresh-process recovery regression:
cargo test -p shell-node --features rocksdb block_signers -- --nocaptureParameters:
| # | Type | Required | Description |
|---|---|---|---|
| 1 | String |
Yes | Block number (hex) or block tag |
Tags select stored canonical headers: latest and pending use the current
head, safe and finalized use the finalized cursor, and earliest selects
genesis. The method does not fabricate signatures for an unsealed candidate.
Returns:
{
"blockNumber": "0x1a",
"signers": [
{
"address": "0x<64 lowercase hex>",
"pqPubkey": "0x...",
"signatureValid": true
}
]
}curl -s http://localhost:8545 -H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","method":"shell_getBlockSigners","params":["latest"],"id":1}'Verifies an ML-DSA-65 post-quantum signature against a message and public key. Unreleased node source also preserves the legacy Dilithium3 verification promise using the existing core verifier. This three-parameter query accepts raw signature and key bytes and reports cryptographic validity; it does not determine a native account identity or authorize a transaction. Algorithm registry rules, signing domains and account permissions are unchanged.
All three values must be 0x-prefixed, whole-byte hexadecimal strings. 0x is a
valid empty message. Malformed hex returns -32602; invalid keys, unsupported raw
formats, incorrect signature lengths and cryptographic mismatches return false.
The query does not write chain state and follows the configured shell namespace
exposure. The server's existing request-body limits apply. Published node versions
must be verified before relying on this method.
From a source checkout, run the self-contained real-key HTTP regression. On Unix
platforms it also runs the example below, using curl and a POSIX shell with
temporary keys held in memory:
cargo test -p shell-rpc verify_pq_signature -- --nocaptureParameters:
| # | Type | Required | Description |
|---|---|---|---|
| 1 | String |
Yes | Hex-encoded message |
| 2 | String |
Yes | Hex-encoded ML-DSA-65 or legacy Dilithium3 signature |
| 3 | String |
Yes | Hex-encoded public key |
Returns: Boolean — true if the signature is valid.
# Set SIGNATURE_HEX and PUBKEY_HEX to the actual 0x-prefixed raw signature
# and public key for the message "hello" (0x68656c6c6f).
curl -s http://localhost:8545 \
-H "Content-Type: application/json" \
-d "{\"jsonrpc\":\"2.0\",\"method\":\"shell_verifyPqSignature\",\"params\":[\"0x68656c6c6f\",\"$SIGNATURE_HEX\",\"$PUBKEY_HEX\"],\"id\":1}"Returns information about the current consensus epoch.
Unreleased node source reads the canonical head and configured consensus engine.
currentEpoch refers to the head's epoch, rather than the next proposer slot.
For a positive epochLength, blocksInEpoch is the head's zero-based block
offset within that epoch. With length zero, epochs are disabled: currentEpoch
is zero and blocksInEpoch is the head height. activeValidators counts the
engine's active authorities, which can differ from pending head Registry changes.
currentBlockTime is the mean timestamp interval over up to ten canonical
intervals ending at the head, or zero at genesis. Missing engine, head or required
canonical history returns an error. The query needs retained headers, not block
bodies, and does not write state. Published node versions must be checked before
relying on this method.
From a node source checkout, run the isolated HTTP regression and the existing signed execution/import fixture, which also checks this query after body pruning and an abrupt child-process exit followed by RocksDB recovery:
cargo test -p shell-rpc epoch_info -- --nocapture
cargo test -p shell-node --features rocksdb fee_history_rewards -- --nocaptureThe isolated regression covers genesis, length-five boundaries, continuous
epochs, active-engine counts, invalid context and unchanged state. On Unix it
also runs the curl example below and requires curl and a POSIX shell. The
recovery fixture uses real legacy Dilithium3 signed transactions and continuous
epochs; it does not prove every algorithm, nonzero-epoch recovery, network
reorganization or machine power-loss combination.
For nonzero epochs with pending Registry changes, the existing two-node
acceptance also checks this query before and after follower restarts. It uses
real ML-DSA-65 signed weight, addition and removal transactions, length-five
boundaries and restarts at heights 7, 12, 17 and 21. Both nodes must report the
canonical epoch and active member count, even when the head Registry already
contains a pending addition or removal; repeated queries must preserve state.
The final restarted follower also runs the curl example below. Follow the
epoch acceptance prerequisites in docs/CONSENSUS_DETAILS.md,
including Node.js 20 or later, curl, a POSIX shell and a compatible built source
SDK (0.14.0-rc.1 tested):
cargo build -p shell-cli --features libp2p
SHELL_SDK_ENTRY=/path/to/shell-sdk/dist/index.js \
node tests/e2e/native-aa-registry.mjs --epoch-restartFor a follower with actual rolling state and body pruning, run the same acceptance with:
SHELL_SDK_ENTRY=/path/to/shell-sdk/dist/index.js \
node tests/e2e/native-aa-registry.mjs --epoch-pruned-restartThis variant retains all data on the producer and uses a light follower with one-block state/body retention. It checks that expired bodies remain absent, including after the final restart at an idle head, while the last finalized epoch snapshot still supplies its historical nonce and active authorities. Expired historical state must return an error rather than current values. The shortened window proves this isolated case, not the default retention window or public package availability.
This case uses one producer retaining quorum weight and graceful follower restarts with unchanged genesis. It does not establish multi-authority availability, network reorganization, machine power-loss recovery or public SDK/binary delivery.
Parameters: None
Returns:
{
"currentEpoch": 0,
"epochLength": 0,
"blocksInEpoch": 1500,
"currentBlockTime": 2.01,
"activeValidators": 3
}curl -s http://localhost:8545 -H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","method":"shell_getEpochInfo","params":[],"id":1}'Returns voting activity statistics for validators in recent blocks.
Parameters: None
Returns:
{
"validators": [
{
"address": "0x...",
"blocksProduced": 500,
"lastBlockProduced": "0x1a",
"uptime": 99.8
}
]
}Returns pending governance proposals that have not yet been finalized.
Parameters: None
Returns:
{
"proposals": [
{
"type": "addValidator",
"target": "0x...",
"proposer": "0x...",
"proposedAt": "0x18",
"status": "pending"
}
]
}These methods return error -32601. Direct validator set mutation is disabled to prevent split-brain issues. Use shell_proposeAddValidator and shell_proposeRemoveValidator instead, which go through the governance transaction flow.
Returns the total number of transactions stored across all blocks (chain-wide counter, not per-address nonce).
Parameters: none
Response: "0x<hex>" — total transaction count as a hex string.
curl -s http://localhost:8545 -H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","method":"shell_transactionCount","params":[],"id":1}'
# → {"result":"0x1a4f"}Returns transactions sent from or received by an address. Supports pagination
and inclusive block-range filters. There is no artificial deep-offset cap; under
live load, clients should pin toBlock from the first page and reuse it for
older pages to avoid gaps or duplicates while new blocks arrive.
Unreleased node source accepts legacy offsets above 10,000 and exact totals over
ranges spanning more than 10,000 blocks, including the default 0 through latest
range. Pages past the exact range total return an empty transactions list while
retaining pagination metadata. Overflowing page * limit remains invalid. Counts
and pages use the existing retained address index without query writes or an index
migration. The v2 address-history and address-summary methods use the same exact
counter when includeTotal is enabled. Published node versions must be checked
before relying on these corrections.
From a node source checkout, run the real stored-index HTTP regression and the
native storage regressions. They cover sender and recipient history, deep ordering,
wide default ranges, empty pages, shared exact totals, unchanged chain state, and
forward-only index reads after RocksDB reopen. On Unix, the HTTP regression also executes the
curl example below and requires curl and a POSIX shell. These regressions do
not run block production or transaction admission:
cargo test -p shell-rpc address_history_deep_pages_http -- --nocapture
cargo test -p shell-storage --features rocksdb address_history -- --nocaptureParameters:
| Name | Type | Description |
|---|---|---|
address |
string | 0x... address |
fromBlock |
number | null | Start block (inclusive, default 0) |
toBlock |
number | null | End block (inclusive, default latest) |
page |
number | null | Page index, 0-based (default 0) |
limit |
number | null | Results per page (default 20) |
Response: paginated object:
| Field | Type | Description |
|---|---|---|
address |
string | Queried 0x... address |
fromBlock |
string | Effective inclusive lower block bound, hex encoded |
toBlock |
string | Effective inclusive upper block snapshot, hex encoded |
page |
number | Page index, 0-based |
limit |
number | Page size |
total |
number | Total matches in the requested range |
transactions |
array | Transaction summaries, including shellType/reward metadata when present |
curl -s http://localhost:8545 -H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","method":"shell_getTransactionsByAddress","params":["0x0000000000000000000000000000000000000000000000000000000000000000",0,null,0,20],"id":1}'Returns the PQ witness bundle for a block — the individual Dilithium3 signatures stored separately from TX bodies. Returns null when witnesses have been pruned (STARK proof received) or the block predates B3 storage.
Parameters:
| Name | Type | Description |
|---|---|---|
block |
string | Block hash (0x...) or block number ("0x<hex>" / "latest") |
Response fields:
| Field | Type | Description |
|---|---|---|
blockHash |
string | Block hash |
witnessRoot |
string | witness_root from block header |
witnessCount |
number | Number of witnesses in bundle |
witnesses |
array | [{ txIndex, sigType, signature, pubkey? }, ...] |
Returns null when no witness bundle is stored (pruned or not applicable).
curl -s http://localhost:8545 -H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","method":"shell_getBlockWitnesses","params":["latest"],"id":1}'Directly sets the balance of an address. Only available when api_modules includes dev. Returns -32601 on production nodes.
Parameters:
| Name | Type | Description |
|---|---|---|
address |
string | Target 0x... address |
balance |
string | New balance in wei as decimal string |
Response: true on success.
curl -s http://localhost:8545 -H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","method":"shell_setBalance","params":["0xabc...","1000000000000000000"],"id":1}'Note: The
debugnamespace must be explicitly enabled via--rpc-api eth,net,web3,shell,debug. It is not enabled by default on validator nodes.
Replays a transaction and returns an execution trace.
Parameters:
| # | Type | Required | Description |
|---|---|---|---|
| 1 | String |
Yes | Transaction hash |
| 2 | Object |
No | Trace options. Only tracer: "callTracer" is supported; unknown options are rejected. |
Returns:
{
"frame": {
"type": "CALL",
"from": "0x...",
"to": "0x...",
"gas": 21000,
"gasUsed": 21000,
"input": "0x",
"output": "0x",
"value": "0xde0b6b3a7640000",
"error": null
},
"failed": false
}curl -s http://localhost:8545 \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","method":"debug_traceTransaction","params":["0xabc123..."],"id":1}'Traces all transactions in a block.
Parameters:
| # | Type | Required | Description |
|---|---|---|---|
| 1 | String |
Yes | Block number (hex) or block tag |
| 2 | Object |
No | Trace options. Only tracer: "callTracer" is supported; unknown options are rejected. |
Returns: Array — Array of trace result objects (one per transaction).
curl -s http://localhost:8545 \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","method":"debug_traceBlockByNumber","params":["0x1a"],"id":1}'OpenEthereum-shaped call and creation traces from isolated historical execution.
trace_transaction and its trace_oeTransaction alias return the root and nested
frames in depth-first order. traceAddress identifies each frame; subtraces
counts its immediate children. Calls include actual return data; creations use
action.init and result.code/result.address. Failed frames contain error
and omit result. AA bundles use a root call with callType: "batch" and their
executed calls as children; this is a Shell-specific extension.
Replay requires retained parent state and matching receipts. AccountManager
rotateKey and clearValidationCode are replayable and return actual native
output and gas without opcode logs. Guardian, recovery and validation-code
changes also support replay, including earlier transactions in the same block,
using a consistent metadata snapshot and the original parent height. These
methods require history within the latest 128 blocks, retained undo journals,
and a native metadata snapshot no larger than 64 MiB. Upgrades do not restore
already-pruned journals. ValidatorRegistry governance calls use the same native
history bounds. Replay uses historical validator/public-key state and parent
height; algorithm changes stay in the worker's private registry.
Missing history and capture/response limits return an RPC error instead of a
receipt-derived approximation. PQVM removes SELFDESTRUCT and CALLCODE, so they
do not produce successful externality events. The same capture and concurrency
bounds as debug_ apply.
Note: Like
debug, thetracenamespace must be explicitly enabled via--rpc-api.
Returns traces for all transactions in a block.
Parameters:
| # | Type | Required | Description |
|---|---|---|---|
| 1 | String |
Yes | Block number (hex) or block tag |
Returns: Array — OpenEthereum-format trace objects.
curl -s http://localhost:8545 \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","method":"trace_block","params":["latest"],"id":1}'Alias for trace_transaction, with the same parameters and executed frame list.
Parameters:
| # | Type | Required | Description |
|---|---|---|---|
| 1 | String |
Yes | Transaction hash |
Returns: Array — Root and nested call/creation traces for the transaction.
curl -s http://localhost:8545 \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","method":"trace_oeTransaction","params":["0xabc123..."],"id":1}'Returns the trace for a specific transaction in standard format.
Parameters:
| # | Type | Required | Description |
|---|---|---|---|
| 1 | String |
Yes | Transaction hash |
Returns: Array — Trace objects for the transaction.
curl -s http://localhost:8545 \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","method":"trace_transaction","params":["0xabc123..."],"id":1}'Returns the live algorithm registry as an array of objects: { algo, status, description }.
Status is active, deprecated, or pending_activation. At startup, the node
restores this registry from the recovered canonical world state before starting
RPC and transaction admission. Restarting does not activate pending algorithms,
reset deprecated entries, or change saved proposal heights and verifier hashes.
Malformed persisted registry state prevents startup instead of falling back to
the compile-time active allowlist. Chains without governance entries retain the
initial allowlist.
Parameters: None
Returns: Array — one entry per registered signature algorithm.
[
{
"algo": "MlDsa65",
"description": "FIPS 204 ML-DSA-65 (NIST post-quantum standard; primary algorithm)",
"status": "active"
},
{
"algo": "Dilithium3",
"description": "CRYSTALS-Dilithium3 (Round-3 pre-FIPS; active for legacy compatibility)",
"status": "active"
}
]Returns the STARK proof amendment for a block if one has been generated asynchronously. See stark-aggregation.md for the full response schema.
Parameters:
| # | Type | Required | Description |
|---|---|---|---|
| 1 | String |
Yes | Block hash (0x...) |
Returns: Object|null — Proof amendment object or null if not yet generated.
Estimates gas for an AA batch transaction.
Parameters:
| # | Type | Required | Description |
|---|---|---|---|
| 1 | Object |
Yes | Batch transaction object |
Returns: String — Hex-encoded gas estimate.
Returns the paymaster policy for a given paymaster address.
Parameters:
| # | Type | Required | Description |
|---|---|---|---|
| 1 | String |
Yes | Paymaster address (0x..., 32 bytes) |
Returns: Object|null — Policy object or null if no policy registered.
Returns whether a transaction would be sponsored by a paymaster.
Parameters:
| # | Type | Required | Description |
|---|---|---|---|
| 1 | Object |
Yes | Transaction object |
Returns: Boolean — true if the transaction would be sponsored.
Returns current consensus engine state.
Parameters: None
Returns:
{
"engine": "wpoa",
"currentProposer": "0x...",
"epochNumber": 5,
"validatorCount": 3,
"finalizedHeight": "0x18"
}For the canonical method list (currently 79 methods across web3_, net_, eth_, debug_, trace_, evm_, shell_ namespaces), see docs/rpc-reference.md, which is auto-generated from crates/rpc/src/api.rs.
Last updated: 2026-06-17