Skip to content

fix(blob/http): mark a blob-store miss with a header so Exists tells it from a proxy 404 - #2057

Open
codenlighten wants to merge 2 commits into
bsv-blockchain:mainfrom
codenlighten:fix/1965-blob-exists-miss-header
Open

codenlighten wants to merge 2 commits into
bsv-blockchain:mainfrom
codenlighten:fix/1965-blob-exists-miss-header

Conversation

@codenlighten

@codenlighten codenlighten commented Oct 26, 2026 •

Copy link
Copy Markdown
Contributor

Refs #1965.

Problem

HTTPStore.Exists sends HEAD, and a HEAD response has no body, so it could not use the NotFoundMsg body-check that #1963 gave GET: it read any 404 as "not held". A wrong base URL or a proxy answering 404 therefore made every blob look absent to callers that branch on Exists.

Fix

  • Server marks its own miss with a header. X-Blob-Miss: 1 is set on every path that answers a miss: handleExists (the HEAD/Exists path) and writeStoreError (GET, ranged GET and PATCH, which all route their miss through it). http.Error sets the status after the header, so it survives.
  • Exists reads a 404 as "not held" only when the header is present. A 404 that carries X-Blob-Miss is a miss; any other 404 is logged (address in the log line, not the error text, as fix(blob/http): keep a blob-store fault from reading as a miss over HTTP #1963 does) and — see skew below — can be surfaced as a StorageError.
  • GET prefers the header too. GetIoReader's miss test is now header present || NotFoundMsg body; the || short-circuits so the body is only read when the header is absent. This keeps working against servers that predate the header and makes GET robust to a proxy that echoes a Not found-ish body.

Version skew

An old server sends no header. Until every blob server does, a bare HEAD 404 must still read as a miss, so the strict behaviour is opt-in and off by default: Exists treats a header-less 404 as a miss unless the store URL carries ?requireMissHeader=true, in which case it is a StorageError. (The issue also floated advertising the header on /health; the setting is the simpler first step and can become the default once every server ships the header. No shipped config uses an HTTP blob store today, so the skew mostly concerns test harnesses.)

The MissHeader constant lives in the client package (stores/blob/http) and the server references it as it already does for NotFoundMsg, so the two cannot drift.

Tests

  • stores/blob/http: TestHTTPStore_ExistsUsesMissHeader — 404+header is not-held/no-error; 200 is held; a bare 404 is a miss by default; a bare 404 is a StorageError under ?requireMissHeader=true (and the fault does not name the server). The existing TestHTTPStore_GetMissIsNotFound still passes (no case sets the header, so the body-check fallback is unchanged).
  • stores/blob: TestHTTPBlobServer_MarksMissWithHeader — the Exists/HEAD miss and the GET miss both carry X-Blob-Miss.

Discrimination: reverting just the behavioural lines (the server's header-set and the client's Exists header-branch), keeping the new symbols, makes both new tests fail — so they pin the behaviour, not vacuously pass.

…it from a proxy 404

Fixes bsv-blockchain#1965.

HTTPStore.Exists sends HEAD, and a HEAD response has no body, so it could not use
the NotFoundMsg body-check that bsv-blockchain#1963 gave Get: it read any 404 as a miss. A wrong
base URL or a proxy answering 404 therefore made every blob look absent to callers
that branch on Exists.

The blob server now marks its own miss with X-Blob-Miss: 1 on every path that
answers one -- handleExists (HEAD) and writeStoreError (GET, ranged GET, PATCH).
Exists reads a 404 as a miss only when the header is present; any other 404 is
logged (the address in the log line, not the error text, as bsv-blockchain#1963 does) and, when
the store URL carries ?requireMissHeader=true, returned as a StorageError. The flag
is off by default so a mixed fleet still works with servers that predate the header;
it can become the default once every server sends it. Get prefers the header too,
falling back to the NotFoundMsg body, and drains the small 404 body first so the
connection stays reusable.

The MissHeader constant lives in the client package and the server references it as
it already does for NotFoundMsg, so the two cannot drift.

Tests: Exists returns not-held for a 404 with the header and for a bare 404 by
default, a StorageError for a bare 404 under requireMissHeader, and still not-held
for a header-carrying 404 under requireMissHeader; the server marks both its HEAD
and Get misses. Reverting the behavioural lines fails these, so they pin the
behaviour and do not vacuously pass.

@icellan icellan left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Header approach is right. Two things block it: the strict mode that fixes the issue is off by default, and the GET header branch has no test.

Comment thread stores/blob/http/http.go Resolved
Comment thread stores/blob/http/http.go Resolved

@oskarszoon oskarszoon left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The miss header is applied on the server paths and the client distinguishes marked misses from foreign 404s when requireMissHeader=true. I found no P0/P1 defect at this head. Default-off behavior follows the version-skew option in #1965, so obtaining strict HEAD classification still requires enabling the URL option after upgrading the blob servers.

@ordishs ordishs left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The change is correct and safe for a mixed fleet. The server sets X-Blob-Miss on every miss path that I found. Exists and GetIoReader read the header correctly, and the strict mode stays opt-in. Tests pass with -race.

Follow-ups. I agree with the open points from the other review:

  1. stores/blob/http/http.go:348-355: no test covers the GET header branch. With miss := false in place of the header check, both packages still pass. Please add a case where a 404 carries X-Blob-Miss and a body other than NotFoundMsg, and the call returns ErrNotFound.
  2. stores/blob/http/http.go:159: requireMissHeader does not appear in docs/references/settings/stores/blob_settings.md. Please add it to the URL parameter tables (for http:// stores, default false).
  3. Default-off and Fixes #1965: default-off follows the version-skew option in the issue. But the merge closes the issue while every deployment keeps the old Exists behaviour. Use Refs #1965, or open a follow-up issue to flip the default.
  4. Optional, http.go:254: in compat mode, the Warn fires on every miss from a server without the header. Log at Debug, or log once, while strict mode is off.
  5. Optional, Del (http.go:543): Del still checks only the body. If you fold the header check into isBlobServerMiss, Del gets the header check too and the inline branch in GetIoReader goes away.

@freemans13 freemans13 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approve at 357b27f. I found no blocking correctness defect or additional finding beyond the existing feedback.

The server marks its HEAD and shared GET/ranged-GET/PATCH miss paths before writing the status. Strict Exists distinguishes an unmarked 404 from a blob miss, and GET preserves compatibility with the old response body. Default-off follows the client-setting option explicitly proposed in the version-skew section of issue 1965, so I do not consider that default a correctness blocker.

I agree with these follow-ups already raised:

  • Add the GET header-only regression case. I disabled the header check through a temporary Go build overlay, and both packages still passed twice under -race. A 404 with X-Blob-Miss: 1 and a body other than NotFoundMsg must return ErrNotFound. Existing discussion.
  • Document requireMissHeader in docs/references/settings/stores/blob_settings.md, including its default and when to enable it. Track the future default change separately if this PR closes the issue. Existing review.

Local verification passed on Go 1.27.3, darwin/arm64:

SETTINGS_CONTEXT=test go test -race -tags testtxmetacache -count=2 ./stores/blob/http ./stores/blob

GitHub's test and smoke-test workflows are action_required; they have not run. I did not run the full repository suite or lint locally. The checkout is unchanged.

…uireMissHeader

Review follow-ups on the miss-header change.

isBlobServerMiss now decides on MissHeader first and falls back to the NotFoundMsg
body, so GetIoReader (and through it Get) and Del read a header-marked 404 the same
way. The inline header branch in GetIoReader is gone, and Del no longer needs the
body to match when the header is present. The body is always drained, so the
connection stays reusable.

Exists logs a bare 404 at Debug while requireMissHeader is off, because every
legitimate miss from a server that predates the header lands there; it stays a Warn
when the flag is on and the 404 is returned as a fault.

TestHTTPStore_MissHeaderAloneDecidesAMiss answers GET and DELETE with the header and a
body that is not NotFoundMsg: the server also sends NotFoundMsg, which had hidden a
header branch that never fired. Disabling the header check fails the GetIoReader, Get
and Del subtests; the two without-header cases pin that a foreign body alone is still
a store fault.

requireMissHeader is added to the URL parameter table in blob_settings.md.

@icellan icellan left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Both blockers addressed. Nits below are non-blocking.

Nit outside the diff: the doc comments on Exists (~218), GetIoReader (~329) and Del (~513) still describe the old contract. Under requireMissHeader a bare HEAD 404 is a storage error, and the header now decides a miss whatever the body says.

Comment thread stores/blob/http/http.go
func isBlobServerMiss(resp *http.Response) bool {
body, err := io.ReadAll(io.LimitReader(resp.Body, notFoundBodyLimit))

// The header decides on its own: it is set on every miss path, whatever the body says.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: any non-empty value counts, so X-Blob-Miss: 0 from a proxy reads as a miss. The server always sends 1; compare against that in one helper and use it here and in Exists (line 258) instead of two copies.

Comment thread stores/blob/http/http.go
case http.StatusNotFound:
// The blob server marks its own miss with MissHeader on every miss path. A HEAD
// has no body, so unlike GET this cannot fall back to NotFoundMsg - the header is
// the only signal that tells the server's miss from a wrong base URL or a proxy

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: the header proves a blob server answered, not the right one. A base URL pointed at another Teranode blob server (e.g. the block store instead of the subtree store) still gets X-Blob-Miss on every key and reads as empty, even with requireMissHeader=true. Worth softening "tells it from a wrong base URL" here and in blob_settings.md.

@sonarqubecloud

Copy link
Copy Markdown

@github-actions

Copy link
Copy Markdown
Contributor

Benchmark Comparison Report

Baseline: main (unknown)

Current: PR-2057 (e810646)

Summary

  • Regressions: 0
  • Improvements: 0
  • Unchanged: 169
  • Significance level: p < 0.05
All benchmark results (sec/op)
Benchmark Baseline Current Change p-value
_NewBlockFromBytes-4 905.8n 896.3n ~ 0.100
Block_ValidOrderAndBlessed_DiskVsMemory/leaves=1024/memory-4 11.53m 11.54m ~ 0.700
Block_ValidOrderAndBlessed_DiskVsMemory/leaves=1024/disk_1-4 11.72m 11.71m ~ 1.000
Block_ValidOrderAndBlessed_DiskVsMemory/leaves=1024/disk_2-4 12.78m 12.78m ~ 0.100
Block_ValidOrderAndBlessed_DiskVsMemory/leaves=16384/memo... 20.68m 20.40m ~ 1.000
Block_ValidOrderAndBlessed_DiskVsMemory/leaves=16384/disk... 26.15m 26.28m ~ 0.700
Block_ValidOrderAndBlessed_DiskVsMemory/leaves=16384/disk... 26.13m 26.14m ~ 1.000
Block_ValidOrderAndBlessed_DiskVsMemory/leaves=131072/mem... 78.84m 78.68m ~ 1.000
Block_ValidOrderAndBlessed_DiskVsMemory/leaves=131072/dis... 176.7m 175.8m ~ 0.400
Block_ValidOrderAndBlessed_DiskVsMemory/leaves=131072/dis... 177.0m 177.7m ~ 0.700
BlockTxMap/txs=16384/nodeindex-4 1.479m 1.479m ~ 1.000
BlockTxMap/txs=16384/swiss-4 7.278m 7.182m ~ 0.400
BlockTxMap/txs=262144/nodeindex-4 11.46m 11.34m ~ 0.100
BlockTxMap/txs=262144/swiss-4 28.30m 28.17m ~ 1.000
BlockTxMap/txs=4194304/nodeindex-4 290.5m 290.2m ~ 0.700
BlockTxMap/txs=4194304/swiss-4 635.8m 631.5m ~ 0.700
TxMapPut_MemoryVsDisk/txs=100000/memory-4 4.405m 4.375m ~ 1.000
TxMapPut_MemoryVsDisk/txs=100000/disk_1-4 7.471m 7.361m ~ 0.200
TxMapPut_MemoryVsDisk/txs=100000/disk_2-4 6.767m 6.781m ~ 1.000
TxMapGetFrozen_MemoryVsDisk/txs=100000/memory/hit-4 2.651m 2.669m ~ 1.000
TxMapGetFrozen_MemoryVsDisk/txs=100000/memory/miss-4 2.096m 2.106m ~ 0.700
TxMapGetFrozen_MemoryVsDisk/txs=100000/disk_1/hit-4 1.091m 1.113m ~ 0.200
TxMapGetFrozen_MemoryVsDisk/txs=100000/disk_1/miss-4 1.172m 1.166m ~ 0.400
TxMapGetFrozen_MemoryVsDisk/txs=100000/disk_2/hit-4 1.097m 1.108m ~ 0.100
TxMapGetFrozen_MemoryVsDisk/txs=100000/disk_2/miss-4 1.175m 1.163m ~ 0.400
ParentSpendsSetIfNotExists_MemoryVsDisk/inputs=200000/dis... 16.40m 16.46m ~ 0.700
ParentSpendsSetIfNotExists_MemoryVsDisk/inputs=200000/dis... 15.27m 15.15m ~ 0.400
InpointDedup/txs=16K-4 3.605m 3.567m ~ 0.700
InpointDedup/txs=128K-4 12.37m 12.37m ~ 0.700
InpointDedup/txs=1M-4 90.78m 90.92m ~ 0.700
InpointDedup_TinyRuns-4 35.01m 34.96m ~ 0.700
MiningCandidate_Stringify_Short-4 112.1n 113.6n ~ 0.100
MiningCandidate_Stringify_Long-4 790.0n 779.6n ~ 0.400
MiningSolution_Stringify-4 445.3n 442.0n ~ 0.800
BlockInfo_MarshalJSON-4 1.087µ 1.168µ ~ 1.000
DecodeSubtreeMeta/go-subtree-4 113.8m 108.9m ~ 0.400
DecodeSubtreeMeta/packed-4 30.31m 30.83m ~ 1.000
DecodeSubtreeMeta/go-subtree/parallel-4 55.25m 56.14m ~ 1.000
DecodeSubtreeMeta/packed/parallel-4 16.09m 16.49m ~ 0.700
ValidateSubtreeNodesMatchKey/leaves=1024-4 176.7µ 176.7µ ~ 0.700
ValidateSubtreeNodesMatchKey/leaves=1048576-4 54.65m 54.60m ~ 0.400
NewFromBytes-4 68.21n 70.15n ~ 0.200
AddTxBatchColumnar_Validation-4 1.140µ 1.159µ ~ 1.000
OffsetValidationLoop-4 329.2n 330.2n ~ 1.000
BuildSubtreeMeta/serialized-4 6.099m 5.383m ~ 0.100
BuildSubtreeMeta/decoded-4 16.15m 15.94m ~ 0.200
Mine_EasyDifficulty-4 37.56µ 36.36µ ~ 0.400
Mine_WithAddress-4 4.534µ 4.316µ ~ 0.100
BlockAssembler_AddTx-4 0.02063n 0.01746n ~ 0.700
AddNode-4 11.11 11.07 ~ 1.000
AddNodeWithMap-4 11.36 11.47 ~ 1.000
DiskTxMap_SetIfNotExists-4 460.3n 511.0n ~ 0.100
DiskTxMap_SetIfNotExists_Parallel-4 155.7n 173.0n ~ 0.100
DiskTxMap_ExistenceOnly-4 242.7n 246.1n ~ 0.700
Queue-4 114.4n 119.6n ~ 0.100
AtomicPointer-4 5.341n 5.324n ~ 1.000
TxMapSetIfNotExists-4 34.40n 35.03n ~ 0.600
TxMapSetIfNotExistsDuplicate-4 34.00n 34.01n ~ 1.000
ChannelSendReceive-4 370.4n 372.3n ~ 1.000
DirectSubtreeAdd/4_per_subtree-4 87.80n 89.91n ~ 1.000
DirectSubtreeAdd/64_per_subtree-4 46.33n 47.48n ~ 0.700
DirectSubtreeAdd/256_per_subtree-4 46.06n 45.36n ~ 1.000
DirectSubtreeAdd/1024_per_subtree-4 45.34n 45.36n ~ 1.000
DirectSubtreeAdd/2048_per_subtree-4 43.46n 43.37n ~ 1.000
SubtreeProcessorAdd/4_per_subtree-4 256.8n 248.9n ~ 0.700
SubtreeProcessorAdd/64_per_subtree-4 265.3n 263.9n ~ 0.700
SubtreeProcessorAdd/256_per_subtree-4 279.3n 281.7n ~ 0.700
SubtreeProcessorAdd/1024_per_subtree-4 287.6n 285.5n ~ 1.000
SubtreeProcessorAdd/2048_per_subtree-4 284.7n 283.6n ~ 0.400
SubtreeProcessorRotate/4_per_subtree-4 281.4n 281.6n ~ 1.000
SubtreeProcessorRotate/64_per_subtree-4 279.4n 279.0n ~ 0.700
SubtreeProcessorRotate/256_per_subtree-4 280.2n 276.5n ~ 0.400
SubtreeProcessorRotate/1024_per_subtree-4 275.6n 281.3n ~ 0.700
SubtreeNodeAddOnly/4_per_subtree-4 104.5n 104.5n ~ 1.000
SubtreeNodeAddOnly/64_per_subtree-4 77.51n 77.60n ~ 0.400
SubtreeNodeAddOnly/256_per_subtree-4 75.97n 76.20n ~ 0.400
SubtreeNodeAddOnly/1024_per_subtree-4 75.70n 75.72n ~ 0.700
SubtreeCreationOnly/4_per_subtree-4 171.7n 170.6n ~ 1.000
SubtreeCreationOnly/64_per_subtree-4 654.5n 624.9n ~ 1.000
SubtreeCreationOnly/256_per_subtree-4 1.768µ 1.746µ ~ 1.000
SubtreeCreationOnly/1024_per_subtree-4 6.029µ 6.007µ ~ 0.700
SubtreeCreationOnly/2048_per_subtree-4 11.28µ 11.16µ ~ 0.400
SubtreeProcessorOverheadBreakdown/64_per_subtree-4 272.0n 272.0n ~ 0.800
SubtreeProcessorOverheadBreakdown/1024_per_subtree-4 271.3n 279.5n ~ 0.200
ParallelGetAndSetIfNotExists/1k_nodes-4 1.020m 1.041m ~ 1.000
ParallelGetAndSetIfNotExists/10k_nodes-4 6.227m 6.293m ~ 0.700
ParallelGetAndSetIfNotExists/50k_nodes-4 7.965m 7.997m ~ 0.400
ParallelGetAndSetIfNotExists/100k_nodes-4 10.10m 10.16m ~ 0.700
SequentialGetAndSetIfNotExists/1k_nodes-4 816.7µ 825.8µ ~ 1.000
SequentialGetAndSetIfNotExists/10k_nodes-4 7.355m 7.098m ~ 0.700
SequentialGetAndSetIfNotExists/50k_nodes-4 20.93m 21.42m ~ 0.700
SequentialGetAndSetIfNotExists/100k_nodes-4 35.92m 36.76m ~ 0.200
ProcessOwnBlockSubtreeNodesParallel/1k_nodes-4 1.081m 1.097m ~ 0.400
ProcessOwnBlockSubtreeNodesParallel/10k_nodes-4 9.123m 9.327m ~ 0.400
ProcessOwnBlockSubtreeNodesParallel/100k_nodes-4 13.49m 13.69m ~ 0.100
ProcessOwnBlockSubtreeNodesSequential/1k_nodes-4 911.4µ 883.1µ ~ 0.700
ProcessOwnBlockSubtreeNodesSequential/10k_nodes-4 10.030m 9.931m ~ 1.000
ProcessOwnBlockSubtreeNodesSequential/100k_nodes-4 62.10m 63.39m ~ 0.700
CalcBlockWork-4 338.8n 337.3n ~ 0.700
CalculateWork-4 456.1n 472.5n ~ 0.700
CheckOldBlockIDs/on-chain-prefetch/1000-4 74.41µ 61.74µ ~ 0.700
CheckOldBlockIDs/in-memory-chain-check/1000-4 1.521m 1.630m ~ 0.200
CheckOldBlockIDs/on-chain-prefetch/10000-4 488.3µ 465.9µ ~ 0.700
CheckOldBlockIDs/in-memory-chain-check/10000-4 2.285m 2.228m ~ 0.100
BuildBlockLocatorString_Helpers/Size_10-4 1.551µ 1.356µ ~ 0.100
BuildBlockLocatorString_Helpers/Size_100-4 14.55µ 12.88µ ~ 0.100
BuildBlockLocatorString_Helpers/Size_1000-4 142.2µ 128.0µ ~ 0.100
CatchupWithHeaderCache-4 107.1m 107.2m ~ 1.000
_BufferPoolAllocation/16KB-4 5.665µ 4.589µ ~ 0.200
_BufferPoolAllocation/32KB-4 9.056µ 9.501µ ~ 0.200
_BufferPoolAllocation/64KB-4 17.87µ 25.35µ ~ 0.100
_BufferPoolAllocation/128KB-4 33.64µ 33.45µ ~ 1.000
_BufferPoolAllocation/512KB-4 153.6µ 148.7µ ~ 0.400
_BufferPoolConcurrent/32KB-4 22.04µ 21.99µ ~ 0.400
_BufferPoolConcurrent/64KB-4 35.37µ 34.99µ ~ 1.000
_BufferPoolConcurrent/512KB-4 181.6µ 192.2µ ~ 0.100
_SubtreeDeserializationWithBufferSizes/16KB-4 690.9µ 699.5µ ~ 0.100
_SubtreeDeserializationWithBufferSizes/32KB-4 674.6µ 688.9µ ~ 0.100
_SubtreeDeserializationWithBufferSizes/64KB-4 670.8µ 688.5µ ~ 0.100
_SubtreeDeserializationWithBufferSizes/128KB-4 672.1µ 689.1µ ~ 0.100
_SubtreeDeserializationWithBufferSizes/512KB-4 695.8µ 706.1µ ~ 0.400
_SubtreeDataDeserializationWithBufferSizes/16KB-4 36.57m 36.27m ~ 1.000
_SubtreeDataDeserializationWithBufferSizes/32KB-4 36.27m 38.19m ~ 0.400
_SubtreeDataDeserializationWithBufferSizes/64KB-4 36.39m 36.26m ~ 0.200
_SubtreeDataDeserializationWithBufferSizes/128KB-4 37.23m 36.38m ~ 0.200
_SubtreeDataDeserializationWithBufferSizes/512KB-4 36.12m 35.99m ~ 0.700
_PooledVsNonPooled/Pooled-4 729.0n 740.5n ~ 0.100
_PooledVsNonPooled/NonPooled-4 8.848µ 10.119µ ~ 0.100
_MemoryFootprint/Current_512KB_32concurrent-4 7.413µ 7.840µ ~ 0.100
_MemoryFootprint/Proposed_32KB_32concurrent-4 10.24µ 11.57µ ~ 0.100
_MemoryFootprint/Alternative_64KB_32concurrent-4 9.444µ 11.229µ ~ 0.100
_prepareTxsPerLevel-4 449.9m 455.4m ~ 0.700
_prepareTxsPerLevelOrdered-4 4.355m 4.469m ~ 1.000
_prepareTxsPerLevel_Comparison/Original-4 447.1m 464.0m ~ 0.200
_prepareTxsPerLevel_Comparison/Optimized-4 4.297m 4.130m ~ 0.100
SubtreeSizes/10k_tx_4_per_subtree-4 1.468m 1.414m ~ 0.400
SubtreeSizes/10k_tx_16_per_subtree-4 349.9µ 327.1µ ~ 0.100
SubtreeSizes/10k_tx_64_per_subtree-4 81.89µ 78.09µ ~ 0.100
SubtreeSizes/10k_tx_256_per_subtree-4 20.57µ 19.59µ ~ 0.100
SubtreeSizes/10k_tx_512_per_subtree-4 10.31µ 10.07µ ~ 0.100
SubtreeSizes/10k_tx_1024_per_subtree-4 5.196µ 5.005µ ~ 0.400
SubtreeSizes/10k_tx_2k_per_subtree-4 2.606µ 2.497µ ~ 0.100
BlockSizeScaling/10k_tx_64_per_subtree-4 85.68µ 80.90µ ~ 0.100
BlockSizeScaling/10k_tx_256_per_subtree-4 19.94µ 20.22µ ~ 1.000
BlockSizeScaling/10k_tx_1024_per_subtree-4 5.411µ 5.200µ ~ 0.100
BlockSizeScaling/50k_tx_64_per_subtree-4 424.2µ 412.7µ ~ 0.200
BlockSizeScaling/50k_tx_256_per_subtree-4 105.8µ 106.0µ ~ 1.000
BlockSizeScaling/50k_tx_1024_per_subtree-4 28.62µ 24.11µ ~ 0.200
SubtreeAllocations/small_subtrees_exists_check-4 182.1µ 183.1µ ~ 0.700
SubtreeAllocations/small_subtrees_data_fetch-4 207.6µ 191.3µ ~ 0.100
SubtreeAllocations/small_subtrees_full_validation-4 398.4µ 382.5µ ~ 0.100
SubtreeAllocations/medium_subtrees_exists_check-4 11.15µ 11.10µ ~ 1.000
SubtreeAllocations/medium_subtrees_data_fetch-4 13.31µ 11.62µ ~ 0.100
SubtreeAllocations/medium_subtrees_full_validation-4 26.36µ 25.25µ ~ 0.100
SubtreeAllocations/large_subtrees_exists_check-4 2.861µ 2.878µ ~ 0.700
SubtreeAllocations/large_subtrees_data_fetch-4 3.439µ 3.064µ ~ 0.100
SubtreeAllocations/large_subtrees_full_validation-4 6.490µ 6.241µ ~ 0.100
StoreBlockForkPath/inMemoryChainCheck=false-4 262.6µ 262.7µ ~ 0.700
StoreBlockForkPath/inMemoryChainCheck=true-4 941.6µ 929.3µ ~ 0.700
StoreBlock_Sequential/BelowCSVHeight-4 66.36µ 62.52µ ~ 0.400
StoreBlock_Sequential/AboveCSVHeight-4 62.90µ 63.47µ ~ 0.400
CheckSpendAndCreateMultiList_FanIn/parents=80000-4 49.52m 53.21m ~ 0.100
CheckSpendAndCreateMultiList_FanIn/parents=160000-4 121.4m 125.9m ~ 0.700
GetUtxoHashes-4 264.3n 263.5n ~ 1.000
GetUtxoHashes_ManyOutputs-4 43.33µ 43.33µ ~ 1.000
MetaBytes-4 64.36n 67.72n ~ 0.100
_NewMetaDataFromBytes-4 206.3n 207.0n ~ 0.800
_Bytes-4 342.1n 343.6n ~ 1.000
_MetaBytes-4 99.89n 99.15n ~ 0.700

Threshold: >10% with p < 0.05 | Generated: 2026-10-28 10:21 UTC

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants