Raw Data Catalog

everything the codebase measures, per transaction & in aggregate source on GitHub ↗

What we collect, block by block

For each transaction in a recent ~20k-block window (not the whole chain), we record the small choices behind how it was built (script types, ordering, fees, and more): the habits of the wallet software, not who sent the money. Rows with a + details button show how common each choice is across that window.

173
per-tx feature columns + 2 identity
21
sparseness axes
9
aggregate views
5
per-signature record fields
Column type bool 0/1 tri tri-state (_yes + _indeterminate pair) one-hot 1 col per value ordinal single integer index num raw count / ratio (f64) hex identifier
epoch — the block-bucket the survey aggregates over; per-epoch counts are the granularity behind every rollup.
joint vector — the tuple of axis values for one transaction; conditional_anonymity reports its per-value anonymity set.
marginal (axis_marginals) — the per-value count distribution of a single axis: how many transactions took each value.
anonymity set (conditional_anonymity) — how many transactions share an identical CORE joint vector; a set of size 1 is uniquely identifying. Reported per fingerprint value, not as a chain-wide distribution.
abstention — when the change-identification heuristic declines to label any output as change (Indeterminate), rather than guessing.
+ details — click a wired row to expand its live per-field distribution for the current scan window (see below).

00 · Identity

Transaction identity

Two non-numeric columns lead every row so a downstream result joins back to the transaction.

txidhexUniquely identifies the transaction, lowercase hex, so any row here joins back to a specific chain event.
block_heightnumThe block height the transaction confirmed in, for slicing results by time.

01 · Booleans & tri-state

Direct signals & heuristic aux flags

Plain 0/1 flags read straight off the transaction, plus the 7 auxiliary heuristics. Tri-state axes (a signal that can be absent) split into a _yes and an _indeterminate column; both zero means “no”.

Direct flags
op_returnboolThe transaction carries a data output at all — the base signal that has_inscription_envelope and has_runestone below narrow down to specific protocols.
round_feerateboolThe feerate is within 0.01 sat/vB of a whole number (and at least 1 sat/vB) — the signature of a human typing a round feerate rather than a fee estimator's output.
low_s_yesboolEvery ECDSA signature in the transaction satisfies BIP-146 low-S — a standardness rule, so true for nearly all on-chain traffic. Emitted as a single bool rather than tri-state: its indeterminate case (no ECDSA signature present) is bit-identical to low_r_indeterminate, so it is not duplicated here.
low_r_yes · low_r_indeterminatetriWhether the wallet grinds its ECDSA signatures for a low-R value — shaving a byte off the DER encoding — versus carrying no ECDSA signature to judge at all. Aggregating across every signature in the transaction is survey logic.
uncompressed_pubkey_yes · _indeterminatetriAn uncompressed public key appears somewhere in the transaction — a legacy-era tell, since modern wallets use compressed keys exclusively — versus no pubkey being visible at all (e.g. a taproot key-path spend).
Auxiliary heuristicsaux.rs
round_feeboolThe absolute fee is a non-zero multiple of 1000 sat — a sign the fee was typed by hand rather than computed by a fee estimator.
round_paymentboolAn output value is a non-zero multiple of 100,000 sat (0.001 BTC) — a coarser round-number signal than round_fee's, aimed at human-entered payment amounts rather than fees.
uih1boolA single input alone already covers the transaction's largest output. Combining more inputs than a payment strictly needs links every one of those coins together and reveals more of the wallet's holdings than a minimal selection would (Unnecessary Input Heuristic 1).
uih2boolAn input is smaller than the transaction's smallest output — the shape a payjoin receiver's contributed input leaves behind (Unnecessary Input Heuristic 2).
address_reuseboolAn output pays back to a script one of the inputs spent from — direct on-chain address reuse.
same_block_parentboolSpends an output created earlier in this very block — a same-block parent-child chain, often a change output being immediately re-spent.
changelessboolFewer than two outputs, so there is nowhere for change to go — a plausibly changeless spend.

02 · Nominal

One-hot categorical axes

Each categorical fingerprint is encoded as one column per possible value. The value domains below are the exhaustive set the classifier can emit.

