Skip to content

fix: single-element JSON-RPC batch response shape for UTXO chains#2242

Merged
nimrod-teich merged 4 commits into
mainfrom
fix/utxo-single-element-batch-response
Mar 19, 2026
Merged

fix: single-element JSON-RPC batch response shape for UTXO chains#2242
nimrod-teich merged 4 commits into
mainfrom
fix/utxo-single-element-batch-response

Conversation

@nimrod-teich

@nimrod-teich nimrod-teich commented Mar 18, 2026

Copy link
Copy Markdown
Contributor

User description

Summary

  • Single-element batch requests ([{"id":"1","method":"getblockhash","params":[0]}]) were treated as non-batch, returning a single object with "id":"-1" instead of an array with the original ID.
  • UTXO chain batch responses (BTC, DOGE, LTC, BCH) had "jsonrpc":"2.0" injected and "error":null stripped by the relay pipeline, breaking JSON-RPC 1.0 compatibility.

Root causes

  1. ParseMsg used len(msgs) == 1 to decide batch vs single — a single-element batch [{...}] matched this condition. Added ParseJsonRPCMsgWithBatchFlag() that checks for [ before unmarshaling and returns an isBatch flag.
  2. checkBTCResponseAndFixReply only handled single (non-array) responses. Renamed to checkUTXOResponseAndFixReply and extended to also process batch responses, stripping the injected jsonrpc field and preserving error:null.

Files changed

File Change
protocol/chainlib/chainproxy/rpcInterfaceMessages/jsonRPCMessage.go Add ParseJsonRPCMsgWithBatchFlag()
protocol/chainlib/jsonRPC.go Use isBatch flag; rename BTC→UTXO
protocol/chainlib/tendermintRPC.go Use isBatch flag
protocol/chainlib/common.go Extend UTXO response fix to handle batch arrays
*_test.go Tests for both fixes

Test plan

  • TestParseJsonRPCMsgWithBatchFlag — single object, single-element array, multi-element array, empty array, missing ID, invalid JSON
  • TestCheckUTXOResponseAndFixReply — single/batch/single-element-batch responses, non-UTXO passthrough, error preservation
  • Full protocol/chainlib/... test suite passes
  • Full protocol/rpcsmartrouter/... test suite passes
  • Manual verification with DOGE single-element batch via SmartRouter

🤖 Generated with Claude Code


Generated description

Below is a concise technical summary of the changes proposed in this PR:
Ensure ParseJsonRPCMsgWithBatchFlag in rpcInterfaceMessages and the JSON-RPC/Tendermint chain parsers detect single-element arrays as batches so JsonRPCChainParser and TendermintChainParser maintain correct requested-block metadata. Normalize UTXO-family replies by routing responses through checkUTXOResponseAndFixReply so injected jsonrpc fields are removed while error:null remains, covering both single and batch payloads.

TopicDetails
Batch detection Ensure single-element array inputs stay batches by checking the first non-whitespace byte in ParseJsonRPCMsgWithBatchFlag, returning an isBatch flag, and using it in the JSON-RPC and Tendermint parsers plus new parser tests.
Modified files (6)
  • protocol/chainlib/chainproxy/rpcInterfaceMessages/jsonRPCMessage.go
  • protocol/chainlib/chainproxy/rpcInterfaceMessages/jsonRPCMessage_test.go
  • protocol/chainlib/jsonRPC.go
  • protocol/chainlib/jsonRPC_test.go
  • protocol/chainlib/tendermintRPC.go
  • protocol/chainlib/tendermintRPC_test.go
Latest Contributors(0)
UserCommitDate
UTXO response Restore JSON-RPC 1.0 responses for UTXO chains by using checkUTXOResponseAndFixReply to strip injected jsonrpc, preserve error:null, and handle batch arrays and add tests for each scenario.
Modified files (2)
  • protocol/chainlib/common.go
  • protocol/chainlib/common_test.go
Latest Contributors(0)
UserCommitDate
This pull request is reviewed by Baz. Review like a pro on (Baz).

…pe for UTXO chains

Single-element batch requests like `[{"id":"1","method":"getblockhash","params":[0]}]`
were incorrectly treated as non-batch requests because `ParseMsg` used `len(msgs) == 1`
to decide batch vs single. This caused two issues:

1. Response returned as a single object instead of an array, with ID replaced by "-1"
   (from the cache formatter's default value in `ecosystem/cache/format/jsonrpc.go`).
2. For UTXO chains (BTC, DOGE, LTC, BCH), the relay pipeline reconstructed batch
   responses adding `"jsonrpc":"2.0"` and stripping `"error":null`, breaking JSON-RPC 1.0
   compatibility.

Changes:
- Add `ParseJsonRPCMsgWithBatchFlag()` that checks for `[` before unmarshaling and
  returns an `isBatch` flag so callers can distinguish `{...}` from `[{...}]`.
- Update `JsonRPCChainParser.ParseMsg` and `TendermintChainParser.ParseMsg` to use the
  flag: `len(msgs) == 1 && !isBatch` for the batch decision.
- Rename `checkBTCResponseAndFixReply` → `checkUTXOResponseAndFixReply` and extend it
  to handle batch (array) responses, stripping injected `jsonrpc` field and preserving
  `error:null` for all UTXO-family chains.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@qodo-code-review

Copy link
Copy Markdown

Review Summary by Qodo

Fix single-element JSON-RPC batch response shape for UTXO chains

🐞 Bug fix

Grey Divider

Walkthroughs

Description
• Fix single-element JSON-RPC batch requests returning wrong response shape
• Detect batch requests by checking for [ before unmarshaling, not just message count
• Extend UTXO response fix to handle batch arrays, preserving error:null and stripping jsonrpc
  field
• Add comprehensive tests for batch detection and UTXO response formatting
Diagram
flowchart LR
  A["Single-element batch request<br/>[{...}]"] --> B["ParseJsonRPCMsgWithBatchFlag<br/>checks for ["]
  B --> C["isBatch flag returned"]
  C --> D["ParseMsg uses isBatch<br/>to decide batch vs single"]
  D --> E["Batch response wrapped<br/>in array"]
  F["UTXO chain response<br/>with jsonrpc:2.0"] --> G["checkUTXOResponseAndFixReply<br/>handles single & batch"]
  G --> H["Strip jsonrpc field<br/>preserve error:null"]
  H --> I["JSON-RPC 1.0 compatible<br/>response"]
Loading

Grey Divider

File Changes

1. protocol/chainlib/chainproxy/rpcInterfaceMessages/jsonRPCMessage.go ✨ Enhancement +24/-15

Add batch detection flag to JSON-RPC parser

• Add ParseJsonRPCMsgWithBatchFlag() function that detects batch requests by checking for [
 before unmarshaling
• Returns tuple of messages, isBatch flag, and error to distinguish single objects from
 single-element arrays
• Refactor ParseJsonRPCMsg() to delegate to new function for backward compatibility
• Simplify error handling by checking batch indicator upfront

protocol/chainlib/chainproxy/rpcInterfaceMessages/jsonRPCMessage.go


2. protocol/chainlib/chainproxy/rpcInterfaceMessages/jsonRPCMessage_test.go 🧪 Tests +61/-0

Test batch detection with comprehensive cases

• Add TestParseJsonRPCMsgWithBatchFlag() with 7 test cases covering single objects, single-element
 arrays, multi-element arrays, empty arrays, missing IDs, and invalid JSON
• Test critical case: single-element batch [{...}] must be detected as batch to receive array
 response
• Verify error handling for both single and batch JSON parsing failures

protocol/chainlib/chainproxy/rpcInterfaceMessages/jsonRPCMessage_test.go


3. protocol/chainlib/common.go 🐞 Bug fix +45/-14

Extend UTXO response fix to handle batch arrays

• Rename checkBTCResponseAndFixReply() to checkUTXOResponseAndFixReply() for clarity
• Add isUTXOFamily() helper to check if chain is BTC, BTCT, LTC, LTCT, DOGE, DOGET, BCH, or BCHT
• Extend function to handle both single responses and batch (array) responses
• Add convertToUTXOResponse() helper that strips jsonrpc field and preserves error field for
 JSON-RPC 1.0 compatibility
• Process batch arrays by converting each element and marshaling back to array format

protocol/chainlib/common.go


View more (3)
4. protocol/chainlib/common_test.go 🧪 Tests +59/-0

Test UTXO response formatting for single and batch

• Add TestCheckUTXOResponseAndFixReply() with 5 test cases
• Test single response with error:null preservation and jsonrpc field stripping
• Test multi-element batch response formatting
• Test single-element batch response stays as array with proper formatting
• Test non-UTXO chains pass through unchanged
• Test actual error objects are preserved correctly

protocol/chainlib/common_test.go


5. protocol/chainlib/jsonRPC.go 🐞 Bug fix +3/-3

Use batch flag in JSON-RPC parser and response handler

• Update JsonRPCChainParser.ParseMsg() to use ParseJsonRPCMsgWithBatchFlag() and receive
 isBatch flag
• Change batch decision logic from len(msgs) == 1 to len(msgs) == 1 && !isBatch to correctly
 handle single-element batches
• Update JsonRPCChainListener.Serve() to call renamed checkUTXOResponseAndFixReply() function

protocol/chainlib/jsonRPC.go


6. protocol/chainlib/tendermintRPC.go 🐞 Bug fix +3/-2

Use batch flag in Tendermint RPC parser

• Update TendermintChainParser.ParseMsg() to use ParseJsonRPCMsgWithBatchFlag() and capture
 isBatch flag
• Change batch decision logic from msgsLength == 1 to msgsLength == 1 && !isBatch
• Apply same fix for single-element batch detection in Tendermint RPC parser

protocol/chainlib/tendermintRPC.go


Grey Divider

Qodo Logo

@qodo-code-review

qodo-code-review Bot commented Mar 18, 2026

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (1) 📘 Rule violations (2) 📎 Requirement gaps (0) 📐 Spec deviations (0)

Grey Divider


Action required

1. Batch whitespace breaks parsing🐞 Bug ✓ Correctness
Description
ParseJsonRPCMsgWithBatchFlag() checks only data[0]=='[' (despite the comment claiming “first
non-whitespace byte”) and removed the prior “try batch on single unmarshal failure” behavior, so a
valid batch like " \n[{...}]" will now error instead of parsing. This rejects otherwise-valid
JSON-RPC batch requests and can break clients that pretty-print or prepend whitespace.
Code

protocol/chainlib/chainproxy/rpcInterfaceMessages/jsonRPCMessage.go[R175-192]

+func ParseJsonRPCMsgWithBatchFlag(data []byte) (msgRet []JsonrpcMessage, isBatch bool, err error) {
+	// Check if the data is a JSON array (batch request) by looking at the first non-whitespace byte.
+	// This must be done before unmarshaling because json.Unmarshal into a single struct may
+	// silently succeed on a single-element array, losing the batch context.
+	isBatch = len(data) > 0 && data[0] == '['
+	if isBatch {
+		var batch []JsonrpcMessage
+		err = json.Unmarshal(data, &batch)
+		if err != nil {
+			return nil, true, err
+		}
+		return batch, true, nil
+	}
+
  var msg JsonrpcMessage
  err = json.Unmarshal(data, &msg)
  if err != nil {
-		// we failed unmarshaling
-		// try to parse a batch
-		var batch []JsonrpcMessage
-		errBatch := json.Unmarshal(data, &batch)
-		if errBatch != nil {
-			// failed parsing both as batch and jsonrpc return the first unmarshal error, unless the first character is "["
-			if len(data) > 0 && data[0] == '[' {
-				return nil, errBatch
-			}
-			return nil, err
-		}
-		return batch, nil
+		return nil, false, err
Evidence
The new implementation sets isBatch based on the first byte only and, when isBatch is false, returns
the single-message unmarshal error without attempting to parse as a batch, so any batch not starting
at byte 0 with '[' (e.g., leading whitespace/BOM) will fail.

protocol/chainlib/chainproxy/rpcInterfaceMessages/jsonRPCMessage.go[171-197]
protocol/chainlib/jsonRPC.go[99-114]
protocol/chainlib/tendermintRPC.go[104-116]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`ParseJsonRPCMsgWithBatchFlag` decides `isBatch` via `data[0] == &amp;#x27;[&amp;#x27;` and, if false, it tries only the single-object unmarshal and returns that error. Valid JSON-RPC batch payloads with leading whitespace/newlines (or UTF-8 BOM) will therefore be rejected.
### Issue Context
The function comment explicitly says “first non-whitespace byte”, but the code does not implement that. Prior behavior also attempted to parse as batch on single-object unmarshal failure; the new code no longer does.
### Fix Focus Areas
- protocol/chainlib/chainproxy/rpcInterfaceMessages/jsonRPCMessage.go[175-197]
### Expected fix
- Determine batch-ness from the first *non-whitespace* byte (e.g., `trimmed := bytes.TrimSpace(data)`; optionally strip BOM).
- Additionally (or alternatively), restore a safe fallback: if single-object unmarshal fails, try unmarshaling into `[]JsonrpcMessage` and set `isBatch=true` when that succeeds.
- Add a unit test for leading-whitespace batch inputs (e.g. `&amp;quot;\n  [{...}]&amp;quot;`).

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


2. Single-batch earliest block wrong 🐞 Bug ✓ Correctness
Description
TendermintChainParser.ParseMsg now routes single-element JSON arrays through the batch path
(msgsLength==1 && !isBatch), but earliestRequestedBlock is only computed when msgsLength>1, so
single-element batches keep earliestRequestedBlock=spectypes.LATEST_BLOCK (-2). This makes
RequestedBlock() report earliest=-2 and can incorrectly disable archive routing for historical-block
requests sent as single-element batches.
Code

protocol/chainlib/tendermintRPC.go[R250-253]

+	if msgsLength == 1 && !isBatch {
  	tenderMsg := rpcInterfaceMessages.TendermintrpcMessage{JsonrpcMessage: msgs[0], Path: ""}
  	if !isJsonrpc {
  		tenderMsg.Path = urlPath // add path
Evidence
With the new && !isBatch condition, a single-element batch (msgsLength==1 and isBatch==true)
falls into the batch message container. But since CompareRequestedBlockInBatch is gated by
msgsLength > 1, earliestRequestedBlock remains initialized to LATEST_BLOCK (-2). Because
baseChainMessageContainer.RequestedBlock returns earliestRequestedBlock when it’s non-zero, the
archive rule sees a negative earliest (treated as “latest/not archive”) and may misroute historical
queries.

protocol/chainlib/tendermintRPC.go[151-155]
protocol/chainlib/tendermintRPC.go[244-262]
protocol/chainlib/chain_message.go[121-127]
protocol/chainlib/extensionslib/archive_parser_rule.go[23-31]
x/spec/types/types.go[28-33]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
After introducing `isBatch`, single-element JSON arrays are treated as batch requests in Tendermint parsing. However, `earliestRequestedBlock` is not updated for `msgsLength==1`, so batch messages can carry `earliestRequestedBlock = spectypes.LATEST_BLOCK (-2)`, which breaks downstream routing logic that relies on `RequestedBlock()`.
### Issue Context
- `earliestRequestedBlock` is initialized to `spectypes.LATEST_BLOCK`.
- `CompareRequestedBlockInBatch` is only called when `msgsLength &amp;gt; 1`.
- For `msgsLength == 1 &amp;amp;&amp;amp; isBatch == true`, code uses `newBatchChainMessage(... earliestRequestedBlock ...)`.
### Fix Focus Areas
- protocol/chainlib/tendermintRPC.go[151-155]
- protocol/chainlib/tendermintRPC.go[244-262]
### Expected fix
Implement one of:
- Update earliest/latest tracking for batch requests regardless of size (e.g., call `CompareRequestedBlockInBatch` when `isBatch` is true, not only when `msgsLength&amp;gt;1`).
- Or, right before building the batch message, add a special-case: if `isBatch &amp;amp;&amp;amp; msgsLength == 1`, set `earliestRequestedBlock = latestRequestedBlock`.
Add a unit/integration test for a single-element Tendermint JSON-RPC batch that requests a historical block and assert `RequestedBlock()` earliest is not `LATEST_BLOCK`.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Remediation recommended

3. TestParseJsonRPCMsgWithBatchFlag naming nonstandard 📘 Rule violation ⚙ Maintainability
Description
The newly added test function name does not follow the required TestComponent_Scenario convention,
which reduces consistency and discoverability across the test suite. This violates the repository’s
standard test naming requirement.
Code

protocol/chainlib/chainproxy/rpcInterfaceMessages/jsonRPCMessage_test.go[160]

+func TestParseJsonRPCMsgWithBatchFlag(t *testing.T) {
Evidence
PR Compliance ID 4 requires new/updated tests to follow the TestComponent_Scenario naming
convention. The added test is named TestParseJsonRPCMsgWithBatchFlag without a scenario suffix.

AGENTS.md
protocol/chainlib/chainproxy/rpcInterfaceMessages/jsonRPCMessage_test.go[160-160]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The new test name does not follow the required `TestComponent_Scenario` naming convention.
## Issue Context
Repository compliance requires consistent test naming for maintainability and searchability.
## Fix Focus Areas
- protocol/chainlib/chainproxy/rpcInterfaceMessages/jsonRPCMessage_test.go[160-160]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


4. TestCheckUTXOResponseAndFixReply not table-driven 📘 Rule violation ⚙ Maintainability
Description
The newly added test cases are implemented as a sequence of t.Run blocks rather than a
table-driven test structure, which the repository expects when multiple similar scenarios are being
validated. This reduces maintainability as new scenarios are added.
Code

protocol/chainlib/common_test.go[R398-455]

+func TestCheckUTXOResponseAndFixReply(t *testing.T) {
+	t.Run("single_response_preserves_error_null", func(t *testing.T) {
+		// BTC-family nodes return "error":null; the relay pipeline uses omitempty which strips it
+		input := `{"jsonrpc":"2.0","id":"1","result":"abc","error":null}`
+		result := checkUTXOResponseAndFixReply("DOGE", []byte(input))
+		// Should preserve error:null and strip jsonrpc (BTC uses JSON-RPC 1.0)
+		var parsed map[string]interface{}
+		require.NoError(t, json.Unmarshal([]byte(result), &parsed))
+		_, hasError := parsed["error"]
+		require.True(t, hasError, "error field must be present (even when null)")
+		_, hasJsonrpc := parsed["jsonrpc"]
+		require.False(t, hasJsonrpc, "jsonrpc field should be stripped for BTC-family chains")
+	})
+
+	t.Run("batch_response_preserves_error_null", func(t *testing.T) {
+		// Multi-element batch: relay pipeline reconstructs with jsonrpc:"2.0" and omitempty on error
+		input := `[{"jsonrpc":"2.0","id":"1","result":"hash1"},{"jsonrpc":"2.0","id":"2","result":"hash2"}]`
+		result := checkUTXOResponseAndFixReply("DOGE", []byte(input))
+		var parsed []map[string]interface{}
+		require.NoError(t, json.Unmarshal([]byte(result), &parsed))
+		require.Len(t, parsed, 2)
+		for i, elem := range parsed {
+			_, hasError := elem["error"]
+			require.True(t, hasError, "batch element %d must have error field", i)
+			_, hasJsonrpc := elem["jsonrpc"]
+			require.False(t, hasJsonrpc, "batch element %d should not have jsonrpc field", i)
+		}
+	})
+
+	t.Run("single_element_batch_response", func(t *testing.T) {
+		// Single-element batch must stay as array
+		input := `[{"jsonrpc":"2.0","id":"1773768178254-0","result":"23699c7e"}]`
+		result := checkUTXOResponseAndFixReply("DOGE", []byte(input))
+		var parsed []map[string]interface{}
+		require.NoError(t, json.Unmarshal([]byte(result), &parsed), "single-element batch must remain an array")
+		require.Len(t, parsed, 1)
+		require.Equal(t, "1773768178254-0", parsed[0]["id"])
+		_, hasError := parsed[0]["error"]
+		require.True(t, hasError, "error field must be present")
+		_, hasJsonrpc := parsed[0]["jsonrpc"]
+		require.False(t, hasJsonrpc, "jsonrpc field should be stripped")
+	})
+
+	t.Run("non_btc_chain_passthrough", func(t *testing.T) {
+		input := `{"jsonrpc":"2.0","id":1,"result":"abc"}`
+		result := checkUTXOResponseAndFixReply("ETH1", []byte(input))
+		require.Equal(t, input, result, "non-BTC chains should pass through unchanged")
+	})
+
+	t.Run("btc_with_actual_error", func(t *testing.T) {
+		input := `{"id":"1","error":{"code":-8,"message":"Block height out of range"},"result":null}`
+		result := checkUTXOResponseAndFixReply("BTC", []byte(input))
+		var parsed map[string]interface{}
+		require.NoError(t, json.Unmarshal([]byte(result), &parsed))
+		errorField := parsed["error"]
+		require.NotNil(t, errorField, "error field must be preserved when not null")
+	})
+}
Evidence
PR Compliance ID 4 requires table-driven tests where appropriate and standard naming. This change
adds multiple closely related scenarios as separate t.Run blocks inside one test function rather
than a table ([]struct{...}) iterated over.

AGENTS.md
protocol/chainlib/common_test.go[398-455]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`TestCheckUTXOResponseAndFixReply` adds multiple scenario checks but is not structured as a table-driven test.
## Issue Context
Table-driven tests make it easier to add new scenarios and keep assertions uniform across similar inputs/outputs.
## Fix Focus Areas
- protocol/chainlib/common_test.go[398-455]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

ⓘ The new review experience is currently in Beta. Learn more

Grey Divider

Qodo Logo

Comment thread protocol/chainlib/chainproxy/rpcInterfaceMessages/jsonRPCMessage.go
Comment thread protocol/chainlib/tendermintRPC.go
@codecov

codecov Bot commented Mar 18, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 93.22034% with 4 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
.../chainproxy/rpcInterfaceMessages/jsonRPCMessage.go 88.00% 2 Missing and 1 partial ⚠️
protocol/chainlib/jsonRPC.go 80.00% 1 Missing ⚠️
Flag Coverage Δ
consensus 8.71% <ø> (ø)
protocol 33.63% <93.22%> (+0.01%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing lines Coverage Δ
protocol/chainlib/common.go 52.84% <100.00%> (+10.86%) ⬆️
protocol/chainlib/tendermintRPC.go 40.27% <100.00%> (+0.35%) ⬆️
protocol/chainlib/jsonRPC.go 44.65% <80.00%> (+0.23%) ⬆️
.../chainproxy/rpcInterfaceMessages/jsonRPCMessage.go 46.15% <88.00%> (+6.29%) ⬆️

... and 9 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@github-actions

github-actions Bot commented Mar 18, 2026

Copy link
Copy Markdown

Test Results

0 tests  ±0   0 ✅ ±0   0s ⏱️ ±0s
0 suites ±0   0 💤 ±0 
7 files   ±0   0 ❌ ±0 

Results for commit 0142119. ± Comparison against base commit 28c9192.

♻️ This comment has been updated with latest results.

Comment thread protocol/chainlib/chainproxy/rpcInterfaceMessages/jsonRPCMessage.go
nimrod-teich and others added 2 commits March 19, 2026 13:11
ParseJsonRPCMsgWithBatchFlag now:
- Strips UTF-8 BOM (0xEF 0xBB 0xBF) before parsing
- Skips JSON whitespace to find the true first byte for batch detection
- Falls back to batch unmarshal if single-object unmarshal fails

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
For single-element batches, CompareRequestedBlockInBatch was never
called (it only runs for idx > 0), leaving earliestRequestedBlock
at its init value (LATEST_BLOCK for tendermint, 0 for jsonrpc).
This broke downstream routing that relies on RequestedBlock().

With one message in the batch, earliest == latest by definition.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Comment thread protocol/chainlib/jsonRPC.go
Add tests for both JsonRPC and TendermintRPC parsers confirming that
a single-element batch requesting a specific block has earliest ==
latest, not the init value (0 or LATEST_BLOCK).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@nimrod-teich nimrod-teich merged commit 9d5d2e2 into main Mar 19, 2026
32 checks passed
@nimrod-teich nimrod-teich deleted the fix/utxo-single-element-batch-response branch March 19, 2026 12:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants