-
Notifications
You must be signed in to change notification settings - Fork 33
docs: Polygon Bor consistency — document flatCallTracer, drop stale Erigon claims #583
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -4,7 +4,7 @@ openapi: /openapi/polygon_node_api/transaction_info/eth_getBlockReceipts.json PO | |
| description: "Polygon API method that retrieves all transaction receipts for a given block. Reference for eth_getBlockReceipts on Polygon via Chainstack." | ||
| --- | ||
|
|
||
| Polygon API method that retrieves all transaction receipts for a given block. Transaction receipts contain information about the execution status of a transaction and can be useful for monitoring the status of transfers or contract execution on the blockchain. This method is available on Erigon only. | ||
| Polygon API method that retrieves all transaction receipts for a given block. Transaction receipts contain information about the execution status of a transaction and can be useful for monitoring the status of transfers or contract execution on the blockchain. | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win 🧩 Analysis chain🏁 Script executed: #!/bin/bash
set -euo pipefail
echo "== locate file =="
git ls-files | grep -F 'reference/polygon-getblockreceipts.mdx' || true
echo "== file excerpt =="
if [ -f reference/polygon-getblockreceipts.mdx ]; then
nl -ba reference/polygon-getblockreceipts.mdx | sed -n '1,120p'
fi
echo "== search for getblockreceipt-related wording =="
rg -n "getblockreceipt|block receipt|transaction receipt|transfer|monitoring" reference -g '*.mdx' -g '*.md' | head -200
echo "== external docs check =="
python3 - <<'PY'
# Read-only semantic check against local file and common Ethereum RPC docs via web if needed.
from pathlib import Path
p = Path('reference/polygon-getblockreceipts.mdx')
text = p.read_text() if p.exists() else ''
print("mentions_transfer_on_same_sentence_as_receipt_or_monitoring:", any(s in text for s in ["receipts for a given block", "monitoring the status of transfers", "contract execution", "transaction receipts"]))
PYRepository: chainstack/dev-portal Length of output: 275 🏁 Script executed: #!/bin/bash
set -euo pipefail
echo "== file excerpt =="
if [ -f reference/polygon-getblockreceipts.mdx ]; then
awk '{printf "%6d\t%s\n", NR, $0}' reference/polygon-getblockreceipts.mdx | sed -n '1,140p'
fi
echo "== search for getblockreceipt-related wording =="
rg -n "getblockreceipt|block receipt|transaction receipt|transfer|monitoring" reference -g '*.mdx' -g '*.md' | head -200 || trueRepository: chainstack/dev-portal Length of output: 46661 Distinguish receipt status from transfer verification.
🤖 Prompt for AI AgentsSource: MCP tools |
||
|
|
||
| <Visibility for="humans"> | ||
| <Check> | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -28,6 +28,7 @@ You can sign up with your GitHub, X, Google, or Microsoft account. | |
| + `4byteTracer` — tracer that captures the function signatures and call data sizes for all functions executed during a transaction, creating a map that links each selector and size combination to the number of times it occurred. This provides valuable information about the frequency and usage of each function within the transaction. | ||
| + `callTracer` — tracer that captures information on all call frames executed during a transaction. The resulting nested list of call frames is organized into a tree structure that reflects the way the Ethereum Virtual Machine works and can be used for debugging and analysis purposes. | ||
| + `prestateTracer` — tracer with two modes: `prestate` and `diff`, where the former returns the accounts needed to execute a transaction, and the latter returns the differences between the pre and post-states of the transaction. The tracer operates by re-executing the transaction and tracking every state change made, resulting in an object with the account addresses as keys and the corresponding trie leaves as values. | ||
| + `flatCallTracer` — tracer that returns the transaction's calls as a flat array in the Parity-style trace format, with each entry's position given by its `traceAddress`. This is the drop-in replacement for the Erigon `trace_*` methods, which Bor does not implement. | ||
|
|
||
| ## Response types | ||
|
|
||
|
|
@@ -49,6 +50,16 @@ You can sign up with your GitHub, X, Google, or Microsoft account. | |
| + `revertReason` — the reason why the transaction was reverted, returned by the smart contract if any. | ||
| + `calls` — a list of sub-calls made by the contract during the call, each represented as a nested call frame object. | ||
|
|
||
| ### `flatCallTracer` response | ||
|
|
||
| * `array` — the block's calls as a flat list in the Parity trace format, one object per call: | ||
| + `action` — the call details: `from`, `to`, `value`, `gas`, `input`, and `callType` (for example, `call`, `delegatecall`, or `staticcall`). Contract creations and self-destructs carry the corresponding Parity `create` and `suicide` fields instead. | ||
| + `result` — the call outcome: `gasUsed` and `output`. Contract creations return the new contract `address` and its `code`. | ||
| + `subtraces` — the number of child calls made directly by this call. | ||
| + `traceAddress` — the position of this call in the call tree, as an array of child indices. | ||
| + `type` — the call type: `call`, `create`, or `suicide`. | ||
| + `error` — present only when the call failed, with the failure reason. | ||
|
|
||
|
Comment on lines
+53
to
+62
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win 🧩 Analysis chain🏁 Script executed: #!/bin/bash
set -euo pipefail
echo "Repository files matching trace MDX:"
git ls-files 'reference/*trace*.mdx' | sed -n '1,120p'
echo
echo "Relevant reference sections:"
for f in reference/polygon-traceblockbyhash.mdx reference/polygon-traceblockbynumber.mdx reference/polygon-tracecall.mdx reference/polygon-tracetransaction.mdx; do
if [ -f "$f" ]; then
echo "--- $f"
wc -l "$f"
sed -n '1,110p' "$f" | nl -ba
else
echo "MISSING $f"
fi
done
echo
echo "Search for flatCallTracer/tracer terminology:"
rg -n "flatCallTracer|tracer|txHash|result" reference -g '*.mdx' | sed -n '1,200p'
echo
echo "Changed files/stat (if available):"
git diff --stat HEAD~1..HEAD 2>/dev/null || git diff --stat 2>/dev/null || trueRepository: chainstack/dev-portal Length of output: 5161 🏁 Script executed: #!/bin/bash
set - eu
for f in reference/polygon-traceblockbyhash.mdx reference/polygon-traceblockbynumber.mdx reference/polygon-tracecall.mdx reference/polygon-tracetransaction.mdx; do
if [ -f "$f" ]; then
echo "--- $f"
wc -l "$f"
cat -n "$f" | sed -n '1,130p'
else
echo "MISSING $f"
fi
done
echo
echo "Search relevant docs terms:"
rg -n "flatCallTracer|tracer|txHash|result|three built-in|built-in tracers" reference -g '*.mdx' | sed -n '1,240p'
echo
echo "Changed files/stat:"
git diff --stat 2>/dev/null || trueRepository: chainstack/dev-portal Length of output: 50379 🌐 Web query:
💡 Result: When using the Citations:
🌐 Web query:
💡 Result: When using the flatCallTracer with Erigon's debug_traceBlockByHash RPC method, the response structure differs significantly from the tree-based callTracer [1][2]. Instead of a nested structure, it returns a flattened list of call frames in a format compatible with OpenEthereum/Parity-style traces [3][2]. For a block trace, the top-level response is typically a JSON-RPC result object containing an array [4]. Each element in this array corresponds to a transaction within the block, often keyed by txHash [4]. The result for each transaction is an array of flat call frame objects [4]. Each flat call frame object typically includes the following fields [5]: - action: An object containing details such as callType, from, to, input, value, and gas [6][4]. - result: An object containing execution results such as gasUsed and output [6][4]. - subtraces: An integer representing the count of sub-calls [3][6]. - traceAddress: An array of integers representing the position of the call within the execution tree [6][5]. - type: A string indicating the type of call (e.g., call, delegatecall, staticcall, create) [6][4]. Unlike the Geth-style output where traces are often nested under a result field, the flatCallTracer organizes all call frames from the execution into a single, linear list [3][2]. Note that Erigon may return these results within a JSON-RPC envelope [4], and users should be aware that discrepancies may exist between Erigon and Geth output formats, such as the inclusion of specific result keys or handling of errors [7][8]. For example, if a method handler crashes or an error occurs during tracing, the response structure might be incomplete or contain error-specific fields [7][5]. Citations:
🌐 Web query:
💡 Result: The flatCallTracer is a native tracer available in Geth and other Ethereum clients that provides a flattened, Parity-style list of call frames, rather than the nested tree structure produced by the default callTracer [1][2][3]. When using flatCallTracer with the debug_traceBlockByHash method, you provide it within the tracer configuration object [4][5][6]. Below is an example of the request structure: curl -X POST <RPC_URL> \ -H "Content-Type: application/json" \ -d '{ "jsonrpc": "2.0", "method": "debug_traceBlockByHash", "params": [ "<BLOCK_HASH>", { "tracer": "flatCallTracer" } ], "id": 1 }' Key characteristics and notes for flatCallTracer: 1. Output Format: It outputs call traces as a flattened list of frames [2][3]. 2. Compatibility: It was implemented in Geth to provide compatibility with Parity/OpenEthereum-style tracing [1]. 3. Implementation Differences: While it mimics Parity-style output, there are known differences, such as how Geth handles errors, gas usage (Geth includes intrinsic gas and refunds, while Parity did not), and how it handles whole-block tracing (Geth typically nests transaction results within a result field) [1]. 4. Block Tracing: When tracing an entire block, the RPC response returns a list of results for all transactions contained within that block [7][1]. 5. Versioning/Bugs: Users should be aware that implementation details may vary between client versions, and specific bugs (such as incorrect hash returns or timeout handling) have been documented in various client implementations [8][9]. Because the debug_traceBlockByHash method expects a block hash as the first parameter and a configuration object (which can include the tracer type) as the second, the txHash is not a direct parameter of this specific RPC call [4][5][6]. If you need a trace for a specific transaction, you should use the debug_traceTransaction method instead [4]. Citations:
🌐 Web query:
💡 Result: The flatCallTracer is a transaction tracing tool designed to provide a flattened, Parity-style list of call frames, rather than the nested tree structure produced by the standard callTracer [1][2][3]. This format is primarily used for compatibility with tooling built for the OpenEthereum/Parity trace format [1][3]. On networks like Polygon (Bor), tracing support—including the availability of specific tracers—can vary based on the node configuration and the specific implementation of the trace API [4][5]. Key Technical Details: - Format: It returns a flattened list of call frames [2][6][3]. - Purpose: It offers a simplified output for complex transactions [7][8][9] and ensures compatibility with legacy OpenEthereum/Parity tooling [1][3]. - Implementation: In go-ethereum (which Bor is based on), the flatCallTracer is implemented as a wrapper that uses the standard callTracer to collect callstack information and then reformats the output into the flat structure [1]. - Bor/Polygon Context: Bor has integrated support for various tracing methods, often backported or adapted from go-ethereum and OpenEthereum implementations [4]. If you are experiencing issues tracing transactions (e.g., state-sync transactions failing) [10][11], it is often due to how the node handles specific transaction types, such as system transactions with zero gas or intrinsic gas issues [10]. Enabling specific flags like borTraceEnabled in the tracer configuration is sometimes required for successful tracing on Bor [5]. If you are attempting to locate a transaction by its hash in a trace result, the flatCallTracer output includes the transactionHash field for each entry [7]. When tracing blocks, the structure typically returns a result containing transaction results, which may vary slightly between implementations regarding how errors are nested [1]. Citations:
🌐 Web query:
💡 Result: The flatCallTracer is a native tracer available in Geth (go-ethereum) designed to provide Parity-style transaction tracing output [1]. It functions as a proxy that utilizes the callTracer to collect call stack information, which is then formatted to align with compatibility requirements for users transitioning from or integrating with systems that expect Parity-style traces [1]. You can use the flatCallTracer with Geth's debug RPC methods, such as debug_traceBlockByHash or debug_traceBlockByNumber, by specifying it in the tracer configuration [2][3]. Example RPC request: { "method": "debug_traceBlockByHash", "params": [ "0xYourBlockHash", { "tracer": "flatCallTracer", "tracerConfig": { "includePrecompiles": false, "convertParityErrors": false } } ], "id": 1, "jsonrpc": "2.0" } Key characteristics and compatibility notes include: 1. Compatibility Options: You can enable includePrecompiles: true to report precompile calls, which are excluded by default [1]. If you require Parity-style error messages, you can set convertParityErrors: true [1]. 2. Output Differences: Unlike Parity, Geth's implementation accounts for intrinsic gas and refunds in the gasUsed field, and it nests transaction results within a result field when tracing an entire block [1]. 3. Maintenance: It is an actively maintained native tracer within the Geth codebase, with bug fixes and updates (such as blob base fee support) integrated to ensure reliability and performance [4][5]. Citations:
🏁 Script executed: #!/bin/bash
set -eu
echo "OpenAPI response schemas for Polygon debug_traceBlock methods:"
fd -a 'debug_traceBlock.*\.(yaml|json|yml|md)' . | sed -n '1,40p'
for f in $(fd 'debug_traceBlock.*\.(json|yaml|yml)$' .); do
echo "--- $f"
# Print lines that mention flatCallTracer/response schema if present
rg -n "flatCallTracer|result|array|object|properties|type" "$f" | sed -n '1,220p'
doneRepository: chainstack/dev-portal Length of output: 19171 🏁 Script executed: #!/bin/bash
set -eu
python3 - <<'PY'
import json
from pathlib import Path
for name in ["debug_traceBlockByHash", "debug_traceBlockByNumber"]:
path = Path("openapi/polygon_node_api/debug_and_trace") / f"{name}.json"
data = json.loads(path.read_text())
result = None
schema = data.get("content", {}).get("application/json", {}).get("schema", {})
def walk(cur):
nonlocal result
if isinstance(cur, dict):
if cur.get("type") == "object" and cur.get("properties"):
if "result" in cur["properties"]:
result = cur["properties"]["result"]
for v in cur.values():
walk(v)
schema.get("properties", {}).get("result", {}).get("items", {})
walk(schema)
print(f"--- {name}")
print(json.dumps(result, indent=2, sort_keys=True, ensure_ascii=False)[:2000])
PYRepository: chainstack/dev-portal Length of output: 236 🏁 Script executed: #!/bin/bash
set -eu
python3 - <<'PY'
import json
from pathlib import Path
for name in ["debug_traceBlockByHash", "debug_traceBlockByNumber"]:
path = Path("openapi/polygon_node_api/debug_and_trace") / f"{name}.json"
data = json.loads(path.read_text())
def find_result_schema(node, depth=0):
if not isinstance(node, dict):
return None
if node.get("type") == "object" and node.get("properties") and "result" in node["properties"]:
return node["properties"]["result"]
for v in node.values():
r = find_result_schema(v, depth + 1)
if r is not None:
return r
return None
result = find_result_schema(data)
print(f"--- {name}: type={result.get('type')}, title={result.get('title')}, description={result.get('description')}")
print(json.dumps(result, indent=2)[:2400])
PY
echo
echo "Top-level API docs around flatCallTracer:"
for f in reference/polygon-debug-trace-rpc-methods.mdx; do
[ -f "$f" ] && cat -n "$f" | sed -n '1,260p'
doneRepository: chainstack/dev-portal Length of output: 3638 Document the flatCallTracer transaction wrapper for both block methods.
📍 Affects 2 files
🤖 Prompt for AI AgentsSource: MCP tools |
||
| ### `prestateTracer` response | ||
|
|
||
| * `object` — the `prestateTracer` traces object: | ||
|
|
@@ -68,7 +79,7 @@ const provider = new ethers.JsonRpcProvider(NODE_URL); | |
|
|
||
| const traceBlockByHash = async (blockHash) => { | ||
|
|
||
| // Specify the type of tracer: 4byteTracer, callTracer, or prestateTracer | ||
| // Specify the type of tracer: 4byteTracer, callTracer, flatCallTracer, or prestateTracer | ||
| const tracer = { tracer: '4byteTracer' }; | ||
| const traces = await provider.send("debug_traceBlockByHash", [blockHash, tracer]); | ||
| console.log(traces); | ||
|
|
@@ -84,7 +95,7 @@ web3 = Web3.HTTPProvider(node_url) | |
|
|
||
| block_hash = "0x22507441629262af0d44bfadebe086470df5936827bc482300b5183b4b8ac8bd" | ||
|
|
||
| # Specify the type of tracer: 4byteTracer, callTracer, or prestateTracer | ||
| # Specify the type of tracer: 4byteTracer, callTracer, flatCallTracer, or prestateTracer | ||
| tracer = { "tracer": '4byteTracer' } | ||
| block_traces = web3.provider.make_request('debug_traceBlockByHash', [block_hash, tracer]) | ||
| print(block_traces) | ||
|
|
@@ -107,7 +118,7 @@ const provider = new ethers.JsonRpcProvider(NODE_URL); | |
|
|
||
| async function traceTransferFunction(blockHash) { | ||
| try { | ||
| // Specify the type of tracer: 4byteTracer, callTracer, or prestateTracer | ||
| // Specify the type of tracer: 4byteTracer, callTracer, flatCallTracer, or prestateTracer | ||
| const tracer = { tracer: '4byteTracer' }; | ||
| const response = await provider.send("debug_traceBlockByHash", [blockHash, tracer]); | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -46,6 +46,7 @@ See the [default block parameter](https://ethereum.org/en/developers/docs/apis/j | |
| + `4byteTracer` — tracer that captures the function signatures and call data sizes for all functions executed during a transaction, creating a map that links each selector and size combination to the number of times it occurred. This provides valuable information about the frequency and usage of each function within the transaction. | ||
| + `callTracer` — tracer that captures information on all call frames executed during a transaction. The resulting nested list of call frames is organized into a tree structure that reflects the way the Ethereum Virtual Machine works and can be used for debugging and analysis purposes. | ||
| + `prestateTracer` — tracer with two modes: `prestate` and `diff`, where the former returns the accounts needed to execute a transaction, and the latter returns the differences between the pre and post-states of the transaction. The tracer operates by re-executing the transaction and tracking every state change made, resulting in an object with the account addresses as keys and the corresponding trie leaves as values. | ||
| + `flatCallTracer` — tracer that returns the call's execution as a flat array in the Parity-style trace format, with each entry's position given by its `traceAddress`. This is the drop-in replacement for the Erigon `trace_*` methods, which Bor does not implement. | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win Remove the stale tracer count. Adding
📍 Affects 2 files
🤖 Prompt for AI Agents |
||
|
|
||
| <Note> | ||
| Find a complete [list of available built-in tracers](/reference/polygon-debug-trace-rpc-methods#pre-built-native-tracers) in the debug and trace overview. | ||
|
|
@@ -97,6 +98,16 @@ When no built-in tracer is selected, the response defaults to the [Struct/opcode | |
| + `revertReason` — the reason why the transaction was reverted, returned by the smart contract, if any. | ||
| + `calls` — a list of sub-calls made by the contract during the call, each represented as a nested call frame object. | ||
|
|
||
| ### `flatCallTracer` response | ||
|
|
||
| * `array` — the call's execution as a flat list in the Parity trace format, one object per call: | ||
| + `action` — the call details: `from`, `to`, `value`, `gas`, `input`, and `callType` (for example, `call`, `delegatecall`, or `staticcall`). Contract creations and self-destructs carry the corresponding Parity `create` and `suicide` fields instead. | ||
| + `result` — the call outcome: `gasUsed` and `output`. Contract creations return the new contract `address` and its `code`. | ||
| + `subtraces` — the number of child calls made directly by this call. | ||
| + `traceAddress` — the position of this call in the call tree, as an array of child indices. | ||
| + `type` — the call type: `call`, `create`, or `suicide`. | ||
| + `error` — present only when the call failed, with the failure reason. | ||
|
|
||
| ### `prestateTracer` response | ||
|
|
||
| * `object` — the `prestateTracer` traces object: | ||
|
|
@@ -137,7 +148,7 @@ const traceCall = async () => { | |
|
|
||
| const block = 'latest' | ||
|
|
||
| // Specify the type of tracer: 4byteTracer, callTracer, or prestateTracer. Leave empty {} for Struct/opcode logger. | ||
| // Specify the type of tracer: 4byteTracer, callTracer, flatCallTracer, or prestateTracer. Leave empty {} for Struct/opcode logger. | ||
| const tracer = {}; | ||
| const traces = await provider.send("debug_traceCall", [call, block, tracer]); | ||
| console.log(traces); | ||
|
|
@@ -161,7 +172,7 @@ call = { | |
|
|
||
| block = 'latest' | ||
|
|
||
| # Specify the type of tracer: 4byteTracer, callTracer, or prestateTracer. Leave empty {} for Struct/opcode logger. | ||
| # Specify the type of tracer: 4byteTracer, callTracer, flatCallTracer, or prestateTracer. Leave empty {} for Struct/opcode logger. | ||
| tracer = { "tracer": 'prestateTracer' } | ||
| tx_traces = web3.provider.make_request('debug_traceCall', [call, block, tracer]) | ||
| print(tx_traces) | ||
|
|
@@ -187,7 +198,7 @@ const provider = new ethers.JsonRpcProvider(NODE_URL); | |
|
|
||
| async function traceCall(call, block) { | ||
| try { | ||
| // Specify the type of tracer: 4byteTracer, callTracer, or prestateTracer. | ||
| // Specify the type of tracer: 4byteTracer, callTracer, flatCallTracer, or prestateTracer. | ||
| // Leave empty {} for Struct/opcode logger. | ||
| const tracer = { tracer: 'callTracer' }; | ||
|
|
||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
Say “debug APIs,” not “debug and trace APIs.”
The paragraph says Bor exposes only
debug_*and does not implementtrace_*, so the opening currently implies unsupported trace APIs are available on dedicated Polygon nodes.🤖 Prompt for AI Agents