Skip to content

Commit 26ab53f

Browse files
authored
feat(openrpc): curated description overrides for params, types, and results (#145)
* feat(openrpc): curated description overrides for params, types, and results Adds three JSON override files under docs/openrpc/ that let humans curate JSON-RPC descriptions on top of the auto-generated `"Go type: ..."` fallbacks the openrpcgen tool produces: - param_overrides.json: per (method, param-name) descriptions; 115 entries covering every previously-ugly top-level param across debug_*, eth_*, miner_*, personal_*, txpool_*, web3_* namespaces. - type_overrides.json: per (Go type, field) descriptions applied at every struct expansion site; seeded with types.TraceConfig (11 fields) and types.ChainConfig (24 fields). Type-keying deduplicates across all methods that consume the same struct. - result_overrides.json: per-method result descriptions; 83 entries with Lumera-specific context (chain ID, no-uncles post-merge, miner_* are no-ops on CometBFT, etc.). Mechanism: each override file is loaded once at generation time and applied as the highest-precedence layer, after AST source comments and existing type-based Go overrides. Missing entries fall through to the prior behavior, so adoption is incremental. Also moves the existing examples_overrides.json into docs/openrpc/ for co-location and drops the redundant `openrpc_` filename prefix now that the directory conveys it. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * chore(docs): remove outdated Lumera_Cosmos_EVM_Integration.pdf The Markdown sources under docs/evm-integration/ are now the canonical reference; the standalone PDF was a stale snapshot. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix(openrpc): preserve type override descriptions * chore(openrpc): address PR review feedback - Makefile: include all tools/openrpcgen/*.go (minus _test.go) in OPENRPC_GENERATOR_INPUTS so edits to schema.go / param_overrides.go / type_overrides.go invalidate the generated spec target. - docs/evm-integration/architecture/app-changes.md: add the result_overrides.json input to the OpenRPC files list. - tools/openrpcgen: add precedence tests covering param and result external JSON overrides (description / schema / required).
1 parent c48449e commit 26ab53f

15 files changed

Lines changed: 1424 additions & 427 deletions

Makefile

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -118,15 +118,18 @@ build-openapi:
118118
${GO} run ./tools/openapigen -config tools/openapigen/config.toml -out docs/static/openapi.yml
119119

120120
OPENRPC_GENERATOR_INPUTS := \
121-
tools/openrpcgen/main.go \
122-
docs/openrpc_examples_overrides.json
121+
$(filter-out %_test.go,$(wildcard tools/openrpcgen/*.go)) \
122+
docs/openrpc/examples_overrides.json \
123+
docs/openrpc/param_overrides.json \
124+
docs/openrpc/type_overrides.json \
125+
docs/openrpc/result_overrides.json
123126

124127
app/openrpc/openrpc.json.gz docs/openrpc.json: $(OPENRPC_GENERATOR_INPUTS)
125128
@echo "Generating OpenRPC spec..."
126129
@# Create a placeholder .gz so the //go:embed directive in spec.go is
127130
@# satisfied during compilation of the generator (same Go module).
128131
@test -f app/openrpc/openrpc.json.gz || echo '{}' | gzip > app/openrpc/openrpc.json.gz
129-
${GO} run ./tools/openrpcgen -out docs/openrpc.json -examples docs/openrpc_examples_overrides.json
132+
${GO} run ./tools/openrpcgen -out docs/openrpc.json -examples docs/openrpc/examples_overrides.json -params docs/openrpc/param_overrides.json -types docs/openrpc/type_overrides.json -results docs/openrpc/result_overrides.json
130133
gzip -c docs/openrpc.json > app/openrpc/openrpc.json.gz
131134
@echo "OpenRPC spec written to docs/openrpc.json (embedded as app/openrpc/openrpc.json.gz)"
132135

app/openrpc/openrpc.json.gz

8.96 KB
Binary file not shown.
-9.48 MB
Binary file not shown.

docs/evm-integration/architecture/app-changes.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -326,7 +326,10 @@ Files:
326326
- `app/openrpc/http.go`
327327
- `app/app.go`
328328
- `tools/openrpcgen/main.go`
329-
- `docs/openrpc_examples_overrides.json`
329+
- `docs/openrpc/examples_overrides.json`
330+
- `docs/openrpc/param_overrides.json`
331+
- `docs/openrpc/type_overrides.json`
332+
- `docs/openrpc/result_overrides.json`
330333
- `Makefile`
331334

332335
Changes:

docs/evm-integration/testing/tests/unit-openrpc.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ Primary files:
2020
| `TestServeHTTPCORSBlockedOrigin` | Verifies unlisted origin gets no `Access-Control-Allow-Origin` header. |
2121
| `TestServeHTTPCORSNoOriginHeader` | Verifies non-browser requests (no Origin) are allowed through. |
2222
| `TestServeHTTPCORSWildcardInList` | Verifies `*` in origins list allows all origins. |
23-
| `TestCollectMethodsPrefersOverrideExamples` | Verifies generator prefers curated overrides from `docs/openrpc_examples_overrides.json`. |
23+
| `TestCollectMethodsPrefersOverrideExamples` | Verifies generator prefers curated overrides from `docs/openrpc/examples_overrides.json`. |
2424
| `TestAlignExampleParamNamesRemapsIndexedArgs` | Verifies generator remaps generic `argN` names to human-readable parameter names. |
2525
| `TestExampleObjectSerializesNullValue` | Verifies generator keeps explicit `result.value: null` instead of dropping the field. |
2626
| `TestCollectMethodsExamplesAlwaysIncludeParamsField` | Verifies generator always emits `params` in examples (empty array when method has no parameters). |

docs/openrpc.json

Lines changed: 409 additions & 409 deletions
Large diffs are not rendered by default.

docs/openrpc/param_overrides.json

Lines changed: 270 additions & 0 deletions
Large diffs are not rendered by default.

docs/openrpc/result_overrides.json

Lines changed: 257 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,257 @@
1+
{
2+
"debug_gcStats": {
3+
"description": "Go runtime garbage-collector statistics: last/2nd-last GC times, total pause durations, pause histogram, and pause-end timestamps."
4+
},
5+
"debug_getBlockRlp": {
6+
"description": "RLP-encoded bytes of the requested block (hex)."
7+
},
8+
"debug_getHeaderRlp": {
9+
"description": "RLP-encoded bytes of the requested header (hex)."
10+
},
11+
"debug_getRawBlock": {
12+
"description": "RLP-encoded bytes of the requested block (hex). Equivalent to `debug_getBlockRlp`."
13+
},
14+
"debug_intermediateRoots": {
15+
"description": "Ordered list of intermediate state roots — one per transaction in the block — produced while re-executing it. Index N is the root after applying tx N."
16+
},
17+
"debug_memStats": {
18+
"description": "Go runtime memory-allocator statistics: heap size, allocation counts, GC overhead, and span-class breakdown."
19+
},
20+
"debug_printBlock": {
21+
"description": "Human-readable string dump of the block (header fields, transactions, uncles)."
22+
},
23+
"debug_setGCPercent": {
24+
"description": "Previous `GOGC` value before this call applied the new one."
25+
},
26+
"debug_stacks": {
27+
"description": "All goroutine stack traces from the running node, formatted as a single text blob (same shape as `go tool pprof`'s goroutine dump)."
28+
},
29+
"debug_traceBlock": {
30+
"description": "Per-transaction trace results for the supplied RLP-encoded block. Each entry contains the tx hash and the tracer-specific result (or an error)."
31+
},
32+
"debug_traceBlockByHash": {
33+
"description": "Per-transaction trace results for the canonical block identified by hash. Each entry contains the tx hash and the tracer-specific result (or an error)."
34+
},
35+
"debug_traceBlockByNumber": {
36+
"description": "Per-transaction trace results for the canonical block at the given height. Each entry contains the tx hash and the tracer-specific result (or an error)."
37+
},
38+
"debug_traceCall": {
39+
"description": "Tracer output for a simulated call. Shape depends on the tracer: opcode tracer returns step-by-step EVM state, `callTracer` returns the call tree, `prestateTracer` returns touched accounts, etc."
40+
},
41+
"debug_traceTransaction": {
42+
"description": "Tracer output for an already-mined transaction, re-executed against its parent state. Shape depends on the tracer (same options as `debug_traceCall`)."
43+
},
44+
45+
"eth_accounts": {
46+
"description": "List of 20-byte addresses currently held in the node's keystore. Empty on nodes without unlocked accounts (which is the typical Lumera deployment)."
47+
},
48+
"eth_blockNumber": {
49+
"description": "Height of the latest committed block on this node, as a hex-encoded integer."
50+
},
51+
"eth_call": {
52+
"description": "Return data from the simulated message call (hex). Empty bytes if the call returned nothing; reverts surface as a JSON-RPC error with the revert payload."
53+
},
54+
"eth_chainId": {
55+
"description": "EIP-155 chain ID as hex. On Lumera mainnet this is `0x494c1a9` (76857769)."
56+
},
57+
"eth_createAccessList": {
58+
"description": "Optimal EIP-2930 access list for the call plus the gas it would consume with that access list applied. Includes any error returned by the simulated execution."
59+
},
60+
"eth_estimateGas": {
61+
"description": "Minimum gas (hex) that makes the supplied call succeed against the chosen block's post-state."
62+
},
63+
"eth_feeHistory": {
64+
"description": "Per-block base fees, gas-used ratios, blob base fees, and (if `rewardPercentiles` was supplied) priority-fee percentiles across the requested range."
65+
},
66+
"eth_fillTransaction": {
67+
"description": "The fully-populated transaction object (nonce, gas, fees set by the node) along with its RLP-encoded raw form ready to sign and broadcast."
68+
},
69+
"eth_gasPrice": {
70+
"description": "Suggested legacy gas price as hex wei. Reflects `baseFee + suggested priority fee` on London-and-later chains."
71+
},
72+
"eth_getBalance": {
73+
"description": "Account balance in wei (hex). Lumera's EVM uses 18-decimal `alume` bridged from 6-decimal `ulume`."
74+
},
75+
"eth_getBlockByHash": {
76+
"description": "Block object: header fields, transactions (full objects or hashes per the `fullTx` flag), and uncles array (always empty on Lumera). `null` if the block is unknown."
77+
},
78+
"eth_getBlockByNumber": {
79+
"description": "Block object: header fields, transactions (full objects or hashes per the `fullTx` flag), and uncles array (always empty on Lumera). `null` if the height is not yet mined."
80+
},
81+
"eth_getBlockReceipts": {
82+
"description": "Receipts for every transaction in the requested block, in execution order. Each entry has status, gas used, cumulative gas used, logs, and (for contract creations) the new contract address."
83+
},
84+
"eth_getBlockTransactionCountByHash": {
85+
"description": "Number of transactions in the block (hex). `null` if the block hash is unknown."
86+
},
87+
"eth_getBlockTransactionCountByNumber": {
88+
"description": "Number of transactions in the block (hex). `null` if the height is not yet mined."
89+
},
90+
"eth_getCode": {
91+
"description": "Deployed contract bytecode at the address (hex). Empty `0x` for externally-owned accounts and for not-yet-deployed contracts."
92+
},
93+
"eth_getFilterChanges": {
94+
"description": "Polling result for an active filter. Logs filter → array of log objects; block filter → array of block hashes; pending-tx filter → array of transaction hashes. Empty array if nothing new since the last poll."
95+
},
96+
"eth_getFilterLogs": {
97+
"description": "All log objects matching the filter's criteria since it was installed. Unlike `eth_getFilterChanges`, this returns the full history rather than only new entries."
98+
},
99+
"eth_getHeaderByHash": {
100+
"description": "Block header fields only — no transactions or uncles. `null` if the hash is unknown."
101+
},
102+
"eth_getHeaderByNumber": {
103+
"description": "Block header fields only — no transactions or uncles. `null` if the height is not yet mined."
104+
},
105+
"eth_getLogs": {
106+
"description": "Log objects matching the criteria. Each log carries the emitting address, indexed topics, raw `data` bytes, and block/tx identifiers."
107+
},
108+
"eth_getProof": {
109+
"description": "Merkle-Patricia proof bundle: account proof, balance, code hash, nonce, storage hash, and one storage proof per requested key. Rooted at the chosen block's state root."
110+
},
111+
"eth_getStorageAt": {
112+
"description": "32-byte value (hex) stored at the requested slot, or `0x000...00` if unset."
113+
},
114+
"eth_getTransactionByBlockHashAndIndex": {
115+
"description": "Transaction object at the given position in the block, or `null` if the index is out of range."
116+
},
117+
"eth_getTransactionByBlockNumberAndIndex": {
118+
"description": "Transaction object at the given position in the block, or `null` if the index is out of range."
119+
},
120+
"eth_getTransactionByHash": {
121+
"description": "Transaction object as it lives on-chain or in the mempool, or `null` if unknown. Includes `from`/`to`/value/input plus EIP-1559 fee fields and (for confirmed txs) `blockNumber`/`blockHash`/`transactionIndex`."
122+
},
123+
"eth_getTransactionCount": {
124+
"description": "Number of transactions sent from the address (i.e. the next nonce), hex-encoded. Reflects the chosen block's post-state."
125+
},
126+
"eth_getTransactionLogs": {
127+
"description": "All log objects emitted by the transaction, in emission order. Empty array if the transaction emitted no events."
128+
},
129+
"eth_getTransactionReceipt": {
130+
"description": "Receipt object: status (`0x0` failure, `0x1` success), gas used, cumulative gas, logs, logs bloom, effective gas price, and (for contract creations) the new contract address. `null` if the tx is still pending."
131+
},
132+
"eth_getUncleByBlockHashAndIndex": {
133+
"description": "Always `null` on Lumera — post-merge chains have no uncles."
134+
},
135+
"eth_getUncleByBlockNumberAndIndex": {
136+
"description": "Always `null` on Lumera — post-merge chains have no uncles."
137+
},
138+
"eth_getUncleCountByBlockHash": {
139+
"description": "Always `0x0` on Lumera — post-merge chains have no uncles."
140+
},
141+
"eth_getUncleCountByBlockNumber": {
142+
"description": "Always `0x0` on Lumera — post-merge chains have no uncles."
143+
},
144+
"eth_maxPriorityFeePerGas": {
145+
"description": "Suggested priority-fee (tip) in wei (hex), based on recent block tips. Use as `maxPriorityFeePerGas` for EIP-1559 transactions."
146+
},
147+
"eth_newBlockFilter": {
148+
"description": "Filter ID. Poll via `eth_getFilterChanges` to receive block hashes as new blocks are committed."
149+
},
150+
"eth_newFilter": {
151+
"description": "Filter ID. Poll via `eth_getFilterChanges` for incremental matches or `eth_getFilterLogs` for the full history."
152+
},
153+
"eth_newPendingTransactionFilter": {
154+
"description": "Filter ID. Poll via `eth_getFilterChanges` to receive pending-transaction hashes as they enter the mempool."
155+
},
156+
"eth_protocolVersion": {
157+
"description": "Ethereum wire-protocol version implemented by the node (hex). Largely historical on Cosmos EVM."
158+
},
159+
"eth_resend": {
160+
"description": "Hash of the newly submitted replacement transaction."
161+
},
162+
"eth_sendRawTransaction": {
163+
"description": "Hash of the submitted transaction. Inclusion in a block is not yet guaranteed at the time of return."
164+
},
165+
"eth_sendTransaction": {
166+
"description": "Hash of the submitted transaction. Requires an unlocked sender account on the node."
167+
},
168+
"eth_sign": {
169+
"description": "65-byte signature (hex) over `keccak256(\\x19Ethereum Signed Message:\\n<len>data)` using the address's key. Layout: `r||s||v`."
170+
},
171+
"eth_signTypedData": {
172+
"description": "65-byte EIP-712 signature (hex) over the typed-data domain-separated digest. Layout: `r||s||v`."
173+
},
174+
"eth_syncing": {
175+
"description": "`false` when the node is fully synced, otherwise an object with `startingBlock`/`currentBlock`/`highestBlock` describing sync progress."
176+
},
177+
"eth_uninstallFilter": {
178+
"description": "`true` if the filter was found and removed; `false` if it had already expired or never existed."
179+
},
180+
181+
"miner_getHashrate": {
182+
"description": "Reported mining hashrate. Effectively meaningless on Cosmos EVM (no proof-of-work)."
183+
},
184+
"miner_setEtherbase": {
185+
"description": "Always `true` on Lumera — block rewards are distributed by the Cosmos staking module, not by the EVM coinbase address."
186+
},
187+
"miner_setExtra": {
188+
"description": "Always `true` on Lumera — block production is driven by CometBFT, not by EVM miner settings."
189+
},
190+
"miner_setGasLimit": {
191+
"description": "Always `true` on Lumera — block gas limit is set by the consensus params, not by an EVM miner config."
192+
},
193+
"miner_setGasPrice": {
194+
"description": "Always `true` on Lumera — local minimum gas prices are configured via app.toml / mempool settings, not via this method."
195+
},
196+
197+
"net_listening": {
198+
"description": "`true` while the node is actively listening for peers."
199+
},
200+
"net_peerCount": {
201+
"description": "Number of currently-connected peers (decimal integer)."
202+
},
203+
"net_version": {
204+
"description": "Network ID as a decimal string. Equal to the EVM chain ID on Lumera (`\"76857769\"`)."
205+
},
206+
207+
"personal_ecRecover": {
208+
"description": "Address that produced the signature, recovered using the Ethereum signed-message prefix."
209+
},
210+
"personal_importRawKey": {
211+
"description": "Address derived from the imported private key."
212+
},
213+
"personal_initializeWallet": {
214+
"description": "Recovery mnemonic / status string returned by the hardware wallet driver after initialization."
215+
},
216+
"personal_listAccounts": {
217+
"description": "All addresses held in the node's keystore."
218+
},
219+
"personal_listWallets": {
220+
"description": "Detailed entries for each detected wallet backend (keystore, USB hardware wallet, etc.) including its status and contained accounts."
221+
},
222+
"personal_lockAccount": {
223+
"description": "`true` if a previously unlocked key was locked; `false` if no key was unlocked for that address."
224+
},
225+
"personal_newAccount": {
226+
"description": "Address of the newly generated keystore account."
227+
},
228+
"personal_sendTransaction": {
229+
"description": "Hash of the submitted transaction."
230+
},
231+
"personal_sign": {
232+
"description": "65-byte signature (hex) layout `r||s||v` over the Ethereum-prefixed digest of `data`."
233+
},
234+
"personal_unlockAccount": {
235+
"description": "`true` if the passphrase was correct and the key was unlocked; `false` otherwise."
236+
},
237+
238+
"txpool_content": {
239+
"description": "Full mempool dump grouped as `{ pending|queued: { address: { nonce: transaction } } }`."
240+
},
241+
"txpool_contentFrom": {
242+
"description": "Mempool entries for one address grouped as `{ pending|queued: { nonce: transaction } }`."
243+
},
244+
"txpool_inspect": {
245+
"description": "Compact mempool dump grouped as `{ pending|queued: { address: { nonce: summary-string } } }`. The summary string has the form `to: value wei + gas × gasPrice wei`."
246+
},
247+
"txpool_status": {
248+
"description": "Counts of pending and queued transactions in the mempool (hex)."
249+
},
250+
251+
"web3_clientVersion": {
252+
"description": "Human-readable node identification string (client name, version, OS, Go version)."
253+
},
254+
"web3_sha3": {
255+
"description": "Keccak-256 digest of the input bytes as 32 hex bytes."
256+
}
257+
}

0 commit comments

Comments
 (0)