Skip to content

aerospike: optional native operate-path for mod-teranode UDFs#821

Closed
icellan wants to merge 8 commits intobsv-blockchain:mainfrom
icellan:feat/teranode-native-ops
Closed

aerospike: optional native operate-path for mod-teranode UDFs#821
icellan wants to merge 8 commits intobsv-blockchain:mainfrom
icellan:feat/teranode-native-ops

Conversation

@icellan
Copy link
Copy Markdown
Contributor

@icellan icellan commented May 6, 2026

Summary

Adds an opt-in path that invokes mod-teranode UDF functions through the native operate-path (TeranodeModifyOp, wire op type 200) instead of the legacy UDF executor. The native path:

  • Bypasses the Aerospike UDF executor (its dedicated thread pool, heap, per-record handoff overhead)
  • Runs under the same lock as native ops like `LIST_APPEND` / `CDT_MODIFY` (finer-grained than UDF context lock)
  • Batches with other native ops in the same wire request

Expected to give meaningful concurrency wins under heavy batch load. The feature is off by default; existing clusters keep working unchanged.

Required server

The BSV fork of `aerospike-server` (branch `feat/teranode-native-op` or merged equivalent), which adds the matching server-side dispatcher (`AS_MSG_OP_TERANODE_MODIFY` = 200, sub-op id table 1..13).

Clusters running stock Aerospike or older versions of the BSV fork are unaffected — the capability probe (described below) detects unsupported servers and falls back to the UDF path.

Decision wrapping

Each call site delegates path selection to a single helper:

```go
batchRecords[i] = s.teranodeBatchRecord(
batchUDFPolicy, usePackage, key, subOpSetMined, "setMined",
minedBlockInfo.BlockID,
minedBlockInfo.BlockHeight,
// ...plain Go values; helper handles wrapping for either path
)
```

The helper returns either an `aerospike.NewBatchWrite(... TeranodeModifyOp(...))` or `aerospike.NewBatchUDF(...)` BatchRecord, depending on:

  1. Setting `aerospike_use_native_teranode_ops` (default `false`)
  2. Capability probe at store init: sends a malformed `TeranodeModifyOp` to a probe key, expects `PARAMETER_ERROR` from the BSV dispatcher. Anything else (timeout, unknown-op error, connection drop) is treated as "not supported" and biases toward false-negatives so the fallback never runs against a server that doesn't support the op.

If either gate is closed, the helper produces the same `NewBatchUDF` call the existing code did. Behavior is byte-identical to the current code path on clusters that don't enable the setting or don't run the BSV server fork.

What's in the diff

Foundation (commit 1)

  • `stores/utxo/aerospike/native_op.go` (new): sub-op id constants, msgpack `[sub_op_id, args]` payload encoder, `teranodeBatchRecord` / `executeTeranodeOp` wrappers, and the capability probe.
  • `stores/utxo/aerospike/aerospike.go`: adds `Store.useNativeTeranodeOps` cached field and `s.initNativeTeranodeOps(ctx)` invocation in `New(...)`.
  • `settings/aerospike_settings.go` + `settings/settings.go`: adds `AerospikeSettings.UseNativeTeranodeOps bool` (default false), keyed `aerospike_use_native_teranode_ops`.

Cutovers (commit 2)

11 mod-teranode UDF call sites swapped from `aerospike.NewBatchUDF(...)` / `s.client.Execute(...)` to `s.teranodeBatchRecord(...)` / `s.executeTeranodeOp(...)`:

File Function Sub-op id
`set_mined.go` setMined 4
`aerospike.go` preserveUntil 9
`alert_system.go` (×3) freeze, unfreeze, reassign 5, 6, 7
`conflicting.go` setConflicting 8
`locked.go` setLocked 10
`spend.go` (×3) incrementSpentExtraRecs (×2), spendMulti 11, 11, 2
`un_spend.go` unspend (single `Execute`) 3