versiontx.version
version_1/2/3/otherone-hotThe transaction's declared nVersion; _other catches any value outside 1–3 (version 3 signals TRUC/ephemeral-anchor policy).
nsequencevalue-pattern class
nsequence_…one-hotClassifies the transaction's nSequence values by the first priority-ordered pattern they match: cake_group_c (first input 0x01, every other input final — a known wallet bug), a lone 0x01 elsewhere, uniform opt-in RBF (0xfffffffd), uniform non-RBF-final (0xfffffffe), uniform max (0xffffffff), or a mixed pattern matching none of those.
rbfmaxfinalcake_group_clone_0x01mixed_other
nlocktimesemantic class
nlocktime_…one-hotInterprets nLockTime against the confirming block's height: zero, a unix timestamp (≥ 500,000,000), a height above the tip (future, nonstandard), within 100 blocks behind the tip (anti_fee_snipe, Core's default), or further back (backdated).
zeroanti_fee_snipebackdatedtimestampfuture
input_order · output_orderOrderClass ×2
{input,output}_order_…one-hotWhether inputs/outputs follow a recognizable ordering rule — an unordered set is itself a wallet fingerprint. bip69 and value-ordering are checked against sorted order; age_ascending (oldest spent coin first) and the surrounding OrderClass wrapper are survey logic. age_ascending is measurable only on the input side (outputs carry no age), so the output column is structurally always 0, kept only for shape symmetry with the input side.
bip69value_ascendingvalue_descendingage_ascendingotherindeterminate
input_subtypewhole-tx uniform-or-mixedThis is where a P2WSH multisig, a P2SH multisig, and a taproot script-path spend read as distinct fingerprints.
input_subtype_…one-hotWhat a wrapped input (P2SH/P2WSH/P2TR) actually resolves to underneath its outer script type, by inspecting the redeem script, witness script, or revealed tapscript.
p2sh_p2wpkhp2sh_multisigp2sh_otherp2wsh_multisigp2wsh_othertaproot_key_pathtaproot_script_pathbaremixedindeterminate
sighash11-way
sighash_…one-hotWhich SIGHASH flag the transaction's signatures use. taproot_default (64B, the implicit SIGHASH_ALL) vs taproot_explicit (65B, an explicit sighash byte) is the P2TR default-vs-explicit split. Reads the first signature found per input — the first witness item, or the first scriptSig push for legacy inputs — not every signature the input carries.
alltaproot_defaulttaproot_explicitnonesingleacp_allacp_noneacp_singleothermixedna
input_typesuniform script type
input_types_…one-hotWhether every input the transaction spends resolves to the same script type (uniform_{type}, one of 8), differs across inputs (mixed), or has a prevout the source couldn't resolve (unknown). The per-type count columns below carry the same information at finer, non-exclusive granularity.
p2pkhp2shp2wpkhp2wshp2trop_returnnonstandardp2pkmixedunknown

03 · Ordinal

Bucketed indices

Ordered categories collapse to a single integer index rather than one-hot, since the order carries meaning.

ecdsa_sigs_indexordinalHow many ECDSA signatures the transaction carries, bucketed: None=0 (e.g. a pure taproot key-path spend), One=1, Few=2 (2–4), Many=3 (5+). Gives low_r its statistical context — a lone non-grinding signature is close to a coin flip on low-R, so agreement across many signatures is far stronger evidence of grinding. The broader, not-ECDSA-scoped signature measure is sigop_count below.
sigop_countnumTotal sig-op cost (legacy ×4, P2SH and witness) from total_sigop_cost over the resolved prevouts. Not scoped to ECDSA, unlike ecdsa_sigs_index, so Schnorr (taproot) and multisig sig ops count.
input_age_indexordinalConfirmations of the youngest coin the transaction spends, bucketed: SameBlock=0 (spent in the block it was created — the strongest temporal tell, e.g. spending an unconfirmed parent), 1 for 1–5 confirmations, 2 for 6–143, 3 for 144+ (Older), 4 when no age can be resolved (Indeterminate).
output_structure_indexordinalHow many outputs the transaction has, bucketed rather than counted raw so wallets that always produce exactly one or two outputs stand out as a class. Single=0, Double=1, Multi=2 (3+), Unknown=3.
feerate_bucket_indexordinalRank of the transaction's sat/vB feerate bucket: integer buckets 0..9, then ten-wide bands up to 100+; Unknown (fee not computable) sorts last.
locktime_offset_index · locktime_offset_not_applicableordinalHow many blocks behind the tip an anti-fee-snipe locktime sits — the observable half of the exact-tip-vs-backdated question nlocktime alone can't answer per transaction. Buckets: block_height − locktime in 0, 1, 2, 3, 4–6, 7–12, 13–25, 26–50, 51–100, with a not-applicable flag set for every other nlocktime class. Offsets ≥ 100 fall outside the anti-fee-snipe window entirely and surface as nlocktime_backdated in the one-hot above instead.

04 · Heuristic

Change identification

