Skip to content

Commit bb1ce79

Browse files
sethatwoodclaude
andcommitted
docs(phase-05): complete phase execution and verification
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 97e514c commit bb1ce79

2 files changed

Lines changed: 172 additions & 2 deletions

File tree

.planning/REQUIREMENTS.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ Requirements for the Network Participant milestone. Each maps to roadmap phases.
1616

1717
### RPC
1818

19-
- [ ] **RPC-01**: Node maintains a transaction index mapping txid to block file position
19+
- [x] **RPC-01**: Node maintains a transaction index mapping txid to block file position
2020
- [x] **RPC-02**: User can query confirmed transactions by txid via getrawtransaction RPC
2121
- [x] **RPC-03**: User can retrieve raw block hex via getblock RPC at verbosity=0
2222
- [x] **RPC-04**: getblockchaininfo returns correct mediantime (median of previous 11 block timestamps)
@@ -74,7 +74,7 @@ Which phases cover which requirements. Updated during roadmap creation.
7474
| P2P-04 | Phase 3 | Complete |
7575
| P2P-03 | Phase 4 | Complete |
7676
| TEST-01 | Phase 4 | Complete |
77-
| RPC-01 | Phase 5 | Pending |
77+
| RPC-01 | Phase 5 | Complete |
7878
| RPC-02 | Phase 5 | Complete |
7979
| RPC-03 | Phase 5 | Complete |
8080
| RPC-04 | Phase 5 | Complete |
Lines changed: 170 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,170 @@
1+
---
2+
phase: 05-storage-layer-and-core-rpc
3+
verified: 2026-02-21T00:00:00Z
4+
status: passed
5+
score: 4/4 success criteria verified
6+
gaps:
7+
- truth: "After a chain reorganization, getrawtransaction for a transaction in a disconnected block returns not-found — stale txindex entries are deleted from blocks.db before the in-memory UTXO revert"
8+
status: partial
9+
reason: "Implementation is correct and wired. REQUIREMENTS.md checkbox for RPC-01 was never updated from [ ] to [x] after Plan 05-01 completed. The traceability table also still shows 'Pending'. The index infrastructure backing this success criterion is fully implemented; only the requirements document is stale."
10+
artifacts:
11+
- path: ".planning/REQUIREMENTS.md"
12+
issue: "RPC-01 checkbox is [ ] (unchecked) and traceability row shows 'Pending' despite the tx_index being fully implemented in commit 3d941c8 and 32dcbcb"
13+
missing:
14+
- "Update RPC-01 checkbox from [ ] to [x] in REQUIREMENTS.md"
15+
- "Update RPC-01 traceability row from 'Pending' to 'Complete' in REQUIREMENTS.md"
16+
human_verification:
17+
- test: "getrawtransaction end-to-end with live synced node"
18+
expected: "curl -s -d '{\"method\":\"getrawtransaction\",\"params\":[\"<known_confirmed_txid>\"]}' http://localhost:8332/ returns witness-serialized hex; txids in pruned blocks return error -5 (not-found)"
19+
why_human: "Requires a synced mainnet node with at least one block confirmed and a known txid; cannot verify disk I/O path programmatically"
20+
- test: "getblock verbosity=0 end-to-end with live synced node"
21+
expected: "curl -s -d '{\"method\":\"getblock\",\"params\":[\"<known_block_hash>\",0]}' http://localhost:8332/ returns a hex string that decodes to a valid block"
22+
why_human: "Requires a synced node with block data on disk"
23+
- test: "getblockchaininfo mediantime with live synced node"
24+
expected: "jq .result.mediantime returns a non-zero Unix timestamp close to current time (not 0); matches the median of the 11 most recent block timestamps"
25+
why_human: "Requires a synced node with at least one block in the in-memory block_index_map"
26+
- test: "Reorg recovery — getrawtransaction returns not-found after block is disconnected"
27+
expected: "After simulating or observing a reorg, a txid that was in a disconnected block returns not-found from getrawtransaction"
28+
why_human: "Requires a real or simulated reorg to exercise the chaser_confirm_reorganize path"
29+
---
30+
31+
# Phase 5: Storage Layer and Core RPC Verification Report
32+
33+
**Phase Goal:** Operators can look up any confirmed transaction by txid, retrieve raw block hex, and read a correct mediantime — all backed by a durable transaction index that survives chain reorganizations
34+
35+
**Verified:** 2026-02-21
36+
**Status:** gaps_found (documentation gap only — one requirements checkbox not updated)
37+
**Re-verification:** No — initial verification
38+
39+
---
40+
41+
## Goal Achievement
42+
43+
### Observable Truths (Success Criteria)
44+
45+
| # | Truth | Status | Evidence |
46+
|---|-------|--------|----------|
47+
| 1 | getrawtransaction with a confirmed txid returns raw hex; pruned block txids return not-found | VERIFIED | rpc.c:1958 calls txindex_lookup, then block_storage_read, then tx_compute_txid scan; pruned/unavailable check at rpc.c:1967-1972 |
48+
| 2 | getblock verbosity=0 returns raw witness-serialized block hex | VERIFIED | rpc.c:1815-1843: block_index_db_lookup_by_hash + BLOCK_STATUS_PRUNED/HAVE_DATA check + block_storage_read + json_builder_hex |
49+
| 3 | getblockchaininfo mediantime equals median of previous 11 block timestamps (not 0) | VERIFIED | rpc.c:1662-1696: in-memory block_index_map walk, insertion sort, timestamps[ts_count/2] — replaces prior `json_builder_uint(builder, 0)` stub |
50+
| 4 | After reorg, getrawtransaction for disconnected block tx returns not-found; deletion before UTXO revert | VERIFIED (code), PARTIAL (docs) | chaser_confirm.c:280-293 calls txindex_delete_by_block at line 285 before chainstate_revert_block at line 296; RPC-01 checkbox in REQUIREMENTS.md not updated |
51+
52+
**Score:** 3/4 automated — 4th criterion is implemented correctly but has a documentation discrepancy in REQUIREMENTS.md (RPC-01 checkbox stale).
53+
54+
---
55+
56+
## Required Artifacts
57+
58+
### Plan 05-01 Artifacts
59+
60+
| Artifact | Expected | Status | Details |
61+
|----------|----------|--------|---------|
62+
| `include/block_index_db.h` | txindex_insert, txindex_lookup, txindex_delete_by_block, txindex_insert_block declarations | VERIFIED | Lines 655-719: all four functions declared with full doc comments; prepared statement fields at lines 89-91 |
63+
| `src/storage/block_index_db.c` | tx_index schema creation, prepared statements, all txindex functions | VERIFIED | Schema at line 147-159; three prepared statements at lines 233-249; finalize at lines 269-271; four full implementations at lines 1592-1746 with mutex protection |
64+
| `src/app/node.c` | txindex_insert_block call in node_apply_block | VERIFIED | Lines 3692-3709: txindex_insert_block called after consensus succeeds and block_index_db_lookup_by_hash retrieves file position; before UTXO DB step (Step 4 at line 3720) |
65+
| `src/node/chaser_confirm.c` | txindex_delete_by_block call in reorg loop before UTXO revert | VERIFIED | Lines 280-293: txindex_delete_by_block at line 285 inside reorg for-loop; chainstate_revert_block at line 296 — ordering is correct |
66+
67+
### Plan 05-02 Artifacts
68+
69+
| Artifact | Expected | Status | Details |
70+
|----------|----------|--------|---------|
71+
| `src/app/rpc.c` | getrawtransaction confirmed tx lookup, getblock v=0 raw hex, mediantime MTP calculation | VERIFIED | txindex_lookup at line 1958; block_storage_read at lines 1836 and 1983; block_index_map_lookup at line 1679; no stub returns remain in these three handlers |
72+
73+
---
74+
75+
## Key Link Verification
76+
77+
### Plan 05-01 Key Links
78+
79+
| From | To | Via | Status | Details |
80+
|------|----|-----|--------|---------|
81+
| `src/app/node.c` (node_apply_block) | `src/storage/block_index_db.c` (txindex_insert_block) | txindex_insert_block after consensus_apply_block | WIRED | Confirmed at node.c:3697; called only when block_index_db_open and data_file >= 0 |
82+
| `src/node/chaser_confirm.c` (reorg loop) | `src/storage/block_index_db.c` (txindex_delete_by_block) | txindex_delete_by_block before chainstate_revert_block | WIRED | Confirmed at chaser_confirm.c:285; ordering verified against revert at line 296 |
83+
84+
### Plan 05-02 Key Links
85+
86+
| From | To | Via | Status | Details |
87+
|------|----|-----|--------|---------|
88+
| `src/app/rpc.c` (rpc_getrawtransaction) | block_index_db.c (txindex_lookup) | txindex_lookup for txid → block file position, then block_storage_read + block_parse + tx scan | WIRED | rpc.c:1958 calls txindex_lookup; rpc.c:1983 calls block_storage_read; rpc.c:2000-2022 scans txs by txid comparison |
89+
| `src/app/rpc.c` (rpc_getblock v=0) | blocks_storage.c (block_storage_read) | block_index_db_lookup_by_hash for file position, then block_storage_read for raw bytes | WIRED | rpc.c:1819 lookup; rpc.c:1823-1828 prune check; rpc.c:1836 block_storage_read; rpc.c:1840 json_builder_hex |
90+
| `src/app/rpc.c` (rpc_getblockchaininfo) | chainstate.c (block_index_map_lookup) | in-memory walk from tip_index backwards 11 blocks via prev_hash | WIRED | rpc.c:1671 chainstate_get_block_index_map; rpc.c:1679 block_index_map_lookup in while-loop |
91+
92+
---
93+
94+
## Requirements Coverage
95+
96+
| Requirement | Source Plan | Description | Status | Evidence |
97+
|-------------|------------|-------------|--------|----------|
98+
| RPC-01 | 05-01 | Node maintains a transaction index mapping txid to block file position | IMPLEMENTED, DOCS STALE | tx_index schema in block_index_db.c:147; all four CRUD functions implemented; REQUIREMENTS.md checkbox not updated to [x] |
99+
| RPC-02 | 05-02 | User can query confirmed transactions by txid via getrawtransaction RPC | SATISFIED | rpc.c:1953-2027: full confirmed tx lookup path via txindex_lookup |
100+
| RPC-03 | 05-02 | User can retrieve raw block hex via getblock RPC at verbosity=0 | SATISFIED | rpc.c:1815-1843: witness-serialized bytes returned via block_storage_read |
101+
| RPC-04 | 05-02 | getblockchaininfo returns correct mediantime | SATISFIED | rpc.c:1662-1696: MTP computed from in-memory block_index_map walk, insertion sort, median at ts_count/2 |
102+
103+
**RPC-01 documentation discrepancy:** The REQUIREMENTS.md checklist shows `- [ ] **RPC-01**` (unchecked) and the traceability table shows `Pending`. The implementation is complete (commits 3d941c8 and 32dcbcb). This is a stale document, not a missing implementation. The checklist for RPC-02, RPC-03, and RPC-04 are all correctly marked `[x]`.
104+
105+
---
106+
107+
## Anti-Patterns Found
108+
109+
| File | Line | Pattern | Severity | Impact |
110+
|------|------|---------|----------|--------|
111+
| `src/app/rpc.c` | 1902 | `TODO: get tx count from storage` | Info | nTx field in getblock verbosity=1 path — explicitly deferred in Plan 05-02 per plan text; not a Phase 5 requirement |
112+
| `src/app/rpc.c` | 2241 | `TODO: process template_request` | Info | getblocktemplate stub — Phase 6 scope (RPC-05) |
113+
| `src/app/node.c` | 1519 | `TODO: Implement proper storage callback` | Info | Pre-existing TODO from earlier phase |
114+
| `src/node/chaser_confirm.c` | 66 | `TODO: Get from config` | Info | Pre-existing TODO for checkpoint config |
115+
116+
No blockers. The two warnings from the clean build (`get_batch_size_for_height` in download_mgr.c, `node_flush_utxo_shutdown` in node.c) are pre-existing from earlier phases — confirmed by git log showing download_mgr.c last modified in phase 1 work.
117+
118+
---
119+
120+
## Mediantime Correctness Analysis
121+
122+
The MTP implementation at rpc.c:1662-1696 is mathematically correct:
123+
124+
- Collects up to 11 timestamps walking backward from `tip_index` via `cur->prev_hash`
125+
- Guards against walking past genesis with `if (cur->height == 0) break`
126+
- Sorts 11 elements ascending using insertion sort
127+
- Takes `timestamps[ts_count / 2]` — with ts_count=11 this is index 5, the 6th of 11 elements (true median)
128+
- With fewer than 11 blocks (e.g., early chain), `ts_count / 2` still gives the correct median
129+
- The tip's own timestamp is included as the most recent block, consistent with Bitcoin Core MTP calculation
130+
131+
---
132+
133+
## Human Verification Required
134+
135+
### 1. getrawtransaction Confirmed Lookup
136+
137+
**Test:** With a synced pruning node, call `curl -s -d '{"method":"getrawtransaction","params":["<confirmed_txid>"]}' http://localhost:8332/`
138+
**Expected:** Returns witness-serialized hex of the transaction; calling for a txid in a pruned block returns a JSON error (not-found)
139+
**Why human:** Requires a synced node with at least one indexed block and a known txid
140+
141+
### 2. getblock Verbosity=0 Raw Hex
142+
143+
**Test:** Call `curl -s -d '{"method":"getblock","params":["<known_block_hash>",0]}' http://localhost:8332/`
144+
**Expected:** Returns a hex string whose decoded bytes parse as a valid block; the block hash of the decoded header matches the request param
145+
**Why human:** Requires a synced node with block data on disk
146+
147+
### 3. getblockchaininfo Mediantime Non-Zero
148+
149+
**Test:** Call `curl -s -d '{"method":"getblockchaininfo"}' http://localhost:8332/ | jq .result.mediantime`
150+
**Expected:** Returns a Unix timestamp in a reasonable range (not 0, not current wall time but within a few hours of it for a synced node)
151+
**Why human:** Requires a synced node with blocks in the in-memory block_index_map
152+
153+
### 4. Reorg Txindex Cleanup
154+
155+
**Test:** Observe or simulate a chain reorg (even a 1-block reorg during normal sync); after the reorg, call getrawtransaction for a txid that was only in the disconnected block
156+
**Expected:** Returns not-found (the txindex deletion at chaser_confirm.c:285 fired before the in-memory UTXO revert)
157+
**Why human:** Real reorgs are rare on mainnet and cannot be triggered programmatically in the running node
158+
159+
---
160+
161+
## Gaps Summary
162+
163+
The single gap is documentation-only: **RPC-01 checkbox in REQUIREMENTS.md was not updated** after Plan 05-01 completed. The implementation is complete, correct, and wired. No code changes are needed.
164+
165+
The four success criteria listed in the phase goal are all implemented in the codebase. The gap is that REQUIREMENTS.md still shows RPC-01 as `[ ]` (pending) despite the tx_index being fully functional. This should be a trivial documentation fix rather than a re-plan.
166+
167+
---
168+
169+
*Verified: 2026-02-21*
170+
*Verifier: Claude (gsd-verifier)*

0 commit comments

Comments
 (0)