Net effect: `-3` lines across the call-site files (the wrapper absorbs `aerospike.NewValue(...)` / `aerospike.BoolValue(...)` ladders, so each call site shrinks).

Module path switch (commit 3)

  • Renames all `github.com/aerospike/aerospike-client-go/v8` imports across 55 files to `github.com/bsv-blockchain/aerospike-client-go/v8`.
  • Drops the local-filesystem `replace` directive.
  • The fork is consumed as a regular dependency at `v8.7.1-bsv1` via the Go module proxy.

The fork is functionally a strict superset of upstream; on clusters that don't enable the new path, the binary behaves identically to one built against upstream v8.7.0.

Sub-op id assignment (frozen wire contract)

sub_op_id UDF function
1 spend
2 spendMulti
3 unspend
4 setMined
5 freeze
6 unfreeze
7 reassign
8 setConflicting
9 preserveUntil
10 setLocked
11 incrementSpentExtraRecs
12 setDeleteAtHeight
13 addDeletedChildren

Matches the SUBOP_TABLE in `modules/mod-teranode/src/main/mod_teranode_native_op.c` on the server fork. Never renumber after merge.

Test plan

  • `go build ./stores/utxo/aerospike/...` clean
  • `go vet ./stores/utxo/aerospike/...` clean
  • `go mod tidy` resolves `github.com/bsv-blockchain/aerospike-client-go/v8 v8.7.1-bsv1` from the module proxy without errors
  • End-to-end smoke test against a live `asd` built from server `feat/teranode-native-op` + this branch, with `aerospike_use_native_teranode_ops=true`: `setMined` round-trips correctly via the native path, producing identical record state to the equivalent BatchUDF call (verified in server's test-native-op driver)
  • CI test suite (deferring to CI run on this PR)
  • Soak test in staging with the setting enabled, comparing throughput vs UDF baseline (planned separate effort post-merge — numbers go in the mod-teranode README)

Compatibility / rollout notes

  • Default off. Turning the setting on requires both the BSV server fork on every cluster node AND the setting flipped to true.
  • Capability probe runs once at store construction. If it fails (e.g. cluster on stock Aerospike), the store logs the decision and falls back to UDF for all subsequent calls. No per-call overhead.
  • No wire-format renumbering. Sub-op id and op-type assignments are wire contract; once shipped, never renumber.
  • Compatibility with upstream client features. The fork merges from upstream v8.7.0 + adds two constructors. All existing aerospike-client-go-v8 APIs work unchanged.

Companion PRs

This PR depends on both being merged before `aerospike_use_native_teranode_ops=true` can do anything useful — but is safe to merge before then because the default-off behavior is byte-identical to current.

🤖 Generated with Claude Code

icellan and others added 3 commits May 6, 2026 15:13
Adds optional support for invoking mod-teranode functions via the
native operate-path (TeranodeModifyOp, wire op type 200) instead of
the legacy UDF path. The new path bypasses the Aerospike UDF
executor and runs under the same lock as native ops like
LIST_APPEND.

Required server: the BSV fork of aerospike-server-private
(feat/teranode-native-op or merged equivalent) on every node.

Decision is wrapped at one place — call sites use
s.teranodeBatchRecord(...) instead of aerospike.NewBatchUDF(...),
and the helper picks the path based on:
  1. Setting aerospike_use_native_teranode_ops (default false)
  2. A startup capability probe against the cluster

If either is false, calls fall back to UDF transparently. Clusters
without the BSV fork keep working unchanged.

Foundation:
- go.mod: replace aerospike-client-go/v8 with the BSV fork
- AerospikeSettings.UseNativeTeranodeOps (default false)
- stores/utxo/aerospike/native_op.go: sub_op id constants, msgpack
  payload encoder, teranodeBatchRecord/executeTeranodeOp wrappers,
  capability probe (sends a malformed payload, expects PARAMETER_ERROR
  from the BSV dispatcher)
- Store.useNativeTeranodeOps cached at construction

Cutovers:
- setMined

Remaining cutovers (follow-up commits): preserveUntil, freeze,
unfreeze, reassign, setConflicting, setLocked, spendMulti, unspend,
incrementSpentExtraRecs (×2 sites).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Routes preserveUntil, freeze, unfreeze, reassign, setConflicting,
setLocked, incrementSpentExtraRecs (×2), spendMulti, and unspend
through the s.teranodeBatchRecord / s.executeTeranodeOp helpers
added in the previous commit. Each call site shrinks because the
aerospike.NewValue / aerospike.BoolValue wrappers are absorbed by
the helper.

Behavior is unchanged when aerospike_use_native_teranode_ops is
false (the default) or when the cluster's capability probe rejects
the new opcode — both result in the helper producing the same
NewBatchUDF / client.Execute call as before.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The BSV fork of aerospike-client-go-v8 is now published at
github.com/bsv-blockchain/aerospike-client-go/v8 v8.7.1-bsv1 — adds
TeranodeModifyOp / TeranodeReadOp wire opcodes 200/201 alongside
the upstream API.

Mechanical sed across 55 files renaming all imports from
github.com/aerospike/aerospike-client-go/v8 to
github.com/bsv-blockchain/aerospike-client-go/v8. Build, vet, and
the package test suite all green.

Drops the local-filesystem replace directive — the require directive
now resolves directly via the Go module proxy. The previously-pinned
upstream github.com/aerospike/aerospike-client-go/v8 v8.4.2 remains
as an indirect dependency of unrelated transitive imports.

The fork is functionally a strict superset of upstream: when
aerospike_use_native_teranode_ops is false (default) and/or the
cluster's capability probe rejects the new opcode, Teranode's calls
go through unchanged NewBatchUDF / client.Execute paths, behaving
identically to upstream.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@icellan icellan requested review from oskarszoon and teracoder May 6, 2026 15:39
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 6, 2026

🤖 Claude Code Review

Status: Complete


Summary

Reviewed 61 changed files implementing optional native operate-path for mod-teranode UDF functions. The implementation is well-structured with appropriate safeguards.

Findings

No critical issues found. The PR demonstrates careful engineering:

  • Robust fallback mechanism: The capability probe (native_op.go:183-273) uses defensive error handling and biases toward false-negatives to ensure safe operation on unsupported servers
  • Wire protocol stability: Sub-op IDs are documented as frozen wire contract with compile-time bounds checking (native_op.go:291-294)
  • Backward compatibility: Default-off setting with transparent UDF fallback preserves existing behavior
  • Test coverage: Includes unit tests for msgpack encoding and helper functions for container setup with env var override support
  • Code organization: Clean separation of concerns with dedicated native_op.go file and wrapper functions that isolate path selection logic

Minor Observations

  1. The probe operation (native_op.go:183-273) creates a temporary record with 60s TTL and deletes it afterward. Consider whether the delete operation should have additional error handling or logging if it fails.

  2. Documentation in settings/aerospike_settings.go:27 could benefit from explicit mention of the capability probe behavior for operators troubleshooting why the setting might not take effect.

These are informational only and do not block merge.

Compatibility Notes Verified

  • Module path switch from upstream to BSV fork properly handled
  • 55 files updated with import changes
  • go.mod correctly specifies v8.7.1-bsv2 dependency
  • Container test helpers support env var override for testing against custom images

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 6, 2026

Benchmark Comparison Report

Baseline: main (unknown)

Current: PR-821 (c18c1c9)

Summary

  • Regressions: 0
  • Improvements: 0
  • Unchanged: 142
  • Significance level: p < 0.05
All benchmark results (sec/op)
Benchmark Baseline Current Change p-value
_NewBlockFromBytes-4 1.794µ 1.821µ ~ 0.400
SplitSyncedParentMap_SetIfNotExists/256_buckets-4 59.43n 59.35n ~ 0.300
SplitSyncedParentMap_SetIfNotExists/16_buckets-4 59.47n 59.58n ~ 0.700
SplitSyncedParentMap_SetIfNotExists/1_bucket-4 59.45n 59.91n ~ 0.800
SplitSyncedParentMap_ConcurrentSetIfNotExists/256_buckets... 42.81n 45.75n ~ 0.400
SplitSyncedParentMap_ConcurrentSetIfNotExists/16_buckets_... 73.90n 73.81n ~ 1.000
SplitSyncedParentMap_ConcurrentSetIfNotExists/1_bucket_pa... 193.7n 200.7n ~ 0.200
MiningCandidate_Stringify_Short-4 264.2n 265.8n ~ 0.100
MiningCandidate_Stringify_Long-4 1.864µ 1.849µ ~ 0.600
MiningSolution_Stringify-4 956.1n 964.7n ~ 0.100
BlockInfo_MarshalJSON-4 1.808µ 1.839µ ~ 0.100
NewFromBytes-4 128.4n 158.1n ~ 0.100
Mine_EasyDifficulty-4 62.12µ 61.70µ ~ 0.400
Mine_WithAddress-4 6.843µ 6.771µ ~ 0.100
DirectSubtreeAdd/4_per_subtree-4 62.43n 61.41n ~ 0.400
DirectSubtreeAdd/64_per_subtree-4 31.44n 28.55n ~ 0.100
DirectSubtreeAdd/256_per_subtree-4 30.23n 27.14n ~ 0.100
DirectSubtreeAdd/1024_per_subtree-4 29.51n 26.23n ~ 0.100
DirectSubtreeAdd/2048_per_subtree-4 28.53n 25.86n ~ 0.100
SubtreeProcessorAdd/4_per_subtree-4 279.7n 281.3n ~ 1.000
SubtreeProcessorAdd/64_per_subtree-4 272.2n 273.2n ~ 1.000
SubtreeProcessorAdd/256_per_subtree-4 276.9n 275.5n ~ 0.400
SubtreeProcessorAdd/1024_per_subtree-4 270.1n 268.1n ~ 0.700
SubtreeProcessorAdd/2048_per_subtree-4 269.2n 269.0n ~ 0.700
SubtreeProcessorRotate/4_per_subtree-4 273.8n 271.6n ~ 0.700
SubtreeProcessorRotate/64_per_subtree-4 273.7n 270.4n ~ 0.200
SubtreeProcessorRotate/256_per_subtree-4 271.0n 268.9n ~ 0.700
SubtreeProcessorRotate/1024_per_subtree-4 271.6n 269.9n ~ 0.100
SubtreeNodeAddOnly/4_per_subtree-4 54.13n 53.64n ~ 0.200
SubtreeNodeAddOnly/64_per_subtree-4 34.07n 34.29n ~ 0.200
SubtreeNodeAddOnly/256_per_subtree-4 33.21n 33.27n ~ 1.000
SubtreeNodeAddOnly/1024_per_subtree-4 32.51n 32.50n ~ 1.000
SubtreeCreationOnly/4_per_subtree-4 111.5n 111.4n ~ 1.000
SubtreeCreationOnly/64_per_subtree-4 386.3n 384.0n ~ 0.400
SubtreeCreationOnly/256_per_subtree-4 1.303µ 1.402µ ~ 0.100
SubtreeCreationOnly/1024_per_subtree-4 4.330µ 4.525µ ~ 0.100
SubtreeCreationOnly/2048_per_subtree-4 7.689µ 8.061µ ~ 0.100
SubtreeProcessorOverheadBreakdown/64_per_subtree-4 270.1n 268.4n ~ 0.100
SubtreeProcessorOverheadBreakdown/1024_per_subtree-4 269.6n 268.0n ~ 0.700
ParallelGetAndSetIfNotExists/1k_nodes-4 585.9µ 590.2µ ~ 1.000
ParallelGetAndSetIfNotExists/10k_nodes-4 1.323m 1.342m ~ 0.400
ParallelGetAndSetIfNotExists/50k_nodes-4 6.589m 6.584m ~ 1.000
ParallelGetAndSetIfNotExists/100k_nodes-4 13.23m 13.21m ~ 0.700
SequentialGetAndSetIfNotExists/1k_nodes-4 655.1µ 657.4µ ~ 0.700
SequentialGetAndSetIfNotExists/10k_nodes-4 2.874m 2.960m ~ 0.200
SequentialGetAndSetIfNotExists/50k_nodes-4 10.48m 10.72m ~ 0.100
SequentialGetAndSetIfNotExists/100k_nodes-4 19.78m 20.70m ~ 0.100
ProcessOwnBlockSubtreeNodesParallel/1k_nodes-4 633.4µ 629.5µ ~ 0.400
ProcessOwnBlockSubtreeNodesParallel/10k_nodes-4 4.174m 4.171m ~ 0.700
ProcessOwnBlockSubtreeNodesParallel/100k_nodes-4 16.49m 16.33m ~ 0.400
ProcessOwnBlockSubtreeNodesSequential/1k_nodes-4 686.7µ 690.8µ ~ 0.700
ProcessOwnBlockSubtreeNodesSequential/10k_nodes-4 5.893m 5.741m ~ 0.100
ProcessOwnBlockSubtreeNodesSequential/100k_nodes-4 37.92m 37.86m ~ 0.200
DiskTxMap_SetIfNotExists-4 3.664µ 3.626µ ~ 0.700
DiskTxMap_SetIfNotExists_Parallel-4 3.343µ 3.493µ ~ 0.100
DiskTxMap_ExistenceOnly-4 305.1n 322.0n ~ 0.100
Queue-4 194.6n 193.7n ~ 0.300
AtomicPointer-4 4.781n 4.050n ~ 0.100
ReorgOptimizations/DedupFilterPipeline/Old/10K-4 858.2µ 847.8µ ~ 0.100
ReorgOptimizations/DedupFilterPipeline/New/10K-4 838.1µ 808.8µ ~ 0.100
ReorgOptimizations/AllMarkFalse/Old/10K-4 122.0µ 106.9µ ~ 0.400
ReorgOptimizations/AllMarkFalse/New/10K-4 62.19µ 62.25µ ~ 1.000
ReorgOptimizations/HashSlicePool/Old/10K-4 73.29µ 66.76µ ~ 0.700
ReorgOptimizations/HashSlicePool/New/10K-4 11.42µ 11.52µ ~ 1.000
ReorgOptimizations/NodeFlags/Old/10K-4 5.355µ 5.432µ ~ 1.000
ReorgOptimizations/NodeFlags/New/10K-4 1.842µ 1.818µ ~ 1.000
ReorgOptimizations/DedupFilterPipeline/Old/100K-4 10.17m 10.65m ~ 0.400
ReorgOptimizations/DedupFilterPipeline/New/100K-4 9.587m 10.264m ~ 0.100
ReorgOptimizations/AllMarkFalse/Old/100K-4 1.175m 1.203m ~ 0.400
ReorgOptimizations/AllMarkFalse/New/100K-4 679.8µ 679.0µ ~ 0.400
ReorgOptimizations/HashSlicePool/Old/100K-4 699.5µ 630.7µ ~ 0.100
ReorgOptimizations/HashSlicePool/New/100K-4 318.8µ 300.5µ ~ 1.000
ReorgOptimizations/NodeFlags/Old/100K-4 55.70µ 56.54µ ~ 0.700
ReorgOptimizations/NodeFlags/New/100K-4 20.15µ 19.22µ ~ 0.100
TxMapSetIfNotExists-4 51.85n 51.07n ~ 0.200
TxMapSetIfNotExistsDuplicate-4 38.33n 37.97n ~ 0.400
ChannelSendReceive-4 635.3n 616.7n ~ 0.100
BlockAssembler_AddTx-4 0.02715n 0.02770n ~ 0.400
AddNode-4 10.89 11.14 ~ 0.400
AddNodeWithMap-4 10.89 10.13 ~ 0.200
CalcBlockWork-4 522.9n 528.4n ~ 1.000
CalculateWork-4 697.3n 678.3n ~ 0.100
BuildBlockLocatorString_Helpers/Size_10-4 1.356µ 1.641µ ~ 0.700
BuildBlockLocatorString_Helpers/Size_100-4 12.80µ 12.86µ ~ 0.400
BuildBlockLocatorString_Helpers/Size_1000-4 133.5µ 126.1µ ~ 0.100
CatchupWithHeaderCache-4 104.5m 104.2m ~ 0.100
_BufferPoolAllocation/16KB-4 3.375µ 3.587µ ~ 0.100
_BufferPoolAllocation/32KB-4 8.870µ 8.886µ ~ 0.700
_BufferPoolAllocation/64KB-4 13.88µ 16.81µ ~ 0.100
_BufferPoolAllocation/128KB-4 30.30µ 29.25µ ~ 0.700
_BufferPoolAllocation/512KB-4 102.8µ 114.3µ ~ 0.100
_BufferPoolConcurrent/32KB-4 18.12µ 19.14µ ~ 0.400
_BufferPoolConcurrent/64KB-4 27.43µ 31.35µ ~ 0.100
_BufferPoolConcurrent/512KB-4 142.4µ 141.3µ ~ 0.700
_SubtreeDeserializationWithBufferSizes/16KB-4 702.8µ 637.2µ ~ 0.100
_SubtreeDeserializationWithBufferSizes/32KB-4 699.7µ 635.1µ ~ 0.100
_SubtreeDeserializationWithBufferSizes/64KB-4 717.3µ 642.0µ ~ 0.100
_SubtreeDeserializationWithBufferSizes/128KB-4 700.3µ 637.1µ ~ 0.100
_SubtreeDeserializationWithBufferSizes/512KB-4 732.6µ 663.1µ ~ 0.100
_SubtreeDataDeserializationWithBufferSizes/16KB-4 35.54m 36.20m ~ 0.100
_SubtreeDataDeserializationWithBufferSizes/32KB-4 35.67m 35.91m ~ 0.400
_SubtreeDataDeserializationWithBufferSizes/64KB-4 35.76m 35.93m ~ 0.400
_SubtreeDataDeserializationWithBufferSizes/128KB-4 35.25m 35.56m ~ 0.200
_SubtreeDataDeserializationWithBufferSizes/512KB-4 34.92m 35.56m ~ 0.100
_PooledVsNonPooled/Pooled-4 743.2n 736.0n ~ 0.100
_PooledVsNonPooled/NonPooled-4 7.462µ 6.785µ ~ 0.100
_MemoryFootprint/Current_512KB_32concurrent-4 6.991µ 6.883µ ~ 0.100
_MemoryFootprint/Proposed_32KB_32concurrent-4 11.090µ 9.840µ ~ 0.100
_MemoryFootprint/Alternative_64KB_32concurrent-4 9.770µ 9.385µ ~ 0.100
_prepareTxsPerLevel-4 417.2m 417.1m ~ 1.000
_prepareTxsPerLevelOrdered-4 4.093m 4.704m ~ 0.400
_prepareTxsPerLevel_Comparison/Original-4 443.0m 429.7m ~ 0.700
_prepareTxsPerLevel_Comparison/Optimized-4 3.840m 4.866m ~ 0.100
SubtreeSizes/10k_tx_4_per_subtree-4 1.275m 1.266m ~ 1.000
SubtreeSizes/10k_tx_16_per_subtree-4 301.5µ 299.0µ ~ 1.000
SubtreeSizes/10k_tx_64_per_subtree-4 71.66µ 71.50µ ~ 0.400
SubtreeSizes/10k_tx_256_per_subtree-4 17.71µ 17.73µ ~ 1.000
SubtreeSizes/10k_tx_512_per_subtree-4 8.839µ 8.801µ ~ 0.400
SubtreeSizes/10k_tx_1024_per_subtree-4 4.341µ 4.357µ ~ 1.000
SubtreeSizes/10k_tx_2k_per_subtree-4 2.182µ 2.173µ ~ 0.700
BlockSizeScaling/10k_tx_64_per_subtree-4 69.85µ 69.51µ ~ 1.000
BlockSizeScaling/10k_tx_256_per_subtree-4 17.48µ 17.51µ ~ 0.400
BlockSizeScaling/10k_tx_1024_per_subtree-4 4.363µ 4.370µ ~ 1.000
BlockSizeScaling/50k_tx_64_per_subtree-4 373.1µ 370.2µ ~ 0.400
BlockSizeScaling/50k_tx_256_per_subtree-4 88.01µ 87.89µ ~ 0.700
BlockSizeScaling/50k_tx_1024_per_subtree-4 21.45µ 21.82µ ~ 0.200
SubtreeAllocations/small_subtrees_exists_check-4 148.9µ 149.0µ ~ 1.000
SubtreeAllocations/small_subtrees_data_fetch-4 157.0µ 157.2µ ~ 1.000
SubtreeAllocations/small_subtrees_full_validation-4 310.5µ 309.4µ ~ 1.000
SubtreeAllocations/medium_subtrees_exists_check-4 8.886µ 8.876µ ~ 1.000
SubtreeAllocations/medium_subtrees_data_fetch-4 9.221µ 9.264µ ~ 1.000
SubtreeAllocations/medium_subtrees_full_validation-4 17.51µ 17.34µ ~ 1.000
SubtreeAllocations/large_subtrees_exists_check-4 2.104µ 2.081µ ~ 0.200
SubtreeAllocations/large_subtrees_data_fetch-4 2.224µ 2.218µ ~ 0.700
SubtreeAllocations/large_subtrees_full_validation-4 4.345µ 4.366µ ~ 1.000
StoreBlock_Sequential/BelowCSVHeight-4 337.5µ 336.9µ ~ 0.700
StoreBlock_Sequential/AboveCSVHeight-4 338.3µ 318.3µ ~ 0.100
GetUtxoHashes-4 260.3n 260.6n ~ 1.000
GetUtxoHashes_ManyOutputs-4 43.39µ 43.91µ ~ 1.000
_NewMetaDataFromBytes-4 240.3n 239.7n ~ 1.000
_Bytes-4 628.3n 627.9n ~ 0.400
_MetaBytes-4 566.9n 570.6n ~ 0.100

Threshold: >10% with p < 0.05 | Generated: 2026-05-07 11:13 UTC

Picks up 15d73f5 on the BSV go-client fork which fixes routing
classification for TeranodeReadOp. The original v8.7.1-bsv1 had
TeranodeReadOp falling into the operate_args.go default branch and
being routed via PartitionForWrite because the client uses explicit
op-type switches that didn't include _TERANODE_READ. Caught on PR
review of bsv-blockchain/aerospike-client-go#1.

No source changes here — only the version pin moves and go.sum
updates with the new tarball hash. Build, vet, mod-tidy all green.
Comment thread stores/utxo/aerospike/container_helper_test.go Outdated
@icellan icellan force-pushed the feat/teranode-native-ops branch from 8ff71c5 to c77a2b5 Compare May 7, 2026 10:53
@sonarqubecloud
Copy link
Copy Markdown

sonarqubecloud Bot commented May 7, 2026

Quality Gate Failed Quality Gate failed

Failed conditions
48.2% Coverage on New Code (required ≥ 80%)

See analysis details on SonarQube Cloud

@icellan
Copy link
Copy Markdown
Contributor Author

icellan commented May 7, 2026

Superseded by #828 (re-opened from a branch on bsv-blockchain/teranode instead of icellan/teranode fork). All review/discussion to continue there.

@icellan icellan closed this May 7, 2026
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.

1 participant