Change Address Heuristics¶
BlockSci provides a number of different heuristics for determining potential change outputs for a given transaction.
The heuristics are sometimes contradictory and thus we provide users with the ability to choose which heuristics they wish to apply.
Further, you can combine different change address heuristics through the various composition operators of the blocksci.heuristics.change.ChangeHeuristic
class.
-
class
blocksci.heuristics.
change
¶ -
class
ChangeHeuristic
¶ Class representing a change heuristic
-
__and__
(other_heuristic: blocksci.heuristics.change.ChangeHeuristic) → blocksci.heuristics.change.ChangeHeuristic¶ Return a new heuristic matching outputs that match both of the given heuristics
-
property
__call__
¶ Return all outputs matching the change heuristic
-
__or__
(other_heuristic: blocksci.heuristics.change.ChangeHeuristic) → blocksci.heuristics.change.ChangeHeuristic¶ Return a new heuristic matching outputs that match either of the given heuristics
-
__sub__
(other_heuristic: blocksci.heuristics.change.ChangeHeuristic) → blocksci.heuristics.change.ChangeHeuristic¶ Return a new heuristic matching outputs matched by the first heuristic unless they’re matched by the second heuristic
-
property
unique_change
¶ Return a new heuristic that will return a single output if it’s the only candidate output, and no outputs otherwise.
-
-
class
Note that many heuristics can return multiple outputs as candidates. To only return an output when there’s only a single candidate, use .unique_change. We recommend against simply using one of these heuristics without further refinement for clustering.
Static Heuristics¶
Static heuristics do not depend on the outputs being spent.
-
change.
address_reuse
= <blocksci.heuristics.change.ChangeHeuristic object>¶ If input addresses appear as an output address, the client might have reused addresses for change.
-
change.
address_type
= <blocksci.heuristics.change.ChangeHeuristic object>¶ If all inputs are of one address type (e.g., P2PKH or P2SH), it is likely that the change output has the same type.
-
change.
optimal_change
= <blocksci.heuristics.change.ChangeHeuristic object>¶ If there exists an output that is smaller than any of the inputs it is likely the change. If a change output was larger than the smallest input, then the coin selection algorithm wouldn’t need to add the input in the first place. (Note that if a transaction has only one input, all outputs are likely to have a value smaller than the input and will be returned).
-
blocksci.heuristics.change.
power_of_ten_value
(digits, tx=None)¶ Detects possible change outputs by excluding output values that are multiples of 10^`digits`, as such values are unlikely to occur randomly.
-
change.
client_change_address_behavior
= <blocksci.heuristics.change.ChangeHeuristic object>¶ Most clients will generate a fresh address for the change. If an output is the first to send value to an address, it is potentially the change.
-
change.
legacy
= <blocksci.heuristics.change.ChangeHeuristic object>¶ The original change address heuristic that was the default used in BlockSci before version 0.6.
Dynamic Heuristics¶
Dynamic heuristics depend on the state of the blockchain. If outputs of a transaction are spent, the results returned by the following heuristics can change.
-
change.
locktime
= <blocksci.heuristics.change.ChangeHeuristic object>¶ Bitcoin Core sets the locktime to the current block height to prevent fee sniping. If an output has been spent and it matches this transaction’s locktime behavior, it is possibly the change output. (This heuristic will return unspent outputs as potential candidates.)
-
change.
peeling_chain
= <blocksci.heuristics.change.ChangeHeuristic object>¶ If the transaction is a peeling chain, returns the outputs that continue the peeling chain. (This heuristic will return unspent outputs as potential candidates.)
Utility Heuristics¶
-
change.
none
= <blocksci.heuristics.change.ChangeHeuristic object>¶ This heuristics will never return any outputs, allowing it to be used to disable clustering based on change addresses.
-
change.
spent
= <blocksci.heuristics.change.ChangeHeuristic object>¶ Returns outputs that have been spent. Useful to exclude unspent outputs from dynamic heuristics that return unspent outputs as potential change outputs.
Using Composition Operators¶
You can use the union (|), intersection (&) and difference (-) operators to combine existing change address heuristics into new ones. This also works with unique_change. For example, the following heuristic would return a single change output only if the address reuse and the optimal change heuristics agree on a unique change output:
blocksci.heuristics.change.address_reuse.unique_change & blocksci.heuristics.change.optimal_change.unique_change
Similarly, if you want to remove unspent outputs from the output candidates returned by the blocksci.heuristics.change.locktime
heuristics, you can do the following:
blocksci.heuristics.change.locktime & blocksci.heuristics.change.spent