Change identification the fingerprints library does not cover yet. Two independent change heuristics run: the script-type match (change_index_by_script_type) and a value-based round-number heuristic. Which one fires, and whether they agree, is itself a fingerprint. Present in the ML matrix, kept out of the joint vector (a heuristic's abstention is not chain diversity).

change_position_first/last/middle/indeterminateone-hotWhich output the script-type heuristic labels as change.
change_type_presentboolThe script-type heuristic identified a change output at all.
change_detected_by_round_numberboolThe independent round-number heuristic fired: exactly two outputs, one a non-zero round multiple of 1000 sat (the payment) and the other not (the change).
change_heuristics_agreeboolBoth heuristics fired and picked the same output. With the two flags above, all combinations — neither, either alone, both-agree, both-disagree — are recoverable.

05 · nSequence bits

BIP-125 / BIP-68 decomposition & the dead locktime

The nSequence field decomposed into its actual bit meaning, separating opt-in RBF from relative timelocks — and the interaction that renders a locktime inert.

bip125_rbfboolAny input signals opt-in RBF (< 0xFFFFFFFE).
all_inputs_finalboolEvery input is 0xFFFFFFFF — the condition that disables nLockTime.
bip68_activeboolv≥2 and an input has bit 31 clear — a BIP-68 relative timelock is in force.
bip68_type_timeboolAmong the BIP-68-active inputs, at least one measures its relative lock in 512-second units (bit 22) rather than blocks.
nsequence_reserved_bits_setboolA should-be-zero reserved bit (mask 0x7FBF0000) is set on a BIP-68-eligible (bit-31-clear) input — nonstandard construction that no known wallet sets deliberately.
bip68_relative_value_maxnumLargest relative-lock value (bits 0–15) among the transaction's BIP-68-active inputs.
nlocktime_deadboolNon-zero locktime that consensus ignores because all inputs are final — leaks a creation height, buys nothing.
nlocktime_optin_without_useboolThe mirror case: locktime is 0 yet an input signals RBF (< 0xFFFFFFFE) — opted into RBF but set no locktime.

06 · Counts & position

Per-type multiset and positional signal

Real per-type counts (a multiset, not a set), plus positional features — both the bounded first/last summary and a per-position type array capped at 10 — that capture the payment-vs-change ordering a count summary can't see, on both sides. The per-input/output type at each position comes from classify_script_pubkey; the counting, positioning, matching and grouping around it is survey — the raw input_count/output_count and the multisig card below are wholly survey.

Type counts
input_count · output_countnumRaw input and output counts — the transaction's size on each side, before any per-type breakdown.
input_count_{type} ×8numInputs of each script type. (input_count_op_return is structurally always 0.)
output_count_{type} ×8numOutputs of each script type, in p2pkh, p2sh, p2wpkh, p2wsh, p2tr, op_return, nonstandard, p2pk order.
legacy roll-upderivedThere is no dedicated legacy column — legacy input/output share is the sum of *_count_p2pkh + *_count_p2sh + *_count_p2pk (P2SH being wrapped-legacy).
Positional
first_output_type_index · last_output_type_indexordinalScript type of the first / last output (-1 if no outputs).
first_input_type_index · last_input_type_indexordinalInput-side mirror: script type (of the spent prevout) of the first / last input (-1 if no inputs).
first_output_matches_input_type · last_output_matches_input_typeboolInputs are uniform and the first/last output is that same type. last & ¬first = payment-then-change, unshuffled.
outputs_type_grouped · inputs_type_groupedboolSame-typed outputs / inputs are contiguous — evidence they were not shuffled.
input_type_at_pos_0..9 ×10ordinalType at each input position, capped at 10 (-1 when the position is absent). Positions ≥ 10 are discarded.
output_type_at_pos_0..9 ×10ordinalType at each output position, same cap and -1-absent convention.
Multisig configuration
multisig_m · multisig_nnumThe m-of-n of the spending inputs' multisig (the dominant input by largest n; 0/0 if none). Read from the bare prevout / P2SH redeem / P2WSH witness script (legacy OP_CHECKMULTISIG) and the taproot script-path tapscript (BIP-342 OP_CHECKSIGADD multi_a; thresholds > 16 pushed as data are not decoded). Quantifies the config input_subtype only flags. 2-of-3, 2-of-2, 3-of-5 are characteristic wallet setups.
multisig_mixedboolInputs carry two or more distinct (m, n) configs.

07 · Feerate

Precision, rounding & block-relative rate

Raw primitives so a consumer can infer the wallet's working unit and rounding, plus the rate relative to the fee market the wallet saw.

fee_sat · vsize · weightnumRaw fee (sat), virtual size (vB), weight (wu) — the three quantities every feerate and precision field below derives from.
feerate_sat_per_vbnumfee / vsize — the feerate unit most wallets target.
feerate_sat_per_kwunumfee·1000 / weight — the lightning / rust-bitcoin FeeRate convention.
fee_is_multiple_of_vsizeboolExact integer sat/vB — signature of sat/vB targeting.
fee_is_multiple_of_kwuboolExact integer sat/kwu (fee·1000 divisible by weight).
fee_is_multiple_of_weightboolExact integer sat/wu (fee % weight == 0) — the third precision unit; stricter than the sat/kwu flag, which it implies.
feerate_over_block_minnumRate ÷ the minimum feerate of its own block (-1 if none).
feerate_over_prev_block_minnumRate ÷ the previous block's minimum — the market visible at build time (-1 if none).
Not observable per-tx: the rounding direction (up/down) depends on the wallet's internal vsize/fee computation and leaves an ambiguous trace — the raw primitives are exposed; inference is the consumer's.

08 · Amounts

Hamming weight & bounded precision

How “round” the values are, measured over the transaction's outputs — a signal of human-typed vs machine-derived amounts.

max_output_value_satnumLargest output value (sat) — the basis every Hamming/precision measure below is computed from.
hamming_decimal · hamming_base2 · hamming_base3numNon-zero-digit count of the largest output in base 10 / 2 / 3 — fewer non-zero digits reads as a rounder amount to a human, regardless of which base they were reasoning in.
decimal_sig_fig_spannumSpan from most- to least-significant non-zero digit — separates 1.1 (2) from 1.00000001 (9) though both weigh 2.
hamming_decimal_min_over_outputsnumRoundest non-zero output in the tx (-1 if none).
distinct_output_value_countnumNumber of distinct output values. Few distinct values over many outputs is the coinjoin / denomination signature.
max_equal_value_output_countnumSize of the largest group of outputs sharing an identical value — a large equal-value cluster is the canonical mixing tell.

09 · Taproot

Script-tree depth
taproot_max_merkle_depthnumDeepest merkle path over script-path inputs, (control_len−33)/32 (annex-aware). 0 if none.
taproot_script_path_input_countnumNumber of taproot script-path inputs — the population taproot_max_merkle_depth is computed over.
taproot_keyspend_non_default_sighashboolAny taproot key-path input whose signature is 65 bytes (an explicit sighash byte) — finer than the tx-level sighash axis, which does not constrain key-path vs script-path.

10 · Standardness

IsStandard() per Bitcoin Core

A mined transaction that is non-standard bypassed default relay — a fingerprint of direct-to-miner submission or a permissive node. The reasons decompose which policy it broke.

is_standardboolPasses the modelled Core policy subset (negation of the six reasons).
nonstd_versionboolVersion ∉ {1,2,3}.
nonstd_weightboolWeight > 400,000 wu.
nonstd_output_typeboolA genuinely non-standard output script (excludes valid bare multisig & OP_RETURN).
nonstd_dustboolA non-OP_RETURN output below its dust threshold (3·(9+spk+67|148)).
nonstd_multi_op_returnboolMore than one OP_RETURN output.
nonstd_bare_multisigboolBare multisig with n > 3.

11 · Protocol

Ordinal / inscription markers
has_inscription_envelopeboolThe Ordinals/BRC-20 envelope OP_FALSE OP_IF "ord" (bytes 00 63 03 6f 72 64) appears in a taproot tapscript — high-certainty on a positive match, though a fragmented or non-canonical envelope can escape detection.
has_runestoneboolA Runestone: OP_RETURN whose second opcode is OP_PUSHNUM_13 (6a 5d).

13 · Aggregates

Report-time rollups (report.json)

Computed once per scan over all epochs (about 340 KB), derived from the joint-vector counts already gathered per epoch — no re-scan needed. These are what the dashboard reads per fingerprint; the per-tx matrix above is the primary output.

Per-value & conditionaldashboardThe dev-facing data: “how common is this fingerprint value, and how much does it isolate a wallet.”
window · totalsnumBlock range, epochs; transaction & defect counts — the run's metadata.
axis_marginals · axis_summariesnumPer-value counts, chain share, and min/max epoch share for every axis — the Explorer's per-fingerprint view.
conditional_anonymitynumPer CORE axis value, the distribution of CORE-joint anonymity-set sizes among the transactions that use it, and the share landing in a set < 10 / < 100 — the “how identifying is this value” number the dashboard leads with. Computed from the aggregated joint-vector map, no re-scan.
Derived views
template_seriesnumPer-epoch share of transactions consistent with a wallet template, keyed by era label (e.g. Name (software RANGE) for versioned entries, bare name for unversioned) — a narrower, wallet-shaped question than the per-axis summaries above, useful for tracking one specific wallet's chain share over time.
encoding_familiesnumOutput address-encoding family shares (base58 / bech32 / bech32m).
aux_flags · change_heuristic_abstention_ratenumAux-flag shares; how often the change heuristic abstains.