Skip to content

Commit d6d6ffe

Browse files
committed
Add object reference support via ref field in protocol
Introduces the object reference and registry pattern for persisting objects across requests. Test cases now include a ref field directly in the request when the expected result is a reference, allowing handlers to store and reuse objects like context, block, and chain throughout the tests. Documents the ref field and registry pattern in handler-spec.md.
1 parent a958350 commit d6d6ffe

File tree

3 files changed

+43
-1
lines changed

3 files changed

+43
-1
lines changed

docs/handler-spec.md

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,14 +17,16 @@ Handlers communicate with the test runner via **stdin/stdout**:
1717
{
1818
"id": "unique-request-id",
1919
"method": "method_name",
20-
"params": { /* method-specific parameters */ }
20+
"params": { /* method-specific parameters */ },
21+
"ref": "reference-name"
2122
}
2223
```
2324

2425
**Fields:**
2526
- `id` (string, required): Unique identifier for this request
2627
- `method` (string, required): The operation to perform. Each unique method must be implemented by the handler to exercise the corresponding binding API operation.
2728
- `params` (object, optional): Method-specific parameters
29+
- `ref` (string, optional): Reference name for storing the returned object. Required for methods that return object references (see [Object References and Registry](#object-references-and-registry))
2830

2931
### Response
3032

@@ -56,6 +58,30 @@ Handlers communicate with the test runner via **stdin/stdout**:
5658
3. **Error Handling**: Return error responses for invalid requests or failed operations
5759
4. **Exit Behavior**: Exit cleanly when stdin closes
5860

61+
## Object References and Registry
62+
63+
Many operations return objects (contexts, blocks, chains, etc.) that must persist across requests. The protocol uses named references and a registry pattern:
64+
65+
**Creating Objects**: Methods that return objects require a `ref` field in the request. The handler stores the object in a registry under that name and returns the reference name as the result.
66+
67+
```json
68+
// Request
69+
{"id": "1", "method": "btck_context_create", "params": {...}, "ref": "$ctx1"}
70+
// Response
71+
{"id": "1", "result": "$ctx1", "error": null}
72+
// Handler action: registry["$ctx1"] = created_context_ptr
73+
```
74+
75+
**Using Objects**: When a parameter is marked as `(reference, required)`, the runner passes the reference name and the handler looks it up:
76+
77+
```json
78+
// Request
79+
{"id": "2", "method": "btck_chainstate_manager_create", "params": {"context": "$ctx1"}, "ref": "$csm1"}
80+
// Handler action: Look up registry["$ctx1"], create manager, store as registry["$csm1"]
81+
```
82+
83+
**Implementation**: Handlers must maintain a registry (map of reference names to object pointers) throughout their lifetime. Objects remain alive until explicitly destroyed or handler exit.
84+
5985
## Test Suites and Expected Responses
6086

6187
The conformance tests are organized into suites, each testing a specific aspect of the Bitcoin Kernel bindings. Test files are located in [`../testdata/`](../testdata/).

runner/runner.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -228,6 +228,19 @@ func validateResponseForError(test TestCase, resp *Response) error {
228228
return nil
229229
}
230230

231+
// extractRefFromExpected extracts a reference name from the expected result if it's a
232+
// string starting with "$". Returns empty string if not a reference.
233+
func extractRefFromExpected(expected Response) string {
234+
var resultStr string
235+
if err := json.Unmarshal(expected.Result, &resultStr); err != nil {
236+
return ""
237+
}
238+
if len(resultStr) > 1 && resultStr[0] == '$' {
239+
return resultStr
240+
}
241+
return ""
242+
}
243+
231244
// validateResponseForSuccess validates that a response correctly represents a success case.
232245
// It ensures the response contains no error, and if a result is expected, it matches the
233246
// expected value.

runner/types.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,9 @@ type Request struct {
3030
ID string `json:"id"`
3131
Method string `json:"method"`
3232
Params json.RawMessage `json:"params,omitempty"`
33+
// Ref specifies the name the handler should use to store the returned object reference
34+
// in its registry. Required for methods that return object handles (e.g., "$ctx1", "$csm1").
35+
Ref string `json:"ref,omitempty"`
3336
}
3437

3538
// Response represents a response from the handler.

0 commit comments

Comments
 (0)